diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index e6889afb1f..31f00754f5 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -2,63 +2,104 @@ trigger: batch: true branches: include: - - master - - release-* + - '*' tags: include: - '*' +pr: + branches: + include: + - '*' jobs: - - job: main_build - displayName: 'Main Build' +- job: Build + displayName: 'Build' - dependsOn: lint - condition: succeeded() + strategy: + matrix: + Development: + BuildConfiguration: development + Production: + BuildConfiguration: production + Standalone: + BuildConfiguration: standalone - pool: - vmImage: 'ubuntu-latest' + pool: + vmImage: 'ubuntu-latest' - steps: - - task: NodeTool@0 - displayName: 'Install Node.js' - inputs: - versionSpec: '10.x' + steps: + - task: NodeTool@0 + displayName: 'Install Node' + inputs: + versionSpec: '12.x' - - script: | - yarn install - displayName: 'Install dependencies' + - task: Cache@2 + displayName: 'Check Cache' + inputs: + key: 'yarn | yarn.lock' + path: 'node_modules' + cacheHitVar: CACHE_RESTORED - - script: | - test -d dist - displayName: 'Check dist directory' + - script: 'yarn install --frozen-lockfile' + displayName: 'Install Dependencies' + condition: ne(variables.CACHE_RESTORED, 'true') - - script: | - yarn pack --filename jellyfin-web.tgz - displayName: 'Build package' + - script: 'yarn build:development' + displayName: 'Build Development' + condition: eq(variables['BuildConfiguration'], 'development') - - task: PublishPipelineArtifact@1 - displayName: 'Publish package' - condition: succeeded() - inputs: - targetPath: '$(Build.SourcesDirectory)/jellyfin-web.tgz' - artifactName: 'jellyfin-web' + - script: 'yarn build:production' + displayName: 'Build Bundle' + condition: eq(variables['BuildConfiguration'], 'production') - - job: lint - displayName: 'Lint' + - script: 'yarn build:standalone' + displayName: 'Build Standalone' + condition: eq(variables['BuildConfiguration'], 'standalone') - pool: - vmImage: 'ubuntu-latest' + - script: 'test -d dist' + displayName: 'Check Build' - steps: - - task: NodeTool@0 - displayName: 'Install Node.js' - inputs: - versionSpec: '10.x' + - script: 'mv dist jellyfin-web' + displayName: 'Rename Directory' - - script: | - yarn install - displayName: 'Install dependencies' + - task: ArchiveFiles@2 + displayName: 'Archive Directory' + inputs: + rootFolderOrFile: 'jellyfin-web' + includeRootFolder: true + archiveFile: 'jellyfin-web-$(BuildConfiguration)' - - script: | - yarn run lint - displayName: 'Run ESLint' + - task: PublishPipelineArtifact@1 + displayName: 'Publish Release' + inputs: + targetPath: '$(Build.SourcesDirectory)/jellyfin-web-$(BuildConfiguration).zip' + artifactName: 'jellyfin-web-$(BuildConfiguration)' + +- job: Lint + displayName: 'Lint' + + pool: + vmImage: 'ubuntu-latest' + + steps: + - task: NodeTool@0 + displayName: 'Install Node' + inputs: + versionSpec: '12.x' + + - task: Cache@2 + displayName: 'Check Cache' + inputs: + key: 'yarn | yarn.lock' + path: 'node_modules' + cacheHitVar: CACHE_RESTORED + + - script: 'yarn install --frozen-lockfile' + displayName: 'Install Dependencies' + condition: ne(variables.CACHE_RESTORED, 'true') + + - script: 'yarn run lint --quiet' + displayName: 'Run ESLint' + + - script: 'yarn run stylelint' + displayName: 'Run Stylelint' diff --git a/.copr/Makefile b/.copr/Makefile new file mode 120000 index 0000000000..ec3c90dfd9 --- /dev/null +++ b/.copr/Makefile @@ -0,0 +1 @@ +../fedora/Makefile \ No newline at end of file diff --git a/.dependabot/config.yml b/.dependabot/config.yml new file mode 100644 index 0000000000..02dfd18aac --- /dev/null +++ b/.dependabot/config.yml @@ -0,0 +1,5 @@ +version: 1 +update_configs: + - package_manager: "javascript" + directory: "/" + update_schedule: "weekly" diff --git a/.editorconfig b/.editorconfig index 81eba8ccc9..92cf9dc590 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,3 +7,6 @@ charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true end_of_line = lf + +[json] +indent_size = 2 diff --git a/.eslintignore b/.eslintignore index 52369be1e3..8e3aee83fb 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,5 @@ -libraries/ +node_modules +dist +.idea +.vscode +src/libraries diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..4a3fec9448 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,193 @@ +module.exports = { + root: true, + plugins: [ + 'promise', + 'import', + 'eslint-comments' + ], + env: { + node: true, + es6: true, + es2017: true, + es2020: true + }, + parserOptions: { + ecmaVersion: 2020, + sourceType: 'module', + ecmaFeatures: { + impliedStrict: true + } + }, + extends: [ + 'eslint:recommended', + // 'plugin:promise/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:eslint-comments/recommended', + 'plugin:compat/recommended' + ], + rules: { + 'block-spacing': ["error"], + 'brace-style': ["error"], + 'comma-dangle': ["error", "never"], + 'comma-spacing': ["error"], + 'eol-last': ["error"], + 'indent': ["error", 4, { "SwitchCase": 1 }], + 'keyword-spacing': ["error"], + 'max-statements-per-line': ["error"], + 'no-floating-decimal': ["error"], + 'no-multi-spaces': ["error"], + 'no-multiple-empty-lines': ["error", { "max": 1 }], + 'no-trailing-spaces': ["error"], + 'one-var': ["error", "never"], + 'quotes': ["error", "single", { "avoidEscape": true, "allowTemplateLiterals": false }], + 'semi': ["error"], + 'space-before-blocks': ["error"] + }, + overrides: [ + { + files: [ + './src/**/*.js' + ], + env: { + node: false, + amd: true, + browser: true, + es6: true, + es2017: true, + es2020: true + }, + globals: { + // Browser globals + 'MediaMetadata': 'readonly', + // Tizen globals + 'tizen': 'readonly', + 'webapis': 'readonly', + // WebOS globals + 'webOS': 'readonly', + // Dependency globals + '$': 'readonly', + 'jQuery': 'readonly', + 'requirejs': 'readonly', + // Jellyfin globals + 'ApiClient': 'writable', + 'AppInfo': 'writable', + 'chrome': 'writable', + 'ConnectionManager': 'writable', + 'DlnaProfilePage': 'writable', + 'Dashboard': 'writable', + 'DashboardPage': 'writable', + 'Emby': 'readonly', + 'Events': 'writable', + 'getParameterByName': 'writable', + 'getWindowLocationSearch': 'writable', + 'Globalize': 'writable', + 'Hls': 'writable', + 'dfnshelper': 'writable', + 'LibraryMenu': 'writable', + 'LinkParser': 'writable', + 'LiveTvHelpers': 'writable', + 'MetadataEditor': 'writable', + 'pageClassOn': 'writable', + 'pageIdOn': 'writable', + 'PlaylistViewer': 'writable', + 'UserParentalControlPage': 'writable', + 'Windows': 'readonly' + }, + rules: { + // TODO: Fix warnings and remove these rules + 'no-redeclare': ["warn"], + 'no-unused-vars': ["warn"], + 'no-useless-escape': ["warn"], + // TODO: Remove after ES6 migration is complete + 'import/no-unresolved': ["off"] + }, + settings: { + polyfills: [ + // Native Promises Only + 'Promise', + // whatwg-fetch + 'fetch', + // document-register-element + 'document.registerElement', + // resize-observer-polyfill + 'ResizeObserver', + // fast-text-encoding + 'TextEncoder', + // intersection-observer + 'IntersectionObserver', + // Core-js + 'Object.assign', + 'Object.is', + 'Object.setPrototypeOf', + 'Object.toString', + 'Object.freeze', + 'Object.seal', + 'Object.preventExtensions', + 'Object.isFrozen', + 'Object.isSealed', + 'Object.isExtensible', + 'Object.getOwnPropertyDescriptor', + 'Object.getPrototypeOf', + 'Object.keys', + 'Object.getOwnPropertyNames', + 'Function.name', + 'Function.hasInstance', + 'Array.from', + 'Array.arrayOf', + 'Array.copyWithin', + 'Array.fill', + 'Array.find', + 'Array.findIndex', + 'Array.iterator', + 'String.fromCodePoint', + 'String.raw', + 'String.iterator', + 'String.codePointAt', + 'String.endsWith', + 'String.includes', + 'String.repeat', + 'String.startsWith', + 'String.trim', + 'String.anchor', + 'String.big', + 'String.blink', + 'String.bold', + 'String.fixed', + 'String.fontcolor', + 'String.fontsize', + 'String.italics', + 'String.link', + 'String.small', + 'String.strike', + 'String.sub', + 'String.sup', + 'RegExp', + 'Number', + 'Math', + 'Date', + 'async', + 'Symbol', + 'Map', + 'Set', + 'WeakMap', + 'WeakSet', + 'ArrayBuffer', + 'DataView', + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array', + 'Reflect', + // Temporary while eslint-compat-plugin is buggy + 'document.querySelector' + ] + } + } + ] +} diff --git a/.eslintrc.yml b/.eslintrc.yml deleted file mode 100644 index b215e15800..0000000000 --- a/.eslintrc.yml +++ /dev/null @@ -1,27 +0,0 @@ -env: - es6: true - browser: true - amd: true - -rules: - block-spacing: ["error"] - brace-style: ["error"] - comma-dangle: ["error", "never"] - comma-spacing: ["error"] - eol-last: ["off"] - indent: ["error", 4, { "SwitchCase": 1 }] - keyword-spacing: ["error"] - line-comment-position: ["off"] - max-statements-per-line: ["error"] - no-empty: ["error"] - no-extra-semi: ["error"] - no-floating-decimal: ["error"] - no-multi-spaces: ["error"] - no-multiple-empty-lines: ["error", { "max": 1 }] - no-trailing-spaces: ["error"] - no-void: ["off"] - one-var: ["error", "never"] - padding-line-between-statements: ["off"] - semi: ["off"] - space-before-blocks: ["error"] - yoda: ["off"] diff --git a/.gitattributes b/.gitattributes index 80f9bc36ed..9e495a4df0 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,35 @@ -/CONTRIBUTORS.md merge=union +* text=auto + +CONTRIBUTORS.md merge=union +README.md text +LICENSE text + +*.css text +*.eot binary +*.gif binary +*.html text diff=html +*.ico binary +*.*ignore text +*.jpg binary +*.js text +*.json text +*.lock text -diff +*.map text -diff +*.md text +*.otf binary +*.png binary +*.py text diff=python +*.svg binary +*.ts text +*.ttf binary +*.sass text +*.vue text +*.webp binary +*.woff binary +*.woff2 binary + +.editorconfig text +.gitattributes export-ignore +.gitignore export-ignore + +*.gitattributes linguist-language=gitattributes diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..a35eb9981f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +.ci @dkanada @EraYaN +.github @jellyfin/core +build.sh @joshuaboniface +deployment @joshuaboniface diff --git a/.gitignore b/.gitignore index 2e12adf220..4adf9558bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,578 +1,11 @@ +# config +config.json -# Created by https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode -# Edit at https://www.gitignore.io/?templates=node,rider,macos,linux,windows,visualstudio,visualstudiocode +# npm +dist +web +node_modules -### Linux ### -*~ - -# temporary files which can be created if a process still has a handle open of a deleted file -.fuse_hidden* - -# KDE directory preferences -.directory - -# Linux trash folder which might appear on any partition or disk -.Trash-* - -# .nfs files are created when an open file is removed but is still being accessed -.nfs* - -### macOS ### -# General -.DS_Store -.AppleDouble -.LSOverride - -# Icon must end with two \r -Icon - -# Thumbnails -._* - -# Files that might appear in the root of a volume -.DocumentRevisions-V100 -.fseventsd -.Spotlight-V100 -.TemporaryItems -.Trashes -.VolumeIcon.icns -.com.apple.timemachine.donotpresent - -# Directories potentially created on remote AFP share -.AppleDB -.AppleDesktop -Network Trash Folder -Temporary Items -.apdisk - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Dependency lockfile -package-lock.json - -# TypeScript v1 declaration files -typings/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test - -# parcel-bundler cache (https://parceljs.org/) -.cache - -# next.js build output -.next - -# nuxt.js build output -.nuxt - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -### Rider ### -# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm -# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 - -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# Gradle and Maven with auto-import -# When using Gradle or Maven with auto-import, you should exclude module files, -# since they will be recreated, and may cause churn. Uncomment if using -# auto-import. -# .idea/modules.xml -# .idea/*.iml -# .idea/modules - -# CMake -cmake-build-*/ - -# Mongo Explorer plugin -.idea/**/mongoSettings.xml - -# File-based project format -*.iws - -# IntelliJ -out/ - -# mpeltonen/sbt-idea plugin -.idea_modules/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Cursive Clojure plugin -.idea/replstate.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties -fabric.properties - -# Editor-based Rest Client -.idea/httpRequests - -# Android studio 3.1+ serialized cache file -.idea/caches/build_file_checksums.ser - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history - -### Windows ### -# Windows thumbnail cache files -Thumbs.db -ehthumbs.db -ehthumbs_vista.db - -# Dump file -*.stackdump - -# Folder config file -[Dd]esktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Windows Installer files -*.cab -*.msi -*.msix -*.msm -*.msp - -# Windows shortcuts -*.lnk - -### VisualStudio ### -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ -# ASP.NET Core default setup: bower directory is configured as wwwroot/lib/ and bower restore is true -**/wwwroot/lib/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- Backup*.rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# End of https://www.gitignore.io/api/node,rider,macos,linux,windows,visualstudio,visualstudiocode - -# dist for webpack output -dist \ No newline at end of file +# ide +.idea +.vscode \ No newline at end of file diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 0000000000..a13acf428d --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,143 @@ +{ + "plugins": [ + "stylelint-no-browser-hacks/lib", + ], + "rules": { + "at-rule-empty-line-before": [ "always", { + except: [ + "blockless-after-same-name-blockless", + "first-nested", + ], + ignore: ["after-comment"], + } ], + "at-rule-name-case": "lower", + "at-rule-name-space-after": "always-single-line", + "at-rule-no-unknown": true, + "at-rule-semicolon-newline-after": "always", + "block-closing-brace-empty-line-before": "never", + "block-closing-brace-newline-after": "always", + "block-closing-brace-newline-before": "always-multi-line", + "block-closing-brace-space-before": "always-single-line", + "block-no-empty": true, + "block-opening-brace-newline-after": "always-multi-line", + "block-opening-brace-space-after": "always-single-line", + "block-opening-brace-space-before": "always", + "color-hex-case": "lower", + "color-hex-length": "short", + "color-no-invalid-hex": true, + "comment-empty-line-before": [ "always", { + except: ["first-nested"], + ignore: ["stylelint-commands"], + } ], + "comment-no-empty": true, + "comment-whitespace-inside": "always", + "custom-property-empty-line-before": [ "always", { + except: [ + "after-custom-property", + "first-nested", + ], + ignore: [ + "after-comment", + "inside-single-line-block", + ], + } ], + "declaration-bang-space-after": "never", + "declaration-bang-space-before": "always", + "declaration-block-no-duplicate-properties": [ + true, + { + ignore: ["consecutive-duplicates-with-different-values"] + } + ], + "declaration-block-no-shorthand-property-overrides": true, + "declaration-block-semicolon-newline-after": "always-multi-line", + "declaration-block-semicolon-space-after": "always-single-line", + "declaration-block-semicolon-space-before": "never", + "declaration-block-single-line-max-declarations": 1, + "declaration-block-trailing-semicolon": "always", + "declaration-colon-newline-after": "always-multi-line", + "declaration-colon-space-after": "always-single-line", + "declaration-colon-space-before": "never", + "font-family-no-duplicate-names": true, + "function-calc-no-invalid": true, + "function-calc-no-unspaced-operator": true, + "function-comma-newline-after": "always-multi-line", + "function-comma-space-after": "always-single-line", + "function-comma-space-before": "never", + "function-linear-gradient-no-nonstandard-direction": true, + "function-max-empty-lines": 0, + "function-name-case": "lower", + "function-parentheses-newline-inside": "always-multi-line", + "function-parentheses-space-inside": "never-single-line", + "function-whitespace-after": "always", + "indentation": 4, + "keyframe-declaration-no-important": true, + "length-zero-no-unit": true, + "max-empty-lines": 1, + "media-feature-colon-space-after": "always", + "media-feature-colon-space-before": "never", + "media-feature-name-case": "lower", + "media-feature-name-no-unknown": true, + "media-feature-parentheses-space-inside": "never", + "media-feature-range-operator-space-after": "always", + "media-feature-range-operator-space-before": "always", + "media-query-list-comma-newline-after": "always-multi-line", + "media-query-list-comma-space-after": "always-single-line", + "media-query-list-comma-space-before": "never", + "no-descending-specificity": true, + "no-duplicate-at-import-rules": true, + "no-duplicate-selectors": true, + "no-empty-source": true, + "no-eol-whitespace": true, + "no-extra-semicolons": true, + "no-invalid-double-slash-comments": true, + "no-missing-end-of-source-newline": true, + "number-leading-zero": "always", + "number-no-trailing-zeros": true, + "plugin/no-browser-hacks": true, + "property-case": "lower", + "property-no-unknown": [ + true, + { + "ignoreProperties": [ + "user-drag" + ] + } + ], + "rule-empty-line-before": [ "always-multi-line", { + except: ["first-nested"], + ignore: ["after-comment"], + } ], + "selector-attribute-brackets-space-inside": "never", + "selector-attribute-operator-space-after": "never", + "selector-attribute-operator-space-before": "never", + "selector-combinator-space-after": "always", + "selector-combinator-space-before": "always", + "selector-descendant-combinator-no-non-space": true, + "selector-list-comma-newline-after": "always", + "selector-list-comma-space-before": "never", + "selector-max-empty-lines": 0, + "selector-pseudo-class-case": "lower", + "selector-pseudo-class-no-unknown": true, + "selector-pseudo-class-parentheses-space-inside": "never", + "selector-pseudo-element-case": "lower", + "selector-pseudo-element-colon-notation": "double", + "selector-pseudo-element-no-unknown": [ + true, + { + "ignorePseudoElements": [ + "cue" + ] + } + ], + "selector-type-case": "lower", + "selector-type-no-unknown": true, + "string-no-newline": true, + "unit-case": "lower", + "unit-no-unknown": true, + "value-list-comma-newline-after": "always-multi-line", + "value-list-comma-space-after": "always-single-line", + "value-list-comma-space-before": "never", + "value-list-max-empty-lines": 0, + } +} diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e0855c1e09..2eae7e6933 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -32,6 +32,9 @@ - [bilde2910](https://github.com/bilde2910) - [Daniel Hartung](https://github.com/dhartung) - [Ryan Hartzell](https://github.com/ryan-hartzell) + - [Thibault Nocchi](https://github.com/ThibaultNocchi) + - [MrTimscampi](https://github.com/MrTimscampi) + - [Sarab Singh](https://github.com/sarab97) # Emby Contributors diff --git a/README.md b/README.md index 6a80b0b09c..e2aac6b155 100644 --- a/README.md +++ b/README.md @@ -45,20 +45,37 @@ Jellyfin Web is the frontend used for most of the clients available for end user ### Dependencies - Yarn +- Gulp-cli ### Getting Started 1. Clone or download this repository. + ```sh git clone https://github.com/jellyfin/jellyfin-web.git cd jellyfin-web ``` + 2. Install build dependencies in the project directory. + ```sh yarn install ``` 3. Run the web client with webpack for local development. + ```sh yarn serve ``` + +4. Build the client with sourcemaps. + + ```sh + yarn build:development + ``` + + You can build a nginx compatible version as well. + + ```sh + yarn build:standalone + ``` \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000000..9f5fa60229 --- /dev/null +++ b/build.sh @@ -0,0 +1,110 @@ +#!/usr/bin/env bash + +# build.sh - Build Jellyfin binary packages +# Part of the Jellyfin Project + +set -o errexit +set -o pipefail + +usage() { + echo -e "build.sh - Build Jellyfin binary packages" + echo -e "Usage:" + echo -e " $0 -t/--type -p/--platform [-k/--keep-artifacts] [-l/--list-platforms]" + echo -e "Notes:" + echo -e " * BUILD_TYPE can be one of: [native, docker] and must be specified" + echo -e " * native: Build using the build script in the host OS" + echo -e " * docker: Build using the build script in a standardized Docker container" + echo -e " * PLATFORM can be any platform shown by -l/--list-platforms and must be specified" + echo -e " * If -k/--keep-artifacts is specified, transient artifacts (e.g. Docker containers) will be" + echo -e " retained after the build is finished; the source directory will still be cleaned" + echo -e " * If -l/--list-platforms is specified, all other arguments are ignored; the script will print" + echo -e " the list of supported platforms and exit" +} + +list_platforms() { + declare -a platforms + platforms=( + $( find deployment -maxdepth 1 -mindepth 1 -name "build.*" | awk -F'.' '{ $1=""; printf $2; if ($3 != ""){ printf "." $3; }; if ($4 != ""){ printf "." $4; }; print ""; }' | sort ) + ) + echo -e "Valid platforms:" + echo + for platform in ${platforms[@]}; do + echo -e "* ${platform} : $( grep '^#=' deployment/build.${platform} | sed 's/^#= //' )" + done +} + +do_build_native() { + export IS_DOCKER=NO + deployment/build.${PLATFORM} +} + +do_build_docker() { + if ! dpkg --print-architecture | grep -q 'amd64'; then + echo "Docker-based builds only support amd64-based cross-building; use a 'native' build instead." + exit 1 + fi + if [[ ! -f deployment/Dockerfile.${PLATFORM} ]]; then + echo "Missing Dockerfile for platform ${PLATFORM}" + exit 1 + fi + if [[ ${KEEP_ARTIFACTS} == YES ]]; then + docker_args="" + else + docker_args="--rm" + fi + + docker build . -t "jellyfin-builder.${PLATFORM}" -f deployment/Dockerfile.${PLATFORM} + mkdir -p ${ARTIFACT_DIR} + docker run $docker_args -v "${SOURCE_DIR}:/jellyfin" -v "${ARTIFACT_DIR}:/dist" "jellyfin-builder.${PLATFORM}" +} + +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -t|--type) + BUILD_TYPE="$2" + shift + shift + ;; + -p|--platform) + PLATFORM="$2" + shift + shift + ;; + -k|--keep-artifacts) + KEEP_ARTIFACTS=YES + shift + ;; + -l|--list-platforms) + list_platforms + exit 0 + ;; + -h|--help) + usage + exit 0 + ;; + *) + echo "Unknown option $1" + usage + exit 1 + ;; + esac +done + +if [[ -z ${BUILD_TYPE} || -z ${PLATFORM} ]]; then + usage + exit 1 +fi + +export SOURCE_DIR="$( pwd )" +export ARTIFACT_DIR="${SOURCE_DIR}/../bin/${PLATFORM}" + +# Determine build type +case ${BUILD_TYPE} in + native) + do_build_native + ;; + docker) + do_build_docker + ;; +esac diff --git a/build.yaml b/build.yaml new file mode 100644 index 0000000000..fe1633faec --- /dev/null +++ b/build.yaml @@ -0,0 +1,9 @@ +--- +# We just wrap `build` so this is really it +name: "jellyfin-web" +version: "10.6.0" +packages: + - debian.all + - fedora.all + - centos.all + - portable diff --git a/bump_version b/bump_version new file mode 100755 index 0000000000..bc8288b829 --- /dev/null +++ b/bump_version @@ -0,0 +1,96 @@ +#!/usr/bin/env bash + +# bump_version - increase the shared version and generate changelogs + +set -o errexit +set -o pipefail + +usage() { + echo -e "bump_version - increase the shared version and generate changelogs" + echo -e "" + echo -e "Usage:" + echo -e " $ bump_version " +} + +if [[ -z $1 ]]; then + usage + exit 1 +fi + +shared_version_file="src/components/apphost.js" +build_file="./build.yaml" + +new_version="$1" + +# Parse the version from shared version file +old_version="$( + grep "appVersion" ${shared_version_file} | head -1 \ + | sed -E 's/var appVersion = "([0-9\.]+)";/\1/' +)" +echo "Old version in appHost is: $old_version" + +# Set the shared version to the specified new_version +old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars +new_version_sed="$( cut -f1 -d'-' <<<"${new_version}" )" +sed -i "s/${old_version_sed}/${new_version_sed}/g" ${shared_version_file} + +old_version="$( + grep "version:" ${build_file} \ + | sed -E 's/version: "([0-9\.]+[-a-z0-9]*)"/\1/' +)" +echo "Old version in ${build_file}: $old_version`" + +# Set the build.yaml version to the specified new_version +old_version_sed="$( sed 's/\./\\./g' <<<"${old_version}" )" # Escape the '.' chars +sed -i "s/${old_version_sed}/${new_version}/g" ${build_file} + +if [[ ${new_version} == *"-"* ]]; then + new_version_deb="$( sed 's/-/~/g' <<<"${new_version}" )" +else + new_version_deb="${new_version}-1" +fi + +# Write out a temporary Debian changelog with our new stuff appended and some templated formatting +debian_changelog_file="debian/changelog" +debian_changelog_temp="$( mktemp )" +# Create new temp file with our changelog +echo -e "jellyfin (${new_version_deb}) unstable; urgency=medium + + * New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version} + + -- Jellyfin Packaging Team $( date --rfc-2822 ) +" >> ${debian_changelog_temp} +cat ${debian_changelog_file} >> ${debian_changelog_temp} +# Move into place +mv ${debian_changelog_temp} ${debian_changelog_file} + +# Write out a temporary Yum changelog with our new stuff prepended and some templated formatting +fedora_spec_file="fedora/jellyfin.spec" +fedora_changelog_temp="$( mktemp )" +fedora_spec_temp_dir="$( mktemp -d )" +fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin.spec.tmp" +# Make a copy of our spec file for hacking +cp ${fedora_spec_file} ${fedora_spec_temp_dir}/ +pushd ${fedora_spec_temp_dir} +# Split out the stuff before and after changelog +csplit jellyfin.spec "/^%changelog/" # produces xx00 xx01 +# Update the version in xx00 +sed -i "s/${old_version_sed}/${new_version_sed}/g" xx00 +# Remove the header from xx01 +sed -i '/^%changelog/d' xx01 +# Create new temp file with our changelog +echo -e "%changelog +* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team +- New upstream version ${new_version}; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v${new_version}" >> ${fedora_changelog_temp} +cat xx01 >> ${fedora_changelog_temp} +# Reassembble +cat xx00 ${fedora_changelog_temp} > ${fedora_spec_temp} +popd +# Move into place +mv ${fedora_spec_temp} ${fedora_spec_file} +# Clean up +rm -rf ${fedora_changelog_temp} ${fedora_spec_temp_dir} + +# Stage the changed files for commit +git add ${shared_version_file} ${build_file} ${debian_changelog_file} ${fedora_spec_file} Dockerfile* +git status diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000000..50966c3a01 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +jellyfin-web (10.6.0-1) unstable; urgency=medium + + * New upstream version 10.6.0; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.0 + + -- Jellyfin Packaging Team Mon, 16 Mar 2020 11:15:00 -0400 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000000..45a4fb75db --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +8 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000000..ce7b130efc --- /dev/null +++ b/debian/control @@ -0,0 +1,16 @@ +Source: jellyfin-web +Section: misc +Priority: optional +Maintainer: Jellyfin Team +Build-Depends: debhelper (>= 9), + npm | nodejs +Standards-Version: 3.9.4 +Homepage: https://jellyfin.org/ +Vcs-Git: https://github.org/jellyfin/jellyfin-web.git +Vcs-Browser: https://github.org/jellyfin/jellyfin-web + +Package: jellyfin-web +Recommends: jellyfin-server +Architecture: all +Description: Jellyfin is the Free Software Media System. + This package provides the Jellyfin web client. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000000..85548075eb --- /dev/null +++ b/debian/copyright @@ -0,0 +1,28 @@ +Format: http://dep.debian.net/deps/dep5 +Upstream-Name: jellyfin-web +Source: https://github.com/jellyfin/jellyfin-web + +Files: * +Copyright: 2018-2020 Jellyfin Team +License: GPL-3.0 + +Files: debian/* +Copyright: 2020 Joshua Boniface +License: GPL-3.0 + +License: GPL-3.0 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this program. If not, see + . + On Debian systems, the complete text of the GNU General + Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". diff --git a/debian/gbp.conf b/debian/gbp.conf new file mode 100644 index 0000000000..60b3d28723 --- /dev/null +++ b/debian/gbp.conf @@ -0,0 +1,6 @@ +[DEFAULT] +pristine-tar = False +cleaner = fakeroot debian/rules clean + +[import-orig] +filter = [ ".git*", ".hg*", ".vs*", ".vscode*" ] diff --git a/debian/install b/debian/install new file mode 100644 index 0000000000..584fe06a11 --- /dev/null +++ b/debian/install @@ -0,0 +1 @@ +web usr/share/jellyfin/ diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 0000000000..cef83a3407 --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] templates diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 0000000000..2cdcae4173 --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,57 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: jellyfin-server\n" +"Report-Msgid-Bugs-To: jellyfin-server@packages.debian.org\n" +"POT-Creation-Date: 2015-06-12 20:51-0600\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: note +#. Description +#: ../templates:1001 +msgid "Jellyfin permission info:" +msgstr "" + +#. Type: note +#. Description +#: ../templates:1001 +msgid "" +"Jellyfin by default runs under a user named \"jellyfin\". Please ensure that the " +"user jellyfin has read and write access to any folders you wish to add to your " +"library. Otherwise please run jellyfin under a different user." +msgstr "" + +#. Type: string +#. Description +#: ../templates:2001 +msgid "Username to run Jellyfin as:" +msgstr "" + +#. Type: string +#. Description +#: ../templates:2001 +msgid "The user that jellyfin will run as." +msgstr "" + +#. Type: note +#. Description +#: ../templates:3001 +msgid "Jellyfin still running" +msgstr "" + +#. Type: note +#. Description +#: ../templates:3001 +msgid "Jellyfin is currently running. Please close it and try again." +msgstr "" diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000000..f3e568225c --- /dev/null +++ b/debian/rules @@ -0,0 +1,20 @@ +#! /usr/bin/make -f +export DH_VERBOSE=1 + +%: + dh $@ + +# disable "make check" +override_dh_auto_test: + +# disable stripping debugging symbols +override_dh_clistrip: + +override_dh_auto_build: + npx yarn install + mv $(CURDIR)/dist $(CURDIR)/web + +override_dh_auto_clean: + test -d $(CURDIR)/dist && rm -rf '$(CURDIR)/dist' || true + test -d $(CURDIR)/web && rm -rf '$(CURDIR)/web' || true + test -d $(CURDIR)/node_modules && rm -rf '$(CURDIR)/node_modules' || true diff --git a/debian/source/format b/debian/source/format new file mode 100644 index 0000000000..d3827e75a5 --- /dev/null +++ b/debian/source/format @@ -0,0 +1 @@ +1.0 diff --git a/debian/source/options b/debian/source/options new file mode 100644 index 0000000000..b7adf56c67 --- /dev/null +++ b/debian/source/options @@ -0,0 +1,7 @@ +tar-ignore='.git*' +tar-ignore='**/.git' +tar-ignore='**/.hg' +tar-ignore='**/.vs' +tar-ignore='**/.vscode' +tar-ignore='deployment' +tar-ignore='*.deb' diff --git a/deployment/Dockerfile.centos.all b/deployment/Dockerfile.centos.all new file mode 100644 index 0000000000..93bf8d6988 --- /dev/null +++ b/deployment/Dockerfile.centos.all @@ -0,0 +1,27 @@ +FROM centos:7 +# Docker build arguments +ARG SOURCE_DIR=/jellyfin +ARG ARTIFACT_DIR=/dist +# Docker run environment +ENV SOURCE_DIR=/jellyfin +ENV ARTIFACT_DIR=/dist +ENV IS_DOCKER=YES + +# Prepare CentOS environment +RUN yum update -y \ + && yum install -y epel-release \ + && yum install -y @buildsys-build rpmdevtools git yum-plugins-core nodejs-yarn autoconf automake glibc-devel + +# Install recent NodeJS and Yarn +RUN curl -fSsLo /etc/yum.repos.d/yarn.repo https://dl.yarnpkg.com/rpm/yarn.repo \ + && rpm -i https://rpm.nodesource.com/pub_10.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm \ + && yum install -y yarn + +# Link to build script +RUN ln -sf ${SOURCE_DIR}/deployment/build.centos.all /build.sh + +VOLUME ${SOURCE_DIR}/ + +VOLUME ${ARTIFACT_DIR}/ + +ENTRYPOINT ["/build.sh"] diff --git a/deployment/Dockerfile.debian.all b/deployment/Dockerfile.debian.all new file mode 100644 index 0000000000..54281a5eb4 --- /dev/null +++ b/deployment/Dockerfile.debian.all @@ -0,0 +1,25 @@ +FROM debian:10 +# Docker build arguments +ARG SOURCE_DIR=/jellyfin +ARG ARTIFACT_DIR=/dist +# Docker run environment +ENV SOURCE_DIR=/jellyfin +ENV ARTIFACT_DIR=/dist +ENV DEB_BUILD_OPTIONS=noddebs +ENV IS_DOCKER=YES + +# Prepare Debian build environment +RUN apt-get update \ + && apt-get install -y debhelper mmv npm git + +# Prepare Yarn +RUN npm install -g yarn + +# Link to build script +RUN ln -sf ${SOURCE_DIR}/deployment/build.debian.all /build.sh + +VOLUME ${SOURCE_DIR}/ + +VOLUME ${ARTIFACT_DIR}/ + +ENTRYPOINT ["/build.sh"] diff --git a/deployment/Dockerfile.fedora.all b/deployment/Dockerfile.fedora.all new file mode 100644 index 0000000000..d47f4ff4da --- /dev/null +++ b/deployment/Dockerfile.fedora.all @@ -0,0 +1,21 @@ +FROM fedora:31 +# Docker build arguments +ARG SOURCE_DIR=/jellyfin +ARG ARTIFACT_DIR=/dist +# Docker run environment +ENV SOURCE_DIR=/jellyfin +ENV ARTIFACT_DIR=/dist +ENV IS_DOCKER=YES + +# Prepare Fedora environment +RUN dnf update -y \ + && dnf install -y @buildsys-build rpmdevtools git dnf-plugins-core nodejs-yarn autoconf automake glibc-devel + +# Link to build script +RUN ln -sf ${SOURCE_DIR}/deployment/build.fedora.all /build.sh + +VOLUME ${SOURCE_DIR}/ + +VOLUME ${ARTIFACT_DIR}/ + +ENTRYPOINT ["/build.sh"] diff --git a/deployment/Dockerfile.portable b/deployment/Dockerfile.portable new file mode 100644 index 0000000000..e0d1f45265 --- /dev/null +++ b/deployment/Dockerfile.portable @@ -0,0 +1,25 @@ +FROM debian:10 +# Docker build arguments +ARG SOURCE_DIR=/jellyfin +ARG ARTIFACT_DIR=/dist +# Docker run environment +ENV SOURCE_DIR=/jellyfin +ENV ARTIFACT_DIR=/dist +ENV DEB_BUILD_OPTIONS=noddebs +ENV IS_DOCKER=YES + +# Prepare Debian build environment +RUN apt-get update \ + && apt-get install -y mmv npm git + +# Prepare Yarn +RUN npm install -g yarn + +# Link to build script +RUN ln -sf ${SOURCE_DIR}/deployment/build.portable /build.sh + +VOLUME ${SOURCE_DIR}/ + +VOLUME ${ARTIFACT_DIR}/ + +ENTRYPOINT ["/build.sh"] diff --git a/deployment/build.centos.all b/deployment/build.centos.all new file mode 100755 index 0000000000..8c2cec6d33 --- /dev/null +++ b/deployment/build.centos.all @@ -0,0 +1,27 @@ +#!/bin/bash + +#= CentOS 7 all .rpm + +set -o errexit +set -o xtrace + +# Move to source directory +pushd ${SOURCE_DIR} + +cp -a yarn.lock /tmp/yarn.lock + +# Build RPM +make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS +rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm + +# Move the artifacts out +mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/ + +if [[ ${IS_DOCKER} == YES ]]; then + chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} +fi + +rm -f fedora/jellyfin*.tar.gz +cp -a /tmp/yarn.lock yarn.lock + +popd diff --git a/deployment/build.debian.all b/deployment/build.debian.all new file mode 100755 index 0000000000..8d617a288e --- /dev/null +++ b/deployment/build.debian.all @@ -0,0 +1,25 @@ +#!/bin/bash + +#= Debian/Ubuntu all .deb + +set -o errexit +set -o xtrace + +# Move to source directory +pushd ${SOURCE_DIR} + +cp -a yarn.lock /tmp/yarn.lock + +# Build DEB +dpkg-buildpackage -us -uc --pre-clean --post-clean + +mkdir -p ${ARTIFACT_DIR}/ +mv ../jellyfin*.{deb,dsc,tar.gz,buildinfo,changes} ${ARTIFACT_DIR}/ + +cp -a /tmp/yarn.lock yarn.lock + +if [[ ${IS_DOCKER} == YES ]]; then + chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} +fi + +popd diff --git a/deployment/build.fedora.all b/deployment/build.fedora.all new file mode 100755 index 0000000000..4ba12f35ea --- /dev/null +++ b/deployment/build.fedora.all @@ -0,0 +1,27 @@ +#!/bin/bash + +#= Fedora 29+ all .rpm + +set -o errexit +set -o xtrace + +# Move to source directory +pushd ${SOURCE_DIR} + +cp -a yarn.lock /tmp/yarn.lock + +# Build RPM +make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS +rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm + +# Move the artifacts out +mv /root/rpmbuild/RPMS/noarch/jellyfin-*.rpm /root/rpmbuild/SRPMS/jellyfin-*.src.rpm ${ARTIFACT_DIR}/ + +if [[ ${IS_DOCKER} == YES ]]; then + chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} +fi + +rm -f fedora/jellyfin*.tar.gz +cp -a /tmp/yarn.lock yarn.lock + +popd diff --git a/deployment/build.portable b/deployment/build.portable new file mode 100755 index 0000000000..c4cbe927e4 --- /dev/null +++ b/deployment/build.portable @@ -0,0 +1,28 @@ +#!/bin/bash + +#= Portable .NET DLL .tar.gz + +set -o errexit +set -o xtrace + +# Move to source directory +pushd ${SOURCE_DIR} + +# Get version +version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )" + +# Build archives +npx yarn install +mv dist/ jellyfin-web_${version} +tar -czf jellyfin-web_${version}_portable.tar.gz jellyfin-web_${version} +rm -rf dist/ + +# Move the artifacts out +mkdir -p ${ARTIFACT_DIR}/ +mv jellyfin[-_]*.tar.gz ${ARTIFACT_DIR}/ + +if [[ ${IS_DOCKER} == YES ]]; then + chown -Rc $(stat -c %u:%g ${ARTIFACT_DIR}) ${ARTIFACT_DIR} +fi + +popd diff --git a/fedora/Makefile b/fedora/Makefile new file mode 100644 index 0000000000..1d3e39ac8b --- /dev/null +++ b/fedora/Makefile @@ -0,0 +1,21 @@ +VERSION := $(shell sed -ne '/^Version:/s/.* *//p' fedora/jellyfin-web.spec) + +srpm: + cd fedora/; \ + SOURCE_DIR=.. \ + WORKDIR="$${PWD}"; \ + tar \ + --transform "s,^\.,jellyfin-web-$(VERSION)," \ + --exclude='.git*' \ + --exclude='**/.git' \ + --exclude='**/.hg' \ + --exclude='deployment' \ + --exclude='*.deb' \ + --exclude='*.rpm' \ + --exclude='jellyfin-web-$(VERSION).tar.gz' \ + -czf "jellyfin-web-$(VERSION).tar.gz" \ + -C $${SOURCE_DIR} ./ + cd fedora/; \ + rpmbuild -bs jellyfin-web.spec \ + --define "_sourcedir $$PWD/" \ + --define "_srcrpmdir $(outdir)" diff --git a/fedora/jellyfin-web.spec b/fedora/jellyfin-web.spec new file mode 100644 index 0000000000..dbc0bd0efa --- /dev/null +++ b/fedora/jellyfin-web.spec @@ -0,0 +1,43 @@ +%global debug_package %{nil} + +Name: jellyfin-web +Version: 10.6.0 +Release: 1%{?dist} +Summary: The Free Software Media System web client +License: GPLv3 +URL: https://jellyfin.org +# Jellyfin Server tarball created by `make -f .copr/Makefile srpm`, real URL ends with `v%{version}.tar.gz` +Source0: jellyfin-web-%{version}.tar.gz + +%if 0%{?centos} +BuildRequires: yarn +%else +BuildRequires nodejs-yarn +%endif +BuildArch: noarch + +# Disable Automatic Dependency Processing +AutoReqProv: no + +%description +Jellyfin is a free software media system that puts you in control of managing and streaming your media. + + +%prep +%autosetup -n jellyfin-web-%{version} -b 0 + +%build + +%install +yarn install +%{__mkdir} -p %{buildroot}%{_datadir} +mv dist %{buildroot}%{_datadir}/jellyfin-web +%{__install} -D -m 0644 LICENSE %{buildroot}%{_datadir}/licenses/jellyfin/LICENSE + +%files +%attr(755,root,root) %{_datadir}/jellyfin-web +%{_datadir}/licenses/jellyfin/LICENSE + +%changelog +* Mon Mar 23 2020 Jellyfin Packaging Team +- Forthcoming stable release diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000000..6c33167386 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,205 @@ +const { src, dest, series, parallel, watch } = require('gulp'); +const browserSync = require('browser-sync').create(); +const del = require('del'); +const babel = require('gulp-babel'); +const concat = require('gulp-concat'); +const terser = require('gulp-terser'); +const htmlmin = require('gulp-htmlmin'); +const imagemin = require('gulp-imagemin'); +const sourcemaps = require('gulp-sourcemaps'); +const mode = require('gulp-mode')({ + modes: ['development', 'production'], + default: 'development', + verbose: false +}); +const stream = require('webpack-stream'); +const inject = require('gulp-inject'); +const postcss = require('gulp-postcss'); +const sass = require('gulp-sass'); +const gulpif = require('gulp-if'); +const lazypipe = require('lazypipe'); + +sass.compiler = require('node-sass'); + +let config; +if (mode.production()) { + config = require('./webpack.prod.js'); +} else { + config = require('./webpack.dev.js'); +} + +const options = { + javascript: { + query: ['src/**/*.js', '!src/bundle.js', '!src/standalone.js', '!src/scripts/apploader.js'] + }, + apploader: { + query: ['src/standalone.js', 'src/scripts/apploader.js'] + }, + css: { + query: ['src/**/*.css', 'src/**/*.scss'] + }, + html: { + query: ['src/**/*.html', '!src/index.html'] + }, + images: { + query: ['src/**/*.png', 'src/**/*.jpg', 'src/**/*.gif', 'src/**/*.svg'] + }, + copy: { + query: ['src/**/*.json', 'src/**/*.ico'] + }, + injectBundle: { + query: 'src/index.html' + } +}; + +function serve() { + browserSync.init({ + server: { + baseDir: './dist' + }, + port: 8080 + }); + + const events = ['add', 'change']; + + watch(options.javascript.query).on('all', function (event, path) { + if (events.includes(event)) { + javascript(path); + } + }); + + watch(options.apploader.query, apploader(true)); + + watch('src/bundle.js', webpack); + + watch(options.css.query).on('all', function (event, path) { + if (events.includes(event)) { + css(path); + } + }); + + watch(options.html.query).on('all', function (event, path) { + if (events.includes(event)) { + html(path); + } + }); + + watch(options.images.query).on('all', function (event, path) { + if (events.includes(event)) { + images(path); + } + }); + + watch(options.copy.query).on('all', function (event, path) { + if (events.includes(event)) { + copy(path); + } + }); + + watch(options.injectBundle.query, injectBundle); +} + +function clean() { + return del(['dist/']); +} + +const pipelineJavascript = lazypipe() + .pipe(function () { + return mode.development(sourcemaps.init({ loadMaps: true })); + }) + .pipe(function () { + return babel({ + presets: [ + ['@babel/preset-env'] + ] + }); + }) + .pipe(function () { + return terser({ + keep_fnames: true, + mangle: false + }); + }) + .pipe(function () { + return mode.development(sourcemaps.write('.')); + }); + +function javascript(query) { + return src(typeof query !== 'function' ? query : options.javascript.query, { base: './src/' }) + .pipe(pipelineJavascript()) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function apploader(standalone) { + function task() { + return src(options.apploader.query, { base: './src/' }) + .pipe(gulpif(standalone, concat('scripts/apploader.js'))) + .pipe(pipelineJavascript()) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); + } + + task.displayName = 'apploader'; + + return task; +} + +function webpack() { + return stream(config) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function css(query) { + return src(typeof query !== 'function' ? query : options.css.query, { base: './src/' }) + .pipe(mode.development(sourcemaps.init({ loadMaps: true }))) + .pipe(sass().on('error', sass.logError)) + .pipe(postcss()) + .pipe(mode.development(sourcemaps.write('.'))) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function html(query) { + return src(typeof query !== 'function' ? query : options.html.query, { base: './src/' }) + .pipe(mode.production(htmlmin({ collapseWhitespace: true }))) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function images(query) { + return src(typeof query !== 'function' ? query : options.images.query, { base: './src/' }) + .pipe(mode.production(imagemin())) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function copy(query) { + return src(typeof query !== 'function' ? query : options.copy.query, { base: './src/' }) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function copyIndex() { + return src(options.injectBundle.query, { base: './src/' }) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function injectBundle() { + return src(options.injectBundle.query, { base: './src/' }) + .pipe(inject( + src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), { relative: true } + )) + .pipe(dest('dist/')) + .pipe(browserSync.stream()); +} + +function build(standalone) { + return series(clean, parallel(javascript, apploader(standalone), webpack, css, html, images, copy)); +} + +exports.default = series(build(false), copyIndex); +exports.standalone = series(build(true), injectBundle); +exports.serve = series(exports.standalone, serve); diff --git a/package.json b/package.json index 76d01b1841..e8e204de8e 100644 --- a/package.json +++ b/package.json @@ -5,39 +5,113 @@ "repository": "https://github.com/jellyfin/jellyfin-web", "license": "GPL-2.0-or-later", "devDependencies": { - "autoprefixer": "^9.7.3", + "@babel/core": "^7.9.6", + "@babel/plugin-transform-modules-amd": "^7.9.6", + "@babel/polyfill": "^7.8.7", + "@babel/preset-env": "^7.8.6", + "autoprefixer": "^9.7.6", + "babel-loader": "^8.0.6", + "browser-sync": "^2.26.7", "clean-webpack-plugin": "^3.0.0", "copy-webpack-plugin": "^5.1.1", - "css-loader": "^2.1.0", - "eslint": "^5.16.0", - "file-loader": "^3.0.1", - "html-webpack-plugin": "^3.2.0", + "css-loader": "^3.4.2", + "cssnano": "^4.1.10", + "del": "^5.1.0", + "eslint": "^6.8.0", + "eslint-plugin-compat": "^3.5.1", + "eslint-plugin-eslint-comments": "^3.1.2", + "eslint-plugin-import": "^2.20.2", + "eslint-plugin-promise": "^4.2.1", + "file-loader": "^6.0.0", + "gulp": "^4.0.2", + "gulp-babel": "^8.0.0", + "gulp-cli": "^2.2.0", + "gulp-concat": "^2.6.1", + "gulp-htmlmin": "^5.0.1", + "gulp-if": "^3.0.0", + "gulp-imagemin": "^7.1.0", + "gulp-inject": "^5.0.5", + "gulp-mode": "^1.0.2", + "gulp-postcss": "^8.0.0", + "gulp-sass": "^4.0.2", + "gulp-sourcemaps": "^2.6.5", + "gulp-terser": "^1.2.0", + "html-webpack-plugin": "^4.3.0", + "lazypipe": "^1.0.2", + "node-sass": "^4.13.1", "postcss-loader": "^3.0.0", - "style-loader": "^0.23.1", - "webpack": "^4.41.0", - "webpack-cli": "^3.3.9", + "postcss-preset-env": "^6.7.0", + "style-loader": "^1.1.3", + "stylelint": "^13.3.3", + "stylelint-config-rational-order": "^0.1.2", + "stylelint-no-browser-hacks": "^1.2.1", + "stylelint-order": "^4.0.0", + "webpack": "^4.41.5", + "webpack-cli": "^3.3.10", "webpack-concat-plugin": "^3.0.0", - "webpack-dev-server": "^3.8.1", - "webpack-merge": "^4.2.2" + "webpack-dev-server": "^3.10.3", + "webpack-merge": "^4.2.2", + "webpack-stream": "^5.2.1" }, "dependencies": { - "alameda": "^1.3.0", - "document-register-element": "^0.5.4", + "alameda": "^1.4.0", + "classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", + "core-js": "^3.6.5", + "date-fns": "^2.13.0", + "document-register-element": "^1.14.3", + "fast-text-encoding": "^1.0.1", "flv.js": "^1.5.0", - "hls.js": "^0.12.4", - "howler": "^2.1.2", - "jquery": "^3.4.1", + "headroom.js": "^0.11.0", + "hls.js": "^0.13.1", + "howler": "^2.1.3", + "intersection-observer": "^0.10.0", + "jellyfin-apiclient": "^1.1.1", + "jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto", + "jquery": "^3.5.1", "jstree": "^3.3.7", - "libjass": "^0.11.0", + "libass-wasm": "https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv", + "material-design-icons-iconfont": "^5.0.1", "native-promise-only": "^0.8.0-a", - "requirejs": "^2.3.5", + "page": "^1.11.6", + "query-string": "^6.11.1", "resize-observer-polyfill": "^1.5.1", - "shaka-player": "^2.5.5", - "sortablejs": "^1.9.0", - "swiper": "^3.4.2", - "libass-wasm": "^2.1.1", + "screenfull": "^5.0.2", + "shaka-player": "^2.5.11", + "sortablejs": "^1.10.2", + "swiper": "^5.3.7", "webcomponents.js": "^0.7.24", - "whatwg-fetch": "^1.1.1" + "whatwg-fetch": "^3.0.0" + }, + "babel": { + "presets": [ + "@babel/preset-env" + ], + "overrides": [ + { + "test": [ + "src/components/autoFocuser.js", + "src/components/cardbuilder/cardBuilder.js", + "src/components/filedownloader.js", + "src/components/images/imageLoader.js", + "src/components/lazyloader/lazyloader-intersectionobserver.js", + "src/components/playback/mediasession.js", + "src/components/sanatizefilename.js", + "src/components/scrollManager.js", + "src/scripts/dfnshelper.js", + "src/scripts/dom.js", + "src/scripts/filesystem.js", + "src/scripts/imagehelper.js", + "src/scripts/inputManager.js", + "src/scripts/keyboardnavigation.js", + "src/scripts/settings/appSettings.js", + "src/scripts/settings/userSettings.js", + "src/scripts/settings/webSettings.js" + ], + "plugins": [ + "@babel/plugin-transform-modules-amd" + ] + } + ] }, "browserslist": [ "last 2 Firefox versions", @@ -46,18 +120,21 @@ "last 2 Safari versions", "last 2 iOS versions", "last 2 Edge versions", + "Chrome 27", "Chrome 38", "Chrome 47", "Chrome 53", "Chrome 56", "Chrome 63", - "Explorer 11", "Firefox ESR" ], "scripts": { - "serve": "webpack-dev-server --config webpack.dev.js --open", - "build": "webpack --config webpack.prod.js", - "lint": "eslint \"src\"", - "prepare": "webpack --config webpack.prod.js" + "serve": "gulp serve --development", + "prepare": "gulp --production", + "build:development": "gulp --development", + "build:production": "gulp --production", + "build:standalone": "gulp standalone --development", + "lint": "eslint \".\"", + "stylelint": "stylelint \"src/**/*.css\"" } } diff --git a/postcss.config.js b/postcss.config.js index a26de7e9f1..bd1651fa19 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,16 @@ -module.exports = { +const packageConfig = require('./package.json'); +const postcssPresetEnv = require('postcss-preset-env'); +const autoprefixer = require('autoprefixer'); +const cssnano = require('cssnano'); + +const config = () => ({ plugins: [ - require('autoprefixer') + // Explicitly specify browserslist to override ones from node_modules + // For example, Swiper has it in its package.json + postcssPresetEnv({browsers: packageConfig.browserslist}), + autoprefixer({overrideBrowserslist: packageConfig.browserslist}), + cssnano() ] -} +}); + +module.exports = config; diff --git a/scripts/scdup.py b/scripts/scdup.py new file mode 100644 index 0000000000..468e31f14a --- /dev/null +++ b/scripts/scdup.py @@ -0,0 +1,41 @@ +import sys +import os +import json + +# load every key in the source language +# check the keys in all translations +# remove keys that only exist in translations + +cwd = os.getcwd() +langdir = cwd + '/../src/strings' +langlst = os.listdir(langdir) + +langlst.remove('en-us.json') +print(langlst) +input('press enter to continue') + +keysus = [] +with open(langdir + '/' + 'en-us.json') as en: + langus = json.load(en) + for key in langus: + keysus.append(key) + +for lang in langlst: + with open(langdir + '/' + lang, 'r') as f: + inde = 2 + if '\n \"' in f.read(): + inde = 4 + f.close() + with open(langdir + '/' + lang, 'r+') as f: + langjson = json.load(f) + langjnew = {} + for key in langjson: + if key in keysus: + langjnew[key] = langjson[key] + f.seek(0) + f.write(json.dumps(langjnew, indent=inde, sort_keys=False, ensure_ascii=False)) + f.write('\n') + f.truncate() + f.close() + +print('DONE') diff --git a/scripts/scgen.py b/scripts/scgen.py new file mode 100644 index 0000000000..0d831426e6 --- /dev/null +++ b/scripts/scgen.py @@ -0,0 +1,40 @@ +import os +import subprocess +import json + +# load all keys in the source language +# check entire codebase for usages +# print unused keys to a text file +# TODO: dynamic string usages cause false positives + +cwd = os.getcwd() +langdir = cwd + '/../src/strings' +langlst = [] +langlst.append('en-us.json') + +# unused keys +dep = [] + +def grep(key): + command = 'grep -r -E "(\(\\\"|\(\'|\{)%s(\\\"|\'|\})" --include=\*.{js,html} --exclude-dir=../src/strings ../src' % key + p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + output = p.stdout.readlines() + if output: + print('DONE: ' + key) + return True + print('UNUSED: ' + key) + dep.append(key) + return False + +for lang in langlst: + with open(langdir + '/' + lang) as f: + langjson = json.load(f) + for key in langjson: + grep(key) + +print(dep) +print('LENGTH: ' + str(len(dep))) +with open('scout.txt', 'w') as out: + for item in dep: + out.write(item + '\n') + out.close() diff --git a/scripts/scrm.py b/scripts/scrm.py new file mode 100644 index 0000000000..9bd5bc2a48 --- /dev/null +++ b/scripts/scrm.py @@ -0,0 +1,34 @@ +import sys +import os +import json + +# load text file containing unused keys +# remove the keys from all string files + +cwd = os.getcwd() +langdir = cwd + '/../src/strings' +langlst = os.listdir(langdir) + +keys = [] + +with open('scout.txt', 'r') as f: + for line in f: + keys.append(line.strip('\n')) + +for lang in langlst: + with open(langdir + '/' + lang, 'r') as f: + inde = 2 + if '\n \"' in f.read(): + inde = 4 + f.close() + with open(langdir + '/' + lang, 'r+') as f: + langjson = json.load(f) + for key in keys: + langjson.pop(key, None) + f.seek(0) + f.write(json.dumps(langjson, indent=inde, sort_keys=False, ensure_ascii=False)) + f.write('\n') + f.truncate() + f.close() + +print('DONE') diff --git a/src/addplugin.html b/src/addplugin.html index 83640033bb..81c671d5bb 100644 --- a/src/addplugin.html +++ b/src/addplugin.html @@ -5,12 +5,11 @@
-

-

-

+

+

@@ -28,7 +27,6 @@
${ServerRestartNeededAfterPluginInstall}
-

@@ -37,9 +35,6 @@ diff --git a/src/addserver.html b/src/addserver.html index 763f56851b..02850fffb8 100644 --- a/src/addserver.html +++ b/src/addserver.html @@ -3,7 +3,7 @@

${HeaderConnectToServer}

- +
${LabelServerHostHelp}

diff --git a/src/apikeys.html b/src/apikeys.html index 47f032c1f4..3cb7cd6de1 100644 --- a/src/apikeys.html +++ b/src/apikeys.html @@ -4,18 +4,19 @@

${HeaderApiKeys}

${HeaderApiKeysHelp}


+ - - - - + + + + diff --git a/src/assets/css/clearbutton.css b/src/assets/css/clearbutton.css index 2d3f8d6800..9e6c105258 100644 --- a/src/assets/css/clearbutton.css +++ b/src/assets/css/clearbutton.css @@ -9,4 +9,4 @@ vertical-align: middle; font-family: inherit; font-size: inherit; -} \ No newline at end of file +} diff --git a/src/assets/css/dashboard.css b/src/assets/css/dashboard.css index d4928db691..894d7332f4 100644 --- a/src/assets/css/dashboard.css +++ b/src/assets/css/dashboard.css @@ -1,262 +1,318 @@ .dashboardColumn, .dashboardSections { flex-direction: column; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; } .dashboardFooter { margin-top: 3.5em; - text-align: center + text-align: center; } .dashboardFooter a { - margin: 0 .7em + margin: 0 0.7em; } progress { appearance: none; + -moz-appearance: none; + -webkit-appearance: none; margin: 0; - background: #ccc !important + background: #ccc !important; } -progress[role]:after { - background-image: none +progress[role]::after { + background-image: none; } progress::-webkit-progress-bar { - background: #ccc + background: #ccc; } progress::-moz-progress-bar { - background-color: #00a4dc + background-color: #00a4dc; } progress::-webkit-progress-value { - background-color: #00a4dc + background-color: #00a4dc; } -progress[aria-valuenow]:before { - border-radius: .4em; - background-color: #00a4dc +progress[aria-valuenow]::before { + border-radius: 0.4em; + background-color: #00a4dc; } .localnav { - margin-bottom: 2.2em !important + margin-bottom: 2.2em !important; } -@media all and (min-width:50em) { - - .type-interior>.ui-panel-content-wrap>div[data-role=content], - .type-interior>div[data-role=content] { +@media all and (min-width: 50em) { + .type-interior > div[data-role=content], + .type-interior > .ui-panel-content-wrap > div[data-role=content] { padding-right: 0; padding-left: 0; padding-top: 0; - overflow: hidden + overflow: hidden; } } .dashboardDocument .dashboardEntryHeaderButton, .dashboardDocument .lnkManageServer { - display: none !important + display: none !important; } .adminDrawerLogo { + display: none; +} + +.layout-mobile .adminDrawerLogo { padding: 1.5em 1em 1.2em; border-bottom: 1px solid #e0e0e0; margin-bottom: 1em; - display: block + display: block; } .adminDrawerLogo img { - height: 4em + height: 4em; +} + +a[data-role=button] { + background: #292929 !important; + background-clip: padding-box; + -webkit-font-smoothing: antialiased; + -webkit-user-select: none; + -webkit-background-clip: padding-box; + cursor: pointer !important; + font-family: inherit !important; + font-weight: 500 !important; + margin: 0 0.25em !important; + display: inline-block; + padding: 0.8em 1em; + text-align: center; + text-decoration: none !important; } div[data-role=controlgroup] a[data-role=button] { display: inline-block !important; margin: 0 !important; + -webkit-box-shadow: none !important; box-shadow: none !important; - border-radius: 0 + -webkit-border-radius: 0; + border-radius: 0; } div[data-role=controlgroup] a[data-role=button]:first-child { - border-bottom-left-radius: .3125em; - border-top-left-radius: .3125em + -webkit-border-bottom-left-radius: 0.3125em; + border-bottom-left-radius: 0.3125em; + -webkit-border-top-left-radius: 0.3125em; + border-top-left-radius: 0.3125em; } div[data-role=controlgroup] a[data-role=button]:last-child { - border-bottom-right-radius: .3125em; - border-top-right-radius: .3125em + -webkit-border-bottom-right-radius: 0.3125em; + border-bottom-right-radius: 0.3125em; + -webkit-border-top-right-radius: 0.3125em; + border-top-right-radius: 0.3125em; } -div[data-role=controlgroup] a[data-role=button]+a[data-role=button] { +div[data-role=controlgroup] a[data-role=button] + a[data-role=button] { border-left-width: 0 !important; - margin: 0 0 0 -.4em !important + margin: 0 0 0 -0.4em !important; } div[data-role=controlgroup] a.ui-btn-active { background: #00a4dc !important; - color: #292929 !important + color: #292929 !important; } -.header .imageLink { - display: inline-block +.sessionAppInfo img { + max-width: 40px; + max-height: 40px; + margin-right: 8px; } -.header .imageLink img { - height: 2.1em; - vertical-align: middle -} - -.content-primary { - padding-top: 6em; - padding-right: 1em; - padding-left: 1em -} - -.withTabs .content-primary { - padding-top: 9em !important -} - -@media all and (min-width:40em) { - .content-primary { - padding-top: 7em - } - - .withTabs .content-primary { - padding-top: 10em !important - } -} - -@media all and (min-width:84em) { - .withTabs .content-primary { - padding-top: 7em !important - } -} - -.content-primary ul:first-child { - margin-top: 0 -} - -.dashboardSections { - display: flex; - flex-direction: column -} - -.dashboardColumn { - display: flex; - flex-direction: column; - flex-shrink: 0; - flex-grow: 1 -} - -.activeSession:not(.playingSession) .sessionNowPlayingContent { - display: none -} - -.dashboardSection { - flex-shrink: 0; - margin: 0 0 2em -} - -.dashboardSection h3 { - margin-top: .5em; - margin-bottom: .5em -} - -.activeRecordingItems>.card { - width: 50% -} - -@media all and (min-width:70em) { - .dashboardSections { - flex-wrap: wrap; - flex-direction: row - } - - .dashboardColumn-2-60 { - width: 46% - } - - .dashboardColumn-2-40 { - width: 27% - } - - .dashboardSection { - padding: 0 1.5em - } - - .activeRecordingItems>.card { - width: 25% - } -} - -.premiumBanner img { - position: absolute; - text-align: right; - top: 0; - right: 0; - width: 4.4em; - height: 4.4em -} - -.wizardContent { - max-width: 62em; - padding: .5em 2em 1em; - margin: 0 auto; - background: #fff -} - -.wizardNavigation { - text-align: right -} - -.wizardContent form { - max-width: 100% +.appLinks img { + height: 36px; } .wizardContent h2 img { height: 2.5em; vertical-align: middle; - margin-right: .5em; + margin-right: 0.5em; position: relative; - top: -.3em + top: -0.3em; } -.scheduledTaskPaperIconItem { - outline: 0 !important +.header .imageLink { + display: inline-block; } -.activeSession { - width: 100% !important +.header .imageLink img { + height: 2.1em; + vertical-align: middle; } -.activitylogUserPhoto { - height:1.71em; - width:1.71em; - border-radius:100%; - margin-right:.5em; - background-size:cover; - background-repeat:no-repeat; - background-position:center; +.content-primary { + padding-top: 6em; + padding-right: 1em; + padding-left: 1em; } -@media all and (min-width:40em) { - .activeSession { - width: 100% !important +.withTabs .content-primary { + padding-top: 9em !important; +} + +@media all and (min-width: 40em) { + .content-primary { + padding-top: 4.6em; + } + + .withTabs .content-primary { + padding-top: 10em !important; } } -@media all and (min-width:50em) { +@media all and (min-width: 84em) { + .withTabs .content-primary { + padding-top: 7em !important; + } +} + +.content-primary ul:first-child { + margin-top: 0; +} + +.dashboardSections { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; +} + +.dashboardColumn { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-direction: column; + flex-direction: column; + -webkit-flex-shrink: 0; + flex-shrink: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; +} + +.sessionNowPlayingContent { + -webkit-background-size: cover; + background-size: cover; + background-repeat: no-repeat; + background-position: center center; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.activeSession:not(.playingSession) .sessionNowPlayingContent { + display: none; +} + +.dashboardSection { + -webkit-flex-shrink: 0; + flex-shrink: 0; + margin: 0 0 2em; +} + +.dashboardSection h3 { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +.activeRecordingItems > .card { + width: 50%; +} + +@media all and (min-width: 70em) { + .dashboardSections { + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + flex-direction: row; + } + + .dashboardColumn-2-60 { + width: 46%; + } + + .dashboardColumn-2-40 { + width: 27%; + } + + .dashboardSection { + padding: 0 1.5em; + } + + .activeRecordingItems > .card { + width: 25%; + } +} + +.wizardContent { + max-width: 62em; + padding: 0.5em 2em 1em; + margin: 0 auto; + background: #fff; +} + +.wizardNavigation { + text-align: right; +} + +.wizardContent form { + max-width: 100%; +} + +.scheduledTaskPaperIconItem { + outline: 0 !important; +} + +.activeSession { + width: 100% !important; +} + +.activitylogUserPhoto { + height: 1.71em; + width: 1.71em; + border-radius: 100%; + margin-right: 0.5em; + background-size: cover; + background-repeat: no-repeat; + background-position: center; +} + +@media all and (min-width: 40em) { .activeSession { - width: 50% !important + width: 100% !important; + } +} + +@media all and (min-width: 50em) { + .activeSession { + width: 50% !important; } } .sessionCardFooter { - padding-top: .5em !important; + padding-top: 0.5em !important; padding-bottom: 1em !important; border-top: 1px solid #eee; text-align: center; - position: relative + position: relative; } .sessionAppInfo { @@ -265,22 +321,11 @@ div[data-role=controlgroup] a.ui-btn-active { } .sessionCardButtons { - min-height: 2.7em + min-height: 2.7em; } .sessionCardButton { - margin: 0 -} - -.sessionNowPlayingContent { - background-size: cover; - background-repeat: no-repeat; - background-position: center center; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0 + margin: 0; } .sessionNowPlayingInnerContent { @@ -289,23 +334,23 @@ div[data-role=controlgroup] a.ui-btn-active { left: 0; right: 0; bottom: 0; - font-weight: 400 + font-weight: 400; } -.sessionNowPlayingContent-withbackground+.sessionNowPlayingInnerContent { +.sessionNowPlayingContent-withbackground + .sessionNowPlayingInnerContent { color: #fff !important; - background: rgba(0, 0, 0, .7) + background: rgba(0, 0, 0, 0.7); } .sessionAppName { vertical-align: top; - max-width: 200px + max-width: 200px; } .sessionNowPlayingDetails { display: flex; position: absolute; - bottom: 0px; + bottom: 0; width: 100%; } @@ -315,12 +360,6 @@ div[data-role=controlgroup] a.ui-btn-active { padding: 0.8em 0.5em; } -.sessionAppInfo img { - max-width: 40px; - max-height: 40px; - margin-right: 8px; -} - .sessionNowPlayingTime { flex-shrink: 0; align-self: flex-end; @@ -332,6 +371,13 @@ div[data-role=controlgroup] a.ui-btn-active { white-space: nowrap; } +.playbackProgress, +.transcodingProgress { + margin: 0; + width: 100%; + background: transparent !important; +} + .activeSession .playbackProgress, .activeSession .transcodingProgress { position: absolute; @@ -342,13 +388,6 @@ div[data-role=controlgroup] a.ui-btn-active { width: 100%; } -.playbackProgress, -.transcodingProgress { - margin: 0px; - width: 100%; - background: transparent !important; -} - .playbackProgress > div { z-index: 1000; background-color: #00a4dc; @@ -358,70 +397,70 @@ div[data-role=controlgroup] a.ui-btn-active { background-color: #dd4919; } -@media all and (max-width:34.375em) { +@media all and (max-width: 34.375em) { .sessionAppName { - max-width: 160px + max-width: 160px; } } -@media all and (max-width:31.25em) { +@media all and (max-width: 31.25em) { .sessionAppName { - max-width: 150px + max-width: 150px; } } .disabledUser { - filter: grayscale(100%) + -webkit-filter: grayscale(100%); + filter: grayscale(100%); } .disabledUserBanner { - margin: 0 0 2em + margin: 0 0 2em; } .appLinks a { - text-decoration: none !important -} - -.appLinks a+a { - margin-left: 5px -} - -.appLinks img { - height: 36px -} - -a[data-role=button] { - background-clip: padding-box; - cursor: pointer !important; - font-family: inherit !important; - font-weight: 500 !important; - margin: 0 .25em !important; - display: inline-block; - padding: .8em 1em; - text-align: center; text-decoration: none !important; - background: #292929 !important; +} + +.appLinks a + a { + margin-left: 5px; +} + +@-webkit-keyframes rotating { + from { + -webkit-transform: rotate(0); + transform: rotate(0); + } + + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } @keyframes rotating { from { - transform: rotate(0) + -webkit-transform: rotate(0); + transform: rotate(0); } to { - transform: rotate(360deg) + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } .rotatingCircle { - animation: rotating 2s linear infinite + -webkit-animation: rotating 2s linear infinite; + animation: rotating 2s linear infinite; } .pluginPreviewImg { - box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37) + -webkit-box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); + box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); } -.ui-bar-a{ +.ui-bar-a { text-align: center; padding: 0 20px; } diff --git a/src/assets/css/detailtable.css b/src/assets/css/detailtable.css index 33f0608365..4e2e16511c 100644 --- a/src/assets/css/detailtable.css +++ b/src/assets/css/detailtable.css @@ -1,7 +1,7 @@ .detailTableBodyCell, .detailTableHeaderCell { border-spacing: 0; - padding: .4em + padding: 0.4em; } .detailTable { @@ -9,11 +9,11 @@ border-spacing: 0; text-align: left; width: 100%; - margin: 0 auto + margin: 0 auto; } .detailTableHeaderCell { font-weight: 700; text-align: left; - vertical-align: top -} \ No newline at end of file + vertical-align: top; +} diff --git a/src/assets/css/flexstyles.css b/src/assets/css/flexstyles.css index b35e25d57b..a5a479f2f5 100644 --- a/src/assets/css/flexstyles.css +++ b/src/assets/css/flexstyles.css @@ -44,4 +44,4 @@ .align-self-flex-end { align-self: flex-end; -} \ No newline at end of file +} diff --git a/src/assets/css/fonts.css b/src/assets/css/fonts.css index da5515fc1e..cb0da0f80f 100644 --- a/src/assets/css/fonts.css +++ b/src/assets/css/fonts.css @@ -1,34 +1,35 @@ 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: "Noto Sans", sans-serif; font-size: 93%; + -webkit-text-size-adjust: 100%; text-size-adjust: 100%; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; } -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, +h2, +h3 { + font-family: "Noto Sans", sans-serif; } h1 { - font-weight: 500; + font-weight: 400; font-size: 1.8em; } h2 { - font-weight: 500; + font-weight: 400; font-size: 1.5em; } h3 { - font-weight: 500; + font-weight: 400; font-size: 1.17em; } .layout-tv { - font-size: 2.5vh; + font-size: 130%; } .layout-mobile { diff --git a/src/assets/css/fonts.sized.css b/src/assets/css/fonts.sized.css index 9cdd666109..f60a94f236 100644 --- a/src/assets/css/fonts.sized.css +++ b/src/assets/css/fonts.sized.css @@ -1,5 +1,5 @@ h1 { - font-weight: 500; + font-weight: 400; font-size: 1.8em; } @@ -8,12 +8,12 @@ h1 { } h2 { - font-weight: 500; + font-weight: 400; font-size: 1.5em; } h3 { - font-weight: 500; + font-weight: 400; font-size: 1.17em; } diff --git a/src/assets/css/ios.css b/src/assets/css/ios.css index 47fa7bd538..57de0c5fdd 100644 --- a/src/assets/css/ios.css +++ b/src/assets/css/ios.css @@ -1,8 +1,8 @@ html { - font-size: 82% !important + font-size: 82% !important; } .formDialogFooter { position: static !important; - margin: 0 -1em !important -} \ No newline at end of file + margin: 0 -1em !important; +} diff --git a/src/assets/css/librarybrowser.css b/src/assets/css/librarybrowser.css index af106959e0..82e704f074 100644 --- a/src/assets/css/librarybrowser.css +++ b/src/assets/css/librarybrowser.css @@ -1,42 +1,47 @@ .headerUserImage, .navMenuOption, .pageTitle { - vertical-align: middle + vertical-align: middle; } -.detailButton-mobile, +.detailButton, .itemLinks, .listPaging, .sectionTabs, .viewSettings { - text-align: center + text-align: center; } .headerSelectedPlayer, .itemMiscInfo, .navMenuOptionText { + -o-text-overflow: ellipsis; text-overflow: ellipsis; - overflow: hidden + overflow: hidden; } .libraryPage { - padding-top: 7em !important + padding-top: 7em !important; +} + +.layout-mobile .libraryPage { + padding-top: 4em !important; } .itemDetailPage { - padding-top: 0em !important + padding-top: 0 !important; } .standalonePage { - padding-top: 4.5em !important + padding-top: 4.5em !important; } .wizardPage { - padding-top: 7em !important + padding-top: 7em !important; } .libraryPage:not(.noSecondaryNavPage) { - padding-top: 7.5em !important + padding-top: 7.5em !important; } .absolutePageTabContent { @@ -47,22 +52,27 @@ z-index: 1; margin: 0 !important; top: 6.9em !important; - transition: transform .2s ease-out + -webkit-transition: -webkit-transform 0.2s ease-out; + -o-transition: transform 0.2s ease-out; + transition: transform 0.2s ease-out; } .pageTabContent:not(.is-active) { - display: none !important + display: none !important; } .headerUserImage { + -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; background-position: center center; + -webkit-border-radius: 100em; border-radius: 100em; - display: inline-block + display: inline-block; } .headerUserButtonRound div { + -webkit-border-radius: 100em; border-radius: 100em; background-size: cover; background-repeat: no-repeat; @@ -70,41 +80,78 @@ } .headerButton { - flex-shrink: 0 + -webkit-flex-shrink: 0; + flex-shrink: 0; } .hideMainDrawer .mainDrawerButton { - display: none + display: none; +} + +.headerLeft { + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + overflow: hidden; + justify-content: flex-start; +} + +.headerRight { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-align-items: center; + align-items: center; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; } .noHeaderRight .headerRight, .noHomeButtonHeader .headerHomeButton { - display: none !important + display: none !important; } .pageTitle { + display: -webkit-inline-box; + display: -webkit-inline-flex; display: inline-flex; - margin: .3em 0 0 .5em; + margin: 0 0 0 0.5em; height: 1.7em; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; - flex-shrink: 1 + -webkit-flex-shrink: 1; + flex-shrink: 1; +} + +.pageTitleWithDefaultLogo { + margin-top: 0; } .headerLeft, .skinHeader { - display: flex; + display: -webkit-box; + display: -webkit-flex; } -.detailButton-mobile, +.detailButton, .skinHeader { flex-direction: column; + -webkit-flex-direction: column; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; } .pageTitleWithLogo { background-position: left center; + -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; - width: 13.2em + width: 13.2em; } .skinHeader { @@ -116,124 +163,118 @@ border: 0; display: flex; flex-direction: column; - contain: layout style paint -} - -.headerLeft, -.headerRight { - justify-content: center; + contain: layout style paint; } .hiddenViewMenuBar .skinHeader { - display: none + display: none; } .headerTop { - padding: .54em 0 -} - -.headerLeft { - display: flex; - align-items: center; - flex-grow: 1; - overflow: hidden; - justify-content: left; + padding: 0.54em 0; } .sectionTabs { - width: 100% -} - -.headerRight { - display: flex; - align-items: center; - justify-content: flex-end + width: 100%; } .selectedMediaFolder { - background-color: #f2f2f2 !important + background-color: #f2f2f2 !important; } .navMenuOption { + display: -webkit-box !important; + display: -webkit-flex !important; display: flex !important; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; text-decoration: none; color: inherit; - padding: .9em 0 .9em 2.4em !important; + padding: 0.9em 0 0.9em 2.4em !important; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; flex-grow: 1; font-weight: 400 !important; margin: 0 !important; - border-radius: 0 !important + -webkit-border-radius: 0 !important; + border-radius: 0 !important; } .navMenuOptionIcon { margin-right: 1.2em; - flex-shrink: 0 + -webkit-flex-shrink: 0; + flex-shrink: 0; } .navMenuOptionText { - white-space: nowrap + white-space: nowrap; + margin-top: 0.25em; } .sidebarHeader { padding-left: 1.2em; - margin: 1em 0 .5em + margin: 1em 0 0.5em; } .dashboardDocument .skinBody { - transition: left ease-in-out .3s, padding ease-in-out .3s; + -webkit-transition: left ease-in-out 0.3s, padding ease-in-out 0.3s; + -o-transition: left ease-in-out 0.3s, padding ease-in-out 0.3s; + transition: left ease-in-out 0.3s, padding ease-in-out 0.3s; position: absolute; top: 0; right: 0; bottom: 0; - left: 0 + left: 0; +} + +.centerMessage { + margin: auto; + width: 30%; + padding: 5em 0; + text-align: center; } .layout-desktop .searchTabButton, .layout-mobile .searchTabButton, .layout-tv .headerSearchButton { - display: none !important + display: none !important; } .mainDrawer-scrollContainer { - padding-bottom: 10vh + padding-bottom: 10vh; } -@media all and (min-width:40em) { - +@media all and (min-width: 40em) { .dashboardDocument .adminDrawerLogo, .dashboardDocument .mainDrawerButton { - display: none !important + display: none !important; } .dashboardDocument .mainDrawer { z-index: inherit !important; left: 0 !important; top: 0 !important; + -webkit-transform: none !important; transform: none !important; + -webkit-box-shadow: none !important; box-shadow: none !important; width: 20.205em !important; - font-size: 94% + font-size: 94%; } .dashboardDocument .mainDrawer-scrollContainer { - margin-top: 5em !important + margin-top: 5em !important; } .dashboardDocument .skinBody { - left: 20em + left: 20em; } } -@media all and (max-width:60em) { - .libraryDocument .mainDrawerButton { - display: none - } -} - -@media all and (max-width:84em) { +@media all and (max-width: 84em) { .withSectionTabs .headerTop { - padding-bottom: 0.2em; + padding-bottom: 0.55em; } .sectionTabs { @@ -241,56 +282,60 @@ } } -@media all and (min-width:84em) { +@media all and (min-width: 84em) { .headerTop { - padding: 1.489em 0 + padding: 0.8em 0.8em; } .headerTabs { + -webkit-align-self: center; align-self: center; width: auto; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; + -webkit-box-pack: center; + -webkit-justify-content: center; justify-content: center; - margin-top: -3.34em; position: relative; - top: -1.05em + margin-top: -4.3em; } .libraryPage:not(.noSecondaryNavPage) { - padding-top: 4.6em !important + padding-top: 4.6em !important; } .pageWithAbsoluteTabs:not(.noSecondaryNavPage) { - padding-top: 6.7em !important + padding-top: 6.7em !important; } .absolutePageTabContent { - top: 5.7em !important + top: 5.7em !important; } .dashboardDocument .mainDrawer-scrollContainer { - margin-top: 6em !important; + margin-top: 4.65em !important; } } .headerSelectedPlayer { max-width: 10em; - white-space: nowrap + white-space: nowrap; } -@media all and (max-width:37.5em) { +@media all and (max-width: 37.5em) { .headerSelectedPlayer { - display: none + display: none; } } .hidingAnimatedTab { - visibility: hidden + visibility: hidden; } .headerArrowImage { height: 20px; - margin-left: .5em + margin-left: 0.5em; } .backdropContainer { @@ -299,512 +344,621 @@ left: 0; right: 0; bottom: 0; - z-index: -1 + z-index: -1; } .libraryPage .header { - padding-bottom: 0 + padding-bottom: 0; } .flexPageTabContent.is-active { - display: flex !important + display: -webkit-box !important; + display: -webkit-flex !important; + display: flex !important; } .viewSettings { - margin: 0 0 .25em + margin: 0 0 0.25em; } -.viewControls+.listTopPaging { - margin-left: .5em !important +.listTopPaging, +.viewControls { + display: inline-block; +} + +.viewControls + .listTopPaging { + margin-left: 0.5em !important; } .criticReview { margin: 1.5em 0; background: #222; - padding: .8em .8em .8em 3em; - border-radius: .3em; - position: relative + padding: 0.8em 0.8em 0.8em 3em; + -webkit-border-radius: 0.3em; + border-radius: 0.3em; + position: relative; } .detailLogo, .itemBackdrop { background-repeat: no-repeat; - background-position: center center + background-position: center center; } .criticReview:first-child { - margin-top: .5em + margin-top: 0.5em; } .criticReview img { - width: 2.4em + width: 2.4em; } .criticRatingScore { - margin-bottom: .5em + margin-bottom: 0.5em; } .itemTag { display: inline-block; - margin-right: 1em + margin-right: 1em; } .itemOverview { - white-space: pre-wrap + white-space: pre-wrap; } .itemLinks { - padding: 0 + padding: 0; } .itemLinks p { - margin: .5em 0 + margin: 0.5em 0; } .reviewLink, .reviewerName { - margin-top: .5em + margin-top: 0.5em; } .reviewerName { - color: #ccc + color: #ccc; } .reviewDate { - margin-left: 1em + margin-left: 1em; } .reviewScore { position: absolute; - left: .8em + left: 0.8em; } .itemBackdrop { + -webkit-background-size: cover; background-size: cover; background-repeat: no-repeat; background-position: center; + background-attachment: fixed; height: 50vh; - position: relative + position: relative; +} + +.layout-mobile .itemBackdrop { + background-attachment: scroll; +} + +.layout-desktop .itemBackdrop::after, +.layout-tv .itemBackdrop::after { + content: ""; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.65); + display: block; +} + +.layout-desktop .noBackdrop .itemBackdrop, +.layout-tv .noBackdrop .itemBackdrop { + display: none; +} + +.detailPageContent { + display: flex; + flex-direction: column; + padding-left: 2%; + padding-right: 2%; +} + +.layout-desktop .noBackdrop .detailPageContent, +.layout-tv .noBackdrop .detailPageContent { + margin-top: 2.5em; +} + +.layout-desktop .noBackdrop .detailImageContainer img, +.layout-tv .noBackdrop .detailImageContainer img { + margin-top: 0; +} + +.personBackdrop { + background-size: contain; } .itemBackdropProgressBar { position: absolute !important; bottom: 0; left: 0; - right: 0 + right: 0; } .desktopMiscInfoContainer { position: absolute; - bottom: .75em + bottom: 0.75em; } -.layout-mobile .detailPagePrimaryContainer { +.parentName { display: block; - position: relative; + margin-bottom: 0.5em; } -.layout-tv .detailPagePrimaryContainer { - position: relative; +.mainDetailButtons { + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + margin: 1em 0; +} + +.detailButton, +.mainDetailButtons { + display: flex; + display: -webkit-box; + display: -webkit-flex; +} + +.itemName { + margin: 0.5em 0; + font-weight: 600; +} + +.nameContainer { + display: flex; + flex-direction: column; + flex-wrap: wrap; +} + +.itemMiscInfo { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; +} + +.layout-mobile .parentName, +.layout-mobile .itemName, +.layout-mobile .itemMiscInfo, +.layout-mobile .mainDetailButtons { + align-items: center; + justify-content: center; + text-align: center; } .detailPagePrimaryContainer { display: flex; align-items: center; align-content: center; - position: sticky; - background-color: #101010; - top: 0; z-index: 2; } +.layout-mobile .detailPagePrimaryContainer { + display: block; + position: relative; + top: 0; +} + +.layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, +.layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer { + position: relative; + top: 0; + padding-left: 32.45vw; +} + +.layout-desktop .detailSticky, +.layout-tv .detailSticky { + margin-top: -7.2em; +} + +.layout-desktop .noBackdrop .detailSticky, +.layout-tv .noBackdrop .detailSticky { + margin-top: 0; +} + .infoWrapper { flex: 1 0 0; } .infoText { white-space: nowrap; - overflow: hidden; text-overflow: ellipsis; text-align: left; } -.detailPageSecondaryContainer { - margin: 1.25em 0; - display: flex; - flex-direction: column; - padding-left: 2%; - padding-right: 2%; +.layout-mobile .infoText { + white-space: normal; } -.layout-mobile .detailImageContainer, -.layout-tv .detailImageContainer { - position: relative; +.detailPageSecondaryContainer { + margin: 1.25em 0; } .detailImageContainer { - margin: 1.25em 0; - position: sticky; - top: 15%; + position: relative; + margin-top: -25vh; float: left; - width: 22.786458333333332vw; + width: 25vw; + z-index: 3; +} + +.layout-desktop .noBackdrop .detailImageContainer, +.layout-tv .noBackdrop .detailImageContainer { + margin-top: 0; } .detailPagePrimaryContent { position: relative; - flex-grow: 1 } .detailLogo { - width: 25em; - height: 9.375em; + width: 30vw; + height: 25vh; position: absolute; - top: 14.5%; - right: 10.5%; - background-size: contain + top: 10vh; + right: 20vw; + background-size: contain; } -@media all and (max-width:87.5em) { - .detailLogo { - right: 5% - } +.noBackdrop .detailLogo { + display: none; } -@media all and (max-width:75em) { +@media all and (max-width: 68.75em) { .detailLogo { - right: 2% - } -} - -@media all and (max-width:68.75em) { - .detailLogo { - width: 14.91em; - height: 3.5em; - right: 5%; - bottom: 5%; - top: auto; - background-position: center right; - display: none + display: none; } } .itemDetailImage { width: 100% !important; - box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37); + -webkit-box-shadow: 0 0.1em 0.5em 0 rgba(0, 0, 0, 0.75); + box-shadow: 0 0.1em 0.5em 0 rgba(0, 0, 0, 0.75); } -@media all and (max-width:62.5em) { - .detailPageContent { - position: relative +div.itemDetailGalleryLink.defaultCardBackground { + text-align: center; +} + +.itemDetailGalleryLink.defaultCardBackground { + height: 23vw; /* Dirty hack to get it to look somewhat square. Less than ideal. */ +} + +.itemDetailGalleryLink.defaultCardBackground > .material-icons { + font-size: 15vw; + margin-top: 50%; + transform: translateY(-50%); +} + +@media all and (max-width: 62.5em) { + .detailPageWrapperContainer { + position: relative; + } + + .layout-desktop .detailPageWrapperContainer, + .layout-tv .detailPageWrapperContainer { + margin-top: 7.2em; + } + + .layout-tv #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer, + .layout-desktop #itemDetailPage:not(.noBackdrop) .detailPagePrimaryContainer { + padding-left: 3.3%; } .btnPlaySimple { - display: none !important + display: none !important; } } -@media all and (max-width:75em) { +@media all and (max-width: 75em) { .lnkSibling { - display: none !important + display: none !important; } } -.parentName { - display: block; - margin-bottom: .5em -} - .emby-button.detailFloatingButton { position: absolute; - background-color: rgba(0, 0, 0, .5) !important; + background-color: rgba(0, 0, 0, 0.5) !important; z-index: 1; top: 50%; left: 50%; margin: -2.2em 0 0 -2.2em; - border: 2.7px solid rgba(255, 255, 255, .6); - padding: .38em !important; - color: rgba(255, 255, 255, .76) + padding: 0.4em !important; + color: rgba(255, 255, 255, 0.76); } -.emby-button.detailFloatingButton i { - font-size: 3.5em +.emby-button.detailFloatingButton .material-icons { + font-size: 3.5em; } -@media all and (max-width:62.5em) { +@media all and (max-width: 62.5em) { .parentName { - margin-bottom: 1em + margin-bottom: 1em; } .itemDetailPage { - padding-top: 0 !important + padding-top: 0 !important; } .detailimg-hidemobile { - display: none + display: none; } } -@media all and (min-width:31.25em) { +@media all and (min-width: 31.25em) { .mobileDetails { - display: none + display: none; } } -@media all and (max-width:31.25em) { +@media all and (max-width: 31.25em) { .desktopDetails { - display: none !important + display: none !important; } } -.detailButton-mobile, -.mainDetailButtons { - display: flex; -} - -.itemName { - margin: .5em 0 -} - .empty { - margin: 0 + margin: 0; } -.detailCollapsibleSection:not(.hide)+.detailCollapsibleSection { - margin-top: -2em +.detailCollapsibleSection:not(.hide) + .detailCollapsibleSection { + margin-top: -2em; } .detailPageCollabsible { - margin-top: 0 -} - -.mainDetailButtons { - display: flex; - align-items: center; - flex-wrap: wrap; - margin: 1em 0; + margin-top: 0; } .recordingFields button { margin-left: 0; - margin-right: .5em; - flex-shrink: 0 + margin-right: 0.5em; + -webkit-flex-shrink: 0; + flex-shrink: 0; } -.mainDetailButtons.hide+.recordingFields { - margin-top: 1.5em !important -} - -.detailButton-mobile { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 0 !important; - padding: .5em .7em !important +.mainDetailButtons.hide + .recordingFields { + margin-top: 1.5em !important; } .detailButton { - margin: 0 .5em 0 0 !important -} - -@media all and (min-width:29em) { - .detailButton-mobile { - padding-left: .75em !important; - padding-right: .75em !important - } -} - -@media all and (min-width:32em) { - .detailButton-mobile { - padding-left: .8em !important; - padding-right: .8em !important - } -} - -@media all and (min-width:35em) { - .detailButton-mobile { - padding-left: .85em !important; - padding-right: .85em !important - } -} - -.detailButton-mobile-content { display: flex; flex-direction: column; + -webkit-box-pack: center; + -webkit-justify-content: center; justify-content: center; - align-items: center + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + margin: 0 !important; + padding: 0.5em 0.7em !important; } -.detailButton-mobile-icon { +@media all and (min-width: 29em) { + .detailButton { + padding-left: 0.75em !important; + padding-right: 0.75em !important; + } +} + +@media all and (min-width: 32em) { + .detailButton { + padding-left: 0.8em !important; + padding-right: 0.8em !important; + } +} + +@media all and (min-width: 35em) { + .detailButton { + padding-left: 0.85em !important; + padding-right: 0.85em !important; + } +} + +.detailButton-content { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; +} + +.detailButton-icon { font-size: 1.6em !important; width: 1em; - height: 1em + height: 1em; } .detailImageProgressContainer { - margin-left: 6px; - width: 21.886458333333332vw; + position: absolute; + bottom: 0; + width: 22.786458333333332vw; } -.detailButton-mobile-text { - margin-top: .7em; +.detailButton-text { + margin-top: 0.7em; font-size: 80%; - font-weight: 400 + font-weight: 400; } -@media all and (max-width:62.5em) { +@media all and (max-width: 62.5em) { .mainDetailButtons { - margin-left: -.5em + margin-left: -0.5em; } - .detailButton { - display: none !important + .detailButtonHideonMobile { + display: none !important; } } -@media all and (min-width:62.5em) { +@media all and (min-width: 62.5em) { + .headerTop { + padding-left: 0.8em; + padding-right: 0.8em; + } + + .headerTabs { + align-self: center; + width: auto; + align-items: center; + justify-content: center; + margin-top: -4.2em; + position: relative; + } + .detailFloatingButton { - display: none !important + display: none !important; + } + + .personBackdrop { + display: none !important; } .mainDetailButtons { font-size: 108%; - margin: 1.25em 0 + margin: 1.25em 0; } } -.listTopPaging, -.viewControls { - display: inline-block -} - -@media all and (max-width:50em) { +@media all and (max-width: 50em) { .editorMenuLink { - display: none + display: none; } } -.itemMiscInfo { - display: flex; - flex-wrap: wrap; - align-items: center -} - -@media all and (max-width:31.25em) { +@media all and (max-width: 31.25em) { .mobileDetails .itemMiscInfo { text-align: center; - justify-content: center + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; } .itemMiscInfo .endsAt { - display: none + display: none; } } .layout-tv .detailVerticalSection { - margin-bottom: 3.4em !important + margin-bottom: 3.4em !important; } -.detailPageContent { +.detailPageWrapperContainer { border-spacing: 0; border-collapse: collapse; } -@media all and (max-width:62.5em) { - .detailPageContent-nodetailimg { - padding-top: 0; - } +.layout-desktop .noBackdrop .detailPageWrapperContainer, +.layout-tv .noBackdrop .detailPageWrapperContainer { + margin-top: 3.8em; } .mediaInfoStream { margin: 0 3em 0 0; display: inline-block; - vertical-align: top + vertical-align: top; } .mediaInfoStreamType { display: block; - margin: 1em 0 + margin: 1em 0; } .mediaInfoAttribute, .mediaInfoLabel { - display: inline-block + display: inline-block; } .mediaInfoLabel { margin-right: 1em; - font-weight: 600 + font-weight: 600; } .recordingProgressBar::-moz-progress-bar { - background-color: #c33 + background-color: #c33; } .recordingProgressBar::-webkit-progress-value { - background-color: #c33 + background-color: #c33; } -.recordingProgressBar[aria-valuenow]:before { - background-color: #c33 +.recordingProgressBar[aria-valuenow]::before { + background-color: #c33; } .timelineHeader { - margin-bottom: .25em; + margin-bottom: 0.25em; line-height: 1.25em; - line-height: initial + line-height: initial; } .itemsContainer { - margin: 0 auto + margin: 0 auto; } -@media all and (max-height:31.25em) { +@media all and (max-height: 31.25em) { .itemBackdrop { - height: 52vh + height: 52vh; } } -@media all and (max-width:75em) { - .listViewUserDataButtons { - display: none !important - } -} - -@media all and (max-width:62.5em) { - .detailsHiddenOnMobile { - display: none - } -} - -.btnSyncComplete { - background: #673AB7 !important -} - -.btnSyncComplete i { - border-radius: 100em +.listViewUserDataButtons { + display: flex; + align-items: center; } .bulletSeparator { - margin: 0 .35em + margin: 0 0.35em; } .mediaInfoIcons { + display: -webkit-box; + display: -webkit-flex; display: flex; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; margin: 1em 0; - flex-wrap: wrap + -webkit-flex-wrap: wrap; + flex-wrap: wrap; } .verticalSection-extrabottompadding { - margin-bottom: 2.7em + margin-bottom: 2.7em; } .sectionTitleButton, .sectionTitleIconButton { margin-right: 0 !important; display: inline-block; - vertical-align: middle + vertical-align: middle; } .sectionTitleContainer { @@ -830,43 +984,49 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { .sectionTitleButton { margin-left: 1.5em !important; - flex-shrink: 0 + -webkit-flex-shrink: 0; + flex-shrink: 0; } .sectionTitleButton + .sectionTitleButton { - margin-left: .5em !important + margin-left: 0.5em !important; } .sectionTitleIconButton { margin-left: 1.5em !important; + -webkit-flex-shrink: 0; flex-shrink: 0; font-size: 84% !important; - padding: .5em !important + padding: 0.5em !important; } .horizontalItemsContainer { - display: flex + display: -webkit-box; + display: -webkit-flex; + display: flex; } .sectionTitleTextButton { margin: 0 !important; + display: -webkit-inline-box !important; + display: -webkit-inline-flex !important; display: inline-flex !important; - color: inherit !important + color: inherit !important; } .sectionTitleTextButton:not(.padded-left) { - padding: 0 !important + padding: 0 !important; } .sectionTitleTextButton.padded-left { padding-bottom: 0 !important; padding-right: 0 !important; - padding-top: 0 !important + padding-top: 0 !important; } -.sectionTitleTextButton>.sectionTitle { - margin-bottom: 0; - margin-top: 0 +.sectionTitleTextButton > .sectionTitle { + margin-bottom: 0.35em; + margin-top: 0; } .padded-left { @@ -895,18 +1055,14 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { margin-bottom: -1em; } -@media all and (min-height:31.25em) { - .padded-left-withalphapicker { - padding-left: 7.5%; - } - +@media all and (min-height: 31.25em) { .padded-right-withalphapicker { padding-right: 7.5%; } } .searchfields-icon { - color: #aaaaaa; + color: #aaa; } .button-accent-flat { @@ -917,25 +1073,74 @@ div:not(.sectionTitleContainer-cards) > .sectionTitle-cards { text-decoration: none; font-weight: inherit !important; vertical-align: middle; - color: inherit !important + color: inherit !important; } .itemsViewSettingsContainer { - justify-content: center + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; } -@media all and (min-width:40em) { +@media all and (min-width: 40em) { .listIconButton-autohide { - display: none !important + display: none !important; } } -@media all and (max-width:40em) { +@media all and (max-width: 40em) { .listTextButton-autohide { - display: none !important + display: none !important; } } -.itemsViewSettingsContainer>.button-flat { - margin: 0 +.itemsViewSettingsContainer > .button-flat { + margin: 0; +} + +.layout-mobile #myPreferencesMenuPage { + padding-top: 3.75em; +} + +.itemDetailsGroup { + margin-bottom: 1.5em; +} + +.trackSelections { + max-width: 44em; +} + +.detailsGroupItem, +.trackSelections .selectContainer { + display: flex; + max-width: 44em; + margin: 0 0 0.5em !important; +} + +.trackSelections .selectContainer { + margin: 0 0 0.3em !important; +} + +.detailsGroupItem .label, +.trackSelections .selectContainer .selectLabel { + cursor: default; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 6.25em; + margin: 0 0.6em 0 0; +} + +.trackSelections .selectContainer .selectLabel { + margin: 0 0.2em 0 0; +} + +.trackSelections .selectContainer .detailTrackSelect { + font-size: inherit; + padding: 0; + overflow: hidden; +} + +.trackSelections .selectContainer .selectArrowContainer .selectArrow { + margin-top: 0; + font-size: 1.4em; } diff --git a/src/assets/css/livetv.css b/src/assets/css/livetv.css index 93e3e029c8..695adff8c5 100644 --- a/src/assets/css/livetv.css +++ b/src/assets/css/livetv.css @@ -1,9 +1,9 @@ .guideVerticalScroller { - padding-bottom: 15em + padding-bottom: 15em; } -@media all and (min-width:62.5em) { +@media all and (min-width: 62.5em) { #guideTab { - padding-left: .5em + padding-left: 0.5em; } -} \ No newline at end of file +} diff --git a/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff b/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff deleted file mode 100644 index 9357bfc6ff..0000000000 Binary files a/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNa.woff and /dev/null differ diff --git a/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 b/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 deleted file mode 100644 index db867bc362..0000000000 Binary files a/src/assets/css/material-icons/flUhRq6tzZclQEJ-Vdg-IuiaDsNc.woff2 and /dev/null differ diff --git a/src/assets/css/material-icons/style.css b/src/assets/css/material-icons/style.css deleted file mode 100644 index 2d410b9985..0000000000 --- a/src/assets/css/material-icons/style.css +++ /dev/null @@ -1,25 +0,0 @@ -@font-face { - 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'); -} - -.md-icon { - font-family: 'Material Icons'; - font-weight: normal; - font-style: normal; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - font-feature-settings: "liga" 1; - line-height: 1; - overflow: hidden; - vertical-align: middle; -} diff --git a/src/assets/css/metadataeditor.css b/src/assets/css/metadataeditor.css index c5de6f3efe..190f53187f 100644 --- a/src/assets/css/metadataeditor.css +++ b/src/assets/css/metadataeditor.css @@ -1,53 +1,57 @@ .editPageSidebar { - display: block + display: block; } .editPageSidebar-withcontent { - display: none + display: none; } .libraryTree { - margin-left: .25em + margin-left: 0.25em; } .offlineEditorNode { - color: #c33 + color: #c33; } .editorNode img { height: 18px; - margin: 0 .35em; + margin: 0 0.35em; vertical-align: middle; position: relative; - top: -2px + top: -2px; } .jstree-anchor { - font-weight: 400 !important + font-weight: 400 !important; } .jstree-wholerow-hovered { background: #38c !important; + -webkit-border-radius: 0 !important; border-radius: 0 !important; - box-shadow: none !important + -webkit-box-shadow: none !important; + box-shadow: none !important; } .jstree-default .jstree-hovered { background: 0 0 !important; + -webkit-border-radius: 0 !important; border-radius: 0 !important; + -webkit-box-shadow: none !important; box-shadow: none !important; - color: #fff !important + color: #fff !important; } .jstree-default .jstree-wholerow-clicked { - background: #00a4dc !important + background: #00a4dc !important; } .metadataSidebarIcon { - margin-right: .4em + margin-right: 0.4em; } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { .editPageSidebar { position: fixed; top: 5.2em; @@ -55,21 +59,21 @@ left: 0; width: 30%; border-right: 1px solid #555; - display: block + display: block; } .editPageInnerContent { float: right; - width: 68.5% + width: 68.5%; } } -@media all and (min-width:112.5em) { +@media all and (min-width: 112.5em) { .editPageSidebar { - width: 25% + width: 25%; } .editPageInnerContent { - width: 73.5% + width: 73.5%; } } diff --git a/src/assets/css/scrollstyles.css b/src/assets/css/scrollstyles.css index 69039ce341..1cb3207e06 100644 --- a/src/assets/css/scrollstyles.css +++ b/src/assets/css/scrollstyles.css @@ -1,5 +1,6 @@ .scrollX { overflow-x: auto; + -webkit-overflow-scrolling: touch; overflow-y: hidden; white-space: nowrap; } @@ -8,39 +9,50 @@ scroll-behavior: smooth; } -.hiddenScrollX, .layout-tv .scrollX { - scrollbar-width: none; +.hiddenScrollX, +.layout-tv .scrollX { + -ms-overflow-style: none; } .hiddenScrollX-forced { - scrollbar-width: none; + overflow: -moz-scrollbars-none; } -.hiddenScrollX::-webkit-scrollbar, .layout-tv .scrollX::-webkit-scrollbar { +.hiddenScrollX::-webkit-scrollbar, +.layout-tv .scrollX::-webkit-scrollbar { height: 0 !important; display: none; } .scrollY { overflow-y: auto; + -webkit-overflow-scrolling: touch; overflow-x: hidden; } .smoothScrollY { overflow-y: auto; + -webkit-overflow-scrolling: touch; overflow-x: hidden; scroll-behavior: smooth; } -.hiddenScrollY, .layout-tv .smoothScrollY { - scrollbar-width: 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 { - scrollbar-width: none; + overflow: -moz-scrollbars-none; } -.hiddenScrollY::-webkit-scrollbar, .layout-tv .smoothScrollY::-webkit-scrollbar, .layout-tv .scrollY::-webkit-scrollbar { +.hiddenScrollY::-webkit-scrollbar, +.layout-tv .smoothScrollY::-webkit-scrollbar, +.layout-tv .scrollY::-webkit-scrollbar { width: 0 !important; display: none; } diff --git a/src/assets/css/site.css b/src/assets/css/site.css index 6491799117..627145abc1 100644 --- a/src/assets/css/site.css +++ b/src/assets/css/site.css @@ -2,7 +2,23 @@ body, html { margin: 0; padding: 0; - height: 100% + height: 100%; +} + +.clipForScreenReader { + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); + height: 1px; + width: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; +} + +.material-icons { + /* Fix font ligatures on older WebOS versions */ + -webkit-font-feature-settings: "liga"; } .backgroundContainer { @@ -11,52 +27,58 @@ html { left: 0; right: 0; bottom: 0; - contain: strict + contain: strict; } html { - line-height: 1.35 + line-height: 1.35; } .layout-mobile, .layout-tv { - user-select: none + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } body { overflow-x: hidden; background-color: transparent !important; + -webkit-font-smoothing: antialiased; } .mainAnimatedPage { - contain: style size !important + contain: style size !important; } .pageContainer { - overflow-x: visible !important + overflow-x: visible !important; } .bodyWithPopupOpen { - overflow-y: hidden !important + overflow-y: hidden !important; } div[data-role=page] { - outline: 0 + outline: 0; } .pageTitle { margin-top: 0; - font-family: inherit + font-family: inherit; } .fieldDescription { - padding-left: .15em; + padding-left: 0.15em; font-weight: 400; - white-space: normal !important + white-space: normal !important; } -.fieldDescription+.fieldDescription { - margin-top: .3em +.fieldDescription + .fieldDescription { + margin-top: 0.3em; } .content-primary, @@ -67,21 +89,34 @@ div[data-role=page] { padding-bottom: 5em !important; } -@media all and (min-width:50em) { +@media all and (min-width: 50em) { .readOnlyContent, form { - max-width: 54em + max-width: 54em; } } .headerHelpButton { margin-left: 1.25em !important; - padding-bottom: .4em !important; - padding-top: .4em !important + padding-bottom: 0.4em !important; + padding-top: 0.4em !important; } .mediaInfoContent { margin-left: auto; margin-right: auto; - width: 85% + width: 85%; +} + +.headroom { + will-change: transform; + transition: transform 200ms linear; +} + +.headroom--pinned { + transform: translateY(0%); +} + +.headroom--unpinned { + transform: translateY(-100%); } diff --git a/src/assets/css/videoosd.css b/src/assets/css/videoosd.css index f20abf9d07..f4f198325b 100644 --- a/src/assets/css/videoosd.css +++ b/src/assets/css/videoosd.css @@ -1,6 +1,9 @@ .chapterThumbTextContainer, .videoOsdBottom { user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; } .osdPoster img, @@ -8,52 +11,59 @@ .videoOsdBottom { bottom: 0; left: 0; - right: 0 + right: 0; } .osdHeader { - transition: opacity .3s ease-out; + -webkit-transition: opacity 0.3s ease-out; + -o-transition: opacity 0.3s ease-out; + transition: opacity 0.3s ease-out; position: relative; z-index: 1; background: rgba(0, 0, 0, 0.7) !important; + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; color: #eee !important; } .osdHeader-hidden { - opacity: 0 + opacity: 0; } .osdHeader .headerButton:not(.headerBackButton):not(.headerCastButton) { - display: none + display: none; } .chapterThumbContainer { + -webkit-box-shadow: 0 0 1.9vh #000; box-shadow: 0 0 1.9vh #000; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; flex-grow: 1; - position: relative + position: relative; } .chapterThumb { background-position: center center; + -webkit-background-size: contain; background-size: contain; background-repeat: no-repeat; border: 0; height: 20vh; - min-width: 20vh + min-width: 20vh; } -@media all and (orientation:portrait) { +@media all and (orientation: portrait) { .chapterThumb { height: 30vw; - min-width: 30vw + min-width: 30vw; } } -@media all and (max-height:50em) and (orientation:landscape) { +@media all and (max-height: 50em) and (orientation: landscape) { .chapterThumb { height: 30vh; - min-width: 30vh + min-width: 30vh; } } @@ -62,161 +72,218 @@ bottom: 0; left: 0; right: 0; - background: rgba(0, 0, 0, .7); - padding: .25em .5em; - user-select: none + background: rgba(0, 0, 0, 0.7); + padding: 0.25em 0.5em; + user-select: none; } .chapterThumbText { - padding: .25em 0; + padding: 0.25em 0; margin: 0; - opacity: 1 + opacity: 1; } .chapterThumbText-dim { - opacity: .6 + opacity: 0.6; } .videoOsdBottom { position: fixed; background-color: rgba(0, 0, 0, 0.7); padding: 1%; + display: -webkit-box; + display: -webkit-flex; display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; flex-direction: row; will-change: opacity; + -webkit-transition: opacity 0.3s ease-out; + -o-transition: opacity 0.3s ease-out; transition: opacity 0.3s ease-out; color: #fff; - user-select: none + user-select: none; + -webkit-touch-callout: none; } .videoOsdBottom-hidden { - opacity: 0 + opacity: 0; } .osdControls { - flex-grow: 1 + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; } .videoOsdBottom .buttons { - padding: .25em 0 0; + padding: 0.25em 0 0; + display: -webkit-box; + display: -webkit-flex; display: flex; + -webkit-flex-wrap: wrap; flex-wrap: wrap; - align-items: center + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; } .osdVolumeSliderContainer { width: 9em; - flex-grow: 1 + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; } .osdMediaInfo, .volumeButtons { display: flex; + display: -webkit-box; + display: -webkit-flex; align-items: center; + -webkit-box-align: center; } .volumeButtons { - margin: 0 .5em 0 auto; + margin: 0 0.5em 0 auto; display: flex; - align-items: center + -webkit-align-items: center; + align-items: center; } .osdTimeText { margin-left: 1em; - user-select: none + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } .osdPoster { width: 10%; position: relative; - margin-right: .5em + margin-right: 0.5em; } .osdPoster img { position: absolute; height: auto; width: 100%; + -webkit-box-shadow: 0 0 1.9vh #000; box-shadow: 0 0 1.9vh #000; - border: .08em solid #222; + border: 0.08em solid #222; user-drag: none; - user-select: none + user-select: none; + -moz-user-select: none; + -webkit-user-drag: none; + -webkit-user-select: none; + -ms-user-select: none; } .osdTitle, .osdTitleSmall { - margin: 0 1em 0 0 + margin: 0 1em 0 0; } .osdMediaInfo { display: flex; - align-items: center + -webkit-align-items: center; + align-items: center; } .osdSecondaryMediaInfo { - padding-left: .6em !important + padding-left: 0.6em !important; } .osdTextContainer { + display: -webkit-box; + display: -webkit-flex; display: flex; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; user-select: none; - margin-bottom: .7em; - padding-left: .5em + margin-bottom: 0.7em; + padding-left: 0.5em; } .osdMainTextContainer { - align-items: baseline + -webkit-box-align: baseline; + -webkit-align-items: baseline; + align-items: baseline; } .osdMediaStatus { margin-left: auto; } +@-moz-keyframes spin { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@-webkit-keyframes spin { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + @keyframes spin { 100% { - transform:rotate(360deg); + -webkit-transform: rotate(360deg); + transform: rotate(360deg); } } .osdMediaStatus .animate { - animation:spin 4s linear infinite; + -webkit-animation: spin 4s linear infinite; + -moz-animation: spin 4s linear infinite; + animation: spin 4s linear infinite; } .pageContainer { top: 0; - position: fixed + position: fixed; } -@media all and (max-width:30em) { - +@media all and (max-width: 30em) { .btnFastForward, .btnRewind, .osdMediaInfo, .osdPoster { - display: none !important + display: none !important; } } -@media all and (max-width:33.75em) { +@media all and (max-width: 33.75em) { .videoOsdBottom .paper-icon-button-light { - margin: 0 + margin: 0; } } -@media all and (max-width:43em) { +@media all and (max-width: 43em) { .videoOsdBottom .volumeButtons, .osdMediaStatus span { - display: none !important - } -} -@media all and (max-width:50em) { - .videoOsdBottom .btnFastForward, .videoOsdBottom .btnRewind { - display: none !important + display: none !important; } } -@media all and (max-width:75em) { - .videoOsdBottom .endsAtText { - display: none !important +@media all and (max-width: 50em) { + .videoOsdBottom .btnFastForward, + .videoOsdBottom .btnRewind { + display: none !important; + } +} + +@media all and (max-width: 75em) { + .videoOsdBottom .endsAtText { + display: none !important; } } diff --git a/src/themes/logodark.png b/src/assets/img/banner-dark.png similarity index 100% rename from src/themes/logodark.png rename to src/assets/img/banner-dark.png diff --git a/src/components/logoscreensaver/logowhite.png b/src/assets/img/banner-light.png similarity index 100% rename from src/components/logoscreensaver/logowhite.png rename to src/assets/img/banner-light.png diff --git a/src/assets/img/devices/android.svg b/src/assets/img/devices/android.svg index c0d377bb72..24edc8bbf9 100644 --- a/src/assets/img/devices/android.svg +++ b/src/assets/img/devices/android.svg @@ -1,4 +1,4 @@ - + diff --git a/src/assets/img/fresh.svg b/src/assets/img/fresh.svg new file mode 100644 index 0000000000..0602ab2481 --- /dev/null +++ b/src/assets/img/fresh.svg @@ -0,0 +1,20 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/img/logo.png b/src/assets/img/icon-transparent.png similarity index 100% rename from src/assets/img/logo.png rename to src/assets/img/icon-transparent.png diff --git a/src/assets/img/rotten.svg b/src/assets/img/rotten.svg new file mode 100644 index 0000000000..04bef05bc1 --- /dev/null +++ b/src/assets/img/rotten.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/availableplugins.html b/src/availableplugins.html index ea1147fbfd..6c9b89c26d 100644 --- a/src/availableplugins.html +++ b/src/availableplugins.html @@ -5,4 +5,4 @@
- \ No newline at end of file + diff --git a/src/bundle.js b/src/bundle.js index 54623fab74..d7ba6c6a51 100644 --- a/src/bundle.js +++ b/src/bundle.js @@ -5,94 +5,174 @@ var _define = window.define; // document-register-element -var docRegister = require("document-register-element"); -_define("document-register-element", function() { +var docRegister = require('document-register-element'); +_define('document-register-element', function() { return docRegister; }); // fetch -var fetch = require("whatwg-fetch"); -_define("fetch", function() { - return fetch +var fetch = require('whatwg-fetch'); +_define('fetch', function() { + return fetch; +}); + +// query-string +var query = require('query-string'); +_define('queryString', function() { + return query; }); // flvjs -var flvjs = require("flv.js").default; -_define("flvjs", function() { +var flvjs = require('flv.js/dist/flv').default; +_define('flvjs', function() { return flvjs; }); // jstree -var jstree = require("jstree"); -require("jstree/dist/themes/default/style.css"); -_define("jstree", function() { +var jstree = require('jstree'); +require('jstree/dist/themes/default/style.css'); +_define('jstree', function() { return jstree; }); // jquery -var jquery = require("jquery"); -_define("jQuery", function() { +var jquery = require('jquery'); +_define('jQuery', function() { return jquery; }); // hlsjs -var hlsjs = require("hls.js"); -_define("hlsjs", function() { +var hlsjs = require('hls.js'); +_define('hlsjs', function() { return hlsjs; }); // howler -var howler = require("howler"); -_define("howler", function() { +var howler = require('howler'); +_define('howler', function() { return howler; }); -// native-promise-only -var nativePromise = require("native-promise-only"); -_define("native-promise-only", function() { - return nativePromise; -}); - // resize-observer-polyfill -var resize = require("resize-observer-polyfill").default; -_define("resize-observer-polyfill", function() { +var resize = require('resize-observer-polyfill').default; +_define('resize-observer-polyfill', function() { return resize; }); // shaka -var shaka = require("shaka-player"); -_define("shaka", function() { +var shaka = require('shaka-player'); +_define('shaka', function() { return shaka; }); // swiper -var swiper = require("swiper"); -require("swiper/dist/css/swiper.min.css"); -_define("swiper", function() { +var swiper = require('swiper/js/swiper'); +require('swiper/css/swiper.min.css'); +_define('swiper', function() { return swiper; }); // sortable -var sortable = require("sortablejs").default; -_define("sortable", function() { +var sortable = require('sortablejs').default; +_define('sortable', function() { return sortable; }); // webcomponents -var webcomponents = require("webcomponents.js/webcomponents-lite"); -_define("webcomponents", function() { - return webcomponents -}); - -// libjass -var libjass = require("libjass"); -require("libjass/libjass.css"); -_define("libjass", function() { - return libjass; +var webcomponents = require('webcomponents.js/webcomponents-lite'); +_define('webcomponents', function() { + return webcomponents; }); // libass-wasm -var libass_wasm = require("libass-wasm"); -_define("JavascriptSubtitlesOctopus", function() { - return libass_wasm; +var libassWasm = require('libass-wasm'); +_define('JavascriptSubtitlesOctopus', function() { + return libassWasm; +}); + +// material-icons +var materialIcons = require('material-design-icons-iconfont/dist/material-design-icons.css'); +_define('material-icons', function() { + return materialIcons; +}); + +// noto font +var noto = require('jellyfin-noto'); +_define('jellyfin-noto', function () { + return noto; +}); + +// page.js +var page = require('page'); +_define('page', function() { + return page; +}); + +// core-js +var polyfill = require('@babel/polyfill/dist/polyfill'); +_define('polyfill', function () { + return polyfill; +}); + +// domtokenlist-shim +var classlist = require('classlist.js'); +_define('classlist-polyfill', function () { + return classlist; +}); + +// Date-FNS +var dateFns = require('date-fns'); +_define('date-fns', function () { + return dateFns; +}); + +var dateFnsLocale = require('date-fns/locale'); +_define('date-fns/locale', function () { + return dateFnsLocale; +}); + +var fast_text_encoding = require('fast-text-encoding'); +_define('fast-text-encoding', function () { + return fast_text_encoding; +}); + +// intersection-observer +var intersection_observer = require('intersection-observer'); +_define('intersection-observer', function () { + return intersection_observer; +}); + +// screenfull +var screenfull = require('screenfull'); +_define('screenfull', function () { + return screenfull; +}); + +// headroom.js +var headroom = require('headroom.js/dist/headroom'); +_define('headroom', function () { + return headroom; +}); + +// apiclient +var apiclient = require('jellyfin-apiclient'); + +_define('apiclient', function () { + return apiclient.ApiClient; +}); + +_define('events', function () { + return apiclient.Events; +}); + +_define('credentialprovider', function () { + return apiclient.Credentials; +}); + +_define('connectionManagerFactory', function () { + return apiclient.ConnectionManager; +}); + +_define('appStorage', function () { + return apiclient.AppStorage; }); diff --git a/src/components/accessschedule/accessschedule.js b/src/components/accessschedule/accessschedule.js index 2f4be8b2a7..870231cf03 100644 --- a/src/components/accessschedule/accessschedule.js +++ b/src/components/accessschedule/accessschedule.js @@ -1,5 +1,5 @@ -define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "formDialogStyle"], function (dialogHelper, datetime) { - "use strict"; +define(['dialogHelper', 'datetime', 'globalize', 'emby-select', 'paper-icon-button-light', 'formDialogStyle'], function (dialogHelper, datetime, globalize) { + 'use strict'; function getDisplayTime(hours) { var minutes = 0; @@ -13,32 +13,32 @@ define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "f } function populateHours(context) { - var html = ""; + var html = ''; for (var i = 0; i < 24; i++) { - html += '"; + html += ''; } - html += '"; - context.querySelector("#selectStart").innerHTML = html; - context.querySelector("#selectEnd").innerHTML = html; + html += ''; + context.querySelector('#selectStart').innerHTML = html; + context.querySelector('#selectEnd').innerHTML = html; } function loadSchedule(context, schedule) { - context.querySelector("#selectDay").value = schedule.DayOfWeek || "Sunday"; - context.querySelector("#selectStart").value = schedule.StartHour || 0; - context.querySelector("#selectEnd").value = schedule.EndHour || 0; + context.querySelector('#selectDay').value = schedule.DayOfWeek || 'Sunday'; + context.querySelector('#selectStart').value = schedule.StartHour || 0; + context.querySelector('#selectEnd').value = schedule.EndHour || 0; } function submitSchedule(context, options) { var updatedSchedule = { - DayOfWeek: context.querySelector("#selectDay").value, - StartHour: context.querySelector("#selectStart").value, - EndHour: context.querySelector("#selectEnd").value + DayOfWeek: context.querySelector('#selectDay').value, + StartHour: context.querySelector('#selectStart').value, + EndHour: context.querySelector('#selectEnd').value }; if (parseFloat(updatedSchedule.StartHour) >= parseFloat(updatedSchedule.EndHour)) { - return void alert(Globalize.translate("ErrorMessageStartHourGreaterThanEnd")); + return void alert(globalize.translate('ErrorMessageStartHourGreaterThanEnd')); } context.submitted = true; @@ -50,32 +50,32 @@ define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "f show: function (options) { return new Promise(function (resolve, reject) { var xhr = new XMLHttpRequest(); - xhr.open("GET", "components/accessschedule/accessschedule.template.html", true); + xhr.open('GET', 'components/accessschedule/accessschedule.template.html', true); xhr.onload = function (e) { var template = this.response; var dlg = dialogHelper.createDialog({ removeOnClose: true, - size: "small" + size: 'small' }); - dlg.classList.add("formDialog"); - var html = ""; - html += Globalize.translateDocument(template); + dlg.classList.add('formDialog'); + var html = ''; + html += globalize.translateDocument(template); dlg.innerHTML = html; populateHours(dlg); loadSchedule(dlg, options.schedule); dialogHelper.open(dlg); - dlg.addEventListener("close", function () { + dlg.addEventListener('close', function () { if (dlg.submitted) { resolve(options.schedule); } else { reject(); } }); - dlg.querySelector(".btnCancel").addEventListener("click", function (e) { + dlg.querySelector('.btnCancel').addEventListener('click', function (e) { dialogHelper.close(dlg); }); - dlg.querySelector("form").addEventListener("submit", function (e) { + dlg.querySelector('form').addEventListener('submit', function (e) { submitSchedule(dlg, options); e.preventDefault(); return false; diff --git a/src/components/accessschedule/accessschedule.template.html b/src/components/accessschedule/accessschedule.template.html index 50d172ae49..493150ae5e 100644 --- a/src/components/accessschedule/accessschedule.template.html +++ b/src/components/accessschedule/accessschedule.template.html @@ -1,6 +1,6 @@
-

${HeaderAccessSchedule} diff --git a/src/components/actionsheet/actionsheet.css b/src/components/actionsheet/actionsheet.css index 8e5084038a..87d6e9466c 100644 --- a/src/components/actionsheet/actionsheet.css +++ b/src/components/actionsheet/actionsheet.css @@ -4,7 +4,7 @@ padding: 0; border: none; max-height: 84%; - border-radius: .1em !important; + border-radius: 0.1em !important; } .actionsheet-not-fullscreen { @@ -24,7 +24,7 @@ .actionSheetContent { margin: 0 !important; - padding: .4em 0 !important; + padding: 0.4em 0 !important; flex-direction: column; display: flex; justify-content: center; @@ -45,7 +45,7 @@ } .actionsheetListItemBody { - padding: .4em 1em .4em .6em !important; + padding: 0.4em 1em 0.4em 0.6em !important; } .actionSheetItemText { @@ -59,13 +59,13 @@ } .actionSheetItemAsideText { - opacity: .7; + opacity: 0.7; font-size: 90%; display: flex; justify-content: flex-end; flex-shrink: 0; margin-left: 5em; - margin-right: .5em; + margin-right: 0.5em; } .actionSheetScroller { @@ -83,14 +83,14 @@ } .actionsheetDivider { - height: .07em; - margin: .25em 0; + height: 0.07em; + margin: 0.25em 0; flex-shrink: 0; } .actionSheetTitle { - margin: .6em 0 .7em !important; - padding: 0 .9em; + margin: 0.6em 0 0.7em !important; + padding: 0 0.9em; flex-grow: 0; } @@ -100,7 +100,7 @@ } .actionsheetMenuItemIcon { - margin: 0 .85em 0 .45em !important; + margin: 0 0.85em 0 0.45em !important; padding: 0 !important; } @@ -110,6 +110,6 @@ .btnCloseActionSheet { position: fixed; - top: .75em; - left: .5em; + top: 0.75em; + left: 0.5em; } diff --git a/src/components/actionsheet/actionsheet.js b/src/components/actionsheet/actionsheet.js index d4e6b61c8a..e08fbf4a25 100644 --- a/src/components/actionsheet/actionsheet.js +++ b/src/components/actionsheet/actionsheet.js @@ -136,7 +136,7 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu // 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;"; + style += 'min-width:' + minWidth + 'px;'; } var i; @@ -158,7 +158,7 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu } if (layoutManager.tv) { - html += ''; + html += ''; } // If any items have an icon, give them all an icon just to make sure they're all lined up evenly @@ -226,9 +226,9 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-bu if (itemIcon) { - html += '' + itemIcon + ''; + html += ''; } else if (renderIcon && !center) { - html += ''; + html += ''; } html += '
'; diff --git a/src/components/activitylog.js b/src/components/activitylog.js index e02fb0c868..a7b3f48bc2 100644 --- a/src/components/activitylog.js +++ b/src/components/activitylog.js @@ -1,60 +1,59 @@ -define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function (events, globalize, dom, datetime, userSettings, serverNotifications, connectionManager) { - "use strict"; +define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings', 'serverNotifications', 'connectionManager', 'emby-button', 'listViewStyle'], function (events, globalize, dom, datefns, dfnshelper, userSettings, serverNotifications, connectionManager) { + 'use strict'; function getEntryHtml(entry, apiClient) { - var html = ""; + var html = ''; html += '
'; - var color = "#00a4dc"; - var icon = "notifications"; + var color = '#00a4dc'; + var icon = 'notifications'; - if ("Error" == entry.Severity || "Fatal" == entry.Severity || "Warn" == entry.Severity) { - color = "#cc0000"; - icon = "notification_important"; + if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) { + color = '#cc0000'; + icon = 'notification_important'; } if (entry.UserId && entry.UserPrimaryImageTag) { - html += 'dvr" + }) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\">"; } else { - html += '' + icon + ''; + html += ''; } html += '
'; html += '
'; html += entry.Name; - html += "
"; + html += '
'; html += '
'; - var date = datetime.parseISO8601Date(entry.Date, true); - html += datetime.toLocaleString(date).toLowerCase(); - html += "
"; + html += datefns.formatRelative(Date.parse(entry.Date), Date.parse(new Date()), { locale: dfnshelper.getLocale() }); + html += '
'; html += '
'; - html += entry.ShortOverview || ""; - html += "
"; - html += "
"; + html += entry.ShortOverview || ''; + html += '

'; + html += ''; if (entry.Overview) { - html += ''; + html += ''; } - return html += ""; + return html += ''; } function renderList(elem, apiClient, result, startIndex, limit) { elem.innerHTML = result.Items.map(function (i) { return getEntryHtml(i, apiClient); - }).join(""); + }).join(''); } function reloadData(instance, elem, apiClient, startIndex, limit) { if (null == startIndex) { - startIndex = parseInt(elem.getAttribute("data-activitystartindex") || "0"); + startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0'); } - limit = limit || parseInt(elem.getAttribute("data-activitylimit") || "7"); + limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7'); var minDate = new Date(); - var hasUserId = "false" !== elem.getAttribute("data-useractivity"); + var hasUserId = 'false' !== elem.getAttribute('data-useractivity'); if (hasUserId) { minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back @@ -62,22 +61,22 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific minDate.setTime(minDate.getTime() - 7 * 24 * 60 * 60 * 1000); // one week back } - ApiClient.getJSON(ApiClient.getUrl("System/ActivityLog/Entries", { + ApiClient.getJSON(ApiClient.getUrl('System/ActivityLog/Entries', { startIndex: startIndex, limit: limit, minDate: minDate.toISOString(), hasUserId: hasUserId })).then(function (result) { - elem.setAttribute("data-activitystartindex", startIndex); - elem.setAttribute("data-activitylimit", limit); + elem.setAttribute('data-activitystartindex', startIndex); + elem.setAttribute('data-activitylimit', limit); if (!startIndex) { - var activityContainer = dom.parentWithClass(elem, "activityContainer"); + var activityContainer = dom.parentWithClass(elem, 'activityContainer'); if (activityContainer) { if (result.Items.length) { - activityContainer.classList.remove("hide"); + activityContainer.classList.remove('hide'); } else { - activityContainer.classList.add("hide"); + activityContainer.classList.add('hide'); } } } @@ -96,10 +95,10 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific } function onListClick(e) { - var btnEntryInfo = dom.parentWithClass(e.target, "btnEntryInfo"); + var btnEntryInfo = dom.parentWithClass(e.target, 'btnEntryInfo'); if (btnEntryInfo) { - var id = btnEntryInfo.getAttribute("data-id"); + var id = btnEntryInfo.getAttribute('data-id'); var items = this.items; if (items) { @@ -115,7 +114,7 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific } function showItemOverview(item) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert({ text: item.Overview }); @@ -125,28 +124,28 @@ define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotific function ActivityLog(options) { this.options = options; var element = options.element; - element.classList.add("activityLogListWidget"); - element.addEventListener("click", onListClick.bind(this)); + element.classList.add('activityLogListWidget'); + element.addEventListener('click', onListClick.bind(this)); var apiClient = connectionManager.getApiClient(options.serverId); reloadData(this, element, apiClient); var onUpdate = onActivityLogUpdate.bind(this); this.updateFn = onUpdate; - events.on(serverNotifications, "ActivityLogEntry", onUpdate); - apiClient.sendMessage("ActivityLogEntryStart", "0,1500"); + events.on(serverNotifications, 'ActivityLogEntry', onUpdate); + apiClient.sendMessage('ActivityLogEntryStart', '0,1500'); } ActivityLog.prototype.destroy = function () { var options = this.options; if (options) { - options.element.classList.remove("activityLogListWidget"); - connectionManager.getApiClient(options.serverId).sendMessage("ActivityLogEntryStop", "0,1500"); + options.element.classList.remove('activityLogListWidget'); + connectionManager.getApiClient(options.serverId).sendMessage('ActivityLogEntryStop', '0,1500'); } var onUpdate = this.updateFn; if (onUpdate) { - events.off(serverNotifications, "ActivityLogEntry", onUpdate); + events.off(serverNotifications, 'ActivityLogEntry', onUpdate); } this.items = null; diff --git a/src/components/alert.js b/src/components/alert.js index 8a4dc11c20..8a37ac1845 100644 --- a/src/components/alert.js +++ b/src/components/alert.js @@ -42,4 +42,4 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize) return Promise.resolve(); }; -}); \ No newline at end of file +}); diff --git a/src/components/alphapicker/alphapicker.js b/src/components/alphapicker/alphapicker.js index b9d31be5dd..79f74879e5 100644 --- a/src/components/alphapicker/alphapicker.js +++ b/src/components/alphapicker/alphapicker.js @@ -67,7 +67,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b html += '
'; if (options.mode === 'keyboard') { - html += ''; + html += ''; } else { letters = ['#']; html += mapLetters(letters, vertical).join(''); @@ -77,7 +77,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b html += mapLetters(letters, vertical).join(''); if (options.mode === 'keyboard') { - html += ''; + html += ''; html += '
'; letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']; @@ -132,7 +132,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b if (alphaPickerButton) { var value = alphaPickerButton.getAttribute('data-value'); - element.dispatchEvent(new CustomEvent("alphavalueclicked", { + element.dispatchEvent(new CustomEvent('alphavalueclicked', { cancelable: false, detail: { value: value @@ -241,7 +241,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b try { btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']'); } catch (err) { - console.log('Error in querySelector: ' + err); + console.error('error in querySelector: ' + err); } if (btn && btn !== selected) { @@ -262,7 +262,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b } if (applyValue) { - element.dispatchEvent(new CustomEvent("alphavaluechanged", { + element.dispatchEvent(new CustomEvent('alphavaluechanged', { cancelable: false, detail: { value: value diff --git a/src/components/alphapicker/style.css b/src/components/alphapicker/style.css index 29543421eb..4e94c0f754 100644 --- a/src/components/alphapicker/style.css +++ b/src/components/alphapicker/style.css @@ -35,16 +35,15 @@ font-size: inherit; min-width: initial; margin: 0; - padding: .1em .4em; + padding: 0.1em 0.4em; width: auto; - border-radius: .1em; + border-radius: 0.1em; font-weight: normal; flex-shrink: 0; flex-grow: 1; } @media all and (max-height: 50em) { - .alphaPicker-fixed { bottom: 5em; } @@ -56,14 +55,12 @@ } @media all and (max-height: 49em) { - .alphaPicker-vertical { font-size: 94%; } } @media all and (max-height: 44em) { - .alphaPicker-vertical { font-size: 90%; } @@ -75,14 +72,12 @@ } @media all and (max-height: 37em) { - .alphaPicker-vertical { font-size: 82%; } } @media all and (max-height: 32em) { - .alphaPicker-vertical { font-size: 74%; } @@ -112,27 +107,17 @@ bottom: 1%; } -.alphaPicker-fixed-left { - left: .4em; -} - .alphaPicker-fixed-right { - right: .4em; + right: 0.4em; } @media all and (min-width: 62.5em) { - - .alphaPicker-fixed-left { - left: 1em; - } - .alphaPicker-fixed-right { right: 1em; } } @media all and (max-height: 31.25em) { - .alphaPicker-fixed { display: none !important; } diff --git a/src/components/appRouter.js b/src/components/appRouter.js index 8643e3f47f..2e11ef88d9 100644 --- a/src/components/appRouter.js +++ b/src/components/appRouter.js @@ -14,6 +14,9 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM }, showSettings: function () { show('/settings/settings.html'); + }, + showNowPlaying: function () { + show('/nowplaying.html'); } }; @@ -197,8 +200,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM var apiClient = this; - if (data.status === 401) { - if (data.errorCode === "ParentalControl") { + if (data.status === 403) { + if (data.errorCode === 'ParentalControl') { var isCurrentAllowed = currentRouteInfo ? (currentRouteInfo.route.anonymous || currentRouteInfo.route.startup) : true; @@ -265,6 +268,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM } function getMaxBandwidth() { + /* eslint-disable compat/compat */ if (navigator.connection) { var max = navigator.connection.downlinkMax; if (max && max > 0 && max < Number.POSITIVE_INFINITY) { @@ -276,6 +280,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM return max; } } + /* eslint-enable compat/compat */ return null; } @@ -367,7 +372,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM } function enableNativeHistory() { - return page.enableNativeHistory(); + return false; } function authenticate(ctx, route, callback) { @@ -387,13 +392,13 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM var apiClient = connectionManager.currentApiClient(); var pathname = ctx.pathname.toLowerCase(); - console.log('appRouter - processing path request ' + pathname); + console.debug('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'); + console.debug('appRouter - route does not allow anonymous access, redirecting to login'); beginConnectionWizard(); return; } @@ -408,10 +413,10 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM if (apiClient && apiClient.isLoggedIn()) { - console.log('appRouter - user is authenticated'); + console.debug('appRouter - user is authenticated'); if (route.isDefaultRoute) { - console.log('appRouter - loading skin home page'); + console.debug('appRouter - loading skin home page'); loadUserSkinWithOptions(ctx); return; } else if (route.roles) { @@ -425,7 +430,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM } } - console.log('appRouter - proceeding to ' + pathname); + console.debug('appRouter - proceeding to ' + pathname); callback(); } @@ -508,9 +513,16 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM return baseRoute; } + var popstateOccurred = false; + window.addEventListener('popstate', function () { + popstateOccurred = true; + }); + function getHandler(route) { return function (ctx, next) { + ctx.isBack = popstateOccurred; handleRoute(ctx, next, route); + popstateOccurred = false; }; } @@ -529,15 +541,15 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM } function param(name, url) { - name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); - var regexS = "[\\?&]" + name + "=([^&#]*)"; - var regex = new RegExp(regexS, "i"); + name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); + var regexS = '[\\?&]' + name + '=([^&#]*)'; + var regex = new RegExp(regexS, 'i'); var results = regex.exec(url || getWindowLocationSearch()); if (results == null) { - return ""; + return ''; } else { - return decodeURIComponent(results[1].replace(/\+/g, " ")); + return decodeURIComponent(results[1].replace(/\+/g, ' ')); } } @@ -545,22 +557,31 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM page.back(); } + /** + * Pages of "no return" (when "Go back" should behave differently, probably quitting the application). + */ + var startPages = ['home', 'login', 'selectserver']; + function canGoBack() { var curr = current(); if (!curr) { return false; } - if (curr.type === 'home') { + if (!document.querySelector('.dialogContainer') && startPages.indexOf(curr.type) !== -1) { return false; } - return page.canGoBack(); + if (enableHistory()) { + return history.length > 1; + } + return (page.len || 0) > 0; } function showDirect(path) { return new Promise(function(resolve, reject) { - resolveOnNextShow = resolve, page.show(baseUrl()+path) - }) + resolveOnNextShow = resolve; + page.show(baseUrl() + path); + }); } function show(path, options) { @@ -658,7 +679,8 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM function pushState(state, title, url) { state.navigate = false; - page.pushState(state, title, url); + history.pushState(state, title, url); + } function setBaseRoute() { @@ -667,7 +689,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM baseRoute = baseRoute.substring(0, baseRoute.length - 1); } - console.log('Setting page base to ' + baseRoute); + console.debug('setting page base to ' + baseRoute); page.base(baseRoute); } @@ -708,7 +730,7 @@ define(['loading', 'globalize', 'events', 'viewManager', 'layoutManager', 'skinM appRouter.getRoutes = getRoutes; appRouter.pushState = pushState; appRouter.enableNativeHistory = enableNativeHistory; - appRouter.handleAnchorClick = page.handleAnchorClick; + appRouter.handleAnchorClick = page.clickHandler; appRouter.TransparencyLevel = { None: 0, Backdrop: 1, diff --git a/src/components/appfooter/appfooter.css b/src/components/appfooter/appfooter.css index 789bc1db20..6dc00b00c2 100644 --- a/src/components/appfooter/appfooter.css +++ b/src/components/appfooter/appfooter.css @@ -2,12 +2,12 @@ position: fixed; left: 0; right: 0; - z-index: 1; + z-index: 10; bottom: 0; transition: transform 180ms linear; contain: layout style; } - .appfooter.headroom--unpinned { - transform: translateY(100%)!important; - } \ No newline at end of file +.appfooter.headroom--unpinned { + transform: translateY(100%) !important; +} diff --git a/src/components/appfooter/appfooter.js b/src/components/appfooter/appfooter.js index 61bb62ec29..07d7701ff2 100644 --- a/src/components/appfooter/appfooter.js +++ b/src/components/appfooter/appfooter.js @@ -2,24 +2,18 @@ define(['browser', 'css!./appfooter'], function (browser) { 'use strict'; function render(options) { - var elem = document.createElement('div'); - elem.classList.add('appfooter'); - 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); }; diff --git a/src/components/apphost.js b/src/components/apphost.js index b1b1c30dc9..75e8ba17f1 100644 --- a/src/components/apphost.js +++ b/src/components/apphost.js @@ -1,17 +1,17 @@ -define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSettings, browser, events, htmlMediaHelper) { - "use strict"; +define(['appSettings', 'browser', 'events', 'htmlMediaHelper', 'webSettings', 'globalize'], function (appSettings, browser, events, htmlMediaHelper, webSettings, globalize) { + 'use strict'; function getBaseProfileOptions(item) { var disableHlsVideoAudioCodecs = []; if (item && htmlMediaHelper.enableHlsJsPlayer(item.RunTimeTicks, item.MediaType)) { if (browser.edge || browser.msie) { - disableHlsVideoAudioCodecs.push("mp3"); + disableHlsVideoAudioCodecs.push('mp3'); } - disableHlsVideoAudioCodecs.push("ac3"); - disableHlsVideoAudioCodecs.push("eac3"); - disableHlsVideoAudioCodecs.push("opus"); + disableHlsVideoAudioCodecs.push('ac3'); + disableHlsVideoAudioCodecs.push('eac3'); + disableHlsVideoAudioCodecs.push('opus'); } return { @@ -22,7 +22,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet function getDeviceProfileForWindowsUwp(item) { return new Promise(function (resolve, reject) { - require(["browserdeviceprofile", "environments/windows-uwp/mediacaps"], function (profileBuilder, uwpMediaCaps) { + require(['browserdeviceprofile', 'environments/windows-uwp/mediacaps'], function (profileBuilder, uwpMediaCaps) { var profileOptions = getBaseProfileOptions(item); profileOptions.supportsDts = uwpMediaCaps.supportsDTS(); profileOptions.supportsTrueHd = uwpMediaCaps.supportsDolby(); @@ -40,26 +40,15 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet } return new Promise(function (resolve) { - require(["browserdeviceprofile"], function (profileBuilder) { + require(['browserdeviceprofile'], function (profileBuilder) { var profile; if (window.NativeShell) { profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder); } else { - profile = profileBuilder(getBaseProfileOptions(item)); - - if (item && !options.isRetry && "allcomplexformats" !== appSettings.get("subtitleburnin")) { - if (!browser.orsay && !browser.tizen) { - profile.SubtitleProfiles.push({ - Format: "ass", - Method: "External" - }); - profile.SubtitleProfiles.push({ - Format: "ssa", - Method: "External" - }); - } - } + var builderOpts = getBaseProfileOptions(item); + builderOpts.enableSsaRender = (item && !options.isRetry && 'allcomplexformats' !== appSettings.get('subtitleburnin')); + profile = profileBuilder(builderOpts); } resolve(profile); @@ -68,12 +57,12 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet } function escapeRegExp(str) { - return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); + return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1'); } function replaceAll(originalString, strReplace, strWith) { var strReplace2 = escapeRegExp(strReplace); - var reg = new RegExp(strReplace2, "ig"); + var reg = new RegExp(strReplace2, 'ig'); return originalString.replace(reg, strWith); } @@ -81,7 +70,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet var keys = []; if (keys.push(navigator.userAgent), keys.push(new Date().getTime()), self.btoa) { - var result = replaceAll(btoa(keys.join("|")), "=", "1"); + var result = replaceAll(btoa(keys.join('|')), '=', '1'); return Promise.resolve(result); } @@ -89,7 +78,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet } function getDeviceId() { - var key = "_deviceId2"; + var key = '_deviceId2'; var deviceId = appSettings.get(key); if (deviceId) { @@ -104,16 +93,16 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet function getDeviceName() { var deviceName; - deviceName = browser.tizen ? "Samsung Smart TV" : browser.web0s ? "LG Smart TV" : browser.operaTv ? "Opera TV" : browser.xboxOne ? "Xbox One" : browser.ps4 ? "Sony PS4" : browser.chrome ? "Chrome" : browser.edge ? "Edge" : browser.firefox ? "Firefox" : browser.msie ? "Internet Explorer" : browser.opera ? "Opera" : "Web Browser"; + deviceName = browser.tizen ? 'Samsung Smart TV' : browser.web0s ? 'LG Smart TV' : browser.operaTv ? 'Opera TV' : browser.xboxOne ? 'Xbox One' : browser.ps4 ? 'Sony PS4' : browser.chrome ? 'Chrome' : browser.edge ? 'Edge' : browser.firefox ? 'Firefox' : browser.msie ? 'Internet Explorer' : browser.opera ? 'Opera' : browser.safari ? 'Safari' : 'Web Browser'; if (browser.ipad) { - deviceName += " iPad"; + deviceName += ' iPad'; } else { if (browser.iphone) { - deviceName += " iPhone"; + deviceName += ' iPhone'; } else { if (browser.android) { - deviceName += " Android"; + deviceName += ' Android'; } } } @@ -135,12 +124,12 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet } var element = document.documentElement; - return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement("video").webkitEnterFullscreen; + return (element.requestFullscreen || element.mozRequestFullScreen || element.webkitRequestFullscreen || element.msRequestFullscreen) || document.createElement('video').webkitEnterFullscreen; } function getSyncProfile() { return new Promise(function (resolve) { - require(["browserdeviceprofile", "appSettings"], function (profileBuilder, appSettings) { + require(['browserdeviceprofile', 'appSettings'], function (profileBuilder, appSettings) { var profile; if (window.NativeShell) { @@ -156,7 +145,7 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet } function getDefaultLayout() { - return "desktop"; + return 'desktop'; } function supportsHtmlMediaAutoplay() { @@ -168,23 +157,25 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet return false; } - var savedResult = appSettings.get(htmlMediaAutoplayAppStorageKey); - return "true" === savedResult || "false" !== savedResult && null; + return true; } - function cueSupported() { + function supportsCue() { try { - var video = document.createElement("video"); - var style = document.createElement("style"); - style.textContent = "video::cue {background: inherit}"; + var video = document.createElement('video'); + var style = document.createElement('style'); + + style.textContent = 'video::cue {background: inherit}'; document.body.appendChild(style); document.body.appendChild(video); - var cue = window.getComputedStyle(video, "::cue").background; + + var cue = window.getComputedStyle(video, '::cue').background; document.body.removeChild(style); document.body.removeChild(video); + return !!cue.length; } catch (err) { - console.log("Error detecting cue support:" + err); + console.error('error detecting cue support: ' + err); return false; } } @@ -192,150 +183,172 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet function onAppVisible() { if (isHidden) { isHidden = false; - console.log("triggering app resume event"); - events.trigger(appHost, "resume"); + console.debug('triggering app resume event'); + events.trigger(appHost, 'resume'); } } function onAppHidden() { if (!isHidden) { isHidden = true; - console.log("app is hidden"); + console.debug('app is hidden'); } } - var htmlMediaAutoplayAppStorageKey = "supportshtmlmediaautoplay0"; - var supportedFeatures = function () { var features = []; if (navigator.share) { - features.push("sharing"); + features.push('sharing'); } if (!browser.edgeUwp && !browser.tv && !browser.xboxOne && !browser.ps4) { - features.push("filedownload"); + features.push('filedownload'); } if (browser.operaTv || browser.tizen || browser.orsay || browser.web0s) { - features.push("exit"); + features.push('exit'); } else { - features.push("exitmenu"); - features.push("plugins"); + features.push('exitmenu'); + features.push('plugins'); } if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.ps4) { - features.push("externallinks"); - features.push("externalpremium"); + features.push('externallinks'); + features.push('externalpremium'); } if (!browser.operaTv) { - features.push("externallinkdisplay"); + features.push('externallinkdisplay'); } if (supportsVoiceInput()) { - features.push("voiceinput"); - } - - if (!browser.tv && !browser.xboxOne) { - browser.ps4; + features.push('voiceinput'); } if (supportsHtmlMediaAutoplay()) { - features.push("htmlaudioautoplay"); - features.push("htmlvideoautoplay"); + features.push('htmlaudioautoplay'); + features.push('htmlvideoautoplay'); } if (browser.edgeUwp) { - features.push("sync"); + features.push('sync'); } if (supportsFullscreen()) { - features.push("fullscreenchange"); + features.push('fullscreenchange'); } if (browser.chrome || browser.edge && !browser.slow) { if (!browser.noAnimation && !browser.edgeUwp && !browser.xboxOne) { - features.push("imageanalysis"); + features.push('imageanalysis'); } } if (browser.tv || browser.xboxOne || browser.ps4 || browser.mobile) { - features.push("physicalvolumecontrol"); + features.push('physicalvolumecontrol'); } if (!browser.tv && !browser.xboxOne && !browser.ps4) { - features.push("remotecontrol"); + features.push('remotecontrol'); } if (!browser.operaTv && !browser.tizen && !browser.orsay && !browser.web0s && !browser.edgeUwp) { - features.push("remotevideo"); + features.push('remotevideo'); } - features.push("displaylanguage"); - features.push("otherapppromotions"); - features.push("displaymode"); - features.push("targetblank"); - // allows users to connect to more than one server - //features.push("multiserver"); - features.push("screensaver"); + features.push('displaylanguage'); + features.push('otherapppromotions'); + features.push('displaymode'); + features.push('targetblank'); + features.push('screensaver'); - if (!browser.orsay && !browser.tizen && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || cueSupported())) { - features.push("subtitleappearancesettings"); + webSettings.enableMultiServer().then(enabled => { + if (enabled) features.push('multiserver'); + }); + + if (!browser.orsay && !browser.msie && (browser.firefox || browser.ps4 || browser.edge || supportsCue())) { + features.push('subtitleappearancesettings'); } - if (!browser.orsay && !browser.tizen) { - features.push("subtitleburnsettings"); + if (!browser.orsay) { + features.push('subtitleburnsettings'); } if (!browser.tv && !browser.ps4 && !browser.xboxOne) { - features.push("fileinput"); + features.push('fileinput'); } if (browser.chrome) { - features.push("chromecast"); + features.push('chromecast'); } return features; }(); - if (supportedFeatures.indexOf("htmlvideoautoplay") === -1 && supportsHtmlMediaAutoplay() !== false) { - require(["autoPlayDetect"], function (autoPlayDetect) { - autoPlayDetect.supportsHtmlMediaAutoplay().then(function () { - appSettings.set(htmlMediaAutoplayAppStorageKey, "true"); - supportedFeatures.push("htmlvideoautoplay"); - supportedFeatures.push("htmlaudioautoplay"); - }, function () { - appSettings.set(htmlMediaAutoplayAppStorageKey, "false"); + /** + * Do exit according to platform + */ + function doExit() { + try { + if (window.NativeShell) { + window.NativeShell.AppHost.exit(); + } else if (browser.tizen) { + tizen.application.getCurrentApplication().exit(); + } else if (browser.web0s) { + webOS.platformBack(); + } else { + window.close(); + } + } catch (err) { + console.error('error closing application: ' + err); + } + } + + var exitPromise; + + /** + * Ask user for exit + */ + function askForExit() { + if (exitPromise) { + return; + } + + require(['actionsheet'], function (actionsheet) { + exitPromise = actionsheet.show({ + title: globalize.translate('MessageConfirmAppExit'), + items: [ + {id: 'yes', name: globalize.translate('Yes')}, + {id: 'no', name: globalize.translate('No')} + ] + }).then(function (value) { + if (value === 'yes') { + doExit(); + } + }).finally(function () { + exitPromise = null; }); }); } var deviceId; var deviceName; - var appName = "Jellyfin Web"; - var appVersion = "10.5.0"; - var visibilityChange; - var visibilityState; + var appName = 'Jellyfin Web'; + var appVersion = '10.6.0'; var appHost = { getWindowState: function () { - return document.windowState || "Normal"; + return document.windowState || 'Normal'; }, setWindowState: function (state) { - alert("setWindowState is not supported and should not be called"); + alert('setWindowState is not supported and should not be called'); }, exit: function () { - if (window.NativeShell) { - window.NativeShell.AppHost.exit(); - } else if (browser.tizen) { - try { - tizen.application.getCurrentApplication().exit(); - } catch (err) { - console.log("error closing application: " + err); - } + if (!!window.appMode && browser.tizen) { + askForExit(); } else { - window.close(); + doExit(); } }, supports: function (command) { @@ -346,14 +359,14 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet return -1 !== supportedFeatures.indexOf(command.toLowerCase()); }, preferVisualCards: browser.android || browser.chrome, - moreIcon: browser.android ? "dots-vert" : "dots-horiz", + moreIcon: browser.android ? 'more_vert' : 'more_horiz', getSyncProfile: getSyncProfile, getDefaultLayout: function () { if (window.NativeShell) { return window.NativeShell.AppHost.getDefaultLayout(); } - return getDefaultLayout() + return getDefaultLayout(); }, getDeviceProfile: getDeviceProfile, init: function () { @@ -382,58 +395,44 @@ define(["appSettings", "browser", "events", "htmlMediaHelper"], function (appSet return {}; }, setThemeColor: function (color) { - var metaThemeColor = document.querySelector("meta[name=theme-color]"); + var metaThemeColor = document.querySelector('meta[name=theme-color]'); if (metaThemeColor) { - metaThemeColor.setAttribute("content", color); + metaThemeColor.setAttribute('content', color); } }, setUserScalable: function (scalable) { if (!browser.tv) { - var att = scalable ? "width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes" : "width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no"; - document.querySelector("meta[name=viewport]").setAttribute("content", att); + var att = scalable ? 'width=device-width, initial-scale=1, minimum-scale=1, user-scalable=yes' : 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no'; + document.querySelector('meta[name=viewport]').setAttribute('content', att); } } }; - var doc = self.document; - - if (doc) { - if (void 0 !== doc.visibilityState) { - visibilityChange = "visibilitychange"; - visibilityState = "hidden"; - } else { - if (void 0 !== doc.mozHidden) { - visibilityChange = "mozvisibilitychange"; - visibilityState = "mozVisibilityState"; - } else { - if (void 0 !== doc.msHidden) { - visibilityChange = "msvisibilitychange"; - visibilityState = "msVisibilityState"; - } else { - if (void 0 !== doc.webkitHidden) { - visibilityChange = "webkitvisibilitychange"; - visibilityState = "webkitVisibilityState"; - } - } - } - } - } var isHidden = false; + var hidden; + var visibilityChange; - if (doc) { - doc.addEventListener(visibilityChange, function () { - if (document[visibilityState]) { - onAppHidden(); - } else { - onAppVisible(); - } - }); + if (typeof document.hidden !== 'undefined') { /* eslint-disable-line compat/compat */ + hidden = 'hidden'; + visibilityChange = 'visibilitychange'; + } else if (typeof document.webkitHidden !== 'undefined') { + hidden = 'webkitHidden'; + visibilityChange = 'webkitvisibilitychange'; } + document.addEventListener(visibilityChange, function () { + /* eslint-disable-next-line compat/compat */ + if (document[hidden]) { + onAppHidden(); + } else { + onAppVisible(); + } + }, false); + if (self.addEventListener) { - self.addEventListener("focus", onAppVisible); - self.addEventListener("blur", onAppHidden); + self.addEventListener('focus', onAppVisible); + self.addEventListener('blur', onAppHidden); } return appHost; diff --git a/src/components/autoFocuser.js b/src/components/autoFocuser.js index 09ded814f2..0a10cabd2f 100644 --- a/src/components/autoFocuser.js +++ b/src/components/autoFocuser.js @@ -1,71 +1,73 @@ -define(["focusManager", "layoutManager"], function (focusManager, layoutManager) { - "use strict"; +/* eslint-disable indent */ + +/** + * Module for performing auto-focus. + * @module components/autoFocuser + */ + +import focusManager from 'focusManager'; +import layoutManager from 'layoutManager'; /** * Previously selected element. */ - var activeElement; + let activeElement; /** - * Returns true if AutoFocuser is enabled. + * Returns _true_ if AutoFocuser is enabled. */ - function isEnabled() { + export function isEnabled() { return layoutManager.tv; } /** - * Start AutoFocuser + * Start AutoFocuser. */ - function enable() { + export function enable() { if (!isEnabled()) { return; } - window.addEventListener("focusin", function (e) { + window.addEventListener('focusin', function (e) { activeElement = e.target; }); - console.log("AutoFocuser enabled"); - } - - /** - * Create an array from some source. - */ - var arrayFrom = Array.prototype.from || function (src) { - return Array.prototype.slice.call(src); + console.debug('AutoFocuser enabled'); } /** * Set focus on a suitable element, taking into account the previously selected. + * @param {HTMLElement} [container] - Element to limit scope. + * @returns {HTMLElement} Focused element. */ - function autoFocus(container) { + export function autoFocus(container) { if (!isEnabled()) { - return; + return null; } container = container || document.body; - var candidates = []; + let candidates = []; if (activeElement) { // These elements are recreated - if (activeElement.classList.contains("btnPreviousPage")) { - candidates.push(container.querySelector(".btnPreviousPage")); - candidates.push(container.querySelector(".btnNextPage")); - } else if (activeElement.classList.contains("btnNextPage")) { - candidates.push(container.querySelector(".btnNextPage")); - candidates.push(container.querySelector(".btnPreviousPage")); - } else if (activeElement.classList.contains("btnSelectView")) { - candidates.push(container.querySelector(".btnSelectView")); + if (activeElement.classList.contains('btnPreviousPage')) { + candidates.push(container.querySelector('.btnPreviousPage')); + candidates.push(container.querySelector('.btnNextPage')); + } else if (activeElement.classList.contains('btnNextPage')) { + candidates.push(container.querySelector('.btnNextPage')); + candidates.push(container.querySelector('.btnPreviousPage')); + } else if (activeElement.classList.contains('btnSelectView')) { + candidates.push(container.querySelector('.btnSelectView')); } candidates.push(activeElement); } - candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnResume"))); - candidates = candidates.concat(arrayFrom(container.querySelectorAll(".btnPlay"))); + candidates = candidates.concat(Array.from(container.querySelectorAll('.btnResume'))); + candidates = candidates.concat(Array.from(container.querySelectorAll('.btnPlay'))); - var focusedElement; + let focusedElement; candidates.every(function (element) { if (focusManager.isCurrentlyFocusable(element)) { @@ -79,7 +81,7 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager) if (!focusedElement) { // FIXME: Multiple itemsContainers - var itemsContainer = container.querySelector(".itemsContainer"); + const itemsContainer = container.querySelector('.itemsContainer'); if (itemsContainer) { focusedElement = focusManager.autoFocus(itemsContainer); @@ -93,9 +95,10 @@ define(["focusManager", "layoutManager"], function (focusManager, layoutManager) return focusedElement; } - return { - isEnabled: isEnabled, - enable: enable, - autoFocus: autoFocus - }; -}); +/* eslint-enable indent */ + +export default { + isEnabled: isEnabled, + enable: enable, + autoFocus: autoFocus +}; diff --git a/src/components/backdrop/backdrop.js b/src/components/backdrop/backdrop.js index ae07ac3abc..c15e35524c 100644 --- a/src/components/backdrop/backdrop.js +++ b/src/components/backdrop/backdrop.js @@ -1,4 +1,4 @@ -define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./backdrop'], function (browser, connectionManager, playbackManager, dom) { +define(['browser', 'connectionManager', 'playbackManager', 'dom', 'userSettings', 'css!./backdrop'], function (browser, connectionManager, playbackManager, dom, userSettings) { 'use strict'; function enableAnimation(elem) { @@ -180,8 +180,9 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./backdro 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", + type: 'Backdrop', tag: imgTag, + maxWidth: dom.getScreenWidth(), index: index })); }); @@ -190,8 +191,9 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./backdro 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", + type: 'Backdrop', tag: imgTag, + maxWidth: dom.getScreenWidth(), index: index })); }); @@ -236,16 +238,22 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./backdro return true; } + function enabled() { + return userSettings.enableBackdrops(); + } + var rotationInterval; var currentRotatingImages = []; var currentRotationIndex = -1; function setBackdrops(items, imageOptions, enableImageRotation) { - var images = getImageUrls(items, imageOptions); + if (enabled()) { + var images = getImageUrls(items, imageOptions); - if (images.length) { - startRotation(images, enableImageRotation); - } else { - clearBackdrop(); + if (images.length) { + startRotation(images, enableImageRotation); + } else { + clearBackdrop(); + } } } @@ -310,4 +318,4 @@ define(['browser', 'connectionManager', 'playbackManager', 'dom', 'css!./backdro clear: clearBackdrop, externalBackdrop: externalBackdrop }; -}); \ No newline at end of file +}); diff --git a/src/components/backdropscreensaver/plugin.js b/src/components/backdropscreensaver/plugin.js index c0bd31fb86..dc0a906ddb 100644 --- a/src/components/backdropscreensaver/plugin.js +++ b/src/components/backdropscreensaver/plugin.js @@ -1,12 +1,12 @@ -define(["connectionManager"], function (connectionManager) { +define(['connectionManager'], function (connectionManager) { return function () { var self = this; - self.name = "Backdrop ScreenSaver"; - self.type = "screensaver"; - self.id = "backdropscreensaver"; + self.name = 'Backdrop ScreenSaver'; + self.type = 'screensaver'; + self.id = 'backdropscreensaver'; self.supportsAnonymous = false; var currentSlideshow; @@ -14,12 +14,12 @@ define(["connectionManager"], function (connectionManager) { self.show = function () { var query = { - ImageTypes: "Backdrop", - EnableImageTypes: "Backdrop", - IncludeItemTypes: "Movie,Series,MusicArtist", - SortBy: "Random", + ImageTypes: 'Backdrop', + EnableImageTypes: 'Backdrop', + IncludeItemTypes: 'Movie,Series,MusicArtist', + SortBy: 'Random', Recursive: true, - Fields: "Taglines", + Fields: 'Taglines', ImageTypeLimit: 1, StartIndex: 0, Limit: 200 @@ -30,7 +30,7 @@ define(["connectionManager"], function (connectionManager) { if (result.Items.length) { - require(["slideshow"], function (slideshow) { + require(['slideshow'], function (slideshow) { var newSlideShow = new slideshow({ showTitle: true, @@ -52,5 +52,5 @@ define(["connectionManager"], function (connectionManager) { currentSlideshow = null; } }; - } + }; }); diff --git a/src/components/cardbuilder/card.css b/src/components/cardbuilder/card.css index 5520ce2c7e..3cd038cd09 100644 --- a/src/components/cardbuilder/card.css +++ b/src/components/cardbuilder/card.css @@ -1,23 +1,24 @@ +button { + -webkit-border-fit: border !important; +} + button::-moz-focus-inner { padding: 0; border: 0; } -button { - -webkit-border-fit: border !important; -} - .card { border: 0; font-size: inherit !important; font-family: inherit !important; text-transform: none; - background-color: transparent !important; background: none !important; + background-color: transparent !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; @@ -54,17 +55,27 @@ button { contain: layout style; } -.cardPadder-backdrop, .cardPadder-mixedBackdrop, .cardPadder-smallBackdrop, .cardPadder-overflowBackdrop, .cardPadder-overflowSmallBackdrop { +.cardPadder-backdrop, +.cardPadder-mixedBackdrop, +.cardPadder-smallBackdrop, +.cardPadder-overflowBackdrop, +.cardPadder-overflowSmallBackdrop { padding-bottom: 56.25%; contain: strict; } -.cardPadder-square, .cardPadder-mixedSquare, .cardPadder-overflowSquare, .overflowSquareCard-textCardPadder { +.cardPadder-square, +.cardPadder-mixedSquare, +.cardPadder-overflowSquare, +.overflowSquareCard-textCardPadder { padding-bottom: 100%; contain: strict; } -.cardPadder-portrait, .cardPadder-mixedPortrait, .cardPadder-overflowPortrait, .overflowPortraitCard-textCardPadder { +.cardPadder-portrait, +.cardPadder-mixedPortrait, +.cardPadder-overflowPortrait, +.overflowPortraitCard-textCardPadder { padding-bottom: 150%; contain: strict; } @@ -79,23 +90,26 @@ button { margin: 0.6em; transition: none; border: 0 solid transparent; + + /* These both are needed in case cardBox is a button */ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); outline: none !important; contain: layout; contain: style; } +.card.show-animation .cardBox { + will-change: transform; + transition: transform 200ms ease-out; +} + .card.show-focus:not(.show-animation) .cardBox { - margin: .4em; + margin: 0.4em; } .card.show-focus:not(.show-animation) .cardBox.visualCardBox, .card.show-focus:not(.show-animation) .cardBox:not(.visualCardBox) .cardScalable { - border: .5em solid transparent; -} - -.card.show-animation .cardBox { - will-change: transform; - transition: transform 200ms ease-out; + border: 0.5em solid transparent; } .card.show-animation:focus > .cardBox { @@ -120,7 +134,7 @@ button { .btnCardOptions { position: absolute; - bottom: .25em; + bottom: 0.25em; right: 0; margin: 0 !important; z-index: 1; @@ -131,8 +145,8 @@ button { position: absolute; align-items: center; justify-content: center; - top: .3em; - left: .3em; + top: 0.3em; + left: 0.3em; text-align: center; vertical-align: middle; width: 1.6em; @@ -146,12 +160,14 @@ button { background-size: cover; background-repeat: no-repeat; background-position: center center; + display: -webkit-flex; display: flex; align-items: center; justify-content: center; position: relative; background-clip: content-box !important; color: inherit; + /* This is only needed for scalable cards */ height: 100%; contain: strict; @@ -173,12 +189,16 @@ button { 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%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); outline: none !important; contain: strict; } @@ -207,10 +227,6 @@ button { box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); } -.cardImageContainer { - display: flex; -} - .cardImage { position: absolute; top: 0; @@ -226,6 +242,7 @@ button { .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%; @@ -252,17 +269,17 @@ button { } .cardFooter { - padding: .3em .3em .5em .3em; + padding: 0.3em 0.3em 0.5em 0.3em; position: relative; } .visualCardBox { box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); - border-radius: .145em; + border-radius: 0.145em; } .innerCardFooter { - background: rgba(0,0,0,.7); + background: rgba(0, 0, 0, 0.7); position: absolute; bottom: 0; left: 0; @@ -282,7 +299,7 @@ button { } .cardText { - padding: .06em .5em; + padding: 0.06em 0.5em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -294,7 +311,24 @@ button { } .cardText-first { - padding-top: .24em; + padding-top: 0.24em; +} + +.textActionButton { + border: 0 !important; + background: transparent; + padding: 0 !important; + cursor: pointer; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + outline: none !important; + color: inherit; + vertical-align: middle; + font-family: inherit; + font-size: inherit; +} + +.textActionButton:hover { + text-decoration: underline; } .cardText > .textActionButton { @@ -304,7 +338,7 @@ button { } .innerCardFooter > .cardText { - padding: .3em .5em; + padding: 0.3em 0.5em; } .cardFooter-withlogo { @@ -336,36 +370,19 @@ button { text-align: center; } -.textActionButton { - border: 0 !important; - background: transparent; - border: 0 !important; - padding: 0 !important; - cursor: pointer; - outline: none !important; - color: inherit; - vertical-align: middle; - font-family: inherit; - font-size: inherit; -} - -.textActionButton:hover { - text-decoration: underline; -} - -.cardImageIcon { +.cardImageContainer .cardImageIcon { font-size: 5em; color: inherit; } .cardImageIcon-small { - font-size: 3em; - margin-bottom: .1em; + font-size: 3em !important; + margin-bottom: 0.1em; } .cardIndicators { - right: .225em; - top: .225em; + right: 0.225em; + top: 0.225em; position: absolute; display: flex; align-items: center; @@ -382,16 +399,16 @@ button { } .programAttributeIndicator { - padding: .18em .5em; + padding: 0.18em 0.5em; color: #fff; font-weight: 500; } .cardOverlayButton { - color: rgba(255, 255, 255, .76); + color: rgba(255, 255, 255, 0.76); margin: 0; z-index: 1; - padding: .75em; + padding: 0.75em; font-size: 88%; } @@ -402,7 +419,7 @@ button { } .cardOverlayButtonIcon { - background-color: rgba(0,0,0,.7) !important; + background-color: rgba(0, 0, 0, 0.7) !important; border-radius: 100em; width: 1.5em !important; height: 1.5em !important; @@ -412,6 +429,12 @@ button { font-size: 1.66956521739130434em !important; } +.cardOverlayButtonIcon.material-icons { + /* material-icons override display, so we need to + make a better matching selector to set it to flex */ + display: flex; +} + .cardOverlayButton-centered { bottom: initial; right: initial; @@ -424,10 +447,10 @@ button { height: 2.6em; top: 50%; left: 50%; - 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); + background-color: rgba(0, 0, 0, 0.5) !important; + border: 0.06em solid rgba(255, 255, 255, 0.6); + padding: 0.38em !important; + color: rgba(255, 255, 255, 0.76); transition: transform 200ms ease-out; } @@ -474,13 +497,15 @@ button { width: 33.333333333333333333333333333333%; } - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 33.333333333333333333333333333333%; } } @media (min-width: 43.75em) { - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 25%; } } @@ -496,7 +521,8 @@ button { width: 50%; } - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 20%; } @@ -516,7 +542,8 @@ button { width: 25%; } - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 16.666666666666666666666666666667%; } @@ -529,9 +556,9 @@ button { } } - @media (min-width: 87.5em) { - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 14.285714285714285714285714285714%; } @@ -549,13 +576,15 @@ button { width: 20%; } - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 12.5%; } } @media (min-width: 120em) { - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 11.111111111111111111111111111111%; } } @@ -565,7 +594,8 @@ button { width: 25%; } - .squareCard, .portraitCard { + .squareCard, + .portraitCard { width: 10%; } } @@ -596,7 +626,8 @@ button { width: 72vw; } -.overflowSquareCard, .overflowPortraitCard { +.overflowSquareCard, +.overflowPortraitCard { width: 40vw; } @@ -621,29 +652,34 @@ button { } @media (min-width: 43.75em) { - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 23.1vw; } } @media (min-width: 48.125em) { - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 30vw; } } @media (orientation: landscape) { - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 30vw; } - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 23.1vw; } } @media (orientation: landscape) and (min-width: 48.125em) { - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 23.1vw; } } @@ -655,55 +691,60 @@ button { } @media (min-width: 50em) { - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 18.5vw; } } @media (min-width: 75em) { - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 23.1vw; } - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 15.5vw; } } @media (min-width: 87.5em) { - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 13.3vw; } } @media (min-width: 100em) { - - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 18.7vw; } - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 11.6vw; } } @media (min-width: 120em) { - - .overflowSquareCard, .overflowPortraitCard { - width: 10.3vw; + .overflowSquareCard, + .overflowPortraitCard { + width: 10.41vw; } } @media (min-width: 131.25em) { - - .overflowSquareCard, .overflowPortraitCard { + .overflowSquareCard, + .overflowPortraitCard { width: 9.3vw; } } @media (min-width: 156.25em) { - - .overflowBackdropCard, .overflowSmallBackdropCard { + .overflowBackdropCard, + .overflowSmallBackdropCard { width: 15.6vw; } } @@ -720,7 +761,8 @@ button { padding-bottom: 87.75%; } -.itemsContainer-tv > .overflowSquareCard, .itemsContainer-tv > .overflowPortraitCard { +.itemsContainer-tv > .overflowSquareCard, +.itemsContainer-tv > .overflowPortraitCard { width: 15.6vw; } @@ -729,9 +771,9 @@ button { } .cardOverlayContainer { - background: rgba(0,0,0,0.5); + background: rgba(0, 0, 0, 0.5); opacity: 0; - transition: opacity .2s; + transition: opacity 0.2s; position: absolute; top: 0; left: 0; @@ -748,7 +790,7 @@ button { opacity: 0; transition: 0.2s; background: transparent; - padding: 0.5em; + padding: 0.25em; } .cardOverlayButtonIcon-hover { @@ -760,7 +802,7 @@ button { } .cardOverlayFab-primary { - background-color: rgba(0,0,0,0.7); + background-color: rgba(0, 0, 0, 0.7); font-size: 130%; padding: 0; width: 3em; diff --git a/src/components/cardbuilder/cardBuilder.js b/src/components/cardbuilder/cardBuilder.js index 44c5b3b079..43ca28f01d 100644 --- a/src/components/cardbuilder/cardBuilder.js +++ b/src/components/cardbuilder/cardBuilder.js @@ -1,11 +1,36 @@ -define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusManager', 'indicators', 'globalize', 'layoutManager', 'apphost', 'dom', 'browser', 'playbackManager', 'itemShortcuts', 'scripts/imagehelper', 'css!./card', 'paper-icon-button-light', 'programStyles'], - function (datetime, imageLoader, connectionManager, itemHelper, focusManager, indicators, globalize, layoutManager, appHost, dom, browser, playbackManager, itemShortcuts, imageHelper) { - 'use strict'; +/* eslint-disable indent */ - var devicePixelRatio = window.devicePixelRatio || 1; - var enableFocusTransform = !browser.slow && !browser.edge; +/** + * Module for building cards from item data. + * @module components/cardBuilder/cardBuilder + */ - function getCardsHtml(items, options) { +import datetime from 'datetime'; +import imageLoader from 'imageLoader'; +import connectionManager from 'connectionManager'; +import itemHelper from 'itemHelper'; +import focusManager from 'focusManager'; +import indicators from 'indicators'; +import globalize from 'globalize'; +import layoutManager from 'layoutManager'; +import dom from 'dom'; +import browser from 'browser'; +import playbackManager from 'playbackManager'; +import itemShortcuts from 'itemShortcuts'; +import imageHelper from 'scripts/imagehelper'; +import 'css!./card'; +import 'paper-icon-button-light'; +import 'programStyles'; + + const enableFocusTransform = !browser.slow && !browser.edge; + + /** + * Generate the HTML markup for cards for a set of items. + * @param items - The items used to generate cards. + * @param options - The options of the cards. + * @returns {string} The HTML markup for the cards. + */ + export function getCardsHtml(items, options) { if (arguments.length === 1) { options = arguments[0]; items = options.items; @@ -14,6 +39,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return buildCardsHtmlInternal(items, options); } + /** + * Computes the number of posters per row. + * @param {string} shape - Shape of the cards. + * @param {number} screenWidth - Width of the screen. + * @param {boolean} isOrientationLandscape - Flag for the orientation of the screen. + * @returns {number} Number of cards per row for an itemsContainer. + */ function getPostersPerRow(shape, screenWidth, isOrientationLandscape) { switch (shape) { case 'portrait': @@ -140,7 +172,6 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } return 100 / 72; } - break; case 'overflowPortrait': if (layoutManager.tv) { @@ -166,7 +197,6 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } return 100 / 42; } - break; case 'overflowSquare': if (layoutManager.tv) { return 100 / 15.5; @@ -191,7 +221,6 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } return 100 / 42; } - break; case 'overflowBackdrop': if (layoutManager.tv) { return 100 / 23.3; @@ -216,16 +245,20 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } return 100 / 72; } - break; default: return 4; } } + /** + * Checks if the window is resizable. + * @param {number} windowWidth - Width of the device's screen. + * @returns {boolean} - Result of the check. + */ function isResizable(windowWidth) { - var screen = window.screen; + const screen = window.screen; if (screen) { - var screenWidth = screen.availWidth; + const screenWidth = screen.availWidth; if ((screenWidth - windowWidth) > 20) { return true; @@ -235,22 +268,31 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return false; } + /** + * Gets the width of a card's image according to the shape and amount of cards per row. + * @param {string} shape - Shape of the card. + * @param {number} screenWidth - Width of the screen. + * @param {boolean} isOrientationLandscape - Flag for the orientation of the screen. + * @returns {number} Width of the image for a card. + */ function getImageWidth(shape, screenWidth, isOrientationLandscape) { - var imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape); - var shapeWidth = screenWidth / imagesPerRow; - - return Math.round(shapeWidth); + const imagesPerRow = getPostersPerRow(shape, screenWidth, isOrientationLandscape); + return Math.round(screenWidth / imagesPerRow) * 2; } + /** + * Normalizes the options for a card. + * @param {Object} items - A set of items. + * @param {Object} options - Options for handling the items. + */ function setCardData(items, options) { + options.shape = options.shape || 'auto'; - options.shape = options.shape || "auto"; + const primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items); - var primaryImageAspectRatio = imageLoader.getPrimaryImageAspectRatio(items); + if (['auto', 'autohome', 'autooverflow', 'autoVertical'].includes(options.shape)) { - if (options.shape === 'auto' || options.shape === 'autohome' || options.shape === 'autooverflow' || options.shape === 'autoVertical') { - - var requestedShape = options.shape; + const requestedShape = options.shape; options.shape = null; if (primaryImageAspectRatio) { @@ -288,11 +330,11 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } if (!options.width) { - var screenWidth = dom.getWindowSize().innerWidth; - var screenHeight = dom.getWindowSize().innerHeight; + let screenWidth = dom.getWindowSize().innerWidth; + const screenHeight = dom.getWindowSize().innerHeight; if (isResizable(screenWidth)) { - var roundScreenTo = 100; + const roundScreenTo = 100; screenWidth = Math.floor(screenWidth / roundScreenTo) * roundScreenTo; } @@ -300,9 +342,14 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } + /** + * Generates the internal HTML markup for cards. + * @param {Object} items - Items for which to generate the markup. + * @param {Object} options - Options for generating the markup. + * @returns {string} The internal HTML markup of the cards. + */ function buildCardsHtmlInternal(items, options) { - - var isVertical; + let isVertical = false; if (options.shape === 'autoVertical') { isVertical = true; @@ -310,24 +357,21 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana setCardData(items, options); - var html = ''; - var itemsInRow = 0; + let html = ''; + let itemsInRow = 0; - var currentIndexValue; - var hasOpenRow; - var hasOpenSection; + let currentIndexValue; + let hasOpenRow; + let hasOpenSection; - var sectionTitleTagName = options.sectionTitleTagName || 'div'; - var apiClient; - var lastServerId; + let sectionTitleTagName = options.sectionTitleTagName || 'div'; + let apiClient; + let lastServerId; - var i; - var length; + for (let i = 0; i < items.length; i++) { - for (i = 0, length = items.length; i < length; i++) { - - var item = items[i]; - var serverId = item.ServerId || options.serverId; + let item = items[i]; + let serverId = item.ServerId || options.serverId; if (serverId !== lastServerId) { lastServerId = serverId; @@ -335,14 +379,14 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } if (options.indexBy) { - var newIndexValue = ''; + let newIndexValue = ''; if (options.indexBy === 'PremiereDate') { if (item.PremiereDate) { try { newIndexValue = datetime.toLocaleDateString(datetime.parseISO8601Date(item.PremiereDate), { weekday: 'long', month: 'long', day: 'numeric' }); - } catch (err) { - console.log('error parsing timestamp for premiere date'); + } catch (error) { + console.error('error parsing timestamp for premiere date', error); } } } else if (options.indexBy === 'ProductionYear') { @@ -417,21 +461,15 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - var cardFooterHtml = ''; - for (i = 0, length = (options.lines || 0); i < length; i++) { - - if (i === 0) { - cardFooterHtml += '
 
'; - } else { - cardFooterHtml += '
 
'; - } - } - return html; } + /** + * Computes the aspect ratio for a card given its shape. + * @param {string} shape - Shape for which to get the aspect ratio. + * @returns {null|number} Ratio of the shape. + */ function getDesiredAspect(shape) { - if (shape) { shape = shape.toLowerCase(); if (shape.indexOf('portrait') !== -1) { @@ -450,72 +488,85 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return null; } + /** Get the URL of the card's image. + * @param {Object} item - Item for which to generate a card. + * @param {Object} apiClient - API client object. + * @param {Object} options - Options of the card. + * @param {string} shape - Shape of the desired image. + * @returns {Object} Object representing the URL of the card's image. + */ function getCardImageUrl(item, apiClient, options, shape) { + item = item.ProgramInfo || item; - 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; + const width = options.width; + let height = null; + const primaryImageAspectRatio = item.PrimaryImageAspectRatio; + let forceName = false; + let imgUrl = null; + let coverImage = false; + let uiAspect = null; if (options.preferThumb && item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + 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", + type: 'Banner', + maxWidth: width, tag: item.ImageTags.Banner }); } else if (options.preferDisc && item.ImageTags && item.ImageTags.Disc) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Disc", + type: 'Disc', + maxWidth: width, tag: item.ImageTags.Disc }); } else if (options.preferLogo && item.ImageTags && item.ImageTags.Logo) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Logo", + type: 'Logo', + maxWidth: width, tag: item.ImageTags.Logo }); } else if (options.preferLogo && item.ParentLogoImageTag && item.ParentLogoItemId) { imgUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { - type: "Logo", + type: 'Logo', + maxWidth: width, tag: item.ParentLogoImageTag }); } else if (options.preferThumb && item.SeriesThumbImageTag && options.inheritThumb !== false) { imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", + 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", + type: 'Thumb', + maxWidth: width, tag: item.ParentThumbImageTag }); } else if (options.preferThumb && item.BackdropImageTags && item.BackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: width, tag: item.BackdropImageTags[0] }); @@ -524,7 +575,8 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } else if (options.preferThumb && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false && item.Type === 'Episode') { imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: width, tag: item.ParentBackdropImageTags[0] }); @@ -533,7 +585,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Primary", + type: 'Primary', + maxHeight: height, + maxWidth: width, tag: item.ImageTags.Primary }); @@ -553,7 +607,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; imgUrl = apiClient.getScaledImageUrl(item.PrimaryImageItemId || item.Id || item.ItemId, { - type: "Primary", + type: 'Primary', + maxHeight: height, + maxWidth: width, tag: item.PrimaryImageTag }); @@ -570,21 +626,25 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } else if (item.ParentPrimaryImageTag) { imgUrl = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { - type: "Primary", + type: 'Primary', + maxWidth: width, tag: item.ParentPrimaryImageTag }); } else if (item.SeriesPrimaryImageTag) { imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Primary", + type: 'Primary', + maxWidth: width, tag: item.SeriesPrimaryImageTag }); } else if (item.AlbumId && item.AlbumPrimaryImageTag) { - width = primaryImageAspectRatio ? Math.round(height * primaryImageAspectRatio) : null; + height = width && primaryImageAspectRatio ? Math.round(width / primaryImageAspectRatio) : null; imgUrl = apiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", + type: 'Primary', + maxHeight: height, + maxWidth: width, tag: item.AlbumPrimaryImageTag }); @@ -597,42 +657,48 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } else if (item.Type === 'Season' && item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', + maxWidth: width, tag: item.ImageTags.Thumb }); } else if (item.BackdropImageTags && item.BackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: width, tag: item.BackdropImageTags[0] }); } else if (item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', + maxWidth: width, tag: item.ImageTags.Thumb }); } else if (item.SeriesThumbImageTag && options.inheritThumb !== false) { imgUrl = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Thumb", + type: 'Thumb', + maxWidth: width, tag: item.SeriesThumbImageTag }); } else if (item.ParentThumbItemId && options.inheritThumb !== false) { imgUrl = apiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: "Thumb", + type: 'Thumb', + maxWidth: width, tag: item.ParentThumbImageTag }); } else if (item.ParentBackdropImageTags && item.ParentBackdropImageTags.length && options.inheritThumb !== false) { imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: width, tag: item.ParentBackdropImageTags[0] }); @@ -645,21 +711,32 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana }; } + /** + * Generates a random integer in a given range. + * @param {number} min - Minimum of the range. + * @param {number} max - Maximum of the range. + * @returns {number} Randomly generated number. + */ function getRandomInt(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; } - var numRandomColors = 5; + /** + * Generates an index used to select the default color of a card based on a string. + * @param {string} str - String to use for generating the index. + * @returns {number} Index of the color. + */ function getDefaultColorIndex(str) { + const numRandomColors = 5; 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++) { + const charIndex = Math.floor(str.length / 2); + const character = String(str.substr(charIndex, 1).charCodeAt()); + let sum = 0; + for (let i = 0; i < character.length; i++) { sum += parseInt(character.charAt(i)); } - var index = String(sum).substr(-1); + let index = String(sum).substr(-1); return (index % numRandomColors) + 1; } else { @@ -667,18 +744,26 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } + /** + * Generates the HTML markup for a card's text. + * @param {Array} lines - Array containing the text lines. + * @param {string} cssClass - Base CSS class to use for the lines. + * @param {boolean} forceLines - Flag to force the rendering of all lines. + * @param {boolean} isOuterFooter - Flag to mark the text lines as outer footer. + * @param {string} cardLayout - DEPRECATED + * @param {boolean} addRightMargin - Flag to add a right margin to the text. + * @param {number} maxLines - Maximum number of lines to render. + * @returns {string} HTML markup for the card's text. + */ function getCardTextLines(lines, cssClass, forceLines, isOuterFooter, cardLayout, addRightMargin, maxLines) { + let html = ''; - var html = ''; + let valid = 0; - var valid = 0; - var i; - var length; + for (let i = 0; i < lines.length; i++) { - for (i = 0, length = lines.length; i < length; i++) { - - var currentCssClass = cssClass; - var text = lines[i]; + let currentCssClass = cssClass; + let text = lines[i]; if (valid > 0 && isOuterFooter) { currentCssClass += ' cardText-secondary'; @@ -693,7 +778,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (text) { html += "
"; html += text; - html += "
"; + html += ''; valid++; if (maxLines && valid >= maxLines) { @@ -704,9 +789,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (forceLines) { - length = maxLines || Math.min(lines.length, maxLines || lines.length); + let linesLength = maxLines || Math.min(lines.length, maxLines || lines.length); - while (valid < length) { + while (valid < linesLength) { html += "
 
"; valid++; } @@ -715,17 +800,29 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return html; } + /** + * Determines if the item is live TV. + * @param {Object} item - Item to use for the check. + * @returns {boolean} Flag showing if the item is live TV. + */ function isUsingLiveTvNaming(item) { return item.Type === 'Program' || item.Type === 'Timer' || item.Type === 'Recording'; } + /** + * Returns the air time text for the item based on the given times. + * @param {object} item - Item used to generate the air time text. + * @param {string} showAirDateTime - ISO8601 date for the start of the show. + * @param {string} showAirEndTime - ISO8601 date for the end of the show. + * @returns {string} The air time text for the item based on the given dates. + */ function getAirTimeText(item, showAirDateTime, showAirEndTime) { + let airTimeText = ''; - var airTimeText = ''; if (item.StartDate) { try { - var date = datetime.parseISO8601Date(item.StartDate); + let date = datetime.parseISO8601Date(item.StartDate); if (showAirDateTime) { airTimeText += datetime.toLocaleDateString(date, { weekday: 'short', month: 'short', day: 'numeric' }) + ' '; @@ -738,36 +835,50 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana airTimeText += ' - ' + datetime.getDisplayTime(date); } } catch (e) { - console.log("Error parsing date: " + item.StartDate); + console.error('error parsing date: ' + item.StartDate); } } return airTimeText; } + /** + * Generates the HTML markup for the card's footer text. + * @param {Object} item - Item used to generate the footer text. + * @param {Object} apiClient - API client instance. + * @param {Object} options - Options used to generate the footer text. + * @param {string} showTitle - Flag to show the title in the footer. + * @param {boolean} forceName - Flag to force showing the name of the item. + * @param {boolean} overlayText - Flag to show overlay text. + * @param {Object} imgUrl - Object representing the card's image URL. + * @param {string} footerClass - CSS classes of the footer element. + * @param {string} progressHtml - HTML markup of the progress bar element. + * @param {string} logoUrl - URL of the logo for the item. + * @param {boolean} isOuterFooter - Flag to mark the text as outer footer. + * @returns {string} HTML markup of the card's footer text element. + */ function getCardFooterText(item, apiClient, options, showTitle, forceName, overlayText, imgUrl, footerClass, progressHtml, logoUrl, isOuterFooter) { - - var html = ''; + let html = ''; if (logoUrl) { html += ''; } - var showOtherText = isOuterFooter ? !overlayText : overlayText; + const showOtherText = isOuterFooter ? !overlayText : overlayText; if (isOuterFooter && options.cardLayout && layoutManager.mobile) { if (options.cardFooterAside !== 'none') { - html += ''; + html += ''; } } - var cssClass = options.centerText ? "cardText cardTextCentered" : "cardText"; - var serverId = item.ServerId || options.serverId; + const cssClass = options.centerText ? 'cardText cardTextCentered' : 'cardText'; + const serverId = item.ServerId || options.serverId; - var lines = []; - var parentTitleUnderneath = item.Type === 'MusicAlbum' || item.Type === 'Audio' || item.Type === 'MusicVideo'; - var titleAdded; + let lines = []; + const parentTitleUnderneath = item.Type === 'MusicAlbum' || item.Type === 'Audio' || item.Type === 'MusicVideo'; + let titleAdded; if (showOtherText) { if ((options.showParentTitle || options.showParentTitleOrTitle) && !parentTitleUnderneath) { @@ -796,7 +907,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } else { - var parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || ""; + const parentTitle = item.SeriesName || item.Series || item.Album || item.AlbumArtist || ''; if (parentTitle || showTitle) { lines.push(parentTitle); @@ -806,14 +917,14 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - var showMediaTitle = (showTitle && !titleAdded) || (options.showParentTitleOrTitle && !lines.length); + let 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, { + const name = options.showTitle === 'auto' && !item.IsFolder && item.MediaType === 'Photo' ? '' : itemHelper.getDisplayName(item, { includeParentInfo: options.includeParentInfoInTitle }); @@ -835,27 +946,23 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana item.AlbumArtists[0].IsFolder = true; lines.push(getTextActionButton(item.AlbumArtists[0], null, serverId)); } else { - lines.push(isUsingLiveTvNaming(item) ? item.Name : (item.SeriesName || item.Series || item.Album || item.AlbumArtist || "")); + lines.push(isUsingLiveTvNaming(item) ? item.Name : (item.SeriesName || item.Series || item.Album || item.AlbumArtist || '')); } } if (options.showItemCounts) { - - var itemCountHtml = getItemCountsHtml(options, item); - - lines.push(itemCountHtml); + lines.push(getItemCountsHtml(options, item)); } if (options.textLines) { - var additionalLines = options.textLines(item); - for (var i = 0, length = additionalLines.length; i < length; i++) { + const additionalLines = options.textLines(item); + for (let i = 0; i < additionalLines.length; i++) { lines.push(additionalLines[i]); } } if (options.showSongCount) { - - var songLine = ''; + let songLine = ''; if (item.SongCount) { songLine = item.SongCount === 1 ? @@ -870,9 +977,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (item.PremiereDate) { try { - - lines.push(getPremiereDateText(item)); - + lines.push(datetime.toLocaleDateString( + datetime.parseISO8601Date(item.PremiereDate), + { weekday: 'long', month: 'long', day: 'numeric' } + )); } catch (err) { lines.push(''); @@ -885,14 +993,14 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (options.showYear || options.showSeriesYear) { if (item.Type === 'Series') { - if (item.Status === "Continuing") { + if (item.Status === 'Continuing') { lines.push(globalize.translate('SeriesYearToPresent', item.ProductionYear || '')); } else { if (item.EndDate && item.ProductionYear) { - var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); + const endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); lines.push(item.ProductionYear + ((endYear === item.ProductionYear) ? '' : (' - ' + endYear))); } else { lines.push(item.ProductionYear || ''); @@ -974,11 +1082,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (options.showPersonRoleOrType) { if (item.Role) { - lines.push('as ' + item.Role); - } else if (item.Type) { - lines.push(globalize.translate('' + item.Type)); - } else { - lines.push(''); + lines.push(globalize.translate('PersonRole', item.Role)); } } } @@ -987,7 +1091,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana lines = []; } - var addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; + const addRightTextMargin = isOuterFooter && options.cardLayout && !options.centerText && options.cardFooterAside !== 'none' && layoutManager.mobile; html += getCardTextLines(lines, cssClass, !options.overlayText, isOuterFooter, options.cardLayout, addRightTextMargin, options.lines); @@ -1001,15 +1105,21 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana html = '
' + html; //cardFooter - html += "
"; + html += ''; } } return html; } + /** + * Generates the HTML markup for the action button. + * @param {Object} item - Item used to generate the action button. + * @param {string} text - Text of the action button. + * @param {string} serverId - ID of the server. + * @returns {string} HTML markup of the action button. + */ function getTextActionButton(item, text, serverId) { - if (!text) { text = itemHelper.getDisplayName(item); } @@ -1018,18 +1128,22 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return text; } - var html = ''; return html; } + /** + * Generates HTML markup for the item count indicator. + * @param {Object} options - Options used to generate the item count. + * @param {Object} item - Item used to generate the item count. + * @returns {string} HTML markup for the item count indicator. + */ function getItemCountsHtml(options, item) { - - var counts = []; - - var childText; + let counts = []; + let childText; if (item.Type === 'Playlist') { @@ -1037,7 +1151,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (item.RunTimeTicks) { - var minutes = item.RunTimeTicks / 600000000; + let minutes = item.RunTimeTicks / 600000000; minutes = minutes || 1; @@ -1077,7 +1191,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana counts.push(childText); } - } else if (item.Type === 'MusicGenre' || options.context === "MusicArtist") { + } else if (item.Type === 'MusicGenre' || options.context === 'MusicArtist') { if (item.AlbumCount) { @@ -1116,49 +1230,37 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return counts.join(', '); } - function getProgramIndicators(item) { + let refreshIndicatorLoaded; - item = item.ProgramInfo || item; - - var html = ''; - - if (item.IsLive) { - html += '
' + globalize.translate('Live') + '
'; - } - - if (item.IsPremiere) { - html += '
' + globalize.translate('Premiere') + '
'; - } else if (item.IsSeries && !item.IsRepeat) { - html += '
' + globalize.translate('AttributeNew') + '
'; - } - //else if (item.IsRepeat) { - // html += '
' + globalize.translate('Repeat') + '
'; - //} - - if (html) { - html = '
' + html; - html += '
'; - } - - return html; - } - - var refreshIndicatorLoaded; + /** + * Imports the refresh indicator element. + */ function requireRefreshIndicator() { - if (!refreshIndicatorLoaded) { refreshIndicatorLoaded = true; require(['emby-itemrefreshindicator']); } } - function getDefaultBackgroundClass(str) { + /** + * Returns the default background class for a card based on a string. + * @param {string} str - Text used to generate the background class. + * @returns {string} CSS classes for default card backgrounds. + */ + export function getDefaultBackgroundClass(str) { return 'defaultCardBackground defaultCardBackground' + getDefaultColorIndex(str); } + /** + * Builds the HTML markup for an individual card. + * @param {number} index - Index of the card + * @param {object} item - Item used to generate the card. + * @param {object} apiClient - API client instance. + * @param {object} options - Options used to generate the card. + * @returns {string} HTML markup for the generated card. + */ function buildCard(index, item, apiClient, options) { - - var action = options.action || 'link'; + let action = options.action || 'link'; if (action === 'play' && item.IsFolder) { // If this hard-coding is ever removed make sure to test nested photo albums @@ -1167,13 +1269,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana action = 'play'; } - var shape = options.shape; + let shape = options.shape; if (shape === 'mixed') { shape = null; - var primaryImageAspectRatio = item.PrimaryImageAspectRatio; + const primaryImageAspectRatio = item.PrimaryImageAspectRatio; if (primaryImageAspectRatio) { @@ -1191,7 +1293,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana // TODO move card creation code to Card component - var className = 'card'; + let className = 'card'; if (shape) { className += ' ' + shape + 'Card'; @@ -1202,7 +1304,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } if (options.cardClass) { - className += " " + options.cardClass; + className += ' ' + options.cardClass; } if (layoutManager.desktop) { @@ -1217,16 +1319,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - var imgInfo = getCardImageUrl(item, apiClient, options, shape); - var imgUrl = imgInfo.imgUrl; + const imgInfo = getCardImageUrl(item, apiClient, options, shape); + const imgUrl = imgInfo.imgUrl; - var forceName = imgInfo.forceName; + const forceName = imgInfo.forceName; - var showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder'); - var overlayText = options.overlayText; + const showTitle = options.showTitle === 'auto' ? true : (options.showTitle || item.Type === 'PhotoAlbum' || item.Type === 'Folder'); + const overlayText = options.overlayText; - var cardImageContainerClass = 'cardImageContainer'; - var coveredImage = options.coverImage || imgInfo.coverImage; + let cardImageContainerClass = 'cardImageContainer'; + const coveredImage = options.coverImage || imgInfo.coverImage; if (coveredImage) { cardImageContainerClass += ' coveredImage'; @@ -1240,27 +1342,27 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana cardImageContainerClass += ' ' + getDefaultBackgroundClass(item.Name); } - var cardBoxClass = options.cardLayout ? 'cardBox visualCardBox' : 'cardBox'; + let cardBoxClass = options.cardLayout ? 'cardBox visualCardBox' : 'cardBox'; - var footerCssClass; - var progressHtml = indicators.getProgressBarHtml(item); + let footerCssClass; + let progressHtml = indicators.getProgressBarHtml(item); - var innerCardFooter = ''; + let innerCardFooter = ''; - var footerOverlayed = false; + let footerOverlayed = false; - var logoUrl; - var logoHeight = 40; + let logoUrl; + const logoHeight = 40; if (options.showChannelLogo && item.ChannelPrimaryImageTag) { logoUrl = apiClient.getScaledImageUrl(item.ChannelId, { - type: "Primary", + type: 'Primary', height: logoHeight, tag: item.ChannelPrimaryImageTag }); } else if (options.showLogo && item.ParentLogoImageTag) { logoUrl = apiClient.getScaledImageUrl(item.ParentLogoItemId, { - type: "Logo", + type: 'Logo', height: logoHeight, tag: item.ParentLogoImageTag }); @@ -1281,12 +1383,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana progressHtml = ''; } - var mediaSourceCount = item.MediaSourceCount || 1; + const mediaSourceCount = item.MediaSourceCount || 1; if (mediaSourceCount > 1) { innerCardFooter += '
' + mediaSourceCount + '
'; } - var outerCardFooter = ''; + let outerCardFooter = ''; if (!overlayText && !footerOverlayed) { footerCssClass = options.cardLayout ? 'cardFooter' : 'cardFooter cardFooter-transparent'; @@ -1305,26 +1407,26 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana cardBoxClass += ' cardBox-bottompadded'; } - var overlayButtons = ''; + let overlayButtons = ''; if (layoutManager.mobile) { - var overlayPlayButton = options.overlayPlayButton; + let overlayPlayButton = options.overlayPlayButton; if (overlayPlayButton == null && !options.overlayMoreButton && !options.overlayInfoButton && !options.cardLayout) { overlayPlayButton = item.MediaType === 'Video'; } - var btnCssClass = 'cardOverlayButton cardOverlayButton-br itemAction'; + const btnCssClass = 'cardOverlayButton cardOverlayButton-br itemAction'; if (options.centerPlayButton) { - overlayButtons += ''; + overlayButtons += ''; } if (overlayPlayButton && !item.IsPlaceHolder && (item.LocationType !== 'Virtual' || !item.MediaType || item.Type === 'Program') && item.Type !== 'Person') { - overlayButtons += ''; + overlayButtons += ''; } if (options.overlayMoreButton) { - overlayButtons += ''; + overlayButtons += ''; } } @@ -1333,12 +1435,12 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } // cardBox can be it's own separate element if an outer footer is ever needed - var cardImageContainerOpen; - var cardImageContainerClose = ''; - var cardBoxClose = ''; - var cardScalableClose = ''; + let cardImageContainerOpen; + let cardImageContainerClose = ''; + let cardBoxClose = ''; + let cardScalableClose = ''; - var cardContentClass = 'cardContent'; + let cardContentClass = 'cardContent'; if (!options.cardLayout) { cardContentClass += ' cardContent-shadow'; } @@ -1356,13 +1458,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana cardImageContainerClose = ''; } - var cardScalableClass = 'cardScalable'; + let cardScalableClass = 'cardScalable'; cardImageContainerOpen = '
' + cardImageContainerOpen; cardBoxClose = '
'; cardScalableClose = '
'; - var indicatorsHtml = ''; + let indicatorsHtml = ''; if (options.missingIndicator !== false) { indicatorsHtml += indicators.getMissingIndicator(item); @@ -1383,7 +1485,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } if (item.Type === 'CollectionFolder' || item.CollectionType) { - var refreshClass = item.RefreshProgress || (item.RefreshStatus && virtualFolder.item !== 'Idle') ? '' : ' class="hide"'; + const refreshClass = item.RefreshProgress ? '' : ' class="hide"'; indicatorsHtml += '
'; requireRefreshIndicator(); } @@ -1392,24 +1494,20 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana cardImageContainerOpen += '
' + indicatorsHtml + '
'; } - //if (item.Type === 'Program' || item.Type === 'Timer') { - // cardImageContainerOpen += getProgramIndicators(item); - //} - if (!imgUrl) { - cardImageContainerOpen += getCardDefaultText(item, options); + cardImageContainerOpen += getDefaultText(item, options); } - var tagName = (layoutManager.tv) && !overlayButtons ? 'button' : 'div'; + const tagName = (layoutManager.tv) && !overlayButtons ? 'button' : 'div'; - var nameWithPrefix = (item.SortName || item.Name || ''); - var prefix = nameWithPrefix.substring(0, Math.min(3, nameWithPrefix.length)); + const nameWithPrefix = (item.SortName || item.Name || ''); + let prefix = nameWithPrefix.substring(0, Math.min(3, nameWithPrefix.length)); if (prefix) { prefix = prefix.toUpperCase(); } - var timerAttributes = ''; + let timerAttributes = ''; if (item.TimerId) { timerAttributes += ' data-timerid="' + item.TimerId + '"'; } @@ -1417,10 +1515,10 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana timerAttributes += ' data-seriestimerid="' + item.SeriesTimerId + '"'; } - var actionAttribute; + let actionAttribute; if (tagName === 'button') { - className += " itemAction"; + className += ' itemAction'; actionAttribute = ' data-action="' + action + '"'; } else { actionAttribute = ''; @@ -1430,16 +1528,16 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana 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 + '"') : ''; + const positionTicksData = item.UserData && item.UserData.PlaybackPositionTicks ? (' data-positionticks="' + item.UserData.PlaybackPositionTicks + '"') : ''; + const collectionIdData = options.collectionId ? (' data-collectionid="' + options.collectionId + '"') : ''; + const playlistIdData = options.playlistId ? (' data-playlistid="' + options.playlistId + '"') : ''; + const mediaTypeData = item.MediaType ? (' data-mediatype="' + item.MediaType + '"') : ''; + const collectionTypeData = item.CollectionType ? (' data-collectiontype="' + item.CollectionType + '"') : ''; + const channelIdData = item.ChannelId ? (' data-channelid="' + item.ChannelId + '"') : ''; + const contextData = options.context ? (' data-context="' + options.context + '"') : ''; + const parentIdData = options.parentId ? (' data-parentid="' + options.parentId + '"') : ''; - var additionalCardContent = ''; + let additionalCardContent = ''; if (layoutManager.desktop) { additionalCardContent += getHoverMenuHtml(item, action); @@ -1448,36 +1546,41 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana 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 + ''; } + /** + * Generates HTML markup for the card overlay. + * @param {object} item - Item used to generate the card overlay. + * @param {string} action - Action assigned to the overlay. + * @returns {string} HTML markup of the card overlay. + */ function getHoverMenuHtml(item, action) { - - var html = ''; + let html = ''; html += '
'; - var btnCssClass = 'cardOverlayButton cardOverlayButton-hover itemAction paper-icon-button-light'; + const btnCssClass = 'cardOverlayButton cardOverlayButton-hover itemAction paper-icon-button-light'; if (playbackManager.canPlay(item)) { - html += ''; + html += ''; } - html += '
'; + html += '
'; - var userData = item.UserData || {}; + const userData = item.UserData || {}; if (itemHelper.canMarkPlayed(item)) { require(['emby-playstatebutton']); - html += ''; + html += ''; } if (itemHelper.canRate(item)) { - var likes = userData.Likes == null ? '' : userData.Likes; + const likes = userData.Likes == null ? '' : userData.Likes; require(['emby-ratingbutton']); - html += ''; + html += ''; } - html += ''; + html += ''; html += '
'; html += '
'; @@ -1485,26 +1588,47 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return html; } - function getCardDefaultText(item, options) { + /** + * Generates the text or icon used for default card backgrounds. + * @param {object} item - Item used to generate the card overlay. + * @param {object} options - Options used to generate the card overlay. + * @returns {string} HTML markup of the card overlay. + */ + export function getDefaultText(item, options) { if (item.CollectionType) { - return '' + imageHelper.getLibraryIcon(item.CollectionType) + '' - } - if (item.Type === 'MusicAlbum') { - return 'album'; - } - if (item.Type === 'MusicArtist' || item.Type === 'Person') { - return 'person'; - } - if (options.defaultCardImageIcon) { - return '' + options.defaultCardImageIcon + ''; + return ''; } - var defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item); + switch (item.Type) { + case 'MusicAlbum': + return ''; + case 'MusicArtist': + case 'Person': + return ''; + case 'Movie': + return ''; + case 'Series': + return ''; + case 'Book': + return ''; + case 'Folder': + return ''; + } + + if (options && options.defaultCardImageIcon) { + return ''; + } + + const defaultName = isUsingLiveTvNaming(item) ? item.Name : itemHelper.getDisplayName(item); return '
' + defaultName + '
'; } - function buildCards(items, options) { - + /** + * Builds a set of cards and inserts them into the page. + * @param {Array} items - Array of items used to build the cards. + * @param {options} options - Options of the cards to build. + */ + export function buildCards(items, options) { // Abort if the container has been disposed if (!document.body.contains(options.itemsContainer)) { return; @@ -1519,7 +1643,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - var html = buildCardsHtmlInternal(items, options); + const html = buildCardsHtmlInternal(items, options); if (html) { @@ -1545,8 +1669,13 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } + /** + * Ensures the indicators for a card exist and creates them if they don't exist. + * @param {HTMLDivElement} card - DOM element of the card. + * @param {HTMLDivElement} indicatorsElem - DOM element of the indicators. + * @returns {HTMLDivElement} - DOM element of the indicators. + */ function ensureIndicators(card, indicatorsElem) { - if (indicatorsElem) { return indicatorsElem; } @@ -1555,7 +1684,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana if (!indicatorsElem) { - var cardImageContainer = card.querySelector('.cardImageContainer'); + const cardImageContainer = card.querySelector('.cardImageContainer'); indicatorsElem = document.createElement('div'); indicatorsElem.classList.add('cardIndicators'); cardImageContainer.appendChild(indicatorsElem); @@ -1564,14 +1693,18 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana return indicatorsElem; } + /** + * Adds user data to the card such as progress indicators and played status. + * @param {HTMLDivElement} card - DOM element of the card. + * @param {Object} userData - User data to apply to the card. + */ 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; + const type = card.getAttribute('data-type'); + const enableCountIndicator = type === 'Series' || type === 'BoxSet' || type === 'Season'; + let indicatorsElem = null; + let playedIndicator = null; + let countIndicator = null; + let itemProgressBar = null; if (userData.Played) { @@ -1585,7 +1718,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana indicatorsElem = ensureIndicators(card, indicatorsElem); indicatorsElem.appendChild(playedIndicator); } - playedIndicator.innerHTML = 'check'; + playedIndicator.innerHTML = ''; } else { playedIndicator = card.querySelector('.playedIndicator'); @@ -1614,7 +1747,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - var progressHtml = indicators.getProgressBarHtml({ + const progressHtml = indicators.getProgressBarHtml({ Type: type, UserData: userData, MediaType: 'Video' @@ -1628,11 +1761,11 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana itemProgressBar = document.createElement('div'); itemProgressBar.classList.add('itemProgressBar'); - var innerCardFooter = card.querySelector('.innerCardFooter'); + let innerCardFooter = card.querySelector('.innerCardFooter'); if (!innerCardFooter) { innerCardFooter = document.createElement('div'); innerCardFooter.classList.add('innerCardFooter'); - var cardImageContainer = card.querySelector('.cardImageContainer'); + const cardImageContainer = card.querySelector('.cardImageContainer'); cardImageContainer.appendChild(innerCardFooter); } innerCardFooter.appendChild(itemProgressBar); @@ -1648,37 +1781,50 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - function onUserDataChanged(userData, scope) { + /** + * Handles when user data has changed. + * @param {Object} userData - User data to apply to the card. + * @param {HTMLElement} scope - DOM element to use as a scope when selecting cards. + */ + export function onUserDataChanged(userData, scope) { + const cards = (scope || document.body).querySelectorAll('.card-withuserdata[data-id="' + userData.ItemId + '"]'); - var cards = (scope || document.body).querySelectorAll('.card-withuserdata[data-id="' + userData.ItemId + '"]'); - - for (var i = 0, length = cards.length; i < length; i++) { + for (let i = 0, length = cards.length; i < length; i++) { updateUserData(cards[i], userData); } } - function onTimerCreated(programId, newTimerId, itemsContainer) { + /** + * Handles when a timer has been created. + * @param {string} programId - ID of the program. + * @param {string} newTimerId - ID of the new timer. + * @param {HTMLElement} itemsContainer - DOM element of the itemsContainer. + */ + export function onTimerCreated(programId, newTimerId, itemsContainer) { + const cells = itemsContainer.querySelectorAll('.card[data-id="' + programId + '"]'); - 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'); + for (let i = 0, length = cells.length; i < length; i++) { + let cell = cells[i]; + const icon = cell.querySelector('.timerIndicator'); if (!icon) { - var indicatorsElem = ensureIndicators(cell); - indicatorsElem.insertAdjacentHTML('beforeend', 'fiber_manual_record'); + const indicatorsElem = ensureIndicators(cell); + indicatorsElem.insertAdjacentHTML('beforeend', ''); } cell.setAttribute('data-timerid', newTimerId); } } - function onTimerCancelled(id, itemsContainer) { + /** + * Handles when a timer has been cancelled. + * @param {string} timerId - ID of the cancelled timer. + * @param {HTMLElement} itemsContainer - DOM element of the itemsContainer. + */ + export function onTimerCancelled(timerId, itemsContainer) { + const cells = itemsContainer.querySelectorAll('.card[data-timerid="' + timerId + '"]'); - 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'); + for (let i = 0; i < cells.length; i++) { + let cell = cells[i]; + let icon = cell.querySelector('.timerIndicator'); if (icon) { icon.parentNode.removeChild(icon); } @@ -1686,13 +1832,17 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - function onSeriesTimerCancelled(id, itemsContainer) { + /** + * Handles when a series timer has been cancelled. + * @param {string} cancelledTimerId - ID of the cancelled timer. + * @param {HTMLElement} itemsContainer - DOM element of the itemsContainer. + */ + export function onSeriesTimerCancelled(cancelledTimerId, itemsContainer) { + const cells = itemsContainer.querySelectorAll('.card[data-seriestimerid="' + cancelledTimerId + '"]'); - 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'); + for (let i = 0; i < cells.length; i++) { + let cell = cells[i]; + let icon = cell.querySelector('.timerIndicator'); if (icon) { icon.parentNode.removeChild(icon); } @@ -1700,12 +1850,15 @@ define(['datetime', 'imageLoader', 'connectionManager', 'itemHelper', 'focusMana } } - return { - getCardsHtml: getCardsHtml, - buildCards: buildCards, - onUserDataChanged: onUserDataChanged, - onTimerCreated: onTimerCreated, - onTimerCancelled: onTimerCancelled, - onSeriesTimerCancelled: onSeriesTimerCancelled - }; - }); +/* eslint-enable indent */ + +export default { + getCardsHtml: getCardsHtml, + getDefaultBackgroundClass: getDefaultBackgroundClass, + getDefaultText: getDefaultText, + buildCards: buildCards, + onUserDataChanged: onUserDataChanged, + onTimerCreated: onTimerCreated, + onTimerCancelled: onTimerCancelled, + onSeriesTimerCancelled: onSeriesTimerCancelled +}; diff --git a/src/components/cardbuilder/chaptercardbuilder.js b/src/components/cardbuilder/chaptercardbuilder.js index 0f42e14584..eae60574b3 100644 --- a/src/components/cardbuilder/chaptercardbuilder.js +++ b/src/components/cardbuilder/chaptercardbuilder.js @@ -68,9 +68,9 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse return apiClient.getScaledImageUrl(item.Id, { - maxWidth: maxWidth, + maxWidth: maxWidth * 2, tag: chapter.ImageTag, - type: "Chapter", + type: 'Chapter', index: index }); } @@ -90,7 +90,7 @@ define(['datetime', 'imageLoader', 'connectionManager', 'layoutManager', 'browse var cardImageContainer = imgUrl ? ('
') : ('
'); if (!imgUrl) { - cardImageContainer += 'local_movies'; + cardImageContainer += ''; } var nameHtml = ''; diff --git a/src/components/castSenderApi.js b/src/components/castSenderApi.js new file mode 100644 index 0000000000..b541c1f87a --- /dev/null +++ b/src/components/castSenderApi.js @@ -0,0 +1,34 @@ +define([], function() { + 'use strict'; + + if (window.appMode === 'cordova' || window.appMode === 'android') { + return { + load: function () { + window.chrome = window.chrome || {}; + return Promise.resolve(); + } + }; + } else { + var ccLoaded = false; + return { + load: function () { + if (ccLoaded) { + return Promise.resolve(); + } + + return new Promise(function (resolve, reject) { + var fileref = document.createElement('script'); + fileref.setAttribute('type', 'text/javascript'); + + fileref.onload = function () { + ccLoaded = true; + resolve(); + }; + + fileref.setAttribute('src', 'https://www.gstatic.com/cv/js/sender/v1/cast_sender.js'); + document.querySelector('head').appendChild(fileref); + }); + } + }; + } +}); diff --git a/src/components/channelmapper/channelmapper.js b/src/components/channelmapper/channelmapper.js index 0247f79a55..83ae4d09c6 100644 --- a/src/components/channelmapper/channelmapper.js +++ b/src/components/channelmapper/channelmapper.js @@ -1,44 +1,33 @@ -define(["dialogHelper", "loading", "connectionManager", "globalize", "actionsheet", "emby-input", "paper-icon-button-light", "emby-button", "listViewStyle", "material-icons", "formDialogStyle"], function (dialogHelper, loading, connectionManager, globalize, actionsheet) { - "use strict"; +define(['dom', 'dialogHelper', 'loading', 'connectionManager', 'globalize', 'actionsheet', 'emby-input', 'paper-icon-button-light', 'emby-button', 'listViewStyle', 'material-icons', 'formDialogStyle'], function (dom, dialogHelper, loading, connectionManager, globalize, actionsheet) { + 'use strict'; return function (options) { - function parentWithClass(elem, className) { - while (!elem.classList || !elem.classList.contains(className)) { - elem = elem.parentNode; - if (!elem) { - return null; - } - } - - return elem; - } - function mapChannel(button, channelId, providerChannelId) { loading.show(); var providerId = options.providerId; connectionManager.getApiClient(options.serverId).ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/ChannelMappings"), + type: 'POST', + url: ApiClient.getUrl('LiveTv/ChannelMappings'), data: { providerId: providerId, tunerChannelId: channelId, providerChannelId: providerChannelId }, - dataType: "json" + dataType: 'json' }).then(function (mapping) { - var listItem = parentWithClass(button, "listItem"); - button.setAttribute("data-providerid", mapping.ProviderChannelId); - listItem.querySelector(".secondary").innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName); + var listItem = dom.parentWithClass(button, 'listItem'); + button.setAttribute('data-providerid', mapping.ProviderChannelId); + listItem.querySelector('.secondary').innerHTML = getMappingSecondaryName(mapping, currentMappingOptions.ProviderName); loading.hide(); }); } function onChannelsElementClick(e) { - var btnMap = parentWithClass(e.target, "btnMap"); + var btnMap = dom.parentWithClass(e.target, 'btnMap'); if (btnMap) { - var channelId = btnMap.getAttribute("data-id"); - var providerChannelId = btnMap.getAttribute("data-providerid"); + var channelId = btnMap.getAttribute('data-id'); + var providerChannelId = btnMap.getAttribute('data-providerid'); var menuItems = currentMappingOptions.ProviderChannels.map(function (m) { return { name: m.Name, @@ -59,56 +48,56 @@ define(["dialogHelper", "loading", "connectionManager", "globalize", "actionshee function getChannelMappingOptions(serverId, providerId) { var apiClient = connectionManager.getApiClient(serverId); - return apiClient.getJSON(apiClient.getUrl("LiveTv/ChannelMappingOptions", { + return apiClient.getJSON(apiClient.getUrl('LiveTv/ChannelMappingOptions', { providerId: providerId })); } function getMappingSecondaryName(mapping, providerName) { - return (mapping.ProviderChannelName || "") + " - " + providerName; + return (mapping.ProviderChannelName || '') + ' - ' + providerName; } function getTunerChannelHtml(channel, providerName) { - var html = ""; + var html = ''; html += '
'; - html += 'dvr'; + html += ''; html += '
'; html += '

'; html += channel.Name; - html += "

"; + html += ''; html += '
'; if (channel.ProviderChannelName) { html += getMappingSecondaryName(channel, providerName); } - html += "
"; - html += "
"; - html += ''; - return html += "
"; + html += '
'; + html += '
'; + html += ''; + return html += '
'; } function getEditorHtml() { - var html = ""; + var html = ''; html += '
'; html += '
'; html += ''; - html += "

" + globalize.translate("HeaderChannels") + "

"; + html += '

' + globalize.translate('HeaderChannels') + '

'; html += '
'; - html += "
"; - html += ""; - html += "
"; - return html += "
"; + html += ''; + html += ''; + html += ''; + return html += ''; } function initEditor(dlg, options) { getChannelMappingOptions(options.serverId, options.providerId).then(function (result) { currentMappingOptions = result; - var channelsElement = dlg.querySelector(".channels"); + var channelsElement = dlg.querySelector('.channels'); channelsElement.innerHTML = result.TunerChannels.map(function (channel) { return getTunerChannelHtml(channel, result.ProviderName); - }).join(""); - channelsElement.addEventListener("click", onChannelsElementClick); + }).join(''); + channelsElement.addEventListener('click', onChannelsElementClick); }); } @@ -119,27 +108,27 @@ define(["dialogHelper", "loading", "connectionManager", "globalize", "actionshee var dialogOptions = { removeOnClose: true }; - dialogOptions.size = "small"; + dialogOptions.size = 'small'; var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - var html = ""; - var title = globalize.translate("MapChannels"); + dlg.classList.add('formDialog'); + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + var html = ''; + var title = globalize.translate('MapChannels'); html += '
'; - html += ''; + html += ''; html += '

'; html += title; - html += "

"; - html += "
"; + html += ''; + html += ''; html += getEditorHtml(); dlg.innerHTML = html; initEditor(dlg, options); - dlg.querySelector(".btnCancel").addEventListener("click", function () { + dlg.querySelector('.btnCancel').addEventListener('click', function () { dialogHelper.close(dlg); }); return new Promise(function (resolve, reject) { - dlg.addEventListener("close", resolve); + dlg.addEventListener('close', resolve); dialogHelper.open(dlg); }); }; diff --git a/src/components/chromecast/chromecasthelpers.js b/src/components/chromecast/chromecasthelpers.js index 9d6f811cb1..ca2d27c977 100644 --- a/src/components/chromecast/chromecasthelpers.js +++ b/src/components/chromecast/chromecasthelpers.js @@ -37,69 +37,69 @@ define(['events'], function (events) { // 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 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 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])"; + 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 + "?" + + protocols + '?' // optional username:password@ - + credentials + "?" + + credentials + '?' // IP address (both v4 and v6) - + "(?:" + + '(?:' // IPv6 + ipv6 // IPv4 - + "|" + ipv4 + + '|' + ipv4 - + ")" + + ')' // end match for protocol / username / password / host - + ")" + + ')' // optional port number - + "(?:\\:\\d{1,5})?" + + '(?:\\:\\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})" + + '(?:[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 @@ -108,9 +108,9 @@ define(['events'], function (events) { // 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|\$" - + ")"; + + ')*' + + '|\\b|\$' + + ')'; // regex = XRegExp(regex,'gi'); var linkRegExp = RegExp(linkRegExpString, 'gi'); @@ -120,7 +120,7 @@ define(['events'], function (events) { // if url doesn't begin with a known protocol, add http by default function ensureProtocol(url) { if (!url.match(protocolRegExp)) { - url = "http://" + url; + url = 'http://' + url; } return url; } @@ -131,8 +131,9 @@ define(['events'], function (events) { var links = []; var match; + // eslint-disable-next-line no-cond-assign while (match = linkRegExp.exec(text)) { - // console.log(matches); + console.debug(match); var txt = match[0]; var pos = match.index; var len = txt.length; @@ -187,9 +188,9 @@ define(['events'], function (events) { return apiClient.getEndpointInfo().then(function (endpoint) { if (endpoint.IsInNetwork) { return apiClient.getPublicSystemInfo().then(function (info) { - var localAddress = info.LocalAddress + var localAddress = info.LocalAddress; if (!localAddress) { - console.log("No valid local address returned, defaulting to external one") + console.debug('No valid local address returned, defaulting to external one'); localAddress = serverAddress; } addToCache(serverAddress, localAddress); @@ -230,4 +231,4 @@ define(['events'], function (events) { return { getServerAddress: getServerAddress }; -}); \ No newline at end of file +}); diff --git a/src/components/chromecast/chromecastplayer.js b/src/components/chromecast/chromecastplayer.js index 7302b74124..52fa4f6bcb 100644 --- a/src/components/chromecast/chromecastplayer.js +++ b/src/components/chromecast/chromecastplayer.js @@ -5,7 +5,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' var currentResolve; var currentReject; - var PlayerName = 'Chromecast'; + var PlayerName = 'Google Cast'; function sendConnectionResult(isOk) { @@ -54,7 +54,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' // production version registered with google // replace this value if you want to test changes on another instance - var applicationID = "F007D354"; + var applicationID = 'F007D354'; var messageNamespace = 'urn:x-cast:com.connectsdk'; @@ -105,7 +105,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' this.sessionListener.bind(this), this.receiverListener.bind(this)); - console.log('chromecast.initialize'); + console.debug('chromecast.initialize'); chrome.cast.initialize(apiConfig, this.onInitSuccess.bind(this), this.errorHandler); }; @@ -114,14 +114,14 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.onInitSuccess = function () { this.isInitialized = true; - console.log("chromecast init success"); + console.debug('chromecast init success'); }; /** * Generic error callback function */ CastPlayer.prototype.onError = function () { - console.log("chromecast error"); + console.debug('chromecast error'); }; /** @@ -177,10 +177,10 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.receiverListener = function (e) { if (e === 'available') { - console.log("chromecast receiver found"); + console.debug('chromecast receiver found'); this.hasReceivers = true; } else { - console.log("chromecast receiver list empty"); + console.debug('chromecast receiver list empty'); this.hasReceivers = false; } }; @@ -190,15 +190,15 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.sessionUpdateListener = function (isAlive) { if (isAlive) { - console.log('sessionUpdateListener: already alive'); + console.debug('sessionUpdateListener: already alive'); } else { this.session = null; this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; - document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false); - document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false); + document.removeEventListener('volumeupbutton', onVolumeUpKeyDown, false); + document.removeEventListener('volumedownbutton', onVolumeDownKeyDown, false); - console.log('sessionUpdateListener: setting currentMediaSession to null'); + console.debug('sessionUpdateListener: setting currentMediaSession to null'); this.currentMediaSession = null; sendConnectionResult(false); @@ -211,7 +211,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * session request in opt_sessionRequest. */ CastPlayer.prototype.launchApp = function () { - console.log("chromecast launching app..."); + console.debug('chromecast launching app...'); chrome.cast.requestSession(this.onRequestSessionSuccess.bind(this), this.onLaunchError.bind(this)); }; @@ -220,7 +220,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * @param {Object} e A chrome.cast.Session object */ CastPlayer.prototype.onRequestSessionSuccess = function (e) { - console.log("chromecast session success: " + e.sessionId); + console.debug('chromecast session success: ' + e.sessionId); this.onSessionConnected(e); }; @@ -232,8 +232,8 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' this.session.addMediaListener(this.sessionMediaListener.bind(this)); this.session.addUpdateListener(this.sessionUpdateListener.bind(this)); - document.addEventListener("volumeupbutton", onVolumeUpKeyDown, false); - document.addEventListener("volumedownbutton", onVolumeDownKeyDown, false); + document.addEventListener('volumeupbutton', onVolumeUpKeyDown, false); + document.addEventListener('volumedownbutton', onVolumeDownKeyDown, false); events.trigger(this, 'connect'); this.sendMessage({ @@ -262,7 +262,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * Callback function for launch error */ CastPlayer.prototype.onLaunchError = function () { - console.log("chromecast launch error"); + console.debug('chromecast launch error'); this.deviceState = DEVICE_STATE.ERROR; sendConnectionResult(false); }; @@ -280,12 +280,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * Callback function for stop app success */ CastPlayer.prototype.onStopAppSuccess = function (message) { - console.log(message); + console.debug(message); this.deviceState = DEVICE_STATE.IDLE; this.castPlayerState = PLAYER_STATE.IDLE; - document.removeEventListener("volumeupbutton", onVolumeUpKeyDown, false); - document.removeEventListener("volumedownbutton", onVolumeDownKeyDown, false); + document.removeEventListener('volumeupbutton', onVolumeUpKeyDown, false); + document.removeEventListener('volumedownbutton', onVolumeDownKeyDown, false); this.currentMediaSession = null; }; @@ -296,7 +296,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.loadMedia = function (options, command) { if (!this.session) { - console.log("no session"); + console.debug('no session'); return Promise.reject(); } @@ -377,7 +377,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' }; CastPlayer.prototype.onPlayCommandSuccess = function () { - //console.log('Message was sent to receiver ok.'); + console.debug('Message was sent to receiver ok.'); }; /** @@ -386,7 +386,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.onMediaDiscovered = function (how, mediaSession) { - //console.log("chromecast new media session ID:" + mediaSession.mediaSessionId + ' (' + how + ')'); + console.debug('chromecast new media session ID:' + mediaSession.mediaSessionId + ' (' + how + ')'); this.currentMediaSession = mediaSession; if (how === 'loadMedia') { @@ -405,7 +405,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * @param {!Boolean} e true/false */ CastPlayer.prototype.onMediaStatusUpdate = function (e) { - //console.log("chromecast updating media: " + e); + console.debug('chromecast updating media: ' + e); if (e === false) { this.castPlayerState = PLAYER_STATE.IDLE; } @@ -417,7 +417,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' */ CastPlayer.prototype.setReceiverVolume = function (mute, vol) { if (!this.currentMediaSession) { - //console.log('this.currentMediaSession is null'); + console.debug('this.currentMediaSession is null'); return; } @@ -443,7 +443,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' * Callback function for media command success */ CastPlayer.prototype.mediaCommandSuccessCallback = function (info, e) { - //console.log(info); + console.debug(info); }; function normalizeImages(state) { @@ -482,7 +482,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' } else { query.Limit = query.Limit || 100; - query.ExcludeLocationTypes = "Virtual"; + query.ExcludeLocationTypes = 'Virtual'; query.EnableTotalRecordCount = false; return apiClient.getItems(userId, query); @@ -493,7 +493,7 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' events.on(instance._castPlayer, eventName, function (e, data) { - //console.log('cc: ' + eventName); + console.debug('cc: ' + eventName); var state = instance.getPlayerStateInternal(data); events.trigger(instance, eventName, [state]); @@ -506,13 +506,13 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' instance._castPlayer = new CastPlayer(); // To allow the native android app to override - document.dispatchEvent(new CustomEvent("chromecastloaded", { + document.dispatchEvent(new CustomEvent('chromecastloaded', { detail: { player: instance } })); - events.on(instance._castPlayer, "connect", function (e) { + events.on(instance._castPlayer, 'connect', function (e) { if (currentResolve) { sendConnectionResult(true); @@ -520,27 +520,27 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' playbackManager.setActivePlayer(PlayerName, instance.getCurrentTargetInfo()); } - console.log('cc: connect'); + console.debug('cc: connect'); // Reset this so that statechange will fire instance.lastPlayerData = null; }); - events.on(instance._castPlayer, "playbackstart", function (e, data) { + events.on(instance._castPlayer, 'playbackstart', function (e, data) { - console.log('cc: playbackstart'); + console.debug('cc: playbackstart'); instance._castPlayer.initializeCastPlayer(); var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "playbackstart", [state]); + events.trigger(instance, 'playbackstart', [state]); }); - events.on(instance._castPlayer, "playbackstop", function (e, data) { + events.on(instance._castPlayer, 'playbackstop', function (e, data) { - console.log('cc: playbackstop'); + console.debug('cc: playbackstop'); var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "playbackstop", [state]); + events.trigger(instance, 'playbackstop', [state]); var state = instance.lastPlayerData.PlayState || {}; var volume = state.VolumeLevel || 0.5; @@ -553,12 +553,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' instance.lastPlayerData.PlayState.IsMuted = mute; }); - events.on(instance._castPlayer, "playbackprogress", function (e, data) { + events.on(instance._castPlayer, 'playbackprogress', function (e, data) { - //console.log('cc: positionchange'); + console.debug('cc: positionchange'); var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "timeupdate", [state]); + events.trigger(instance, 'timeupdate', [state]); }); bindEventForRelay(instance, 'timeupdate'); @@ -567,12 +567,12 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' bindEventForRelay(instance, 'volumechange'); bindEventForRelay(instance, 'repeatmodechange'); - events.on(instance._castPlayer, "playstatechange", function (e, data) { + events.on(instance._castPlayer, 'playstatechange', function (e, data) { - //console.log('cc: playstatechange'); + console.debug('cc: playstatechange'); var state = instance.getPlayerStateInternal(data); - events.trigger(instance, "pause", [state]); + events.trigger(instance, 'pause', [state]); }); } @@ -630,24 +630,24 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' name: PlayerName, id: PlayerName, playerName: PlayerName, - playableMediaTypes: ["Audio", "Video"], + playableMediaTypes: ['Audio', 'Video'], isLocalPlayer: false, appName: PlayerName, deviceName: appName, supportedCommands: [ - "VolumeUp", - "VolumeDown", - "Mute", - "Unmute", - "ToggleMute", - "SetVolume", - "SetAudioStreamIndex", - "SetSubtitleStreamIndex", - "DisplayContent", - "SetRepeatMode", - "EndSession", - "PlayMediaSource", - "PlayTrailers" + 'VolumeUp', + 'VolumeDown', + 'Mute', + 'Unmute', + 'ToggleMute', + 'SetVolume', + 'SetAudioStreamIndex', + 'SetSubtitleStreamIndex', + 'DisplayContent', + 'SetRepeatMode', + 'EndSession', + 'PlayMediaSource', + 'PlayTrailers' ] }; }; @@ -664,10 +664,10 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' normalizeImages(data); - //console.log(JSON.stringify(data)); + console.debug(JSON.stringify(data)); if (triggerStateChange) { - events.trigger(this, "statechange", [data]); + events.trigger(this, 'statechange', [data]); } return data; @@ -686,6 +686,13 @@ define(['appSettings', 'userSettings', 'playbackManager', 'connectionManager', ' }); } + if (options.items.length > 1 && options && options.ids) { + // Use the original request id array for sorting the result in the proper order + options.items.sort(function (a, b) { + return options.ids.indexOf(a.Id) - options.ids.indexOf(b.Id); + }); + } + return this._castPlayer.loadMedia(options, command); }; diff --git a/src/components/collectioneditor/collectioneditor.js b/src/components/collectioneditor/collectioneditor.js index a91594556e..46b0640305 100644 --- a/src/components/collectioneditor/collectioneditor.js +++ b/src/components/collectioneditor/collectioneditor.js @@ -1,25 +1,12 @@ -define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { +define(['dom', 'dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-checkbox', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button', 'flexStyles'], function (dom, dialogHelper, loading, appHost, layoutManager, connectionManager, appRouter, globalize) { 'use strict'; var currentServerId; - function parentWithClass(elem, className) { - - 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'); + var panel = dom.parentWithClass(this, 'dialog'); var collectionId = panel.querySelector('#selectCollectionToAddTo').value; @@ -37,7 +24,7 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage function createCollection(apiClient, dlg) { - var url = apiClient.getUrl("Collections", { + var url = apiClient.getUrl('Collections', { Name: dlg.querySelector('#txtNewCollectionName').value, IsLocked: !dlg.querySelector('#chkEnableInternetMetadata').checked, @@ -45,9 +32,9 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage }); apiClient.ajax({ - type: "POST", + type: 'POST', url: url, - dataType: "json" + dataType: 'json' }).then(function (result) { @@ -69,13 +56,13 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage function addToCollection(apiClient, dlg, id) { - var url = apiClient.getUrl("Collections/" + id + "/Items", { + var url = apiClient.getUrl('Collections/' + id + '/Items', { Ids: dlg.querySelector('.fldSelectedItemIds').value || '' }); apiClient.ajax({ - type: "POST", + type: 'POST', url: url }).then(function () { @@ -106,8 +93,8 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage var options = { Recursive: true, - IncludeItemTypes: "BoxSet", - SortBy: "SortName", + IncludeItemTypes: 'BoxSet', + SortBy: 'SortName', EnableTotalRecordCount: false }; @@ -243,13 +230,13 @@ define(['dialogHelper', 'loading', 'apphost', 'layoutManager', 'connectionManage var title = items.length ? globalize.translate('HeaderAddToCollection') : globalize.translate('NewCollection'); html += '
'; - html += ''; + html += ''; html += '

'; html += title; html += '

'; if (appHost.supports('externallinks')) { - html += 'info' + globalize.translate('Help') + ''; + html += '' + globalize.translate('Help') + ''; } html += '
'; diff --git a/src/components/confirm/confirm.js b/src/components/confirm/confirm.js index f104350c87..517d6fa9be 100644 --- a/src/components/confirm/confirm.js +++ b/src/components/confirm/confirm.js @@ -1,40 +1,65 @@ -define(['dialog', 'globalize'], function (dialog, globalize) { +define(['browser', 'dialog', 'globalize'], function(browser, dialog, globalize) { 'use strict'; - return function (text, title) { + function replaceAll(str, find, replace) { + return str.split(find).join(replace); + } - var options; - if (typeof text === 'string') { - options = { - title: title, - text: text - }; - } else { - options = text; - } - - var items = []; - - items.push({ - name: options.cancelText || globalize.translate('ButtonCancel'), - id: 'cancel', - type: 'cancel' - }); - - items.push({ - name: options.confirmText || globalize.translate('ButtonOk'), - id: 'ok', - type: options.primary === 'delete' ? 'delete' : 'submit' - }); - - options.buttons = items; - - return dialog(options).then(function (result) { - if (result === 'ok') { - return Promise.resolve(); + if (browser.tv && window.confirm) { + // Use the native confirm dialog + return function (options) { + if (typeof options === 'string') { + options = { + title: '', + text: options + }; } - return Promise.reject(); - }); - }; + var text = replaceAll(options.text || '', '
', '\n'); + var result = confirm(text); + + if (result) { + return Promise.resolve(); + } else { + return Promise.reject(); + } + }; + } else { + // Use our own dialog + return function (text, title) { + var options; + if (typeof text === 'string') { + options = { + title: title, + text: text + }; + } else { + options = text; + } + + var items = []; + + items.push({ + name: options.cancelText || globalize.translate('ButtonCancel'), + id: 'cancel', + type: 'cancel' + }); + + items.push({ + name: options.confirmText || globalize.translate('ButtonOk'), + id: 'ok', + type: options.primary === 'delete' ? 'delete' : 'submit' + }); + + options.buttons = items; + + return dialog(options).then(function (result) { + if (result === 'ok') { + return Promise.resolve(); + } + + return Promise.reject(); + }); + }; + } }); diff --git a/src/components/confirm/nativeconfirm.js b/src/components/confirm/nativeconfirm.js deleted file mode 100644 index fd586ad1d5..0000000000 --- a/src/components/confirm/nativeconfirm.js +++ /dev/null @@ -1,27 +0,0 @@ -define([], function () { - 'use strict'; - - function replaceAll(str, find, replace) { - - 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/components/dialog/dialog.template.html b/src/components/dialog/dialog.template.html index eae210d14e..bee0ef7f73 100644 --- a/src/components/dialog/dialog.template.html +++ b/src/components/dialog/dialog.template.html @@ -12,4 +12,4 @@
-
\ No newline at end of file + diff --git a/src/components/dialogHelper/dialogHelper.js b/src/components/dialogHelper/dialogHelper.js index bddd839760..8b08cde678 100644 --- a/src/components/dialogHelper/dialogHelper.js +++ b/src/components/dialogHelper/dialogHelper.js @@ -32,7 +32,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', try { parentNode.removeChild(elem); } catch (err) { - console.log('Error removing dialog element: ' + err); + console.error('error removing dialog element: ' + err); } } } @@ -141,7 +141,7 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', animateDialogOpen(dlg); if (isHistoryEnabled(dlg)) { - appRouter.pushState({ dialogId: hash }, "Dialog", '#' + hash); + appRouter.pushState({ dialogId: hash }, 'Dialog', '#' + hash); window.addEventListener('popstate', onHashChange); } else { @@ -169,6 +169,15 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', }, { passive: true }); + + dom.addEventListener((dlg.dialogContainer || backdrop), 'contextmenu', function (e) { + if (e.target === dlg.dialogContainer) { + // Close the application dialog menu + close(dlg); + // Prevent the default browser context menu from appearing + e.preventDefault(); + } + }); } function isHistoryEnabled(dlg) { @@ -242,9 +251,15 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', var onAnimationFinish = function () { focusManager.pushScope(dlg); + if (dlg.getAttribute('data-autofocus') === 'true') { focusManager.autoFocus(dlg); } + + if (document.activeElement && !dlg.contains(document.activeElement)) { + // Blur foreign element to prevent triggering of an action from the previous scope + document.activeElement.blur(); + } }; if (enableAnimation()) { @@ -481,4 +496,4 @@ define(['appRouter', 'focusManager', 'browser', 'layoutManager', 'inputManager', globalOnOpenCallback = val; } }; -}); \ No newline at end of file +}); diff --git a/src/components/dialogHelper/dialoghelper.css b/src/components/dialogHelper/dialoghelper.css index aa4145e016..df2adf075f 100644 --- a/src/components/dialogHelper/dialoghelper.css +++ b/src/components/dialogHelper/dialoghelper.css @@ -15,10 +15,12 @@ .dialog { margin: 0; - border-radius: .2em; + border-radius: 0.2em; + -webkit-font-smoothing: antialiased; border: 0; padding: 0; will-change: transform, opacity; + /* Strict does not work well with actionsheet */ contain: style paint; 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); @@ -50,13 +52,13 @@ to { opacity: 0; - transform: scale(.5); + transform: scale(0.5); } } @keyframes scaleup { from { - transform: scale(.5); + transform: scale(0.5); opacity: 0; } @@ -77,7 +79,6 @@ } @keyframes fadeout { - from { opacity: 1; } @@ -100,7 +101,6 @@ } @keyframes slidedown { - from { opacity: 1; transform: none; @@ -113,8 +113,8 @@ } @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; @@ -126,7 +126,6 @@ } @media all and (min-width: 80em) and (min-height: 45em) { - .dialog-medium { width: 80%; height: 80%; @@ -168,5 +167,5 @@ } .dialogBackdropOpened { - opacity: .5; + opacity: 0.5; } diff --git a/src/components/directorybrowser/directorybrowser.css b/src/components/directorybrowser/directorybrowser.css index 0f3f22f073..ef6d58934f 100644 --- a/src/components/directorybrowser/directorybrowser.css +++ b/src/components/directorybrowser/directorybrowser.css @@ -1,8 +1,8 @@ #ulDirectoryPickerList a { - padding-top: .4em; - padding-bottom: .4em + padding-top: 0.4em; + padding-bottom: 0.4em; } .lblDirectoryPickerPath { - white-space: nowrap -} \ No newline at end of file + white-space: nowrap; +} diff --git a/src/components/directorybrowser/directorybrowser.js b/src/components/directorybrowser/directorybrowser.js index 344d4bb593..7f13f89ef5 100644 --- a/src/components/directorybrowser/directorybrowser.js +++ b/src/components/directorybrowser/directorybrowser.js @@ -1,4 +1,4 @@ -define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom) { +define(['loading', 'dialogHelper', 'dom', 'globalize', 'listViewStyle', 'emby-input', 'paper-icon-button-light', 'css!./directorybrowser', 'formDialogStyle', 'emby-button'], function(loading, dialogHelper, dom, globalize) { 'use strict'; function getSystemInfo() { @@ -7,24 +7,24 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- systemInfo = info; return info; } - ) + ); } function onDialogClosed() { - loading.hide() + loading.hide(); } function refreshDirectoryBrowser(page, path, fileOptions, updatePathOnError) { if (path && typeof path !== 'string') { - throw new Error("invalid path"); + throw new Error('invalid path'); } loading.show(); var promises = []; - if ("Network" === path) { - promises.push(ApiClient.getNetworkDevices()) + if ('Network' === path) { + promises.push(ApiClient.getNetworkDevices()); } else { if (path) { promises.push(ApiClient.getDirectoryContents(path, fileOptions)); @@ -37,31 +37,31 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- Promise.all(promises).then( function(responses) { var folders = responses[0]; - var parentPath = responses[1] || ""; - var html = ""; + var parentPath = responses[1] || ''; + var html = ''; - page.querySelector(".results").scrollTop = 0; - page.querySelector("#txtDirectoryPickerPath").value = path || ""; + page.querySelector('.results').scrollTop = 0; + page.querySelector('#txtDirectoryPickerPath').value = path || ''; if (path) { - html += getItem("lnkPath lnkDirectory", "", parentPath, "..."); + html += getItem('lnkPath lnkDirectory', '', parentPath, '...'); } for (var i = 0, length = folders.length; i < length; i++) { var folder = folders[i]; - var cssClass = "File" === folder.Type ? "lnkPath lnkFile" : "lnkPath lnkDirectory"; + var cssClass = 'File' === folder.Type ? 'lnkPath lnkFile' : 'lnkPath lnkDirectory'; html += getItem(cssClass, folder.Type, folder.Path, folder.Name); } if (!path) { - html += getItem("lnkPath lnkDirectory", "", "Network", Globalize.translate("ButtonNetwork")); + html += getItem('lnkPath lnkDirectory', '', 'Network', globalize.translate('ButtonNetwork')); } - page.querySelector(".results").innerHTML = html; + page.querySelector('.results').innerHTML = html; loading.hide(); }, function() { if (updatePathOnError) { - page.querySelector("#txtDirectoryPickerPath").value = ""; - page.querySelector(".results").innerHTML = ""; + page.querySelector('#txtDirectoryPickerPath').value = ''; + page.querySelector('.results').innerHTML = ''; loading.hide(); } } @@ -69,74 +69,74 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- } function getItem(cssClass, type, path, name) { - var html = ""; + var html = ''; html += '
'; html += '
'; html += '
'; html += name; - html += "
"; - html += "
"; - html += 'arrow_forward'; - html += "
"; + html += ''; + html += ''; + html += ''; + html += ''; return html; } function getEditorHtml(options, systemInfo) { - var html = ""; + var html = ''; html += '
'; html += '
'; if (!options.pathReadOnly) { - var instruction = options.instruction ? options.instruction + "

" : ""; + var instruction = options.instruction ? options.instruction + '

' : ''; html += '
'; html += instruction; - html += Globalize.translate("MessageDirectoryPickerInstruction").replace("{0}", "\\\\server").replace("{1}", "\\\\192.168.1.101"); - if ("bsd" === systemInfo.OperatingSystem.toLowerCase()) { - html += "
"; - html += "
"; - html += Globalize.translate("MessageDirectoryPickerBSDInstruction"); - html += "
"; - } else if ("linux" === systemInfo.OperatingSystem.toLowerCase()) { - html += "
"; - html += "
"; - html += Globalize.translate("MessageDirectoryPickerLinuxInstruction"); - html += "
"; + html += globalize.translate('MessageDirectoryPickerInstruction', '\\\\server', '\\\\192.168.1.101'); + if ('bsd' === systemInfo.OperatingSystem.toLowerCase()) { + html += '
'; + html += '
'; + html += globalize.translate('MessageDirectoryPickerBSDInstruction'); + html += '
'; + } else if ('linux' === systemInfo.OperatingSystem.toLowerCase()) { + html += '
'; + html += '
'; + html += globalize.translate('MessageDirectoryPickerLinuxInstruction'); + html += '
'; } - html += "
" + html += '
'; } html += '
'; html += '
'; html += '
'; var labelKey; if (options.includeFiles !== true) { - labelKey = "LabelFolder"; + labelKey = 'LabelFolder'; } else { - labelKey = "LabelPath"; + labelKey = 'LabelPath'; } - var readOnlyAttribute = options.pathReadOnly ? " readonly" : ""; - html += ''; - html += "
"; + var readOnlyAttribute = options.pathReadOnly ? ' readonly' : ''; + html += ''; + html += '
'; if (!readOnlyAttribute) { - html += ''; + html += ''; } - html += "
"; + html += ''; if (!readOnlyAttribute) { html += '
'; } if (options.enableNetworkSharePath) { html += '
'; - html += ''; + html += ''; html += '
'; - html += Globalize.translate("LabelOptionalNetworkPathHelp"); - html += "
"; - html += "
"; + html += globalize.translate('LabelOptionalNetworkPathHelp'); + html += ''; + html += ''; } html += '
'; - html += '"; - html += "
"; - html += ""; - html += ""; - html += ""; - html += ""; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; return html; } @@ -144,75 +144,74 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- function alertText(text) { alertTextWithOptions({ text: text - }) + }); } function alertTextWithOptions(options) { - require(["alert"], function(alert) { - alert(options) - }) + require(['alert'], function(alert) { + alert(options); + }); } function validatePath(path, validateWriteable, apiClient) { return apiClient.ajax({ - type: "POST", - url: apiClient.getUrl("Environment/ValidatePath"), + type: 'POST', + url: apiClient.getUrl('Environment/ValidatePath'), data: { ValidateWriteable: validateWriteable, Path: path } }).catch(function(response) { if (response) { - // TODO All alerts (across the project), should use Globalize.translate() if (response.status === 404) { - alertText("The path could not be found. Please ensure the path is valid and try again."); + alertText(globalize.translate('PathNotFound')); return Promise.reject(); } if (response.status === 500) { if (validateWriteable) { - alertText("Jellyfin Server requires write access to this folder. Please ensure write access and try again."); + alertText(globalize.translate('WriteAccessRequired')); } else { - alertText("The path could not be found. Please ensure the path is valid and try again.") + alertText(globalize.translate('PathNotFound')); } - return Promise.reject() + return Promise.reject(); } } - return Promise.resolve() + return Promise.resolve(); }); } function initEditor(content, options, fileOptions) { - content.addEventListener("click", function(e) { - var lnkPath = dom.parentWithClass(e.target, "lnkPath"); + content.addEventListener('click', function(e) { + var lnkPath = dom.parentWithClass(e.target, 'lnkPath'); if (lnkPath) { - var path = lnkPath.getAttribute("data-path"); - if (lnkPath.classList.contains("lnkFile")) { - content.querySelector("#txtDirectoryPickerPath").value = path; + var path = lnkPath.getAttribute('data-path'); + if (lnkPath.classList.contains('lnkFile')) { + content.querySelector('#txtDirectoryPickerPath').value = path; } else { - refreshDirectoryBrowser(content, path, fileOptions, true) + refreshDirectoryBrowser(content, path, fileOptions, true); } } }); - content.addEventListener("click", function(e) { - if (dom.parentWithClass(e.target, "btnRefreshDirectories")) { - var path = content.querySelector("#txtDirectoryPickerPath").value; + content.addEventListener('click', function(e) { + if (dom.parentWithClass(e.target, 'btnRefreshDirectories')) { + var path = content.querySelector('#txtDirectoryPickerPath').value; refreshDirectoryBrowser(content, path, fileOptions); } }); - content.addEventListener("change", function(e) { - var txtDirectoryPickerPath = dom.parentWithTag(e.target, "INPUT"); - if (txtDirectoryPickerPath && "txtDirectoryPickerPath" === txtDirectoryPickerPath.id) { + content.addEventListener('change', function(e) { + var txtDirectoryPickerPath = dom.parentWithTag(e.target, 'INPUT'); + if (txtDirectoryPickerPath && 'txtDirectoryPickerPath' === txtDirectoryPickerPath.id) { refreshDirectoryBrowser(content, txtDirectoryPickerPath.value, fileOptions); } }); - content.querySelector("form").addEventListener("submit", function(e) { + content.querySelector('form').addEventListener('submit', function(e) { if (options.callback) { - var networkSharePath = this.querySelector("#txtNetworkPath"); + var networkSharePath = this.querySelector('#txtNetworkPath'); networkSharePath = networkSharePath ? networkSharePath.value : null; - var path = this.querySelector("#txtDirectoryPickerPath").value; + var path = this.querySelector('#txtDirectoryPickerPath').value; validatePath(path, options.validateWriteable, ApiClient).then(options.callback(path, networkSharePath)); } e.preventDefault(); @@ -225,11 +224,11 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- if (options.path) { return Promise.resolve(options.path); } else { - return ApiClient.getJSON(ApiClient.getUrl("Environment/DefaultDirectoryBrowser")).then( + return ApiClient.getJSON(ApiClient.getUrl('Environment/DefaultDirectoryBrowser')).then( function(result) { - return result.Path || ""; + return result.Path || ''; }, function() { - return ""; + return ''; } ); } @@ -254,35 +253,35 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- var systemInfo = responses[0]; var initialPath = responses[1]; var dlg = dialogHelper.createDialog({ - size: "medium-tall", + size: 'medium-tall', removeOnClose: true, scrollY: false }); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - dlg.classList.add("directoryPicker"); - dlg.classList.add("formDialog"); + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + dlg.classList.add('directoryPicker'); + dlg.classList.add('formDialog'); - var html = ""; + var html = ''; html += '
'; - html += ''; + html += ''; html += '

'; - html += options.header || Globalize.translate("HeaderSelectPath"); - html += "

"; - html += "
"; + html += options.header || globalize.translate('HeaderSelectPath'); + html += ''; + html += ''; html += getEditorHtml(options, systemInfo); dlg.innerHTML = html; initEditor(dlg, options, fileOptions); - dlg.addEventListener("close", onDialogClosed); + dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); - dlg.querySelector(".btnCloseDialog").addEventListener("click", function() { - dialogHelper.close(dlg) + dlg.querySelector('.btnCloseDialog').addEventListener('click', function() { + dialogHelper.close(dlg); }); currentDialog = dlg; - dlg.querySelector("#txtDirectoryPickerPath").value = initialPath; - var txtNetworkPath = dlg.querySelector("#txtNetworkPath"); + dlg.querySelector('#txtDirectoryPickerPath').value = initialPath; + var txtNetworkPath = dlg.querySelector('#txtNetworkPath'); if (txtNetworkPath) { - txtNetworkPath.value = options.networkSharePath || ""; + txtNetworkPath.value = options.networkSharePath || ''; } if (!options.pathReadOnly) { refreshDirectoryBrowser(dlg, initialPath, fileOptions, true); @@ -294,9 +293,9 @@ define(['loading', 'dialogHelper', 'dom', 'listViewStyle', 'emby-input', 'paper- if (currentDialog) { dialogHelper.close(currentDialog); } - } + }; } var systemInfo; - return directoryBrowser + return directoryBrowser; }); diff --git a/src/components/displaysettings/displaysettings.js b/src/components/displaysettings/displaysettings.js index fea7d9bd3e..2b7b4bb60c 100644 --- a/src/components/displaysettings/displaysettings.js +++ b/src/components/displaysettings/displaysettings.js @@ -1,5 +1,5 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', 'apphost', 'focusManager', 'datetime', 'globalize', 'loading', 'connectionManager', 'skinManager', 'dom', 'events', 'emby-select', 'emby-checkbox', 'emby-button'], function (require, browser, layoutManager, appSettings, pluginManager, appHost, focusManager, datetime, globalize, loading, connectionManager, skinManager, dom, events) { - "use strict"; + 'use strict'; function fillThemes(select, isDashboard) { select.innerHTML = skinManager.getThemes().map(function (t) { @@ -180,11 +180,14 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' context.querySelector('#chkThemeSong').checked = userSettings.enableThemeSongs(); context.querySelector('#chkThemeVideo').checked = userSettings.enableThemeVideos(); + context.querySelector('#chkFadein').checked = userSettings.enableFastFadein(); context.querySelector('#chkBackdrops').checked = userSettings.enableBackdrops(); context.querySelector('#selectLanguage').value = userSettings.language() || ''; context.querySelector('.selectDateTimeLocale').value = userSettings.dateTimeLocale() || ''; + context.querySelector('#txtLibraryPageSize').value = userSettings.libraryPageSize(); + selectDashboardTheme.value = userSettings.dashboardTheme() || ''; selectTheme.value = userSettings.theme() || ''; @@ -214,8 +217,11 @@ define(['require', 'browser', 'layoutManager', 'appSettings', 'pluginManager', ' userSettingsInstance.soundEffects(context.querySelector('.selectSoundEffects').value); userSettingsInstance.screensaver(context.querySelector('.selectScreensaver').value); + userSettingsInstance.libraryPageSize(context.querySelector('#txtLibraryPageSize').value); + userSettingsInstance.skin(context.querySelector('.selectSkin').value); + userSettingsInstance.enableFastFadein(context.querySelector('#chkFadein').checked); userSettingsInstance.enableBackdrops(context.querySelector('#chkBackdrops').checked); if (user.Id === apiClient.getCurrentUserId()) { diff --git a/src/components/displaysettings/displaysettings.template.html b/src/components/displaysettings/displaysettings.template.html index f469d8d5ce..b8ab1a9ba5 100644 --- a/src/components/displaysettings/displaysettings.template.html +++ b/src/components/displaysettings/displaysettings.template.html @@ -3,6 +3,7 @@

${Display}

+
- + @@ -133,6 +134,7 @@
+
@@ -141,6 +143,19 @@
+
+ +
${LabelLibraryPageSizeHelp}
+
+ +
+ +
${EnableFastImageFadeInHelp}
+
+
${EnableBackdropsHelp}
+
${EnableThemeSongsHelp}
+
'; if (enableScrollX()) { - var scrollXClass = "scrollX hiddenScrollX"; + var scrollXClass = 'scrollX hiddenScrollX'; if (layoutManager.tv) { - scrollXClass += " smoothScrollX"; + scrollXClass += ' smoothScrollX'; } html += '
'; @@ -154,7 +154,7 @@ define(["loading", "libraryBrowser", "cardBuilder", "dom", "apphost", "imageLoad html += '
'; } - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle; cardLayout = false; html += cardBuilder.getCardsHtml(result.Items, { @@ -172,7 +172,7 @@ define(["loading", "libraryBrowser", "cardBuilder", "dom", "apphost", "imageLoad allowBottomPadding: !enableScrollX(), cardLayout: cardLayout }); - html += "
"; + html += '
'; } elem.innerHTML = html; @@ -183,7 +183,7 @@ define(["loading", "libraryBrowser", "cardBuilder", "dom", "apphost", "imageLoad function loadSections(page, userId, topParentId, types) { loading.show(); var sections = getSections(); - var sectionid = getParameterByName("sectionid"); + var sectionid = getParameterByName('sectionid'); if (sectionid) { sections = sections.filter(function (s) { @@ -199,10 +199,10 @@ define(["loading", "libraryBrowser", "cardBuilder", "dom", "apphost", "imageLoad var i; var length; - var elem = page.querySelector(".favoriteSections"); + var elem = page.querySelector('.favoriteSections'); if (!elem.innerHTML) { - var html = ""; + var html = ''; for (i = 0, length = sections.length; i < length; i++) { html += '
'; @@ -215,7 +215,7 @@ define(["loading", "libraryBrowser", "cardBuilder", "dom", "apphost", "imageLoad for (i = 0, length = sections.length; i < length; i++) { var section = sections[i]; - elem = page.querySelector(".section" + section.id); + elem = page.querySelector('.section' + section.id); promises.push(loadSection(elem, userId, topParentId, section, 1 === sections.length)); } diff --git a/src/components/fetchhelper.js b/src/components/fetchhelper.js index bb7f21e75e..08fe803ecf 100644 --- a/src/components/fetchhelper.js +++ b/src/components/fetchhelper.js @@ -51,7 +51,7 @@ define([], function () { function fetchWithTimeout(url, options, timeoutMs) { - console.log('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url); + console.debug('fetchWithTimeout: timeoutMs: ' + timeoutMs + ', url: ' + url); return new Promise(function (resolve, reject) { @@ -63,14 +63,14 @@ define([], function () { fetch(url, options).then(function (response) { clearTimeout(timeout); - console.log('fetchWithTimeout: succeeded connecting to url: ' + url); + console.debug('fetchWithTimeout: succeeded connecting to url: ' + url); resolve(response); }, function (error) { clearTimeout(timeout); - console.log('fetchWithTimeout: timed out connecting to url: ' + url); + console.debug('fetchWithTimeout: timed out connecting to url: ' + url); reject(); }); @@ -86,28 +86,24 @@ define([], function () { var value = params[key]; if (value !== null && value !== undefined && value !== '') { - values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)); + values.push(encodeURIComponent(key) + '=' + encodeURIComponent(value)); } } return values.join('&'); } function ajax(request) { - if (!request) { - throw new Error("Request cannot be null"); + throw new Error('Request cannot be null'); } request.headers = request.headers || {}; - console.log('requesting url: ' + request.url); + console.debug('requesting url: ' + request.url); return getFetchPromise(request).then(function (response) { - - console.log('response status: ' + response.status + ', url: ' + request.url); - + console.debug('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) { @@ -118,10 +114,8 @@ define([], function () { } else { return Promise.reject(response); } - }, function (err) { - - console.log('request failed to url: ' + request.url); + console.error('request failed to url: ' + request.url); throw err; }); } @@ -129,4 +123,4 @@ define([], function () { getFetchPromise: getFetchPromise, ajax: ajax }; -}); \ No newline at end of file +}); diff --git a/src/components/filedownloader.js b/src/components/filedownloader.js index c5810b460e..f2ca42211f 100644 --- a/src/components/filedownloader.js +++ b/src/components/filedownloader.js @@ -1,18 +1,14 @@ -define(['multi-download'], function (multiDownload) { - 'use strict'; +import multiDownload from 'multi-download'; - return { - download: function (items) { +export function download(items) { - if (window.NativeShell) { - items.map(function (item) { - window.NativeShell.downloadFile(item.url); - }); - } else { - multiDownload(items.map(function (item) { - return item.url; - })); - } - } - }; -}); \ No newline at end of file + if (window.NativeShell) { + items.map(function (item) { + window.NativeShell.downloadFile(item); + }); + } else { + multiDownload(items.map(function (item) { + return item.url; + })); + } +} diff --git a/src/components/filesystem.js b/src/components/filesystem.js deleted file mode 100644 index 3ab759b28a..0000000000 --- a/src/components/filesystem.js +++ /dev/null @@ -1,18 +0,0 @@ -define([], function () { - 'use strict'; - - return { - fileExists: function (path) { - if (window.NativeShell && window.NativeShell.FileSystem) { - return window.NativeShell.FileSystem.fileExists(path); - } - return Promise.reject(); - }, - directoryExists: function (path) { - if (window.NativeShell && window.NativeShell.FileSystem) { - return window.NativeShell.FileSystem.directoryExists(path); - } - return Promise.reject(); - } - }; -}); \ No newline at end of file diff --git a/src/components/filterdialog/filterdialog.js b/src/components/filterdialog/filterdialog.js index 7301c65669..1dfd04c679 100644 --- a/src/components/filterdialog/filterdialog.js +++ b/src/components/filterdialog/filterdialog.js @@ -1,52 +1,49 @@ -define(["dialogHelper", "globalize", "connectionManager", "events", "browser", "require", "emby-checkbox", "emby-collapse", "css!./style"], function (dialogHelper, globalize, connectionManager, events, browser, require) { - "use strict"; +define(['dom', 'dialogHelper', 'globalize', 'connectionManager', 'events', 'browser', 'require', 'emby-checkbox', 'emby-collapse', 'css!./style'], function (dom, dialogHelper, globalize, connectionManager, events, browser, require) { + 'use strict'; function renderOptions(context, selector, cssClass, items, isCheckedFn) { var elem = context.querySelector(selector); if (items.length) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } - var html = ""; + var html = ''; html += '
'; html += items.map(function (filter) { - var itemHtml = ""; - var checkedHtml = isCheckedFn(filter) ? " checked" : ""; - itemHtml += "'; return itemHtml; - }).join(""); - html += "
"; - elem.querySelector(".filterOptions").innerHTML = html; + }).join(''); + html += ''; + elem.querySelector('.filterOptions').innerHTML = html; } function renderFilters(context, result, query) { - if (result.Tags) { - result.Tags.length = Math.min(result.Tags.length, 50); - } - renderOptions(context, ".genreFilters", "chkGenreFilter", result.Genres, function (i) { - var delimeter = "|"; - return (delimeter + (query.Genres || "") + delimeter).indexOf(delimeter + i + delimeter) != -1; + renderOptions(context, '.genreFilters', 'chkGenreFilter', result.Genres, function (i) { + var delimeter = '|'; + return (delimeter + (query.Genres || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; }); - renderOptions(context, ".officialRatingFilters", "chkOfficialRatingFilter", result.OfficialRatings, function (i) { - var delimeter = "|"; - return (delimeter + (query.OfficialRatings || "") + delimeter).indexOf(delimeter + i + 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, '.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; + renderOptions(context, '.yearFilters', 'chkYearFilter', result.Years, function (i) { + var delimeter = ','; + return (delimeter + (query.Years || '') + delimeter).indexOf(delimeter + i + delimeter) != -1; }); } function loadDynamicFilters(context, apiClient, userId, itemQuery) { - return apiClient.getJSON(apiClient.getUrl("Items/Filters", { + return apiClient.getJSON(apiClient.getUrl('Items/Filters', { UserId: userId, ParentId: itemQuery.ParentId, IncludeItemTypes: itemQuery.IncludeItemTypes @@ -61,108 +58,98 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " var length; var query = options.query; - if (options.mode == "livetvchannels") { - context.querySelector(".chkFavorite").checked = query.IsFavorite == true; - context.querySelector(".chkLikes").checked = query.IsLiked == true; - context.querySelector(".chkDislikes").checked = query.IsDisliked == true; + if (options.mode == 'livetvchannels') { + context.querySelector('.chkFavorite').checked = query.IsFavorite == true; + context.querySelector('.chkLikes').checked = query.IsLiked == true; + context.querySelector('.chkDislikes').checked = query.IsDisliked == true; } else { - elems = context.querySelectorAll(".chkStandardFilter"); + elems = context.querySelectorAll('.chkStandardFilter'); for (i = 0, length = elems.length; i < length; i++) { var chkStandardFilter = elems[i]; - var filters = "," + (query.Filters || ""); - var filterName = chkStandardFilter.getAttribute("data-filter"); - chkStandardFilter.checked = filters.indexOf("," + filterName) != -1; + var filters = ',' + (query.Filters || ''); + var filterName = chkStandardFilter.getAttribute('data-filter'); + chkStandardFilter.checked = filters.indexOf(',' + filterName) != -1; } } - elems = context.querySelectorAll(".chkVideoTypeFilter"); + elems = context.querySelectorAll('.chkVideoTypeFilter'); for (i = 0, length = elems.length; i < length; i++) { var chkVideoTypeFilter = elems[i]; - var filters = "," + (query.VideoTypes || ""); - var filterName = chkVideoTypeFilter.getAttribute("data-filter"); - chkVideoTypeFilter.checked = filters.indexOf("," + filterName) != -1; + var filters = ',' + (query.VideoTypes || ''); + var filterName = chkVideoTypeFilter.getAttribute('data-filter'); + chkVideoTypeFilter.checked = filters.indexOf(',' + filterName) != -1; } - context.querySelector(".chk3DFilter").checked = query.Is3D == true; - context.querySelector(".chkHDFilter").checked = query.IsHD == true; - context.querySelector(".chk4KFilter").checked = query.Is4K == true; - context.querySelector(".chkSDFilter").checked = query.IsHD == true; - context.querySelector("#chkSubtitle").checked = query.HasSubtitles == true; - context.querySelector("#chkTrailer").checked = query.HasTrailer == true; - context.querySelector("#chkThemeSong").checked = query.HasThemeSong == true; - context.querySelector("#chkThemeVideo").checked = query.HasThemeVideo == true; - context.querySelector("#chkSpecialFeature").checked = query.HasSpecialFeature == true; - context.querySelector("#chkSpecialEpisode").checked = query.ParentIndexNumber == 0; - context.querySelector("#chkMissingEpisode").checked = query.IsMissing == true; - context.querySelector("#chkFutureEpisode").checked = query.IsUnaired == true; + context.querySelector('.chk3DFilter').checked = query.Is3D == true; + context.querySelector('.chkHDFilter').checked = query.IsHD == true; + context.querySelector('.chk4KFilter').checked = query.Is4K == true; + context.querySelector('.chkSDFilter').checked = query.IsHD == true; + context.querySelector('#chkSubtitle').checked = query.HasSubtitles == true; + context.querySelector('#chkTrailer').checked = query.HasTrailer == true; + context.querySelector('#chkThemeSong').checked = query.HasThemeSong == true; + context.querySelector('#chkThemeVideo').checked = query.HasThemeVideo == true; + context.querySelector('#chkSpecialFeature').checked = query.HasSpecialFeature == true; + context.querySelector('#chkSpecialEpisode').checked = query.ParentIndexNumber == 0; + context.querySelector('#chkMissingEpisode').checked = query.IsMissing == true; + context.querySelector('#chkFutureEpisode').checked = query.IsUnaired == true; for (i = 0, length = elems.length; i < length; i++) { var chkStatus = elems[i]; - var filters = "," + (query.SeriesStatus || ""); - var filterName = chkStatus.getAttribute("data-filter"); - chkStatus.checked = filters.indexOf("," + filterName) != -1; + var filters = ',' + (query.SeriesStatus || ''); + var filterName = chkStatus.getAttribute('data-filter'); + chkStatus.checked = filters.indexOf(',' + filterName) != -1; } } function triggerChange(instance) { - events.trigger(instance, "filterchange"); - } - - function parentWithClass(elem, className) { - while (!elem.classList || !elem.classList.contains(className)) { - elem = elem.parentNode; - if (!elem) { - return null; - } - } - return elem; + events.trigger(instance, 'filterchange'); } function setVisibility(context, options) { - if (options.mode == "livetvchannels" || options.mode == "albums" || options.mode == "artists" || options.mode == "albumartists" || options.mode == "songs") { - hideByClass(context, "videoStandard"); + if (options.mode == 'livetvchannels' || options.mode == 'albums' || options.mode == 'artists' || options.mode == 'albumartists' || options.mode == 'songs') { + hideByClass(context, 'videoStandard'); } if (enableDynamicFilters(options.mode)) { - context.querySelector(".genreFilters").classList.remove("hide"); - context.querySelector(".officialRatingFilters").classList.remove("hide"); - context.querySelector(".tagFilters").classList.remove("hide"); - context.querySelector(".yearFilters").classList.remove("hide"); + context.querySelector('.genreFilters').classList.remove('hide'); + context.querySelector('.officialRatingFilters').classList.remove('hide'); + context.querySelector('.tagFilters').classList.remove('hide'); + context.querySelector('.yearFilters').classList.remove('hide'); } - if (options.mode == "movies" || options.mode == "episodes") { - context.querySelector(".videoTypeFilters").classList.remove("hide"); + if (options.mode == 'movies' || options.mode == 'episodes') { + context.querySelector('.videoTypeFilters').classList.remove('hide'); } - if (options.mode == "movies" || options.mode == "series" || options.mode == "episodes") { - context.querySelector(".features").classList.remove("hide"); + if (options.mode == 'movies' || options.mode == 'series' || options.mode == 'episodes') { + context.querySelector('.features').classList.remove('hide'); } - if (options.mode == "series") { - context.querySelector(".seriesStatus").classList.remove("hide"); + if (options.mode == 'series') { + context.querySelector('.seriesStatus').classList.remove('hide'); } - if (options.mode == "episodes") { - showByClass(context, "episodeFilter"); + if (options.mode == 'episodes') { + showByClass(context, 'episodeFilter'); } } function showByClass(context, className) { - var elems = context.querySelectorAll("." + className); + var elems = context.querySelectorAll('.' + className); for (var i = 0, length = elems.length; i < length; i++) { - elems[i].classList.remove("hide"); + elems[i].classList.remove('hide'); } } function hideByClass(context, className) { - var elems = context.querySelectorAll("." + className); + var elems = context.querySelectorAll('.' + className); for (var i = 0, length = elems.length; i < length; i++) { - elems[i].classList.add("hide"); + elems[i].classList.add('hide'); } } function enableDynamicFilters(mode) { - return mode == "movies" || mode == "series" || mode == "albums" || mode == "albumartists" || mode == "artists" || mode == "songs" || mode == "episodes"; + return mode == 'movies' || mode == 'series' || mode == 'albums' || mode == 'albumartists' || mode == 'artists' || mode == 'songs' || mode == 'episodes'; } return function (options) { @@ -175,12 +162,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " function onStandardFilterChange() { var query = options.query; - var filterName = this.getAttribute("data-filter"); - var filters = query.Filters || ""; - filters = ("," + filters).replace("," + filterName, "").substring(1); + var filterName = this.getAttribute('data-filter'); + var filters = query.Filters || ''; + filters = (',' + filters).replace(',' + filterName, '').substring(1); if (this.checked) { - filters = filters ? filters + "," + filterName : filterName; + filters = filters ? filters + ',' + filterName : filterName; } query.StartIndex = 0; @@ -190,12 +177,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " function onVideoTypeFilterChange() { var query = options.query; - var filterName = this.getAttribute("data-filter"); - var filters = query.VideoTypes || ""; - filters = ("," + filters).replace("," + filterName, "").substring(1); + var filterName = this.getAttribute('data-filter'); + var filters = query.VideoTypes || ''; + filters = (',' + filters).replace(',' + filterName, '').substring(1); if (this.checked) { - filters = filters ? filters + "," + filterName : filterName; + filters = filters ? filters + ',' + filterName : filterName; } query.StartIndex = 0; @@ -205,12 +192,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " function onStatusChange() { var query = options.query; - var filterName = this.getAttribute("data-filter"); - var filters = query.SeriesStatus || ""; - filters = ("," + filters).replace("," + filterName, "").substring(1); + var filterName = this.getAttribute('data-filter'); + var filters = query.SeriesStatus || ''; + filters = (',' + filters).replace(',' + filterName, '').substring(1); if (this.checked) { - filters = filters ? filters + "," + filterName : filterName; + filters = filters ? filters + ',' + filterName : filterName; } query.SeriesStatus = filters; @@ -224,86 +211,86 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " var length; var query = options.query; - if (options.mode == "livetvchannels") { - elems = context.querySelectorAll(".chkFavorite"); + if (options.mode == 'livetvchannels') { + elems = context.querySelectorAll('.chkFavorite'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("change", onFavoriteChange); + elems[i].addEventListener('change', onFavoriteChange); } - context.querySelector(".chkLikes").addEventListener("change", function () { + context.querySelector('.chkLikes').addEventListener('change', function () { query.StartIndex = 0; query.IsLiked = this.checked ? true : null; triggerChange(self); }); - context.querySelector(".chkDislikes").addEventListener("change", function () { + context.querySelector('.chkDislikes').addEventListener('change', function () { query.StartIndex = 0; query.IsDisliked = this.checked ? true : null; triggerChange(self); }); } else { - elems = context.querySelectorAll(".chkStandardFilter"); + elems = context.querySelectorAll('.chkStandardFilter'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("change", onStandardFilterChange); + elems[i].addEventListener('change', onStandardFilterChange); } } - elems = context.querySelectorAll(".chkVideoTypeFilter"); + elems = context.querySelectorAll('.chkVideoTypeFilter'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("change", onVideoTypeFilterChange); + elems[i].addEventListener('change', onVideoTypeFilterChange); } - context.querySelector(".chk3DFilter").addEventListener("change", function () { + context.querySelector('.chk3DFilter').addEventListener('change', function () { query.StartIndex = 0; query.Is3D = this.checked ? true : null; triggerChange(self); }); - context.querySelector(".chk4KFilter").addEventListener("change", function () { + context.querySelector('.chk4KFilter').addEventListener('change', function () { query.StartIndex = 0; query.Is4K = this.checked ? true : null; triggerChange(self); }); - context.querySelector(".chkHDFilter").addEventListener("change", function () { + context.querySelector('.chkHDFilter').addEventListener('change', function () { query.StartIndex = 0; query.IsHD = this.checked ? true : null; triggerChange(self); }); - context.querySelector(".chkSDFilter").addEventListener("change", function () { + context.querySelector('.chkSDFilter').addEventListener('change', function () { query.StartIndex = 0; query.IsHD = this.checked ? false : null; triggerChange(self); }); - elems = context.querySelectorAll(".chkStatus"); + elems = context.querySelectorAll('.chkStatus'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("change", onStatusChange); + elems[i].addEventListener('change', onStatusChange); } - context.querySelector("#chkTrailer").addEventListener("change", function () { + context.querySelector('#chkTrailer').addEventListener('change', function () { query.StartIndex = 0; query.HasTrailer = this.checked ? true : null; triggerChange(self); }); - context.querySelector("#chkThemeSong").addEventListener("change", function () { + context.querySelector('#chkThemeSong').addEventListener('change', function () { query.StartIndex = 0; query.HasThemeSong = this.checked ? true : null; triggerChange(self); }); - context.querySelector("#chkSpecialFeature").addEventListener("change", function () { + context.querySelector('#chkSpecialFeature').addEventListener('change', function () { query.StartIndex = 0; query.HasSpecialFeature = this.checked ? true : null; triggerChange(self); }); - context.querySelector("#chkThemeVideo").addEventListener("change", function () { + context.querySelector('#chkThemeVideo').addEventListener('change', function () { query.StartIndex = 0; query.HasThemeVideo = this.checked ? true : null; triggerChange(self); }); - context.querySelector("#chkMissingEpisode").addEventListener("change", function () { + context.querySelector('#chkMissingEpisode').addEventListener('change', function () { query.StartIndex = 0; query.IsMissing = this.checked ? true : false; triggerChange(self); }); - context.querySelector("#chkSpecialEpisode").addEventListener("change", function () { + context.querySelector('#chkSpecialEpisode').addEventListener('change', function () { query.StartIndex = 0; query.ParentIndexNumber = this.checked ? 0 : null; triggerChange(self); }); - context.querySelector("#chkFutureEpisode").addEventListener("change", function () { + context.querySelector('#chkFutureEpisode').addEventListener('change', function () { query.StartIndex = 0; if (this.checked) { query.IsUnaired = true; @@ -314,18 +301,18 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " } triggerChange(self); }); - context.querySelector("#chkSubtitle").addEventListener("change", function () { + context.querySelector('#chkSubtitle').addEventListener('change', function () { query.StartIndex = 0; query.HasSubtitles = this.checked ? true : null; triggerChange(self); }); - context.addEventListener("change", function (e) { - var chkGenreFilter = parentWithClass(e.target, "chkGenreFilter"); + context.addEventListener('change', function (e) { + var chkGenreFilter = dom.parentWithClass(e.target, 'chkGenreFilter'); if (chkGenreFilter) { - var filterName = chkGenreFilter.getAttribute("data-filter"); - var filters = query.Genres || ""; - var delimiter = "|"; - filters = (delimiter + filters).replace(delimiter + filterName, "").substring(1); + var filterName = chkGenreFilter.getAttribute('data-filter'); + var filters = query.Genres || ''; + var delimiter = '|'; + filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); if (chkGenreFilter.checked) { filters = filters ? (filters + delimiter + filterName) : filterName; } @@ -334,12 +321,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " triggerChange(self); return; } - var chkTagFilter = parentWithClass(e.target, "chkTagFilter"); + var chkTagFilter = dom.parentWithClass(e.target, 'chkTagFilter'); if (chkTagFilter) { - var filterName = chkTagFilter.getAttribute("data-filter"); - var filters = query.Tags || ""; - var delimiter = "|"; - filters = (delimiter + filters).replace(delimiter + filterName, "").substring(1); + var filterName = chkTagFilter.getAttribute('data-filter'); + var filters = query.Tags || ''; + var delimiter = '|'; + filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); if (chkTagFilter.checked) { filters = filters ? (filters + delimiter + filterName) : filterName; } @@ -348,12 +335,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " triggerChange(self); return; } - var chkYearFilter = parentWithClass(e.target, "chkYearFilter"); + var chkYearFilter = dom.parentWithClass(e.target, 'chkYearFilter'); if (chkYearFilter) { - var filterName = chkYearFilter.getAttribute("data-filter"); - var filters = query.Years || ""; - var delimiter = ","; - filters = (delimiter + filters).replace(delimiter + filterName, "").substring(1); + var filterName = chkYearFilter.getAttribute('data-filter'); + var filters = query.Years || ''; + var delimiter = ','; + filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); if (chkYearFilter.checked) { filters = filters ? (filters + delimiter + filterName) : filterName; } @@ -362,12 +349,12 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " triggerChange(self); return; } - var chkOfficialRatingFilter = parentWithClass(e.target, "chkOfficialRatingFilter"); + var chkOfficialRatingFilter = dom.parentWithClass(e.target, 'chkOfficialRatingFilter'); if (chkOfficialRatingFilter) { - var filterName = chkOfficialRatingFilter.getAttribute("data-filter"); - var filters = query.OfficialRatings || ""; - var delimiter = "|"; - filters = (delimiter + filters).replace(delimiter + filterName, "").substring(1); + var filterName = chkOfficialRatingFilter.getAttribute('data-filter'); + var filters = query.OfficialRatings || ''; + var delimiter = '|'; + filters = (delimiter + filters).replace(delimiter + filterName, '').substring(1); if (chkOfficialRatingFilter.checked) { filters = filters ? (filters + delimiter + filterName) : filterName; } @@ -383,23 +370,23 @@ define(["dialogHelper", "globalize", "connectionManager", "events", "browser", " self.show = function () { return new Promise(function (resolve, reject) { - require(["text!./filterdialog.template.html"], function (template) { + require(['text!./filterdialog.template.html'], function (template) { var dlg = dialogHelper.createDialog({ removeOnClose: true, modal: false }); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - dlg.classList.add("formDialog"); - dlg.classList.add("filterDialog"); + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + dlg.classList.add('formDialog'); + dlg.classList.add('filterDialog'); dlg.innerHTML = globalize.translateDocument(template); setVisibility(dlg, options); dialogHelper.open(dlg); - dlg.addEventListener("close", resolve); + dlg.addEventListener('close', resolve); updateFilterControls(dlg, options); bindEvents(dlg); if (enableDynamicFilters(options.mode)) { - dlg.classList.add("dynamicFilterDialog"); + dlg.classList.add('dynamicFilterDialog'); var apiClient = connectionManager.getApiClient(options.serverId); loadDynamicFilters(dlg, apiClient, apiClient.getCurrentUserId(), options.query); } diff --git a/src/components/filterdialog/style.css b/src/components/filterdialog/style.css index 69a82d2408..f05ef2e4a8 100644 --- a/src/components/filterdialog/style.css +++ b/src/components/filterdialog/style.css @@ -5,31 +5,32 @@ margin-top: 0 !important; margin-bottom: 0 !important; margin-right: 0 !important; + -webkit-border-radius: 0 !important; border-radius: 0 !important; max-height: none !important; - max-width: none !important + max-width: none !important; } -@media all and (min-height:600px) { +@media all and (min-height: 600px) { .dynamicFilterDialog { top: 10% !important; - bottom: 25% !important + bottom: 25% !important; } } -@media all and (max-width:400px) { +@media all and (max-width: 400px) { .dynamicFilterDialog { width: auto; left: 10vw !important; right: 10vw !important; - margin-left: 0 !important + margin-left: 0 !important; } } -@media all and (min-width:400px) { +@media all and (min-width: 400px) { .dynamicFilterDialog { - width: 300px; - margin-left: -150px !important; - left: 50% !important + width: 20.16em; + margin-left: -10.08em !important; + left: 50% !important; } } diff --git a/src/components/filtermenu/filtermenu.js b/src/components/filtermenu/filtermenu.js index f2196bf632..c189856e7b 100644 --- a/src/components/filtermenu/filtermenu.js +++ b/src/components/filtermenu/filtermenu.js @@ -279,7 +279,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'apphost', var html = ''; html += '
'; - html += ''; + html += ''; html += '

${Filters}

'; html += '
'; diff --git a/src/components/filtermenu/filtermenu.template.html b/src/components/filtermenu/filtermenu.template.html index 1cadab2d1f..1a5545baa3 100644 --- a/src/components/filtermenu/filtermenu.template.html +++ b/src/components/filtermenu/filtermenu.template.html @@ -105,4 +105,4 @@ - \ No newline at end of file + diff --git a/src/components/focusManager.js b/src/components/focusManager.js index 56ff324e23..f2022cc445 100644 --- a/src/components/focusManager.js +++ b/src/components/focusManager.js @@ -43,7 +43,7 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) { preventScroll: scrollManager.isEnabled() }); } catch (err) { - console.log('Error in focusManager.autoFocus: ' + err); + console.error('Error in focusManager.autoFocus: ' + err); } } @@ -117,7 +117,7 @@ define(['dom', 'scrollManager'], function (dom, scrollManager) { return false; } - if (elem.getAttribute('tabindex') === "-1") { + if (elem.getAttribute('tabindex') === '-1') { return false; } diff --git a/src/components/formdialog.css b/src/components/formdialog.css index b976d8130e..788331da94 100644 --- a/src/components/formdialog.css +++ b/src/components/formdialog.css @@ -5,14 +5,15 @@ } .formDialogHeader { - padding: 1em .5em; + padding: 1em 0.5em; display: flex; align-items: center; flex-shrink: 0; } .formDialogHeaderTitle { - margin-left: .25em; + margin-left: 0.25em; + /* In case of h1, h2, h3 */ margin-top: 0; margin-bottom: 0; @@ -23,7 +24,7 @@ } .dialogContentInner { - padding: .5em 1em 20em 1em; + padding: 0.5em 1em 20em 1em; } .dialogContentInner-mini { @@ -46,6 +47,7 @@ display: flex; position: absolute; padding: 1.25em 1em; + /* Without this emby-checkbox is able to appear on top */ z-index: 1; align-items: center; @@ -62,11 +64,11 @@ padding-bottom: 1.5em; flex-direction: column; width: 80% !important; - padding-top: .5em; + padding-top: 0.5em; } .formDialogFooterItem { - margin: .5em !important; + margin: 0.5em !important; flex-grow: 1; text-align: center; flex-basis: 0; @@ -91,7 +93,6 @@ } @media all and (min-width: 50em) { - .formDialogFooterItem { max-width: 80%; } @@ -103,7 +104,6 @@ } @media all and (min-width: 80em) { - .formDialogFooterItem { max-width: 70%; } diff --git a/src/components/fullscreenManager.js b/src/components/fullscreenManager.js deleted file mode 100644 index 8ae31073a2..0000000000 --- a/src/components/fullscreenManager.js +++ /dev/null @@ -1,103 +0,0 @@ -define(['events', 'dom', 'apphost', 'browser'], function (events, dom, appHost, browser) { - 'use strict'; - - 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 (!this.isFullScreen()) { - return; - } - 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(); - } - }; - - // TODO: use screenfull.js - fullscreenManager.prototype.isFullScreen = function () { - return document.fullscreen || - document.mozFullScreen || - document.webkitIsFullScreen || - document.msFullscreenElement || /* IE/Edge syntax */ - document.fullscreenElement || /* Standard syntax */ - document.webkitFullscreenElement || /* Chrome, Safari and Opera syntax */ - document.mozFullScreenElement; /* Firefox syntax */ - }; - - var manager = new fullscreenManager(); - - function onFullScreenChange() { - events.trigger(manager, 'fullscreenchange'); - } - - dom.addEventListener(document, 'fullscreenchange', onFullScreenChange, { - passive: true - }); - - dom.addEventListener(document, 'webkitfullscreenchange', onFullScreenChange, { - passive: true - }); - - dom.addEventListener(document, 'mozfullscreenchange', onFullScreenChange, { - passive: true - }); - - function isTargetValid(target) { - return !dom.parentWithTag(target, ['BUTTON', 'INPUT', 'TEXTAREA']); - } - if (appHost.supports("fullscreenchange") && (browser.edgeUwp || -1 !== navigator.userAgent.toLowerCase().indexOf("electron"))) { - - dom.addEventListener(window, 'dblclick', function (e) { - - if (isTargetValid(e.target)) { - if (manager.isFullScreen()) { - manager.exitFullscreen(); - } else { - manager.requestFullscreen(); - } - } - - }, { - passive: true - }); - } - - return manager; -}); diff --git a/src/components/groupedcards.js b/src/components/groupedcards.js index ad638ecdd9..602c4310f4 100644 --- a/src/components/groupedcards.js +++ b/src/components/groupedcards.js @@ -1,28 +1,28 @@ -define(["dom", "appRouter", "connectionManager"], function (dom, appRouter, connectionManager) { - "use strict"; +define(['dom', 'appRouter', 'connectionManager'], function (dom, appRouter, connectionManager) { + 'use strict'; function onGroupedCardClick(e, card) { - var itemId = card.getAttribute("data-id"); - var serverId = card.getAttribute("data-serverid"); + var itemId = card.getAttribute('data-id'); + var serverId = card.getAttribute('data-serverid'); var apiClient = connectionManager.getApiClient(serverId); var userId = apiClient.getCurrentUserId(); - var playedIndicator = card.querySelector(".playedIndicator"); + var playedIndicator = card.querySelector('.playedIndicator'); var playedIndicatorHtml = playedIndicator ? playedIndicator.innerHTML : null; var options = { - Limit: parseInt(playedIndicatorHtml || "10"), - Fields: "PrimaryImageAspectRatio,DateCreated", + Limit: parseInt(playedIndicatorHtml || '10'), + Fields: 'PrimaryImageAspectRatio,DateCreated', ParentId: itemId, GroupItems: false }; - var actionableParent = dom.parentWithTag(e.target, ["A", "BUTTON", "INPUT"]); + var actionableParent = dom.parentWithTag(e.target, ['A', 'BUTTON', 'INPUT']); - if (!actionableParent || actionableParent.classList.contains("cardContent")) { - apiClient.getJSON(apiClient.getUrl("Users/" + userId + "/Items/Latest", options)).then(function (items) { + if (!actionableParent || actionableParent.classList.contains('cardContent')) { + apiClient.getJSON(apiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { if (1 === items.length) { return void appRouter.showItem(items[0]); } - var url = "itemdetails.html?id=" + itemId + "&serverId=" + serverId; + var url = 'itemdetails.html?id=' + itemId + '&serverId=' + serverId; Dashboard.navigate(url); }); e.stopPropagation(); @@ -32,7 +32,7 @@ define(["dom", "appRouter", "connectionManager"], function (dom, appRouter, conn } function onItemsContainerClick(e) { - var groupedCard = dom.parentWithClass(e.target, "groupedCard"); + var groupedCard = dom.parentWithClass(e.target, 'groupedCard'); if (groupedCard) { onGroupedCardClick(e, groupedCard); diff --git a/src/components/guide/guide-settings.js b/src/components/guide/guide-settings.js index 9ee43be9f1..7409a7e943 100644 --- a/src/components/guide/guide-settings.js +++ b/src/components/guide/guide-settings.js @@ -89,20 +89,6 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio } } - 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(); - } - } - } - function showEditor(options) { return new Promise(function (resolve, reject) { @@ -171,4 +157,4 @@ define(['dialogHelper', 'globalize', 'userSettings', 'layoutManager', 'connectio return { show: showEditor }; -}); \ No newline at end of file +}); diff --git a/src/components/guide/guide-settings.template.html b/src/components/guide/guide-settings.template.html index d85b4a71b9..edb2ffa8d3 100644 --- a/src/components/guide/guide-settings.template.html +++ b/src/components/guide/guide-settings.template.html @@ -1,5 +1,7 @@
- +

${Settings}

diff --git a/src/components/guide/guide.css b/src/components/guide/guide.css index 7dd0594149..3b776e6dde 100644 --- a/src/components/guide/guide.css +++ b/src/components/guide/guide.css @@ -14,12 +14,12 @@ } .layout-desktop .tvGuideHeader { - margin-bottom: .5em; + margin-bottom: 0.5em; } .guideHeaderDateSelection { font-size: 86%; - padding: .4em 0; + padding: 0.4em 0; } .guide-headerTimeslots { @@ -39,10 +39,10 @@ .guideProgramIndicator { text-transform: uppercase; - border-radius: .25em; - margin-right: .5em; + border-radius: 0.25em; + margin-right: 0.5em; font-size: 82%; - padding: .2em .25em; + padding: 0.2em 0.25em; display: inline-flex; align-items: center; justify-content: center; @@ -51,6 +51,8 @@ } .guide-channelTimeslotHeader { + border: 0 !important; + border-right-color: transparent; flex-shrink: 0; justify-content: center; } @@ -69,9 +71,14 @@ } .channelPrograms { + height: 4.42em; + contain: strict; + display: flex; + flex-direction: column; + border-style: solid; + border-width: 1px 0 1px 0; white-space: nowrap; position: relative; - contain: strict; box-sizing: border-box; } @@ -80,31 +87,32 @@ } .guideSpacer { - width: .3em; + width: 0.3em; flex-shrink: 0; } -.channelPrograms, .timeslotHeadersInner { +.channelPrograms, +.timeslotHeadersInner { width: 1800vw; } @media all and (min-width: 37.5em) { - - .channelPrograms, .timeslotHeadersInner { + .channelPrograms, + .timeslotHeadersInner { width: 1400vw; } } @media all and (min-width: 50em) { - - .channelPrograms, .timeslotHeadersInner { + .channelPrograms, + .timeslotHeadersInner { width: 1200vw; } } @media all and (min-width: 80em) { - - .channelPrograms, .timeslotHeadersInner { + .channelPrograms, + .timeslotHeadersInner { width: 810vw; } } @@ -112,11 +120,17 @@ .timeslotHeader { display: inline-flex; align-items: center; - text-indent: .25em; + text-indent: 0.25em; width: 2.0833333333333333333333333333333%; } -.guide-channelHeaderCell, .guide-channelTimeslotHeader { +.programCell, +.guide-channelHeaderCell { + outline: none !important; +} + +.guide-channelHeaderCell, +.guide-channelTimeslotHeader { padding: 0 !important; cursor: pointer; outline: none !important; @@ -130,11 +144,12 @@ display: flex; align-items: center; text-decoration: none; + /* Needed in firefox */ text-align: left; contain: strict; flex-shrink: 0; - border-radius: .12em; + border-radius: 0.12em; color: inherit; } @@ -148,37 +163,38 @@ background: transparent; } -.guide-channelTimeslotHeader { - border: 0 !important; -} - /* 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 { +.channelsContainer, +.guide-channelTimeslotHeader { width: 24vw; } -@media all and (min-width:31.25em) { - .channelsContainer, .guide-channelTimeslotHeader { +@media all and (min-width: 31.25em) { + .channelsContainer, + .guide-channelTimeslotHeader { width: 16vw; } } -@media all and (min-width:37.5em) { - .channelsContainer, .guide-channelTimeslotHeader { +@media all and (min-width: 37.5em) { + .channelsContainer, + .guide-channelTimeslotHeader { width: 16vw; } } -@media all and (min-width:50em) { - .channelsContainer, .guide-channelTimeslotHeader { +@media all and (min-width: 50em) { + .channelsContainer, + .guide-channelTimeslotHeader { width: 14vw; } } -@media all and (min-width:80em) { - .channelsContainer, .guide-channelTimeslotHeader { +@media all and (min-width: 80em) { + .channelsContainer, + .guide-channelTimeslotHeader { width: 12vw; } } @@ -197,34 +213,26 @@ } @media all and (max-width: 50em) { - - .newTvProgram, .liveTvProgram, .premiereTvProgram, .guideHdIcon { + .newTvProgram, + .liveTvProgram, + .premiereTvProgram, + .guideHdIcon { display: none; } } -.channelPrograms { - height: 4.42em; - contain: strict; - display: flex; - flex-direction: column; - 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 { +.channelPrograms-tv, +.guide-channelHeaderCell-tv { height: 3em; } -.guide-channelTimeslotHeader { - border-right-color: transparent; -} - -.guide-channelTimeslotHeader, .timeslotHeader { +.guide-channelTimeslotHeader, +.timeslotHeader { background: transparent !important; height: 2.8em; } @@ -253,6 +261,7 @@ text-decoration: none; overflow: hidden; align-items: center; + /* Needed for Firefox */ text-align: left; contain: strict; @@ -261,7 +270,7 @@ } .guideProgramName { - padding: 0 .7em 0; + padding: 0 0.7em 0; overflow: hidden; text-overflow: ellipsis; align-items: center; @@ -269,7 +278,8 @@ position: relative; flex-grow: 1; contain: layout style paint; - /*transition: transform 60ms ease-out;*/ + + /* transition: transform 60ms ease-out; */ } .guide-programNameCaret { @@ -289,11 +299,11 @@ .guideProgramSecondaryInfo { display: flex; align-items: center; - margin-top: .1em; + margin-top: 0.1em; } .programIcon { - margin-left: .5em; + margin-left: 0.5em; height: 1em; width: 1em; font-size: 1.6em; @@ -304,16 +314,16 @@ .guide-programTextIcon { font-weight: bold; - font-size: .9em; - padding: .16em .3em; - border-radius: .25em; - margin-right: .35em; + font-size: 0.9em; + padding: 0.16em 0.3em; + border-radius: 0.25em; + margin-right: 0.35em; width: auto; height: auto; } .guide-programTextIcon-tv { - font-size: .74em; + font-size: 0.74em; } .guideChannelNumber { @@ -345,14 +355,12 @@ } @media all and (min-width: 62.5em) { - .guideChannelName { max-width: 40%; } } @media all and (max-width: 62.5em) { - .guideChannelNumber { display: none; } @@ -368,21 +376,19 @@ flex-direction: column; } -.channelsContainer, .programGrid { +.channelsContainer, +.programGrid { contain: layout style paint; } -.programCell, .guide-channelHeaderCell { - outline: none !important; -} - -.timerIcon, .seriesTimerIcon { - color: #cc3333 !important; +.timerIcon, +.seriesTimerIcon { + color: #c33 !important; } .seriesTimerIcon-inactive { color: inherit !important; - opacity: .7; + opacity: 0.7; } .guideOptions { @@ -392,7 +398,6 @@ } @media all and (max-width: 50em), all and (max-height: 37.5em) { - .tvGuideHeader { padding-left: 0; } @@ -415,16 +420,16 @@ } .guide-date-tab-button { - padding: .3em .7em !important; - margin: 0 .3em !important; + padding: 0.3em 0.7em !important; + margin: 0 0.3em !important; 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.show-focus:focus { - border-radius: .15em !important; - transform: none !important; - } +.guide-date-tab-button.show-focus:focus { + border-radius: 0.15em !important; + transform: none !important; +} diff --git a/src/components/guide/guide.js b/src/components/guide/guide.js index c8ed31df0f..223d3a2063 100644 --- a/src/components/guide/guide.js +++ b/src/components/guide/guide.js @@ -1,4 +1,4 @@ -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) { +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-programcell', '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) { @@ -29,7 +29,6 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', var offset = newPct - left; var pctOfWidth = (offset / width) * 100; - //console.log(pctOfWidth); var guideProgramName = cell.guideProgramName; if (!guideProgramName) { guideProgramName = cell.querySelector('.guideProgramName'); @@ -228,7 +227,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', channelQuery.Limit = channelLimit; channelQuery.AddCurrentProgram = false; channelQuery.EnableUserData = false; - channelQuery.EnableImageTypes = "Primary"; + channelQuery.EnableImageTypes = 'Primary'; var categories = self.categoryOptions.categories || []; var displayMovieContent = !categories.length || categories.indexOf('movies') !== -1; @@ -262,8 +261,8 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', } if (userSettings.get('livetv-channelorder') === 'DatePlayed') { - channelQuery.SortBy = "DatePlayed"; - channelQuery.SortOrder = "Descending"; + channelQuery.SortBy = 'DatePlayed'; + channelQuery.SortOrder = 'Descending'; } else { channelQuery.SortBy = null; channelQuery.SortOrder = null; @@ -330,7 +329,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', ImageTypeLimit: 1, EnableImages: false, //EnableImageTypes: layoutManager.tv ? "Primary,Backdrop" : "Primary", - SortBy: "StartDate", + SortBy: 'StartDate', EnableTotalRecordCount: false, EnableUserData: false }; @@ -396,7 +395,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', try { program.StartDateLocal = datetime.parseISO8601Date(program.StartDate, { toLocal: true }); } catch (err) { - console.log('error parsing timestamp for start date'); + console.error('error parsing timestamp for start date'); } } @@ -404,7 +403,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', try { program.EndDateLocal = datetime.parseISO8601Date(program.EndDate, { toLocal: true }); } catch (err) { - console.log('error parsing timestamp for end date'); + console.error('error parsing timestamp for end date'); } } @@ -416,7 +415,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', var status; if (item.Type === 'SeriesTimer') { - return 'fiber_smart_record'; + return ''; } else if (item.TimerId || item.SeriesTimerId) { status = item.Status || 'Cancelled'; @@ -430,13 +429,13 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', if (item.SeriesTimerId) { if (status !== 'Cancelled') { - return 'fiber_smart_record'; + return ''; } - return 'fiber_smart_record'; + return ''; } - return 'fiber_manual_record'; + return ''; } function getChannelProgramsHtml(context, date, channel, programs, options, listInfo) { @@ -503,7 +502,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', var endPercent = (renderEndMs - renderStartMs) / msPerDay; endPercent *= 100; - var cssClass = "programCell itemAction"; + var cssClass = 'programCell itemAction'; var accentCssClass = null; var displayInnerContent = true; @@ -526,11 +525,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', } if (displayInnerContent && enableColorCodedBackgrounds && accentCssClass) { - cssClass += " programCell-" + accentCssClass; + cssClass += ' programCell-' + accentCssClass; } if (now >= startDateLocalMs && now < endDateLocalMs) { - cssClass += " programCell-active"; + cssClass += ' programCell-active'; } var timerAttributes = ''; @@ -546,11 +545,11 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', html += ''; if (displayInnerContent) { - var guideProgramNameClass = "guideProgramName"; + var guideProgramNameClass = 'guideProgramName'; html += '
'; - html += '
keyboard_arrow_left
'; + html += '
'; html += '
' + program.Name; @@ -578,7 +577,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', html += '
'; if (program.IsHD && options.showHdIcon) { - //html += 'hd'; + //html += ''; if (layoutManager.tv) { html += '
HD
'; } else { @@ -631,7 +630,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', var url = apiClient.getScaledImageUrl(channel.Id, { maxHeight: 220, tag: channel.ImageTags.Primary, - type: "Primary" + type: 'Primary' }); html += '
'; @@ -1106,7 +1105,7 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', var icon = cell.querySelector('.timerIcon'); if (!icon) { - cell.querySelector('.guideProgramName').insertAdjacentHTML('beforeend', 'fiber_manual_record'); + cell.querySelector('.guideProgramName').insertAdjacentHTML('beforeend', ''); } if (newTimerId) { @@ -1253,18 +1252,5 @@ define(['require', 'inputManager', 'browser', 'globalize', 'connectionManager', }); } - 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' - }); - return Guide; }); diff --git a/src/components/guide/programs.css b/src/components/guide/programs.css index 7a559e173f..34976e81ec 100644 --- a/src/components/guide/programs.css +++ b/src/components/guide/programs.css @@ -1,15 +1,15 @@ .newTvProgram { - background: #3388cc; + background: #38c; color: #fff; } .liveTvProgram { - background: #cc3333; + background: #c33; color: #fff; } .premiereTvProgram { - background: #EF6C00; + background: #ef6c00; color: #fff; } diff --git a/src/components/guide/tvguide.template.html b/src/components/guide/tvguide.template.html index 7edffec6d1..367aac6c17 100644 --- a/src/components/guide/tvguide.template.html +++ b/src/components/guide/tvguide.template.html @@ -9,8 +9,8 @@
-
@@ -29,10 +29,10 @@
- -
diff --git a/src/components/headroom/headroom.css b/src/components/headroom/headroom.css deleted file mode 100644 index caac40a1b6..0000000000 --- a/src/components/headroom/headroom.css +++ /dev/null @@ -1,11 +0,0 @@ -.headroom { - transition: transform 140ms linear; -} - -.headroom--pinned { - transform: none; -} - -.headroom--unpinned:not(.headroomDisabled) { - transform: translateY(-100%); -} \ No newline at end of file diff --git a/src/components/headroom/headroom.js b/src/components/headroom/headroom.js deleted file mode 100644 index 9c058a8e82..0000000000 --- a/src/components/headroom/headroom.js +++ /dev/null @@ -1,343 +0,0 @@ -/*! - * 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 = 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; - } - - /** - * 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 = false; - - this.initialClass = options.initialClass; - this.unPinnedClass = options.unPinnedClass; - this.pinnedClass = options.pinnedClass; - - this.state = 'clear'; - - this.options = { - offset: 0, - scroller: window, - initialClass: 'headroom', - unPinnedClass: 'headroom--unpinned', - pinnedClass: 'headroom--pinned' - }; - - this.add = function (elem) { - - if (browser.supportsCssAnimation()) { - elem.classList.add(this.initialClass); - elem.addEventListener('clearheadroom', onHeadroomClearedExternally.bind(this)); - this.elems.push(elem); - } - }; - - this.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); - } - }; - - this.pause = function () { - this.paused = true; - }; - - this.resume = function () { - this.paused = false; - }; - - /** - * Unattaches events and removes any classes that were added - */ - this.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 - */ - this.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 - */ - this.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(unpinnedClass); - //classList.remove(pinnedClass); - } - }; - - /** - * Unpins the header if it's currently pinned - */ - this.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); - } - }; - - /** - * Unpins the header if it's currently pinned - */ - this.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); - } - }; - - /** - * 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 - */ - this.getScrollY = function () { - - var scroller = this.scroller; - - if (scroller.getScrollPosition) { - return scroller.getScrollPosition(); - } - - var pageYOffset = scroller.pageYOffset; - if (pageYOffset !== undefined) { - return pageYOffset; - } - - var scrollTop = scroller.scrollTop; - if (scrollTop !== undefined) { - return scrollTop; - } - - return (document.documentElement || document.body).scrollTop; - }; - - /** - * determine if it is appropriate to unpin - * @param {int} currentScrollY the current y scroll position - * @return {bool} true if should unpin, false otherwise - */ - this.shouldUnpin = function (currentScrollY) { - var scrollingDown = currentScrollY > this.lastKnownScrollY; - var pastOffset = currentScrollY >= this.offset; - - return scrollingDown && pastOffset; - }; - - /** - * determine if it is appropriate to pin - * @param {int} currentScrollY the current y scroll position - * @return {bool} true if should pin, false otherwise - */ - this.shouldPin = function (currentScrollY) { - var scrollingUp = currentScrollY < this.lastKnownScrollY; - var pastOffset = currentScrollY <= this.offset; - - return scrollingUp || pastOffset; - }; - - /** - * Handles updating the state of the widget - */ - this.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; - }; - - 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(); - } - } - - function onScroll() { - - if (this.paused) { - return; - } - - requestAnimationFrame(this.rafCallback || (this.rafCallback = this.update.bind(this))); - } - - /** - * Default options - * @type {Object} - */ - Headroom.options = { - offset: 0, - scroller: window, - initialClass: 'headroom', - unPinnedClass: 'headroom--unpinned', - pinnedClass: 'headroom--pinned' - }; - - return Headroom; -}); \ No newline at end of file diff --git a/src/components/homescreensettings/homescreensettings.js b/src/components/homescreensettings/homescreensettings.js index 5b966327eb..15812647cc 100644 --- a/src/components/homescreensettings/homescreensettings.js +++ b/src/components/homescreensettings/homescreensettings.js @@ -1,5 +1,5 @@ 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"; + 'use strict'; var numConfigurableSections = 7; @@ -149,7 +149,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa currentHtml += '
'; - currentHtml += 'folder_open'; + currentHtml += ''; currentHtml += '
'; @@ -159,8 +159,8 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa currentHtml += '
'; - currentHtml += ''; - currentHtml += ''; + currentHtml += ''; + currentHtml += ''; currentHtml += '
'; @@ -276,7 +276,7 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa updateHomeSectionValues(context, userSettings); var promise1 = apiClient.getUserViews({ IncludeHidden: true }, user.Id); - var promise2 = apiClient.getJSON(apiClient.getUrl("Users/" + user.Id + "/GroupingOptions")); + var promise2 = apiClient.getJSON(apiClient.getUrl('Users/' + user.Id + '/GroupingOptions')); Promise.all([promise1, promise2]).then(function (responses) { @@ -363,17 +363,17 @@ define(['require', 'apphost', 'layoutManager', 'focusManager', 'globalize', 'loa user.Configuration.HidePlayedInLatest = context.querySelector('.chkHidePlayedFromLatest').checked; - user.Configuration.LatestItemsExcludes = getCheckboxItems(".chkIncludeInLatest", context, false).map(function (i) { + user.Configuration.LatestItemsExcludes = getCheckboxItems('.chkIncludeInLatest', context, false).map(function (i) { return i.getAttribute('data-folderid'); }); - user.Configuration.MyMediaExcludes = getCheckboxItems(".chkIncludeInMyMedia", context, false).map(function (i) { + 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) { + user.Configuration.GroupedFolders = getCheckboxItems('.chkGroupFolder', context, true).map(function (i) { return i.getAttribute('data-folderid'); }); diff --git a/src/components/homescreensettings/homescreensettings.template.html b/src/components/homescreensettings/homescreensettings.template.html index 1ed2ec1b9c..8515f3f0ad 100644 --- a/src/components/homescreensettings/homescreensettings.template.html +++ b/src/components/homescreensettings/homescreensettings.template.html @@ -10,6 +10,13 @@
${LabelPleaseRestart}
+
+ +
+
- ${HideWatchedContentFromLatestMedia} - -
-

${HeaderLibraryFolders}

@@ -129,4 +129,4 @@ - \ No newline at end of file + diff --git a/src/components/homesections/homesections.css b/src/components/homesections/homesections.css index 5df2440f82..2a119c0981 100644 --- a/src/components/homesections/homesections.css +++ b/src/components/homesections/homesections.css @@ -1,23 +1,24 @@ .homeLibraryButton { min-width: 18%; - margin: .5em !important; + margin: 0.5em !important; } @media all and (max-width: 50em) { - .homeLibraryButton { width: 46% !important; } } .homeLibraryIcon { - margin-left: .5em; - margin-right: .5em; - flex-shrink: 0 + margin-left: 0.5em; + margin-right: 0.5em; + -webkit-flex-shrink: 0; + flex-shrink: 0; } .homeLibraryText { white-space: nowrap; + -o-text-overflow: ellipsis; text-overflow: ellipsis; - overflow: hidden + overflow: hidden; } diff --git a/src/components/homesections/homesections.js b/src/components/homesections/homesections.js index 3f86e16796..3cd30893b9 100644 --- a/src/components/homesections/homesections.js +++ b/src/components/homesections/homesections.js @@ -40,26 +40,48 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la return getUserViews(apiClient, user.Id).then(function (userViews) { var html = ''; - var sectionCount = 7; - for (var i = 0; i < sectionCount; i++) { - html += '
'; - } + if (userViews.length) { + var sectionCount = 7; + for (var i = 0; i < sectionCount; i++) { + html += '
'; + } - elem.innerHTML = html; - elem.classList.add('homeSectionsContainer'); + elem.innerHTML = html; + elem.classList.add('homeSectionsContainer'); - var promises = []; - var sections = getAllSectionsToShow(userSettings, sectionCount); - for (var i = 0; i < sections.length; i++) { - promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i)); - } + var promises = []; + var sections = getAllSectionsToShow(userSettings, sectionCount); + for (var i = 0; i < sections.length; i++) { + promises.push(loadSection(elem, apiClient, user, userSettings, userViews, sections, i)); + } - return Promise.all(promises).then(function () { - return resume(elem, { - refresh: true, - returnPromise: false + return Promise.all(promises).then(function () { + return resume(elem, { + refresh: true, + returnPromise: false + }); }); - }); + } else { + var noLibDescription; + if (user['Policy'] && user['Policy']['IsAdministrator']) { + noLibDescription = globalize.translate('NoCreatedLibraries', '
', ''); + } else { + noLibDescription = globalize.translate('AskAdminToCreateLibrary'); + } + + html += '
'; + html += '

' + globalize.translate('MessageNothingHere') + '

'; + html += '

' + noLibDescription + '

'; + html += '
'; + elem.innerHTML = html; + + var createNowLink = elem.querySelector('#button-createLibrary'); + if (createNowLink) { + createNowLink.addEventListener('click', function () { + Dashboard.navigate('library.html'); + }); + } + } }); } @@ -109,7 +131,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la } else if (section === 'librarytiles' || section === 'smalllibrarytiles' || section === 'smalllibrarytiles-automobile' || section === 'librarytiles-automobile') { loadLibraryTiles(elem, apiClient, user, userSettings, 'smallBackdrop', userViews, allSections); } else if (section === 'librarybuttons') { - loadlibraryButtons(elem, apiClient, user, userSettings, userViews, allSections); + loadlibraryButtons(elem, apiClient, user, userSettings, userViews); } else if (section === 'resume') { loadResumeVideo(elem, apiClient, userId); } else if (section === 'resumeaudio') { @@ -150,7 +172,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la } function getLibraryButtonsHtml(items) { - var html = ""; + var html = ''; html += '
'; html += '

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

'; @@ -161,7 +183,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la for (var i = 0, length = items.length; i < length; i++) { var item = items[i]; var icon = imageHelper.getLibraryIcon(item.CollectionType); - html += '' + icon + '' + item.Name + ''; + html += '' + item.Name + ''; } html += '
'; @@ -207,9 +229,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la var options = { Limit: limit, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', ParentId: parentId }; @@ -221,9 +243,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la return function (items) { var cardLayout = false; var shape; - if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books') { + if (itemType === 'Channel' || viewType === 'movies' || viewType === 'books' || viewType === 'tvshows') { shape = getPortraitShape(); - } else if (viewType === 'music') { + } else if (viewType === 'music' || viewType === 'homevideos') { shape = getSquareShape(); } else { shape = getThumbShape(); @@ -260,7 +282,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '

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

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

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

'; @@ -268,7 +290,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '
'; if (enableScrollX()) { - html += '
'; + html += '
'; html += '
'; } else { html += '
'; @@ -321,7 +343,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la if (userViews.length) { html += '

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

'; if (enableScrollX()) { - html += '
'; + html += '
'; html += '
'; } else { html += '
'; @@ -364,9 +386,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la var options = { Limit: limit, Recursive: true, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', EnableTotalRecordCount: false, MediaTypes: 'Video' }; @@ -401,7 +423,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '

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

'; if (enableScrollX()) { - html += '
'; + html += '
'; html += '
'; } else { html += '
'; @@ -437,9 +459,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la var options = { Limit: limit, Recursive: true, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', EnableTotalRecordCount: false, MediaTypes: 'Audio' }; @@ -474,7 +496,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '

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

'; if (enableScrollX()) { - html += '
'; + html += '
'; html += '
'; } else { html += '
'; @@ -502,9 +524,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la IsAiring: true, limit: 24, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Thumb,Backdrop", + EnableImageTypes: 'Primary,Thumb,Backdrop', EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio" + Fields: 'ChannelInfo,PrimaryImageAspectRatio' }); }; } @@ -543,9 +565,9 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la IsAiring: true, limit: 1, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Thumb,Backdrop", + EnableImageTypes: 'Primary,Thumb,Backdrop', EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio" + Fields: 'ChannelInfo,PrimaryImageAspectRatio' }).then(function (result) { var html = ''; if (result.Items.length) { @@ -560,7 +582,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '
'; if (enableScrollX()) { - html += '
'; + html += '
'; html += '
'; } else { html += '
'; @@ -608,7 +630,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '

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

'; - html += 'chevron_right'; + html += ''; html += ''; } else { @@ -617,8 +639,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '
'; if (enableScrollX()) { - html += '
'; - html += '
' + html += '
'; + html += '
'; } else { html += '
'; } @@ -645,10 +667,10 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la var apiClient = connectionManager.getApiClient(serverId); return apiClient.getNextUpEpisodes({ Limit: enableScrollX() ? 24 : 15, - Fields: "PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo', UserId: apiClient.getCurrentUserId(), ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }); }; @@ -683,7 +705,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '

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

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

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

'; @@ -691,8 +713,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '
'; if (enableScrollX()) { - html += '
'; - html += '
' + html += '
'; + html += '
'; } else { html += '
'; } @@ -717,7 +739,7 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la return apiClient.getLiveTvRecordings({ userId: apiClient.getCurrentUserId(), Limit: enableScrollX() ? 12 : 5, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', EnableTotalRecordCount: false, IsLibraryItem: activeRecordingsOnly ? null : false, IsInProgress: activeRecordingsOnly ? true : null @@ -763,8 +785,8 @@ define(['connectionManager', 'cardBuilder', 'appSettings', 'dom', 'apphost', 'la html += '
'; if (enableScrollX()) { - html += '
'; - html += '
' + html += '
'; + html += '
'; } else { html += '
'; } diff --git a/src/components/htmlMediaHelper.js b/src/components/htmlMediaHelper.js index 86f05dabfa..3f17eeb336 100644 --- a/src/components/htmlMediaHelper.js +++ b/src/components/htmlMediaHelper.js @@ -2,12 +2,12 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve 'use strict'; function getSavedVolume() { - return appSettings.get("volume") || 1; + return appSettings.get('volume') || 1; } function saveVolume(value) { if (value) { - appSettings.set("volume", value); + appSettings.set('volume', value); } } @@ -31,7 +31,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve } function enableHlsShakaPlayer(item, mediaSource, mediaType) { - + /* eslint-disable-next-line compat/compat */ if (!!window.MediaSource && !!MediaSource.isTypeSupported) { if (canPlayNativeHls()) { @@ -109,17 +109,17 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve var now = Date.now(); if (window.performance && window.performance.now) { - now = performance.now(); + now = performance.now(); // eslint-disable-line compat/compat } if (!recoverDecodingErrorDate || (now - recoverDecodingErrorDate) > 3000) { recoverDecodingErrorDate = now; - console.log('try to recover media Error ...'); + console.debug('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 ...'); + console.debug('try to swap Audio Codec and recover media Error ...'); hlsPlayer.swapAudioCodec(); hlsPlayer.recoverMediaError(); } else { @@ -162,7 +162,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve } } - function seekOnPlaybackStart(instance, element, ticks) { + function seekOnPlaybackStart(instance, element, ticks, onMediaReady) { var seconds = (ticks || 0) / 10000000; @@ -171,13 +171,31 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve // 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 { + + if (element.duration >= seconds) { + // media is ready, seek immediately setCurrentTimeIfNeeded(element, seconds); + if (onMediaReady) onMediaReady(); + } else { + // update video player position when media is ready to be sought + var events = ['durationchange', 'loadeddata', 'play', 'loadedmetadata']; + var onMediaChange = function(e) { + if (element.currentTime === 0 && element.duration >= seconds) { + // seek only when video position is exactly zero, + // as this is true only if video hasn't started yet or + // user rewound to the very beginning + // (but rewinding cannot happen as the first event with media of non-empty duration) + console.debug(`seeking to ${seconds} on ${e.type} event`); + setCurrentTimeIfNeeded(element, seconds); + events.map(function(name) { + element.removeEventListener(name, onMediaChange); + }); + if (onMediaReady) onMediaReady(); + } + }; + events.map(function (name) { + return element.addEventListener(name, onMediaChange); + }); } } } @@ -233,7 +251,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve return Promise.resolve(); } } catch (err) { - console.log('error calling video.play: ' + err); + console.error('error calling video.play: ' + err); return Promise.reject(); } } @@ -245,7 +263,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve try { player.unload(); } catch (err) { - console.log(err); + console.error(err); } instance._castPlayer = null; @@ -258,7 +276,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve try { player.destroy(); } catch (err) { - console.log(err); + console.error(err); } instance._shakaPlayer = null; @@ -271,7 +289,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve try { player.destroy(); } catch (err) { - console.log(err); + console.error(err); } instance._hlsPlayer = null; @@ -286,7 +304,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve player.detachMediaElement(); player.destroy(); } catch (err) { - console.log(err); + console.error(err); } instance._flvPlayer = null; @@ -307,14 +325,14 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve hls.on(Hls.Events.ERROR, function (event, data) { - console.log('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false)); + console.error('HLS Error: Type: ' + data.type + ' Details: ' + (data.details || '') + ' Fatal: ' + (data.fatal || false)); switch (data.type) { case Hls.ErrorTypes.NETWORK_ERROR: // 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); + console.debug('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(); @@ -343,7 +361,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve // This could be a CORS error related to access control response headers - console.log('hls.js response error code: ' + data.response.code); + console.debug('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(); @@ -355,20 +373,20 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve onErrorInternal(instance, 'network'); } } else { - console.log("fatal network error encountered, try to recover"); + console.debug('fatal network error encountered, try to recover'); hls.startLoad(); } break; case Hls.ErrorTypes.MEDIA_ERROR: - console.log("fatal media error encountered, try to recover"); + console.debug('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'); + console.debug('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(); @@ -391,7 +409,7 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve elem.src = ''; elem.innerHTML = ''; - elem.removeAttribute("src"); + elem.removeAttribute('src'); destroyHlsPlayer(instance); destroyFlvPlayer(instance); @@ -463,4 +481,4 @@ define(['appSettings', 'browser', 'events'], function (appSettings, browser, eve getCrossOriginValue: getCrossOriginValue, getBufferedRanges: getBufferedRanges }; -}); \ No newline at end of file +}); diff --git a/src/components/htmlaudioplayer/plugin.js b/src/components/htmlaudioplayer/plugin.js index ef64bad046..c3a5484aca 100644 --- a/src/components/htmlaudioplayer/plugin.js +++ b/src/components/htmlaudioplayer/plugin.js @@ -1,5 +1,5 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelper'], function (events, browser, require, appHost, appSettings, htmlMediaHelper) { - "use strict"; + 'use strict'; function getDefaultProfile() { return new Promise(function (resolve, reject) { @@ -16,7 +16,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp // 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); + console.debug('fading volume to ' + newVolume); elem.volume = newVolume; if (newVolume <= 0) { @@ -101,7 +101,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp self._timeUpdated = false; self._currentTime = null; - var elem = createMediaElement(options); + var elem = createMediaElement(); return setCurrentSrc(elem, options); }; @@ -113,7 +113,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp bindEvents(elem); var val = options.url; - console.log('playing url: ' + val); + console.debug('playing url: ' + val); // Convert to seconds var seconds = (options.playerStartPositionTicks || 0) / 10000000; @@ -298,7 +298,7 @@ define(['events', 'browser', 'require', 'apphost', 'appSettings', 'htmlMediaHelp var errorCode = this.error ? (this.error.code || 0) : 0; var errorMessage = this.error ? (this.error.message || '') : ''; - console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage); + console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage); var type; diff --git a/src/components/htmlvideoplayer/plugin.js b/src/components/htmlvideoplayer/plugin.js index e52ac0ec7e..87bfb29ad8 100644 --- a/src/components/htmlvideoplayer/plugin.js +++ b/src/components/htmlvideoplayer/plugin.js @@ -1,5 +1,6 @@ -define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'fullscreenManager'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, fullscreenManager) { - "use strict"; +define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager', 'htmlMediaHelper', 'itemHelper', 'screenfull', 'globalize'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager, htmlMediaHelper, itemHelper, screenfull, globalize) { + 'use strict'; + /* globals cast */ var mediaManager; @@ -11,7 +12,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa try { parentNode.removeChild(elem); } catch (err) { - console.log('Error removing dialog element: ' + err); + console.error('error removing dialog element: ' + err); } } } @@ -79,7 +80,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if (track) { var format = (track.Codec || '').toLowerCase(); if (format === 'ssa' || format === 'ass') { - // libjass is needed here return false; } } @@ -95,23 +95,19 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } function getMediaStreamAudioTracks(mediaSource) { - return mediaSource.MediaStreams.filter(function (s) { return s.Type === 'Audio'; }); } function getMediaStreamTextTracks(mediaSource) { - return mediaSource.MediaStreams.filter(function (s) { return s.Type === 'Subtitle'; }); } function zoomIn(elem) { - 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, { @@ -120,8 +116,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa }); } - function normalizeTrackEventText(text) { - return text.replace(/\\N/gi, '\n'); + function normalizeTrackEventText(text, useHtml) { + var result = text.replace(/\\N/gi, '\n').replace(/\r/gi, ''); + return useHtml ? result.replace(/\n/gi, '
') : result; } function setTracks(elem, tracks, item, mediaSource) { @@ -215,7 +212,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa function incrementFetchQueue() { if (self._fetchQueue <= 0) { self.isFetching = true; - events.trigger(self, "beginFetch"); + events.trigger(self, 'beginFetch'); } self._fetchQueue++; @@ -226,7 +223,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if (self._fetchQueue <= 0) { self.isFetching = false; - events.trigger(self, "endFetch"); + events.trigger(self, 'endFetch'); } } @@ -246,7 +243,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa loading.show(); - console.log('prefetching hls playlist: ' + hlsPlaylistUrl); + console.debug('prefetching hls playlist: ' + hlsPlaylistUrl); return connectionManager.getApiClient(item.ServerId).ajax({ @@ -255,7 +252,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa }).then(function () { - console.log('completed prefetching hls playlist: ' + hlsPlaylistUrl); + console.debug('completed prefetching hls playlist: ' + hlsPlaylistUrl); loading.hide(); streamInfo.url = hlsPlaylistUrl; @@ -264,7 +261,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa }, function () { - console.log('error prefetching hls playlist: ' + hlsPlaylistUrl); + console.error('error prefetching hls playlist: ' + hlsPlaylistUrl); loading.hide(); return Promise.resolve(); @@ -293,7 +290,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa return createMediaElement(options).then(function (elem) { - return updateVideoUrl(options, options.mediaSource).then(function () { + return updateVideoUrl(options).then(function () { return setCurrentSrc(elem, options); }); }); @@ -361,6 +358,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa return new Promise(function (resolve, reject) { require(['shaka'], function () { + /* globals shaka */ var player = new shaka.Player(elem); @@ -412,7 +410,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa lrd.media.streamType = cast.receiver.media.StreamType.OTHER; lrd.media.customData = options; - console.log('loading media url into mediaManager'); + console.debug('loading media url into media manager'); try { mediaManager.load(lrd); @@ -422,7 +420,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa return Promise.resolve(); } catch (err) { - console.log('mediaManager error: ' + err); + console.debug('media manager error: ' + err); return Promise.reject(); } } @@ -464,11 +462,11 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa protocol = cast.player.api.CreateSmoothStreamingProtocol(host); } - console.log('loading playback url: ' + url); - console.log('contentType: ' + contentType); + console.debug('loading playback url: ' + url); + console.debug('content type: ' + contentType); host.onError = function (errorCode) { - console.log("Fatal Error - " + errorCode); + console.error('fatal Error - ' + errorCode); }; mediaElement.autoplay = false; @@ -503,7 +501,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa elem.removeEventListener('error', onError); var val = options.url; - console.log('playing url: ' + val); + console.debug('playing url: ' + val); // Convert to seconds var seconds = (options.playerStartPositionTicks || 0) / 10000000; @@ -570,19 +568,19 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa self.resetSubtitleOffset = function() { currentTrackOffset = 0; showTrackOffset = false; - } + }; self.enableShowingSubtitleOffset = function() { showTrackOffset = true; - } + }; self.disableShowingSubtitleOffset = function() { showTrackOffset = false; - } + }; self.isShowingSubtitleOffsetEnabled = function() { return showTrackOffset; - } + }; function getTextTrack() { var videoElement = self._mediaElement; @@ -602,8 +600,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var offsetValue = parseFloat(offset); // if .ass currently rendering - if (currentAssRenderer) { + if (currentSubtitlesOctopus) { updateCurrentTrackOffset(offsetValue); + currentSubtitlesOctopus.timeOffset = (self._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + offsetValue; } else { var trackElement = getTextTrack(); // if .vtt currently rendering @@ -612,7 +611,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } else if (currentTrackEvents) { setTrackEventsSubtitleOffset(currentTrackEvents, offsetValue); } else { - console.log("No available track, cannot apply offset: ", offsetValue); + console.debug('No available track, cannot apply offset: ', offsetValue); } } }; @@ -654,7 +653,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa self.getSubtitleOffset = function() { return currentTrackOffset; - } + }; function isAudioStreamSupported(stream, deviceProfile) { @@ -731,22 +730,18 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa // https://msdn.microsoft.com/en-us/library/hh772507(v=vs.85).aspx var elemAudioTracks = elem.audioTracks || []; - console.log('found ' + elemAudioTracks.length + ' audio tracks'); + console.debug('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'); + console.debug('setting audio track ' + i + ' to enabled'); elemAudioTracks[i].enabled = true; } else { - console.log('setting audio track ' + i + ' to disabled'); + console.debug('setting audio track ' + i + ' to disabled'); elemAudioTracks[i].enabled = false; } } - - setTimeout(function () { - elem.currentTime = elem.currentTime; - }, 100); }; self.stop = function (destroyPlayer) { @@ -800,7 +795,9 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa dlg.parentNode.removeChild(dlg); } - fullscreenManager.exitFullscreen(); + if (screenfull.isEnabled) { + screenfull.exit(); + } }; function onEnded() { @@ -862,7 +859,13 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa loading.hide(); - htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks); + htmlMediaHelper.seekOnPlaybackStart(self, e.target, self._currentPlayOptions.playerStartPositionTicks, function () { + if (currentSubtitlesOctopus) { + currentSubtitlesOctopus.timeOffset = (self._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000 + currentTrackOffset; + currentSubtitlesOctopus.resize(); + currentSubtitlesOctopus.resetRenderAheadCache(false); + } + }); if (self._currentPlayOptions.fullscreen) { @@ -915,7 +918,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa function onError() { var errorCode = this.error ? (this.error.code || 0) : 0; var errorMessage = this.error ? (this.error.message || '') : ''; - console.log('Media element error: ' + errorCode.toString() + ' ' + errorMessage); + console.error('media element error: ' + errorCode.toString() + ' ' + errorMessage); var type; @@ -1026,7 +1029,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa xhr.onerror = function (e) { reject(e); decrementFetchQueue(); - } + }; xhr.send(); }); @@ -1053,97 +1056,39 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa lastCustomTrackMs = 0; } - function renderWithSubtitlesOctopus(videoElement, track, item) { + function renderSsaAss(videoElement, track, item) { var attachments = self._currentPlayOptions.mediaSource.MediaAttachments || []; + var apiClient = connectionManager.getApiClient(item); var options = { video: videoElement, subUrl: getTextTrackUrl(track, item), - fonts: attachments.map(i => i.DeliveryUrl), - workerUrl: appRouter.baseUrl() + "/libraries/subtitles-octopus-worker.js", + fonts: attachments.map(function (i) { + return apiClient.getUrl(i.DeliveryUrl); + }), + workerUrl: appRouter.baseUrl() + '/libraries/subtitles-octopus-worker.js', + legacyWorkerUrl: appRouter.baseUrl() + '/libraries/subtitles-octopus-worker-legacy.js', onError: function() { - htmlMediaHelper.onErrorInternal(self, 'mediadecodeerror') - } + htmlMediaHelper.onErrorInternal(self, 'mediadecodeerror'); + }, + timeOffset: (self._currentPlayOptions.transcodingOffsetTicks || 0) / 10000000, + + // new octopus options; override all, even defaults + renderMode: 'blend', + dropAllAnimations: false, + libassMemoryLimit: 40, + libassGlyphLimit: 40, + targetFps: 24, + prescaleTradeoff: 0.8, + softHeightLimit: 1080, + hardHeightLimit: 2160, + resizeVariation: 0.2, + renderAhead: 90 }; require(['JavascriptSubtitlesOctopus'], function(SubtitlesOctopus) { currentSubtitlesOctopus = new SubtitlesOctopus(options); }); } - function renderWithLibjass(videoElement, track, item) { - - var rendererSettings = {}; - - 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 () { - try { - 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 renderSsaAss(videoElement, track, item) { - if (supportsCanvas() && supportsWebWorkers()) { - renderWithSubtitlesOctopus(videoElement, track, item); - } else { - console.log('rendering subtitles with libjass'); - renderWithLibjass(videoElement, track, item); - } - } - - function onVideoResize() { - if (browser.iOS) { - // the new sizes will be delayed for about 500ms with wkwebview - setTimeout(resetVideoRendererSize, 500); - } else { - resetVideoRendererSize(); - } - } - - function resetVideoRendererSize() { - var renderer = currentAssRenderer; - if (renderer) { - 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() { // after a system update, ps4 isn't showing anything when creating a track element dynamically @@ -1233,7 +1178,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if (!itemHelper.isLocalItem(item) || track.IsExternal) { var format = (track.Codec || '').toLowerCase(); if (format === 'ssa' || format === 'ass') { - // libjass is needed here renderSsaAss(videoElement, track, item); return; } @@ -1256,7 +1200,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa trackElement.removeCue(trackElement.cues[0]); } } catch (e) { - console.log('Error removing cue from textTrack'); + console.error('error removing cue from textTrack'); } trackElement.mode = 'disabled'; @@ -1270,13 +1214,13 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa fetchSubtitles(track, item).then(function (data) { // show in ui - console.log('downloaded ' + data.TrackEvents.length + ' track events'); + console.debug('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)); + var cue = new trackCueObject(trackEvent.StartPositionTicks / 10000000, trackEvent.EndPositionTicks / 10000000, normalizeTrackEventText(trackEvent.Text, false)); trackElement.addCue(cue); }); @@ -1286,17 +1230,12 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa function updateSubtitleText(timeMs) { - // handle offset for ass tracks - if (currentTrackOffset) { - timeMs += (currentTrackOffset * 1000); - } - var clock = currentClock; if (clock) { try { clock.seek(timeMs / 1000); } catch (err) { - console.log('Error in libjass: ' + err); + console.error('error in libjass: ' + err); } return; } @@ -1317,8 +1256,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } if (selectedTrackEvent && selectedTrackEvent.Text) { - - subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text); + subtitleTextElement.innerHTML = normalizeTrackEventText(selectedTrackEvent.Text, true); subtitleTextElement.classList.remove('hide'); } else { @@ -1329,7 +1267,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa function setCurrentTrackElement(streamIndex) { - console.log('Setting new text track index to: ' + streamIndex); + console.debug('setting new text track index to: ' + streamIndex); var mediaStreamTextTracks = getMediaStreamTextTracks(self._currentPlayOptions.mediaSource); @@ -1350,38 +1288,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa } } - 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) { if (browser.tv || browser.iOS || browser.mobile) { @@ -1405,7 +1311,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa dlg.classList.add('videoPlayerContainer'); if (options.backdropUrl) { - dlg.classList.add('videoPlayerContainer-withBackdrop'); dlg.style.backgroundImage = "url('" + options.backdropUrl + "')"; } @@ -1414,11 +1319,7 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa dlg.classList.add('videoPlayerContainer-onTop'); } - // playsinline new for iOS 10 - // https://developer.apple.com/library/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html - var html = ''; - var cssClass = 'htmlvideoplayer'; if (!browser.chromecast) { @@ -1429,7 +1330,6 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa if (!appHost.supports('htmlvideoautoplay')) { html += '
"; - html += '
' + globalize.translate("LabelMetadataReadersHelp") + "
"; + html += '
'; + html += '
' + globalize.translate('LabelMetadataReadersHelp') + '
'; if (plugins.length < 2) { - elem.classList.add("hide"); + elem.classList.add('hide'); } else { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } elem.innerHTML = html; return true; } function renderMetadataSavers(page, metadataSavers) { - var html = ""; - var elem = page.querySelector(".metadataSavers"); - if (!metadataSavers.length) return elem.innerHTML = "", elem.classList.add("hide"), false; - html += '

' + globalize.translate("LabelMetadataSavers") + "

"; + var html = ''; + var elem = page.querySelector('.metadataSavers'); + if (!metadataSavers.length) return elem.innerHTML = '', elem.classList.add('hide'), false; + html += '

' + globalize.translate('LabelMetadataSavers') + '

'; html += '
'; for (var i = 0; i < metadataSavers.length; i++) { var plugin = metadataSavers[i]; - html += '"; + html += ''; } - html += "
"; - html += '
' + globalize.translate("LabelMetadataSaversHelp") + "
"; + html += '
'; + html += '
' + globalize.translate('LabelMetadataSaversHelp') + '
'; elem.innerHTML = html; - elem.classList.remove("hide"); + elem.classList.remove('hide'); return true; } function getMetadataFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) { - var html = ""; + var html = ''; var plugins = availableTypeOptions.MetadataFetchers; plugins = getOrderedPlugins(plugins, libraryOptionsForType.MetadataFetcherOrder || []); if (!plugins.length) return html; html += '
'; - html += '

' + globalize.translate("LabelTypeMetadataDownloaders", availableTypeOptions.Type) + "

"; + html += '

' + globalize.translate('LabelTypeMetadataDownloaders', globalize.translate(availableTypeOptions.Type)) + '

'; html += '
'; - for (var i = 0; i < plugins.length; i++) { - var plugin = plugins[i]; + + plugins.forEach((plugin, index) => { html += '
'; var isChecked = libraryOptionsForType.MetadataFetchers ? -1 !== libraryOptionsForType.MetadataFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled; - var checkedHtml = isChecked ? ' checked="checked"' : ""; - html += '"; + var checkedHtml = isChecked ? ' checked="checked"' : ''; + html += ''; html += '
'; html += '

'; html += plugin.Name; - html += "

"; - html += "
"; - i > 0 ? html += '' : plugins.length > 1 && (html += ''), html += "
" - } - html += "
"; - html += '
' + globalize.translate("LabelMetadataDownloadersHelp") + "
"; - html += "
"; + html += ''; + html += '
'; + index > 0 ? html += '' : plugins.length > 1 && (html += ''), html += '
'; + }); + + html += '
'; + html += '
' + globalize.translate('LabelMetadataDownloadersHelp') + '
'; + html += '
'; return html; } @@ -138,62 +139,62 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct } function renderMetadataFetchers(page, availableOptions, libraryOptions) { - var html = ""; - var elem = page.querySelector(".metadataFetchers"); + var html = ''; + var elem = page.querySelector('.metadataFetchers'); for (var i = 0; i < availableOptions.TypeOptions.length; i++) { var availableTypeOptions = availableOptions.TypeOptions[i]; html += getMetadataFetchersForTypeHtml(availableTypeOptions, getTypeOptions(libraryOptions, availableTypeOptions.Type) || {}); } elem.innerHTML = html; if (html) { - elem.classList.remove("hide"); - page.querySelector(".fldAutoRefreshInterval").classList.remove("hide"); - page.querySelector(".fldMetadataLanguage").classList.remove("hide"); - page.querySelector(".fldMetadataCountry").classList.remove("hide"); + elem.classList.remove('hide'); + page.querySelector('.fldAutoRefreshInterval').classList.remove('hide'); + page.querySelector('.fldMetadataLanguage').classList.remove('hide'); + page.querySelector('.fldMetadataCountry').classList.remove('hide'); } else { - elem.classList.add("hide"); - page.querySelector(".fldAutoRefreshInterval").classList.add("hide"); - page.querySelector(".fldMetadataLanguage").classList.add("hide"); - page.querySelector(".fldMetadataCountry").classList.add("hide"); + elem.classList.add('hide'); + page.querySelector('.fldAutoRefreshInterval').classList.add('hide'); + page.querySelector('.fldMetadataLanguage').classList.add('hide'); + page.querySelector('.fldMetadataCountry').classList.add('hide'); } return true; } function renderSubtitleFetchers(page, availableOptions, libraryOptions) { - var html = ""; - var elem = page.querySelector(".subtitleFetchers"); + var html = ''; + var elem = page.querySelector('.subtitleFetchers'); var plugins = availableOptions.SubtitleFetchers; plugins = getOrderedPlugins(plugins, libraryOptions.SubtitleFetcherOrder || []); if (!plugins.length) return html; - html += '

' + globalize.translate("LabelSubtitleDownloaders") + "

"; + html += '

' + globalize.translate('LabelSubtitleDownloaders') + '

'; html += '
'; for (var i = 0; i < plugins.length; i++) { var plugin = plugins[i]; html += '
'; var isChecked = libraryOptions.DisabledSubtitleFetchers ? -1 === libraryOptions.DisabledSubtitleFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled; - var checkedHtml = isChecked ? ' checked="checked"' : ""; - html += '"; + var checkedHtml = isChecked ? ' checked="checked"' : ''; + html += ''; html += '
'; html += '

'; html += plugin.Name; - html += "

"; - html += "
"; + html += ''; + html += '
'; if (i > 0) { - html += ''; + html += ''; } else if (plugins.length > 1) { - html += ''; + html += ''; } - html += "
"; + html += '
'; } - html += "
"; - html += '
' + globalize.translate("SubtitleDownloadersHelp") + "
"; + html += '
'; + html += '
' + globalize.translate('SubtitleDownloadersHelp') + '
'; elem.innerHTML = html; } function getImageFetchersForTypeHtml(availableTypeOptions, libraryOptionsForType) { - var html = ""; + var html = ''; var plugins = availableTypeOptions.ImageFetchers; plugins = getOrderedPlugins(plugins, libraryOptionsForType.ImageFetcherOrder || []); @@ -201,60 +202,60 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct html += '
'; html += '
'; - html += '

' + globalize.translate("HeaderTypeImageFetchers", availableTypeOptions.Type) + "

"; + html += '

' + globalize.translate('HeaderTypeImageFetchers', availableTypeOptions.Type) + '

'; var supportedImageTypes = availableTypeOptions.SupportedImageTypes || []; - if (supportedImageTypes.length > 1 || 1 === supportedImageTypes.length && "Primary" !== supportedImageTypes[0]) { - html += '"; + if (supportedImageTypes.length > 1 || 1 === supportedImageTypes.length && 'Primary' !== supportedImageTypes[0]) { + html += ''; } - html += "
"; + html += '
'; html += '
'; for (var i = 0; i < plugins.length; i++) { var plugin = plugins[i]; html += '
'; var isChecked = libraryOptionsForType.ImageFetchers ? -1 !== libraryOptionsForType.ImageFetchers.indexOf(plugin.Name) : plugin.DefaultEnabled; - var checkedHtml = isChecked ? ' checked="checked"' : ""; - html += '"; + var checkedHtml = isChecked ? ' checked="checked"' : ''; + html += ''; html += '
'; html += '

'; html += plugin.Name; - html += "

"; - html += "
"; + html += ''; + html += '
'; if (i > 0) { - html += ''; + html += ''; } else if (plugins.length > 1) { - html += ''; + html += ''; } - html += "
"; + html += '
'; } - html += "
"; - html += '
' + globalize.translate("LabelImageFetchersHelp") + "
"; - html += "
"; + html += '
'; + html += '
' + globalize.translate('LabelImageFetchersHelp') + '
'; + html += '
'; return html; } function renderImageFetchers(page, availableOptions, libraryOptions) { - var html = ""; - var elem = page.querySelector(".imageFetchers"); + var html = ''; + var elem = page.querySelector('.imageFetchers'); for (var i = 0; i < availableOptions.TypeOptions.length; i++) { var availableTypeOptions = availableOptions.TypeOptions[i]; html += getImageFetchersForTypeHtml(availableTypeOptions, getTypeOptions(libraryOptions, availableTypeOptions.Type) || {}); } elem.innerHTML = html; if (html) { - elem.classList.remove("hide"); - page.querySelector(".chkDownloadImagesInAdvanceContainer").classList.remove("hide"); - page.querySelector(".chkSaveLocalContainer").classList.remove("hide"); + elem.classList.remove('hide'); + page.querySelector('.chkDownloadImagesInAdvanceContainer').classList.remove('hide'); + page.querySelector('.chkSaveLocalContainer').classList.remove('hide'); } else { - elem.classList.add("hide"); - page.querySelector(".chkDownloadImagesInAdvanceContainer").classList.add("hide"); - page.querySelector(".chkSaveLocalContainer").classList.add("hide"); + elem.classList.add('hide'); + page.querySelector('.chkDownloadImagesInAdvanceContainer').classList.add('hide'); + page.querySelector('.chkSaveLocalContainer').classList.add('hide'); } return true; } function populateMetadataSettings(parent, contentType, isNewLibrary) { - var isNewLibrary = parent.classList.contains("newlibrary"); - return ApiClient.getJSON(ApiClient.getUrl("Libraries/AvailableOptions", { + var isNewLibrary = parent.classList.contains('newlibrary'); + return ApiClient.getJSON(ApiClient.getUrl('Libraries/AvailableOptions', { LibraryContentType: contentType, IsNewLibrary: isNewLibrary })).then(function(availableOptions) { @@ -265,65 +266,80 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct renderMetadataFetchers(parent, availableOptions, {}); renderSubtitleFetchers(parent, availableOptions, {}); renderImageFetchers(parent, availableOptions, {}); - availableOptions.SubtitleFetchers.length ? parent.querySelector(".subtitleDownloadSettings").classList.remove("hide") : parent.querySelector(".subtitleDownloadSettings").classList.add("hide") + availableOptions.SubtitleFetchers.length ? parent.querySelector('.subtitleDownloadSettings').classList.remove('hide') : parent.querySelector('.subtitleDownloadSettings').classList.add('hide'); }).catch(function() { return Promise.resolve(); - }) + }); } function adjustSortableListElement(elem) { - var btnSortable = elem.querySelector(".btnSortable"); + var btnSortable = elem.querySelector('.btnSortable'); + var inner = btnSortable.querySelector('.material-icons'); if (elem.previousSibling) { - btnSortable.classList.add("btnSortableMoveUp"); - btnSortable.classList.remove("btnSortableMoveDown"); - btnSortable.querySelector("i").innerHTML = "keyboard_arrow_up"; + btnSortable.title = globalize.translate('ButtonUp'); + btnSortable.classList.add('btnSortableMoveUp'); + btnSortable.classList.remove('btnSortableMoveDown'); + inner.classList.remove('keyboard_arrow_down'); + inner.classList.add('keyboard_arrow_up'); } else { - btnSortable.classList.remove("btnSortableMoveUp"); - btnSortable.classList.add("btnSortableMoveDown"); - btnSortable.querySelector("i").innerHTML = "keyboard_arrow_down"; + btnSortable.title = globalize.translate('ButtonDown'); + btnSortable.classList.remove('btnSortableMoveUp'); + btnSortable.classList.add('btnSortableMoveDown'); + inner.classList.remove('keyboard_arrow_up'); + inner.classList.add('keyboard_arrow_down'); } } function showImageOptionsForType(type) { - require(["imageoptionseditor"], function(ImageOptionsEditor) { + require(['imageoptionseditor'], function(ImageOptionsEditor) { var typeOptions = getTypeOptions(currentLibraryOptions, type); - typeOptions || (typeOptions = { - Type: type - }, currentLibraryOptions.TypeOptions.push(typeOptions)); + if (!typeOptions) { + typeOptions = { + Type: type + }; + currentLibraryOptions.TypeOptions.push(typeOptions); + } var availableOptions = getTypeOptions(currentAvailableOptions || {}, type); - (new ImageOptionsEditor).show(type, typeOptions, availableOptions) - }) + var imageOptionsEditor = new ImageOptionsEditor(); + imageOptionsEditor.show(type, typeOptions, availableOptions); + }); } function onImageFetchersContainerClick(e) { - var btnImageOptionsForType = dom.parentWithClass(e.target, "btnImageOptionsForType"); + var btnImageOptionsForType = dom.parentWithClass(e.target, 'btnImageOptionsForType'); if (btnImageOptionsForType) { - return void showImageOptionsForType(dom.parentWithClass(btnImageOptionsForType, "imageFetcher").getAttribute("data-type")); + return void showImageOptionsForType(dom.parentWithClass(btnImageOptionsForType, 'imageFetcher').getAttribute('data-type')); } onSortableContainerClick.call(this, e); } function onSortableContainerClick(e) { - var btnSortable = dom.parentWithClass(e.target, "btnSortable"); + var btnSortable = dom.parentWithClass(e.target, 'btnSortable'); if (btnSortable) { - var li = dom.parentWithClass(btnSortable, "sortableOption"); - var list = dom.parentWithClass(li, "paperList"); - if (btnSortable.classList.contains("btnSortableMoveDown")) { + var li = dom.parentWithClass(btnSortable, 'sortableOption'); + var list = dom.parentWithClass(li, 'paperList'); + if (btnSortable.classList.contains('btnSortableMoveDown')) { var next = li.nextSibling; - next && (li.parentNode.removeChild(li), next.parentNode.insertBefore(li, next.nextSibling)) + if (next) { + li.parentNode.removeChild(li); + next.parentNode.insertBefore(li, next.nextSibling); + } } else { var prev = li.previousSibling; - prev && (li.parentNode.removeChild(li), prev.parentNode.insertBefore(li, prev)) + if (prev) { + li.parentNode.removeChild(li); + prev.parentNode.insertBefore(li, prev); + } } - Array.prototype.forEach.call(list.querySelectorAll(".sortableOption"), adjustSortableListElement) + Array.prototype.forEach.call(list.querySelectorAll('.sortableOption'), adjustSortableListElement); } } function bindEvents(parent) { - parent.querySelector(".metadataReaders").addEventListener("click", onSortableContainerClick); - parent.querySelector(".subtitleFetchers").addEventListener("click", onSortableContainerClick); - parent.querySelector(".metadataFetchers").addEventListener("click", onSortableContainerClick); - parent.querySelector(".imageFetchers").addEventListener("click", onImageFetchersContainerClick); + parent.querySelector('.metadataReaders').addEventListener('click', onSortableContainerClick); + parent.querySelector('.subtitleFetchers').addEventListener('click', onSortableContainerClick); + parent.querySelector('.metadataFetchers').addEventListener('click', onSortableContainerClick); + parent.querySelector('.imageFetchers').addEventListener('click', onImageFetchersContainerClick); } function embed(parent, contentType, libraryOptions) { @@ -332,15 +348,15 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct }; currentAvailableOptions = null; var isNewLibrary = null === libraryOptions; - isNewLibrary && parent.classList.add("newlibrary"); + isNewLibrary && parent.classList.add('newlibrary'); return new Promise(function(resolve, reject) { var xhr = new XMLHttpRequest; - xhr.open("GET", "components/libraryoptionseditor/libraryoptionseditor.template.html", true); + xhr.open('GET', 'components/libraryoptionseditor/libraryoptionseditor.template.html', true); xhr.onload = function(e) { var template = this.response; parent.innerHTML = globalize.translateDocument(template); - populateRefreshInterval(parent.querySelector("#selectAutoRefreshInterval")); - var promises = [populateLanguages(parent), populateCountries(parent.querySelector("#selectCountry"))]; + populateRefreshInterval(parent.querySelector('#selectAutoRefreshInterval')); + var promises = [populateLanguages(parent), populateCountries(parent.querySelector('#selectCountry'))]; Promise.all(promises).then(function() { return setContentType(parent, contentType).then(function() { libraryOptions && setLibraryOptions(parent, libraryOptions); @@ -354,63 +370,69 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct } function setAdvancedVisible(parent, visible) { - var elems = parent.querySelectorAll(".advanced"); + var elems = parent.querySelectorAll('.advanced'); for (var i = 0; i < elems.length; i++) { - visible ? elems[i].classList.remove("advancedHide") : elems[i].classList.add("advancedHide"); + visible ? elems[i].classList.remove('advancedHide') : elems[i].classList.add('advancedHide'); } } function setContentType(parent, contentType) { - if (contentType === "homevideos" || contentType === "photos") { - parent.querySelector(".chkEnablePhotosContainer").classList.remove("hide"); + if (contentType === 'homevideos' || contentType === 'photos') { + parent.querySelector('.chkEnablePhotosContainer').classList.remove('hide'); } else { - parent.querySelector(".chkEnablePhotosContainer").classList.add("hide"); + parent.querySelector('.chkEnablePhotosContainer').classList.add('hide'); } - if (contentType !== "tvshows" && contentType !== "movies" && contentType !== "homevideos" && contentType !== "musicvideos" && contentType !== "mixed") { - parent.querySelector(".chapterSettingsSection").classList.add("hide"); + if (contentType !== 'tvshows' && contentType !== 'movies' && contentType !== 'homevideos' && contentType !== 'musicvideos' && contentType !== 'mixed') { + parent.querySelector('.chapterSettingsSection').classList.add('hide'); } else { - parent.querySelector(".chapterSettingsSection").classList.remove("hide"); + parent.querySelector('.chapterSettingsSection').classList.remove('hide'); } - if (contentType === "tvshows") { - parent.querySelector(".chkImportMissingEpisodesContainer").classList.remove("hide"); - parent.querySelector(".chkAutomaticallyGroupSeriesContainer").classList.remove("hide"); - parent.querySelector(".fldSeasonZeroDisplayName").classList.remove("hide"); - parent.querySelector("#txtSeasonZeroName").setAttribute("required", "required"); + if (contentType === 'tvshows') { + parent.querySelector('.chkImportMissingEpisodesContainer').classList.remove('hide'); + parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.remove('hide'); + parent.querySelector('.fldSeasonZeroDisplayName').classList.remove('hide'); + parent.querySelector('#txtSeasonZeroName').setAttribute('required', 'required'); } else { - parent.querySelector(".chkImportMissingEpisodesContainer").classList.add("hide"); - parent.querySelector(".chkAutomaticallyGroupSeriesContainer").classList.add("hide"); - parent.querySelector(".fldSeasonZeroDisplayName").classList.add("hide"); - parent.querySelector("#txtSeasonZeroName").removeAttribute("required"); + parent.querySelector('.chkImportMissingEpisodesContainer').classList.add('hide'); + parent.querySelector('.chkAutomaticallyGroupSeriesContainer').classList.add('hide'); + parent.querySelector('.fldSeasonZeroDisplayName').classList.add('hide'); + parent.querySelector('#txtSeasonZeroName').removeAttribute('required'); } - if (contentType === "books" || contentType === "boxsets" || contentType === "playlists" || contentType === "music") { - parent.querySelector(".chkEnableEmbeddedTitlesContainer").classList.add("hide"); + if (contentType === 'books' || contentType === 'boxsets' || contentType === 'playlists' || contentType === 'music') { + parent.querySelector('.chkEnableEmbeddedTitlesContainer').classList.add('hide'); } else { - parent.querySelector(".chkEnableEmbeddedTitlesContainer").classList.remove("hide"); + parent.querySelector('.chkEnableEmbeddedTitlesContainer').classList.remove('hide'); + } + + if (contentType === 'tvshows') { + parent.querySelector('.chkEnableEmbeddedEpisodeInfosContainer').classList.remove('hide'); + } else { + parent.querySelector('.chkEnableEmbeddedEpisodeInfosContainer').classList.add('hide'); } return populateMetadataSettings(parent, contentType); } function setSubtitleFetchersIntoOptions(parent, options) { - options.DisabledSubtitleFetchers = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkSubtitleFetcher"), function(elem) { - return !elem.checked + options.DisabledSubtitleFetchers = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleFetcher'), function(elem) { + return !elem.checked; }), function(elem) { - return elem.getAttribute("data-pluginname") + return elem.getAttribute('data-pluginname'); }); - options.SubtitleFetcherOrder = Array.prototype.map.call(parent.querySelectorAll(".subtitleFetcherItem"), function(elem) { - return elem.getAttribute("data-pluginname") + options.SubtitleFetcherOrder = Array.prototype.map.call(parent.querySelectorAll('.subtitleFetcherItem'), function(elem) { + return elem.getAttribute('data-pluginname'); }); } function setMetadataFetchersIntoOptions(parent, options) { - var sections = parent.querySelectorAll(".metadataFetcher"); + var sections = parent.querySelectorAll('.metadataFetcher'); for (var i = 0; i < sections.length; i++) { var section = sections[i]; - var type = section.getAttribute("data-type"); + var type = section.getAttribute('data-type'); var typeOptions = getTypeOptions(options, type); if (!typeOptions) { typeOptions = { @@ -418,23 +440,23 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct }; options.TypeOptions.push(typeOptions); } - typeOptions.MetadataFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll(".chkMetadataFetcher"), function(elem) { + typeOptions.MetadataFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkMetadataFetcher'), function(elem) { return elem.checked; }), function(elem) { - return elem.getAttribute("data-pluginname"); + return elem.getAttribute('data-pluginname'); }); - typeOptions.MetadataFetcherOrder = Array.prototype.map.call(section.querySelectorAll(".metadataFetcherItem"), function(elem) { - return elem.getAttribute("data-pluginname"); + typeOptions.MetadataFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.metadataFetcherItem'), function(elem) { + return elem.getAttribute('data-pluginname'); }); } } function setImageFetchersIntoOptions(parent, options) { - var sections = parent.querySelectorAll(".imageFetcher"); + var sections = parent.querySelectorAll('.imageFetcher'); for (var i = 0; i < sections.length; i++) { var section = sections[i]; - var type = section.getAttribute("data-type"); + var type = section.getAttribute('data-type'); var typeOptions = getTypeOptions(options, type); if (!typeOptions) { typeOptions = { @@ -443,14 +465,14 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct options.TypeOptions.push(typeOptions); } - typeOptions.ImageFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll(".chkImageFetcher"), function(elem) { - return elem.checked + typeOptions.ImageFetchers = Array.prototype.map.call(Array.prototype.filter.call(section.querySelectorAll('.chkImageFetcher'), function(elem) { + return elem.checked; }), function(elem) { - return elem.getAttribute("data-pluginname") + return elem.getAttribute('data-pluginname'); }); - typeOptions.ImageFetcherOrder = Array.prototype.map.call(section.querySelectorAll(".imageFetcherItem"), function(elem) { - return elem.getAttribute("data-pluginname") + typeOptions.ImageFetcherOrder = Array.prototype.map.call(section.querySelectorAll('.imageFetcherItem'), function(elem) { + return elem.getAttribute('data-pluginname'); }); } } @@ -463,7 +485,7 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct if (!typeOptions) { typeOptions = { - Type: type + Type: originalTypeOption.Type }; options.TypeOptions.push(typeOptions); } @@ -474,39 +496,40 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct function getLibraryOptions(parent) { var options = { EnableArchiveMediaFiles: false, - EnablePhotos: parent.querySelector(".chkEnablePhotos").checked, - EnableRealtimeMonitor: parent.querySelector(".chkEnableRealtimeMonitor").checked, - ExtractChapterImagesDuringLibraryScan: parent.querySelector(".chkExtractChaptersDuringLibraryScan").checked, - EnableChapterImageExtraction: parent.querySelector(".chkExtractChapterImages").checked, - DownloadImagesInAdvance: parent.querySelector("#chkDownloadImagesInAdvance").checked, + EnablePhotos: parent.querySelector('.chkEnablePhotos').checked, + EnableRealtimeMonitor: parent.querySelector('.chkEnableRealtimeMonitor').checked, + ExtractChapterImagesDuringLibraryScan: parent.querySelector('.chkExtractChaptersDuringLibraryScan').checked, + EnableChapterImageExtraction: parent.querySelector('.chkExtractChapterImages').checked, + DownloadImagesInAdvance: parent.querySelector('#chkDownloadImagesInAdvance').checked, EnableInternetProviders: true, - ImportMissingEpisodes: parent.querySelector("#chkImportMissingEpisodes").checked, - SaveLocalMetadata: parent.querySelector("#chkSaveLocal").checked, - EnableAutomaticSeriesGrouping: parent.querySelector(".chkAutomaticallyGroupSeries").checked, - PreferredMetadataLanguage: parent.querySelector("#selectLanguage").value, - MetadataCountryCode: parent.querySelector("#selectCountry").value, - SeasonZeroDisplayName: parent.querySelector("#txtSeasonZeroName").value, - AutomaticRefreshIntervalDays: parseInt(parent.querySelector("#selectAutoRefreshInterval").value), - EnableEmbeddedTitles: parent.querySelector("#chkEnableEmbeddedTitles").checked, - SkipSubtitlesIfEmbeddedSubtitlesPresent: parent.querySelector("#chkSkipIfGraphicalSubsPresent").checked, - SkipSubtitlesIfAudioTrackMatches: parent.querySelector("#chkSkipIfAudioTrackPresent").checked, - SaveSubtitlesWithMedia: parent.querySelector("#chkSaveSubtitlesLocally").checked, - RequirePerfectSubtitleMatch: parent.querySelector("#chkRequirePerfectMatch").checked, - MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkMetadataSaver"), function(elem) { - return elem.checked + ImportMissingEpisodes: parent.querySelector('#chkImportMissingEpisodes').checked, + SaveLocalMetadata: parent.querySelector('#chkSaveLocal').checked, + EnableAutomaticSeriesGrouping: parent.querySelector('.chkAutomaticallyGroupSeries').checked, + PreferredMetadataLanguage: parent.querySelector('#selectLanguage').value, + MetadataCountryCode: parent.querySelector('#selectCountry').value, + SeasonZeroDisplayName: parent.querySelector('#txtSeasonZeroName').value, + AutomaticRefreshIntervalDays: parseInt(parent.querySelector('#selectAutoRefreshInterval').value), + EnableEmbeddedTitles: parent.querySelector('#chkEnableEmbeddedTitles').checked, + EnableEmbeddedEpisodeInfos: parent.querySelector('#chkEnableEmbeddedEpisodeInfos').checked, + SkipSubtitlesIfEmbeddedSubtitlesPresent: parent.querySelector('#chkSkipIfGraphicalSubsPresent').checked, + SkipSubtitlesIfAudioTrackMatches: parent.querySelector('#chkSkipIfAudioTrackPresent').checked, + SaveSubtitlesWithMedia: parent.querySelector('#chkSaveSubtitlesLocally').checked, + RequirePerfectSubtitleMatch: parent.querySelector('#chkRequirePerfectMatch').checked, + MetadataSavers: Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkMetadataSaver'), function(elem) { + return elem.checked; }), function(elem) { - return elem.getAttribute("data-pluginname") + return elem.getAttribute('data-pluginname'); }), TypeOptions: [] }; - options.LocalMetadataReaderOrder = Array.prototype.map.call(parent.querySelectorAll(".localReaderOption"), function(elem) { - return elem.getAttribute("data-pluginname") + options.LocalMetadataReaderOrder = Array.prototype.map.call(parent.querySelectorAll('.localReaderOption'), function(elem) { + return elem.getAttribute('data-pluginname'); }); - options.SubtitleDownloadLanguages = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll(".chkSubtitleLanguage"), function(elem) { - return elem.checked + options.SubtitleDownloadLanguages = Array.prototype.map.call(Array.prototype.filter.call(parent.querySelectorAll('.chkSubtitleLanguage'), function(elem) { + return elem.checked; }), function(elem) { - return elem.getAttribute("data-lang") + return elem.getAttribute('data-lang'); }); setSubtitleFetchersIntoOptions(parent, options); setMetadataFetchersIntoOptions(parent, options); @@ -519,7 +542,7 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct function getOrderedPlugins(plugins, configuredOrder) { plugins = plugins.slice(0); plugins.sort(function(a, b) { - return a = configuredOrder.indexOf(a.Name), b = configuredOrder.indexOf(b.Name), a < b ? -1 : a > b ? 1 : 0 + return a = configuredOrder.indexOf(a.Name), b = configuredOrder.indexOf(b.Name), a < b ? -1 : a > b ? 1 : 0; }); return plugins; } @@ -527,28 +550,29 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct function setLibraryOptions(parent, options) { currentLibraryOptions = options; currentAvailableOptions = parent.availableOptions; - parent.querySelector("#selectLanguage").value = options.PreferredMetadataLanguage || ""; - parent.querySelector("#selectCountry").value = options.MetadataCountryCode || ""; - parent.querySelector("#selectAutoRefreshInterval").value = options.AutomaticRefreshIntervalDays || "0"; - parent.querySelector("#txtSeasonZeroName").value = options.SeasonZeroDisplayName || "Specials"; - parent.querySelector(".chkEnablePhotos").checked = options.EnablePhotos; - parent.querySelector(".chkEnableRealtimeMonitor").checked = options.EnableRealtimeMonitor; - parent.querySelector(".chkExtractChaptersDuringLibraryScan").checked = options.ExtractChapterImagesDuringLibraryScan; - parent.querySelector(".chkExtractChapterImages").checked = options.EnableChapterImageExtraction; - parent.querySelector("#chkDownloadImagesInAdvance").checked = options.DownloadImagesInAdvance; - parent.querySelector("#chkSaveLocal").checked = options.SaveLocalMetadata; - parent.querySelector("#chkImportMissingEpisodes").checked = options.ImportMissingEpisodes; - parent.querySelector(".chkAutomaticallyGroupSeries").checked = options.EnableAutomaticSeriesGrouping; - parent.querySelector("#chkEnableEmbeddedTitles").checked = options.EnableEmbeddedTitles; - parent.querySelector("#chkSkipIfGraphicalSubsPresent").checked = options.SkipSubtitlesIfEmbeddedSubtitlesPresent; - parent.querySelector("#chkSaveSubtitlesLocally").checked = options.SaveSubtitlesWithMedia; - parent.querySelector("#chkSkipIfAudioTrackPresent").checked = options.SkipSubtitlesIfAudioTrackMatches; - parent.querySelector("#chkRequirePerfectMatch").checked = options.RequirePerfectSubtitleMatch; - Array.prototype.forEach.call(parent.querySelectorAll(".chkMetadataSaver"), function(elem) { - elem.checked = options.MetadataSavers ? -1 !== options.MetadataSavers.indexOf(elem.getAttribute("data-pluginname")) : "true" === elem.getAttribute("data-defaultenabled") + parent.querySelector('#selectLanguage').value = options.PreferredMetadataLanguage || ''; + parent.querySelector('#selectCountry').value = options.MetadataCountryCode || ''; + parent.querySelector('#selectAutoRefreshInterval').value = options.AutomaticRefreshIntervalDays || '0'; + parent.querySelector('#txtSeasonZeroName').value = options.SeasonZeroDisplayName || 'Specials'; + parent.querySelector('.chkEnablePhotos').checked = options.EnablePhotos; + parent.querySelector('.chkEnableRealtimeMonitor').checked = options.EnableRealtimeMonitor; + parent.querySelector('.chkExtractChaptersDuringLibraryScan').checked = options.ExtractChapterImagesDuringLibraryScan; + parent.querySelector('.chkExtractChapterImages').checked = options.EnableChapterImageExtraction; + parent.querySelector('#chkDownloadImagesInAdvance').checked = options.DownloadImagesInAdvance; + parent.querySelector('#chkSaveLocal').checked = options.SaveLocalMetadata; + parent.querySelector('#chkImportMissingEpisodes').checked = options.ImportMissingEpisodes; + parent.querySelector('.chkAutomaticallyGroupSeries').checked = options.EnableAutomaticSeriesGrouping; + parent.querySelector('#chkEnableEmbeddedTitles').checked = options.EnableEmbeddedTitles; + parent.querySelector('#chkEnableEmbeddedEpisodeInfos').checked = options.EnableEmbeddedEpisodeInfos; + parent.querySelector('#chkSkipIfGraphicalSubsPresent').checked = options.SkipSubtitlesIfEmbeddedSubtitlesPresent; + parent.querySelector('#chkSaveSubtitlesLocally').checked = options.SaveSubtitlesWithMedia; + parent.querySelector('#chkSkipIfAudioTrackPresent').checked = options.SkipSubtitlesIfAudioTrackMatches; + parent.querySelector('#chkRequirePerfectMatch').checked = options.RequirePerfectSubtitleMatch; + Array.prototype.forEach.call(parent.querySelectorAll('.chkMetadataSaver'), function(elem) { + elem.checked = options.MetadataSavers ? -1 !== options.MetadataSavers.indexOf(elem.getAttribute('data-pluginname')) : 'true' === elem.getAttribute('data-defaultenabled'); }); - Array.prototype.forEach.call(parent.querySelectorAll(".chkSubtitleLanguage"), function(elem) { - elem.checked = !!options.SubtitleDownloadLanguages && -1 !== options.SubtitleDownloadLanguages.indexOf(elem.getAttribute("data-lang")) + Array.prototype.forEach.call(parent.querySelectorAll('.chkSubtitleLanguage'), function(elem) { + elem.checked = !!options.SubtitleDownloadLanguages && -1 !== options.SubtitleDownloadLanguages.indexOf(elem.getAttribute('data-lang')); }); renderMetadataReaders(parent, getOrderedPlugins(parent.availableOptions.MetadataReaders, options.LocalMetadataReaderOrder || [])); renderMetadataFetchers(parent, parent.availableOptions, options); @@ -565,5 +589,5 @@ define(["globalize", "dom", "emby-checkbox", "emby-select", "emby-input"], funct getLibraryOptions: getLibraryOptions, setLibraryOptions: setLibraryOptions, setAdvancedVisible: setAdvancedVisible - } + }; }); diff --git a/src/components/libraryoptionseditor/libraryoptionseditor.template.html b/src/components/libraryoptionseditor/libraryoptionseditor.template.html index ebfdacaa19..caa177108d 100644 --- a/src/components/libraryoptionseditor/libraryoptionseditor.template.html +++ b/src/components/libraryoptionseditor/libraryoptionseditor.template.html @@ -28,6 +28,13 @@
${PreferEmbeddedTitlesOverFileNamesHelp}
+
+ +
${PreferEmbeddedEpisodeInfosOverFileNamesHelp}
+
${SaveSubtitlesIntoMediaFoldersHelp}
-
\ No newline at end of file +
diff --git a/src/components/listview/listview.css b/src/components/listview/listview.css index 4d3b27ce75..1e485a80ed 100644 --- a/src/components/listview/listview.css +++ b/src/components/listview/listview.css @@ -10,7 +10,7 @@ display: block; align-items: center; text-align: left; - padding: .25em .25em .25em .5em; + padding: 0.25em 0.25em 0.25em 0.5em; cursor: pointer; overflow: hidden; } @@ -35,6 +35,8 @@ } .listItem-indexnumberleft { + min-width: 2%; + text-align: center; margin-right: 1em; } @@ -48,14 +50,18 @@ } .listItem-border.show-focus:focus { - transform: scale(1.0) !important; + transform: scale(1) !important; } -.listItemImage, .listItemIcon, .listItemAside { +.listItemImage, +.listItemIcon, +.listItemAside { flex-shrink: 0; } -.listItemBody, .listItemImage, .listItemIcon { +.listItemBody, +.listItemImage, +.listItemIcon { display: inline-block; vertical-align: middle; } @@ -69,13 +75,13 @@ } .listViewDragHandle { - margin-left: -.25em !important; + margin-left: -0.25em !important; touch-action: none; } .listItemBody { flex-grow: 1; - padding: .85em .75em; + padding: 0.85em 0.75em; overflow: hidden; text-overflow: ellipsis; flex-direction: column; @@ -83,8 +89,15 @@ justify-content: center; } +.listItem, +.listItemBody, +.listItemMediaInfo { + display: flex; + contain: layout style; +} + .layout-tv .listItemBody { - padding: .35em .75em; + padding: 0.35em 0.75em; } .listItemBody-noleftpadding { @@ -93,11 +106,15 @@ .listItemBodyText { margin: 0; - padding: .1em 0; + padding: 0.1em 0; overflow: hidden; text-overflow: ellipsis; } +.layout-desktop .listItemBodyText { + margin: 0.25em 0 0 0; +} + .listItemBodyText-nowrap { white-space: nowrap; } @@ -119,7 +136,7 @@ width: 19.5vw; height: 13vw; background-position: center center; - margin-right: .75em; + margin-right: 0.75em; } .listItemImageButton { @@ -149,23 +166,24 @@ @media all and (max-width: 64em) { .listItemImage-large { - width: 33.75vw; - height: 22.5vw; + width: 22vw; + height: 16vw; margin-right: 0 !important; } + .listItemIndicators, .listItemImageButton { - font-size: 1em !important; + font-size: 0.6em !important; } .listItemBody { - padding-left: .75em; + padding-left: 0.75em; } } @media all and (max-width: 50em) { .listItemBody { - padding-right: .5em; + padding-right: 0.5em; } } @@ -178,15 +196,15 @@ width: 1em !important; height: 1em !important; font-size: 143%; - padding: 0 .25em 0 0; + padding: 0 0.25em 0 0; } .listItemIcon:not(.listItemIcon-transparent) { background-color: #00a4dc; color: #fff; - padding: .5em; + padding: 0.5em; border-radius: 100em; - margin: 0 .2em 0 .4em; + margin: 0 0.2em 0 0.4em; } .listItemProgressBar { @@ -197,7 +215,7 @@ } .listItem:focus { - border-radius: .2em; + border-radius: 0.2em; } .listItem:focus .secondary { @@ -205,7 +223,7 @@ } .listItem-focusscale { - transition: transform .2s ease-out; + transition: transform 0.2s ease-out; } .listItem-focusscale:focus { @@ -213,45 +231,35 @@ } .paperList { - margin: .5em auto; + margin: 0.5em auto; } .paperList-clear { background-color: transparent !important; } -.listItemMediaInfo { - /* Don't display if flex not supported */ - display: none; - align-items: center; - margin-right: 1em; -} - .listGroupHeader-first { margin-top: 0; } .listItemIndicators { - right: .324em; - top: .324em; + right: 0.324em; + top: 0.324em; position: absolute; display: flex; align-items: center; } -.listItem, .listItemBody, .listItemMediaInfo { - display: flex; - contain: layout style; -} - .listItem-bottomoverview { font-size: 88%; margin-bottom: 1em; - margin-top: .2em; + margin-top: 0.2em; } @media all and (max-width: 50em) { - .listItem .endsAt, .listItem .criticRating, .listItem-overview { + .listItem .endsAt, + .listItem .criticRating, + .listItem-overview { display: none !important; } } diff --git a/src/components/listview/listview.js b/src/components/listview/listview.js index 94535deb6f..0743b35280 100644 --- a/src/components/listview/listview.js +++ b/src/components/listview/listview.js @@ -72,8 +72,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var apiClient = connectionManager.getApiClient(item.ServerId); var options = { - width: width, - type: "Primary" + maxWidth: width * 2, + type: 'Primary' }; if (item.ImageTags && item.ImageTags.Primary) { @@ -105,8 +105,8 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var apiClient = connectionManager.getApiClient(item.ServerId); var options = { - width: width, - type: "Primary" + maxWidth: width * 2, + type: 'Primary' }; if (item.ChannelId && item.ChannelPrimaryImageTag) { @@ -160,7 +160,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var button = options.rightButtons[i]; - html += ''; + html += ''; } return html; @@ -219,7 +219,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan } } - var cssClass = "listItem"; + var cssClass = 'listItem'; if (options.border || (options.highlight !== false && !layoutManager.tv)) { cssClass += ' listItem-border'; @@ -236,7 +236,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan var downloadWidth = 80; if (isLargeStyle) { - cssClass += " listItem-largeImage"; + cssClass += ' listItem-largeImage'; downloadWidth = 500; } @@ -262,14 +262,13 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan } if (!clickEntireItem && options.dragHandle) { - //html += ''; + //html += ''; // Firefox and Edge are not allowing the button to be draggable - html += 'drag_handle'; + 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) { @@ -298,7 +297,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan } if (playOnImageClick) { - html += ''; + html += ''; } var progressHtml = indicators.getProgressBarHtml(item, { @@ -356,7 +355,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan }); if (options.showIndexNumber && item.IndexNumber != null) { - displayName = item.IndexNumber + ". " + displayName; + displayName = item.IndexNumber + '. ' + displayName; } if (options.showParentTitle && options.parentTitleWithTitle) { @@ -427,7 +426,7 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan html += '
'; - var moreIcon = 'more_horiz'; + const moreIcon = 'more_horiz'; html += getTextLinesHtml(textlines, isLargeStyle); @@ -471,18 +470,20 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan html += indicators.getTimerIndicator(item).replace('indicatorIcon', 'indicatorIcon listItemAside'); } + html += '
'; + if (!clickEntireItem) { if (options.addToListButton) { - html += ''; + html += ''; } if (options.moreButton !== false) { - html += ''; + html += ''; } if (options.infoButton) { - html += ''; + html += ''; } if (options.rightButtons) { @@ -491,22 +492,19 @@ define(['itemHelper', 'mediaInfo', 'indicators', 'connectionManager', 'layoutMan if (options.enableUserDataButtons !== false) { - html += ''; - var userData = item.UserData || {}; var likes = userData.Likes == null ? '' : userData.Likes; if (itemHelper.canMarkPlayed(item)) { - html += ''; + html += ''; } if (itemHelper.canRate(item)) { - html += ''; + html += ''; } - - html += ''; } } + html += '
'; if (enableContentWrapper) { html += '
'; diff --git a/src/components/loading/loading.css b/src/components/loading/loading.css index e3f10c0e2e..dae33aa9b8 100644 --- a/src/components/loading/loading.css +++ b/src/components/loading/loading.css @@ -7,11 +7,20 @@ .mdlSpinnerActive { display: inline-block; + -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); + } +} + @keyframes mdl-spinner__container-rotate { to { + -webkit-transform: rotate(360deg); transform: rotate(360deg); } } @@ -24,67 +33,121 @@ } .mdl-spinner__layer-1 { - border-color: rgb(66,165,245); + border-color: rgb(66, 165, 245); } .mdl-spinner__layer-1-active { + -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: rgb(244,67,54); + border-color: rgb(244, 67, 54); } .mdl-spinner__layer-2-active { + -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: rgb(253,216,53); + border-color: rgb(253, 216, 53); } .mdl-spinner__layer-3-active { + -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: rgb(76,175,80); + border-color: rgb(76, 175, 80); } .mdl-spinner__layer-4-active { + -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; } -@keyframes mdl-spinner__fill-unfill-rotate { +@-webkit-keyframes mdl-spinner__fill-unfill-rotate { 12.5% { + -webkit-transform: rotate(135deg); transform: rotate(135deg); } 25% { + -webkit-transform: rotate(270deg); transform: rotate(270deg); } 37.5% { + -webkit-transform: rotate(405deg); transform: rotate(405deg); } 50% { + -webkit-transform: rotate(540deg); transform: rotate(540deg); } 62.5% { + -webkit-transform: rotate(675deg); transform: rotate(675deg); } 75% { + -webkit-transform: rotate(810deg); transform: rotate(810deg); } 87.5% { + -webkit-transform: rotate(945deg); transform: rotate(945deg); } to { + -webkit-transform: rotate(1080deg); + transform: rotate(1080deg); + } +} + +@keyframes mdl-spinner__fill-unfill-rotate { + 12.5% { + -webkit-transform: rotate(135deg); + transform: rotate(135deg); + } + + 25% { + -webkit-transform: rotate(270deg); + transform: rotate(270deg); + } + + 37.5% { + -webkit-transform: rotate(405deg); + transform: rotate(405deg); + } + + 50% { + -webkit-transform: rotate(540deg); + transform: rotate(540deg); + } + + 62.5% { + -webkit-transform: rotate(675deg); + transform: rotate(675deg); + } + + 75% { + -webkit-transform: rotate(810deg); + transform: rotate(810deg); + } + + 87.5% { + -webkit-transform: rotate(945deg); + transform: rotate(945deg); + } + + to { + -webkit-transform: rotate(1080deg); transform: rotate(1080deg); } } @@ -98,6 +161,32 @@ * - 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 { + from { + opacity: 0.99; + } + + 25% { + opacity: 0.99; + } + + 26% { + opacity: 0; + } + + 89% { + opacity: 0; + } + + 90% { + opacity: 0.99; + } + + 100% { + opacity: 0.99; + } +} + @keyframes mdl-spinner__layer-1-fade-in-out { from { opacity: 0.99; @@ -124,6 +213,28 @@ } } +@-webkit-keyframes mdl-spinner__layer-2-fade-in-out { + from { + opacity: 0; + } + + 15% { + opacity: 0; + } + + 25% { + opacity: 0.99; + } + + 50% { + opacity: 0.99; + } + + 51% { + opacity: 0; + } +} + @keyframes mdl-spinner__layer-2-fade-in-out { from { opacity: 0; @@ -146,6 +257,28 @@ } } +@-webkit-keyframes mdl-spinner__layer-3-fade-in-out { + from { + opacity: 0; + } + + 40% { + opacity: 0; + } + + 50% { + opacity: 0.99; + } + + 75% { + opacity: 0.99; + } + + 76% { + opacity: 0; + } +} + @keyframes mdl-spinner__layer-3-fade-in-out { from { opacity: 0; @@ -168,6 +301,28 @@ } } +@-webkit-keyframes mdl-spinner__layer-4-fade-in-out { + from { + opacity: 0; + } + + 65% { + opacity: 0; + } + + 75% { + opacity: 0.99; + } + + 90% { + opacity: 0.99; + } + + 100% { + opacity: 0; + } +} + @keyframes mdl-spinner__layer-4-fade-in-out { from { opacity: 0; @@ -190,6 +345,23 @@ } } +.mdl-spinner__circle { + box-sizing: border-box; + height: 100%; + border-width: 0.21em; + border-style: solid; + border-color: inherit; + border-bottom-color: transparent !important; + border-radius: 50%; + -webkit-animation: none; + animation: none; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; +} + .mdl-spinner__circle-clipper { display: inline-block; position: relative; @@ -199,69 +371,97 @@ border-color: inherit; } - .mdl-spinner__circle-clipper .mdl-spinner__circle { - width: 200%; - } - -.mdl-spinner__circle { - box-sizing: border-box; - height: 100%; - border-width: .21em; - border-style: solid; - border-color: inherit; - border-bottom-color: transparent !important; - border-radius: 50%; - animation: none; - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; +.mdl-spinner__circle-clipper .mdl-spinner__circle { + width: 200%; } .mdl-spinner__circleLeft { border-right-color: transparent !important; + -webkit-transform: rotate(129deg); transform: rotate(129deg); } .mdl-spinner__circleLeft-active { + -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); } .mdl-spinner__circleRight-active { + -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; } -@keyframes mdl-spinner__left-spin { +@-webkit-keyframes mdl-spinner__left-spin { from { + -webkit-transform: rotate(130deg); transform: rotate(130deg); } 50% { + -webkit-transform: rotate(-5deg); transform: rotate(-5deg); } to { + -webkit-transform: rotate(130deg); transform: rotate(130deg); } } +@keyframes mdl-spinner__left-spin { + from { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); + } + + 50% { + -webkit-transform: rotate(-5deg); + transform: rotate(-5deg); + } + + to { + -webkit-transform: rotate(130deg); + transform: rotate(130deg); + } +} + +@-webkit-keyframes mdl-spinner__right-spin { + from { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); + } + + 50% { + -webkit-transform: rotate(5deg); + transform: rotate(5deg); + } + + to { + -webkit-transform: rotate(-130deg); + transform: rotate(-130deg); + } +} + @keyframes mdl-spinner__right-spin { from { + -webkit-transform: rotate(-130deg); transform: rotate(-130deg); } 50% { + -webkit-transform: rotate(5deg); transform: rotate(5deg); } to { + -webkit-transform: rotate(-130deg); transform: rotate(-130deg); } } diff --git a/src/components/loading/loading.js b/src/components/loading/loading.js index 510f311217..9a9aa3ca7d 100644 --- a/src/components/loading/loading.js +++ b/src/components/loading/loading.js @@ -19,7 +19,7 @@ define(['components/loading/loadingLegacy', 'browser', 'css!./loading'], functio if (!elem) { - elem = document.createElement("div"); + elem = document.createElement('div'); loadingElem = elem; elem.classList.add('docspinner'); @@ -81,4 +81,4 @@ define(['components/loading/loadingLegacy', 'browser', 'css!./loading'], functio } } }; -}); \ No newline at end of file +}); diff --git a/src/components/loading/loadingLegacy.js b/src/components/loading/loadingLegacy.js index 757cea0160..d766a4aca4 100644 --- a/src/components/loading/loadingLegacy.js +++ b/src/components/loading/loadingLegacy.js @@ -7,7 +7,7 @@ define(['require', 'css!./loadingLegacy'], function (require) { show: function () { var elem = loadingElem; if (!elem) { - elem = document.createElement("img"); + elem = document.createElement('img'); elem.src = require.toUrl('.').split('?')[0] + '/loader.gif'; loadingElem = elem; diff --git a/src/components/logoscreensaver/plugin.js b/src/components/logoscreensaver/plugin.js index 521afd2690..f9dd901982 100644 --- a/src/components/logoscreensaver/plugin.js +++ b/src/components/logoscreensaver/plugin.js @@ -1,12 +1,12 @@ -define(["pluginManager"], function (pluginManager) { +define(['pluginManager'], function (pluginManager) { return function () { var self = this; - self.name = "Logo ScreenSaver"; - self.type = "screensaver"; - self.id = "logoscreensaver"; + self.name = 'Logo ScreenSaver'; + self.type = 'screensaver'; + self.id = 'logoscreensaver'; self.supportsAnonymous = true; var interval; @@ -24,7 +24,7 @@ define(["pluginManager"], function (pluginManager) { rotateOut ]; - var elem = document.querySelector(".logoScreenSaverImage"); + var elem = document.querySelector('.logoScreenSaverImage'); if (elem && elem.animate) { var random = getRandomInt(0, animations.length - 1); @@ -39,96 +39,96 @@ define(["pluginManager"], function (pluginManager) { function bounceInLeft(elem, iterations) { var keyframes = [ - { transform: "translate3d(-3000px, 0, 0)", opacity: "0", offset: 0 }, - { transform: "translate3d(25px, 0, 0)", opacity: "1", offset: 0.6 }, - { transform: "translate3d(-100px, 0, 0)", offset: 0.75 }, - { transform: "translate3d(5px, 0, 0)", offset: 0.9 }, - { transform: "none", opacity: "1", offset: 1 }]; - var timing = { duration: 900, iterations: iterations, easing: "cubic-bezier(0.215, 0.610, 0.355, 1.000)" }; + { transform: 'translate3d(-3000px, 0, 0)', opacity: '0', offset: 0 }, + { transform: 'translate3d(25px, 0, 0)', opacity: '1', offset: 0.6 }, + { transform: 'translate3d(-100px, 0, 0)', offset: 0.75 }, + { transform: 'translate3d(5px, 0, 0)', offset: 0.9 }, + { transform: 'none', opacity: '1', offset: 1 }]; + var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' }; return elem.animate(keyframes, timing); } function bounceInRight(elem, iterations) { var keyframes = [ - { transform: "translate3d(3000px, 0, 0)", opacity: "0", offset: 0 }, - { transform: "translate3d(-25px, 0, 0)", opacity: "1", offset: 0.6 }, - { transform: "translate3d(100px, 0, 0)", offset: 0.75 }, - { transform: "translate3d(-5px, 0, 0)", offset: 0.9 }, - { transform: "none", opacity: "1", offset: 1 }]; - var timing = { duration: 900, iterations: iterations, easing: "cubic-bezier(0.215, 0.610, 0.355, 1.000)" }; + { transform: 'translate3d(3000px, 0, 0)', opacity: '0', offset: 0 }, + { transform: 'translate3d(-25px, 0, 0)', opacity: '1', offset: 0.6 }, + { transform: 'translate3d(100px, 0, 0)', offset: 0.75 }, + { transform: 'translate3d(-5px, 0, 0)', offset: 0.9 }, + { transform: 'none', opacity: '1', offset: 1 }]; + var timing = { duration: 900, iterations: iterations, easing: 'cubic-bezier(0.215, 0.610, 0.355, 1.000)' }; return elem.animate(keyframes, timing); } function shake(elem, iterations) { var keyframes = [ - { transform: "translate3d(0, 0, 0)", offset: 0 }, - { transform: "translate3d(-10px, 0, 0)", offset: 0.1 }, - { transform: "translate3d(10px, 0, 0)", offset: 0.2 }, - { transform: "translate3d(-10px, 0, 0)", offset: 0.3 }, - { transform: "translate3d(10px, 0, 0)", offset: 0.4 }, - { transform: "translate3d(-10px, 0, 0)", offset: 0.5 }, - { transform: "translate3d(10px, 0, 0)", offset: 0.6 }, - { transform: "translate3d(-10px, 0, 0)", offset: 0.7 }, - { transform: "translate3d(10px, 0, 0)", offset: 0.8 }, - { transform: "translate3d(-10px, 0, 0)", offset: 0.9 }, - { transform: "translate3d(0, 0, 0)", offset: 1 }]; + { transform: 'translate3d(0, 0, 0)', offset: 0 }, + { transform: 'translate3d(-10px, 0, 0)', offset: 0.1 }, + { transform: 'translate3d(10px, 0, 0)', offset: 0.2 }, + { transform: 'translate3d(-10px, 0, 0)', offset: 0.3 }, + { transform: 'translate3d(10px, 0, 0)', offset: 0.4 }, + { transform: 'translate3d(-10px, 0, 0)', offset: 0.5 }, + { transform: 'translate3d(10px, 0, 0)', offset: 0.6 }, + { transform: 'translate3d(-10px, 0, 0)', offset: 0.7 }, + { transform: 'translate3d(10px, 0, 0)', offset: 0.8 }, + { transform: 'translate3d(-10px, 0, 0)', offset: 0.9 }, + { transform: 'translate3d(0, 0, 0)', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); } function swing(elem, iterations) { var keyframes = [ - { transform: "translate(0%)", offset: 0 }, - { transform: "rotate3d(0, 0, 1, 15deg)", offset: 0.2 }, - { transform: "rotate3d(0, 0, 1, -10deg)", offset: 0.4 }, - { transform: "rotate3d(0, 0, 1, 5deg)", offset: 0.6 }, - { transform: "rotate3d(0, 0, 1, -5deg)", offset: 0.8 }, - { transform: "rotate3d(0, 0, 1, 0deg)", offset: 1 }]; + { transform: 'translate(0%)', offset: 0 }, + { transform: 'rotate3d(0, 0, 1, 15deg)', offset: 0.2 }, + { transform: 'rotate3d(0, 0, 1, -10deg)', offset: 0.4 }, + { transform: 'rotate3d(0, 0, 1, 5deg)', offset: 0.6 }, + { transform: 'rotate3d(0, 0, 1, -5deg)', offset: 0.8 }, + { transform: 'rotate3d(0, 0, 1, 0deg)', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); } function tada(elem, iterations) { var keyframes = [ - { transform: "scale3d(1, 1, 1)", offset: 0 }, - { transform: "scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)", offset: 0.1 }, - { transform: "scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)", offset: 0.2 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)", offset: 0.3 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)", offset: 0.4 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)", offset: 0.5 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)", offset: 0.6 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)", offset: 0.7 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)", offset: 0.8 }, - { transform: "scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)", offset: 0.9 }, - { transform: "scale3d(1, 1, 1)", offset: 1 }]; + { transform: 'scale3d(1, 1, 1)', offset: 0 }, + { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.1 }, + { transform: 'scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)', offset: 0.2 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.3 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.4 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.5 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.6 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.7 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)', offset: 0.8 }, + { transform: 'scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)', offset: 0.9 }, + { transform: 'scale3d(1, 1, 1)', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); } function wobble(elem, iterations) { var keyframes = [ - { transform: "translate(0%)", offset: 0 }, - { transform: "translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)", offset: 0.15 }, - { transform: "translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)", offset: 0.45 }, - { transform: "translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)", offset: 0.6 }, - { transform: "translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)", offset: 0.75 }, - { transform: "translateX(0%)", offset: 1 }]; + { transform: 'translate(0%)', offset: 0 }, + { transform: 'translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg)', offset: 0.15 }, + { transform: 'translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg)', offset: 0.45 }, + { transform: 'translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg)', offset: 0.6 }, + { transform: 'translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg)', offset: 0.75 }, + { transform: 'translateX(0%)', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); } function rotateIn(elem, iterations) { - var transformOrigin = elem.style["transform-origin"]; - var keyframes = [{ transform: "rotate3d(0, 0, 1, -200deg)", opacity: "0", transformOrigin: "center", offset: 0 }, - { transform: "none", opacity: "1", transformOrigin: "center", offset: 1 }]; + var transformOrigin = elem.style['transform-origin']; + var keyframes = [{ transform: 'rotate3d(0, 0, 1, -200deg)', opacity: '0', transformOrigin: 'center', offset: 0 }, + { transform: 'none', opacity: '1', transformOrigin: 'center', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); } function rotateOut(elem, iterations) { - var transformOrigin = elem.style["transform-origin"]; - var keyframes = [{ transform: "none", opacity: "1", transformOrigin: "center", offset: 0 }, - { transform: "rotate3d(0, 0, 1, 200deg)", opacity: "0", transformOrigin: "center", offset: 1 }]; + var transformOrigin = elem.style['transform-origin']; + var keyframes = [{ transform: 'none', opacity: '1', transformOrigin: 'center', offset: 0 }, + { transform: 'rotate3d(0, 0, 1, 200deg)', opacity: '0', transformOrigin: 'center', offset: 1 }]; var timing = { duration: 900, iterations: iterations }; return elem.animate(keyframes, timing); @@ -136,8 +136,8 @@ define(["pluginManager"], function (pluginManager) { function fadeOut(elem, iterations) { var keyframes = [ - { opacity: "1", offset: 0 }, - { opacity: "0", offset: 1 }]; + { opacity: '1', offset: 0 }, + { opacity: '0', offset: 1 }]; var timing = { duration: 400, iterations: iterations }; return elem.animate(keyframes, timing); } @@ -151,16 +151,16 @@ define(["pluginManager"], function (pluginManager) { self.show = function () { - require(["css!" + pluginManager.mapPath(self, "style.css")], function () { + require(['css!' + pluginManager.mapPath(self, 'style.css')], function () { - var elem = document.querySelector(".logoScreenSaver"); + var elem = document.querySelector('.logoScreenSaver'); if (!elem) { - elem = document.createElement("div"); - elem.classList.add("logoScreenSaver"); + elem = document.createElement('div'); + elem.classList.add('logoScreenSaver'); document.body.appendChild(elem); - elem.innerHTML = ''; + elem.innerHTML = ''; } stopInterval(); @@ -172,7 +172,7 @@ define(["pluginManager"], function (pluginManager) { stopInterval(); - var elem = document.querySelector(".logoScreenSaver"); + var elem = document.querySelector('.logoScreenSaver'); if (elem) { @@ -188,5 +188,5 @@ define(["pluginManager"], function (pluginManager) { } } }; - } + }; }); diff --git a/src/components/maintabsmanager.js b/src/components/maintabsmanager.js index 64e25b4870..e1c5434363 100644 --- a/src/components/maintabsmanager.js +++ b/src/components/maintabsmanager.js @@ -166,6 +166,7 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom, }).join('') + '
'; tabsContainerElem.innerHTML = tabsHtml; + window.CustomElements.upgradeSubtree(tabsContainerElem); document.body.classList.add('withSectionTabs'); tabOwnerView = view; @@ -264,4 +265,4 @@ define(['dom', 'browser', 'events', 'emby-tabs', 'emby-button'], function (dom, getTabsElement: getTabsElement, selectedTabIndex: selectedTabIndex }; -}); \ No newline at end of file +}); diff --git a/src/components/mediainfo/fresh.png b/src/components/mediainfo/fresh.png deleted file mode 100644 index 701ef6a8c0..0000000000 Binary files a/src/components/mediainfo/fresh.png and /dev/null differ diff --git a/src/components/mediainfo/mediainfo.css b/src/components/mediainfo/mediainfo.css index 2203ba6676..1883b78726 100644 --- a/src/components/mediainfo/mediainfo.css +++ b/src/components/mediainfo/mediainfo.css @@ -4,13 +4,13 @@ } .mediaInfoText { - padding: .22em .5em; - border-radius: .25em; + padding: 0.22em 0.5em; + border-radius: 0.25em; font-size: 92%; display: flex; align-items: center; white-space: nowrap; - margin: 0 .5em 0 0; + margin: 0 0.5em 0 0; } .mediaInfoText-upper { @@ -21,7 +21,7 @@ width: auto; height: auto; font-size: 1.6em; - margin-right: .6em; + margin-right: 0.6em; } .mediaInfoItem:last-child { @@ -54,17 +54,17 @@ } .mediaInfoCriticRatingFresh { - background-image: url(fresh.png); + background-image: url(../../assets/img/fresh.svg); } .mediaInfoCriticRatingRotten { - background-image: url(rotten.png); + background-image: url(../../assets/img/rotten.svg); } .mediaInfoProgramAttribute { text-transform: uppercase; - padding: .16em .6em; - border-radius: .15em; + padding: 0.16em 0.6em; + border-radius: 0.15em; font-size: 80%; } @@ -73,13 +73,13 @@ } .mediaInfoOfficialRating { - border: .09em solid currentColor; - padding: 0 .6em; + border: 0.09em solid currentColor; + padding: 0 0.6em; height: 1.3em; line-height: 1.8em; display: flex; align-items: center; justify-content: center; - border-radius: .1em; + border-radius: 0.1em; font-size: 96%; } diff --git a/src/components/mediainfo/mediainfo.js b/src/components/mediainfo/mediainfo.js index 04df34685d..0c9a87e800 100644 --- a/src/components/mediainfo/mediainfo.js +++ b/src/components/mediainfo/mediainfo.js @@ -6,7 +6,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater var status; if (item.Type === 'SeriesTimer') { - return 'fiber_smart_record'; + return ''; } else if (item.TimerId || item.SeriesTimerId) { status = item.Status || 'Cancelled'; @@ -20,13 +20,13 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater if (item.SeriesTimerId) { if (status !== 'Cancelled') { - return 'fiber_smart_record'; + return ''; } - return 'fiber_smart_record'; + return ''; } - return 'fiber_manual_record'; + return ''; } function getProgramInfoHtml(item, options) { @@ -57,7 +57,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater miscInfo.push(text); } catch (e) { - console.log("Error parsing date: " + item.StartDate); + console.error('error parsing date: ' + item.StartDate); } } @@ -109,7 +109,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater var minutes; var count; - var showFolderRuntime = item.Type === "MusicAlbum" || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre'; + var showFolderRuntime = item.Type === 'MusicAlbum' || item.MediaType === 'MusicArtist' || item.MediaType === 'Playlist' || item.MediaType === 'MusicGenre'; if (showFolderRuntime) { @@ -123,7 +123,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater if (item.RunTimeTicks) { miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); } - } else if (item.Type === "PhotoAlbum" || item.Type === "BoxSet") { + } else if (item.Type === 'PhotoAlbum' || item.Type === 'BoxSet') { count = item.ChildCount; @@ -133,7 +133,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater } } - if ((item.Type === "Episode" || item.MediaType === 'Photo') && options.originalAirDate !== false) { + if ((item.Type === 'Episode' || item.MediaType === 'Photo') && options.originalAirDate !== false) { if (item.PremiereDate) { @@ -143,7 +143,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater text = datetime.toLocaleDateString(date); miscInfo.push(text); } catch (e) { - console.log("Error parsing date: " + item.PremiereDate); + console.error('error parsing date: ' + item.PremiereDate); } } } @@ -171,18 +171,18 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater text = datetime.toLocaleDateString(date); miscInfo.push(text); - if (item.Type !== "Recording") { + if (item.Type !== 'Recording') { text = datetime.getDisplayTime(date); miscInfo.push(text); } } catch (e) { - console.log("Error parsing date: " + item.StartDate); + console.error('error parsing date: ' + item.StartDate); } } - if (options.year !== false && item.ProductionYear && item.Type === "Series") { + if (options.year !== false && item.ProductionYear && item.Type === 'Series') { - if (item.Status === "Continuing") { + if (item.Status === 'Continuing') { miscInfo.push(globalize.translate('SeriesYearToPresent', item.ProductionYear)); } else if (item.ProductionYear) { @@ -196,11 +196,11 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater var endYear = datetime.parseISO8601Date(item.EndDate).getFullYear(); if (endYear !== item.ProductionYear) { - text += "-" + datetime.parseISO8601Date(item.EndDate).getFullYear(); + text += '-' + datetime.parseISO8601Date(item.EndDate).getFullYear(); } } catch (e) { - console.log("Error parsing date: " + item.EndDate); + console.error('error parsing date: ' + item.EndDate); } } @@ -248,7 +248,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater text = globalize.translate('OriginalAirDateValue', datetime.toLocaleDateString(date)); miscInfo.push(text); } catch (e) { - console.log("Error parsing date: " + item.PremiereDate); + console.error('error parsing date: ' + item.PremiereDate); } } else if (item.ProductionYear) { miscInfo.push(item.ProductionYear); @@ -256,7 +256,7 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater } 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.Type !== 'Series' && item.Type !== 'Episode' && item.Type !== 'Person' && item.MediaType !== 'Photo' && item.Type !== 'Program' && item.Type !== 'Season') { if (item.ProductionYear) { @@ -267,15 +267,15 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater text = datetime.parseISO8601Date(item.PremiereDate).getFullYear(); miscInfo.push(text); } catch (e) { - console.log("Error parsing date: " + item.PremiereDate); + console.error('error parsing date: ' + item.PremiereDate); } } } } - if (item.RunTimeTicks && item.Type !== "Series" && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { + if (item.RunTimeTicks && item.Type !== 'Series' && item.Type !== 'Program' && !showFolderRuntime && options.runtime !== false) { - if (item.Type === "Audio") { + if (item.Type === 'Audio') { miscInfo.push(datetime.getDisplayRunningTime(item.RunTimeTicks)); @@ -284,11 +284,11 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater minutes = minutes || 1; - miscInfo.push(Math.round(minutes) + " mins"); + miscInfo.push(Math.round(minutes) + ' mins'); } } - if (item.OfficialRating && item.Type !== "Season" && item.Type !== "Episode") { + if (item.OfficialRating && item.Type !== 'Season' && item.Type !== 'Episode') { miscInfo.push({ text: item.OfficialRating, cssClass: 'mediaInfoOfficialRating' @@ -296,11 +296,11 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater } if (item.Video3DFormat) { - miscInfo.push("3D"); + miscInfo.push('3D'); } if (item.MediaType === 'Photo' && item.Width && item.Height) { - miscInfo.push(item.Width + "x" + item.Height); + miscInfo.push(item.Width + 'x' + item.Height); } if (options.container !== false && item.Type === 'Audio' && item.Container) { @@ -385,16 +385,13 @@ define(['datetime', 'globalize', 'appRouter', 'itemHelper', 'indicators', 'mater } function getStarIconsHtml(item) { - var html = ''; - var rating = item.CommunityRating; - - if (rating) { + if (item.CommunityRating) { html += '
'; - html += 'star'; - html += rating; + html += ''; + html += item.CommunityRating.toFixed(1); html += '
'; } diff --git a/src/components/mediainfo/rotten.png b/src/components/mediainfo/rotten.png deleted file mode 100644 index 8f81822a9d..0000000000 Binary files a/src/components/mediainfo/rotten.png and /dev/null differ diff --git a/src/components/medialibrarycreator/medialibrarycreator.js b/src/components/medialibrarycreator/medialibrarycreator.js index 183e22551f..450f5a64e6 100644 --- a/src/components/medialibrarycreator/medialibrarycreator.js +++ b/src/components/medialibrarycreator/medialibrarycreator.js @@ -1,37 +1,44 @@ -define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionseditor/libraryoptionseditor", "emby-toggle", "emby-input", "emby-select", "paper-icon-button-light", "listViewStyle", "formDialogStyle", "emby-button", "flexStyles"], function(loading, dialogHelper, dom, $, libraryoptionseditor) { - "use strict"; +define(['loading', 'dialogHelper', 'dom', 'jQuery', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-toggle', 'emby-input', 'emby-select', 'paper-icon-button-light', 'listViewStyle', 'formDialogStyle', 'emby-button', 'flexStyles'], function (loading, dialogHelper, dom, $, libraryoptionseditor, globalize) { + 'use strict'; function onAddLibrary() { - if (isCreating) return false; + if (isCreating) { + return false; + } if (pathInfos.length == 0) { - require(["alert"], function(alert) { + require(['alert'], function (alert) { alert({ - text: Globalize.translate("PleaseAddAtLeastOneFolder"), - type: "error" - }) + text: globalize.translate('PleaseAddAtLeastOneFolder'), + type: 'error' + }); }); + return false; } isCreating = true; loading.show(); + var dlg = dom.parentWithClass(this, 'dlg-librarycreator'); + var name = $('#txtValue', dlg).val(); + var type = $('#selectCollectionType', dlg).val(); - var dlg = dom.parentWithClass(this, "dlg-librarycreator"); - var name = $("#txtValue", dlg).val(); - var type = $("#selectCollectionType", dlg).val(); - if (type == "mixed") type = null; - var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector(".libraryOptions")); + if (type == 'mixed') { + type = null; + } + + var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions')); libraryOptions.PathInfos = pathInfos; - ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(function() { + ApiClient.addVirtualFolder(name, type, currentOptions.refresh, libraryOptions).then(function () { hasChanges = true; isCreating = false; loading.hide(); dialogHelper.close(dlg); - }, function() { - require(["toast"], function(toast) { - toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder")); + }, function () { + require(['toast'], function (toast) { + toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder')); }); + isCreating = false; loading.hide(); }); @@ -39,96 +46,122 @@ define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionsed } function getCollectionTypeOptionsHtml(collectionTypeOptions) { - return collectionTypeOptions.map(function(i) { - return '"; - }).join(""); + return collectionTypeOptions.map(function (i) { + return ''; + }).join(''); } function initEditor(page, collectionTypeOptions) { - $("#selectCollectionType", page).html(getCollectionTypeOptionsHtml(collectionTypeOptions)).val("").on("change", function() { + $('#selectCollectionType', page).html(getCollectionTypeOptionsHtml(collectionTypeOptions)).val('').on('change', function () { var value = this.value; - var dlg = $(this).parents(".dialog")[0]; - libraryoptionseditor.setContentType(dlg.querySelector(".libraryOptions"), value == "mixed" ? "" : value); + var dlg = $(this).parents('.dialog')[0]; + libraryoptionseditor.setContentType(dlg.querySelector('.libraryOptions'), value == 'mixed' ? '' : value); + if (value) { - dlg.querySelector(".libraryOptions").classList.remove("hide"); + dlg.querySelector('.libraryOptions').classList.remove('hide'); } else { - dlg.querySelector(".libraryOptions").classList.add("hide"); + dlg.querySelector('.libraryOptions').classList.add('hide'); } - if (value != "mixed") { + if (value != 'mixed') { var index = this.selectedIndex; + if (index != -1) { - var name = this.options[index].innerHTML.replace("*", "").replace("&", "&"); - $("#txtValue", dlg).val(name); - var folderOption = collectionTypeOptions.filter(function(i) { - return i.value == value + var name = this.options[index].innerHTML.replace('*', '').replace('&', '&'); + $('#txtValue', dlg).val(name); + var folderOption = collectionTypeOptions.filter(function (i) { + return i.value == value; })[0]; - $(".collectionTypeFieldDescription", dlg).html(folderOption.message || "") + $('.collectionTypeFieldDescription', dlg).html(folderOption.message || ''); } } }); - - page.querySelector(".btnAddFolder").addEventListener("click", onAddButtonClick); - page.querySelector(".btnSubmit").addEventListener("click", onAddLibrary); - page.querySelector(".folderList").addEventListener("click", onRemoveClick); - page.querySelector(".chkAdvanced").addEventListener("change", onToggleAdvancedChange); + page.querySelector('.btnAddFolder').addEventListener('click', onAddButtonClick); + page.querySelector('.btnSubmit').addEventListener('click', onAddLibrary); + page.querySelector('.folderList').addEventListener('click', onRemoveClick); + page.querySelector('.chkAdvanced').addEventListener('change', onToggleAdvancedChange); } function onToggleAdvancedChange() { - var dlg = dom.parentWithClass(this, "dlg-librarycreator"); - libraryoptionseditor.setAdvancedVisible(dlg.querySelector(".libraryOptions"), this.checked); + var dlg = dom.parentWithClass(this, 'dlg-librarycreator'); + libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked); } function onAddButtonClick() { - var page = dom.parentWithClass(this, "dlg-librarycreator"); - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; + var page = dom.parentWithClass(this, 'dlg-librarycreator'); + + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); picker.show({ enableNetworkSharePath: true, - callback: function(path, networkSharePath) { - path && addMediaLocation(page, path, networkSharePath); + callback: function (path, networkSharePath) { + if (path) { + addMediaLocation(page, path, networkSharePath); + } + picker.close(); } - }) - }) + }); + }); } function getFolderHtml(pathInfo, index) { - var html = ""; - return html += '
', html += '
', html += '
' + pathInfo.Path + "
", pathInfo.NetworkPath && (html += '
' + pathInfo.NetworkPath + "
"), html += "
", html += '', html += "
" + var html = ''; + html += '
'; + html += '
'; + html += '
' + pathInfo.Path + '
'; + + if (pathInfo.NetworkPath) { + html += '
' + pathInfo.NetworkPath + '
'; + } + + html += '
'; + html += ''; + html += '
'; + return html; } function renderPaths(page) { - var foldersHtml = pathInfos.map(getFolderHtml).join(""); - var folderList = page.querySelector(".folderList"); + var foldersHtml = pathInfos.map(getFolderHtml).join(''); + var folderList = page.querySelector('.folderList'); folderList.innerHTML = foldersHtml; - foldersHtml ? folderList.classList.remove("hide") : folderList.classList.add("hide"); + + if (foldersHtml) { + folderList.classList.remove('hide'); + } else { + folderList.classList.add('hide'); + } } function addMediaLocation(page, path, networkSharePath) { var pathLower = path.toLowerCase(); - var pathFilter = pathInfos.filter(function(p) { + var pathFilter = pathInfos.filter(function (p) { return p.Path.toLowerCase() == pathLower; }); + if (!pathFilter.length) { var pathInfo = { Path: path }; - networkSharePath && (pathInfo.NetworkPath = networkSharePath); + + if (networkSharePath) { + pathInfo.NetworkPath = networkSharePath; + } + pathInfos.push(pathInfo); renderPaths(page); } } function onRemoveClick(e) { - var button = dom.parentWithClass(e.target, "btnRemovePath"); - var index = parseInt(button.getAttribute("data-index")); + var button = dom.parentWithClass(e.target, 'btnRemovePath'); + var index = parseInt(button.getAttribute('data-index')); var location = pathInfos[index].Path; var locationLower = location.toLowerCase(); - pathInfos = pathInfos.filter(function(p) { + pathInfos = pathInfos.filter(function (p) { return p.Path.toLowerCase() != locationLower; }); - renderPaths(dom.parentWithClass(button, "dlg-librarycreator")); + renderPaths(dom.parentWithClass(button, 'dlg-librarycreator')); } function onDialogClosed() { @@ -136,54 +169,54 @@ define(["loading", "dialogHelper", "dom", "jQuery", "components/libraryoptionsed } function initLibraryOptions(dlg) { - libraryoptionseditor.embed(dlg.querySelector(".libraryOptions")).then(function() { - $("#selectCollectionType", dlg).trigger("change"); - onToggleAdvancedChange.call(dlg.querySelector(".chkAdvanced")); - }) + libraryoptionseditor.embed(dlg.querySelector('.libraryOptions')).then(function () { + $('#selectCollectionType', dlg).trigger('change'); + onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced')); + }); } function editor() { - this.show = function(options) { - return new Promise(function(resolve, reject) { + this.show = function (options) { + return new Promise(function (resolve, reject) { currentOptions = options; currentResolve = resolve; hasChanges = false; - var xhr = new XMLHttpRequest; - xhr.open("GET", "components/medialibrarycreator/medialibrarycreator.template.html", true); - xhr.onload = function(e) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'components/medialibrarycreator/medialibrarycreator.template.html', true); + + xhr.onload = function (e) { var template = this.response; var dlg = dialogHelper.createDialog({ - size: "medium-tall", + size: 'medium-tall', modal: false, removeOnClose: true, scrollY: false }); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - dlg.classList.add("dlg-librarycreator"); - dlg.classList.add("formDialog"); - dlg.innerHTML = Globalize.translateDocument(template); + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + dlg.classList.add('dlg-librarycreator'); + dlg.classList.add('formDialog'); + dlg.innerHTML = globalize.translateDocument(template); initEditor(dlg, options.collectionTypeOptions); - dlg.addEventListener("close", onDialogClosed); + dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); - dlg.querySelector(".btnCancel").addEventListener("click", function() { - dialogHelper.close(dlg) + dlg.querySelector('.btnCancel').addEventListener('click', function () { + dialogHelper.close(dlg); }); pathInfos = []; renderPaths(dlg); initLibraryOptions(dlg); }; + xhr.send(); }); - } + }; } var pathInfos = []; var currentResolve; var currentOptions; - var hasChanges = false; var isCreating = false; - - return editor + return editor; }); diff --git a/src/components/medialibrarycreator/medialibrarycreator.template.html b/src/components/medialibrarycreator/medialibrarycreator.template.html index c7073bc9f2..f92a63e403 100644 --- a/src/components/medialibrarycreator/medialibrarycreator.template.html +++ b/src/components/medialibrarycreator/medialibrarycreator.template.html @@ -1,5 +1,5 @@
- +

${ButtonAddMediaLibrary}

@@ -26,7 +26,7 @@

${HeadersFolders}

diff --git a/src/components/medialibraryeditor/medialibraryeditor.js b/src/components/medialibraryeditor/medialibraryeditor.js index a1ee53f72b..3141509629 100644 --- a/src/components/medialibraryeditor/medialibraryeditor.js +++ b/src/components/medialibraryeditor/medialibraryeditor.js @@ -1,22 +1,22 @@ -define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionseditor/libraryoptionseditor", "emby-button", "listViewStyle", "paper-icon-button-light", "formDialogStyle", "emby-toggle", "flexStyles"], function(jQuery, loading, dialogHelper, dom, libraryoptionseditor) { - "use strict"; +define(['jQuery', 'loading', 'dialogHelper', 'dom', 'components/libraryoptionseditor/libraryoptionseditor', 'globalize', 'emby-button', 'listViewStyle', 'paper-icon-button-light', 'formDialogStyle', 'emby-toggle', 'flexStyles'], function (jQuery, loading, dialogHelper, dom, libraryoptionseditor, globalize) { + 'use strict'; function onEditLibrary() { - if (isCreating) return false; + if (isCreating) { + return false; + } isCreating = true; loading.show(); - - var dlg = dom.parentWithClass(this, "dlg-libraryeditor"); - var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector(".libraryOptions")); + var dlg = dom.parentWithClass(this, 'dlg-libraryeditor'); + var libraryOptions = libraryoptionseditor.getLibraryOptions(dlg.querySelector('.libraryOptions')); libraryOptions = Object.assign(currentOptions.library.LibraryOptions || {}, libraryOptions); - - ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(function() { + ApiClient.updateVirtualFolderOptions(currentOptions.library.ItemId, libraryOptions).then(function () { hasChanges = true; isCreating = false; loading.hide(); dialogHelper.close(dlg); - }, function() { + }, function () { isCreating = false; loading.hide(); }); @@ -26,12 +26,12 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed function addMediaLocation(page, path, networkSharePath) { var virtualFolder = currentOptions.library; var refreshAfterChange = currentOptions.refresh; - ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(function() { + ApiClient.addMediaPath(virtualFolder.Name, path, networkSharePath, refreshAfterChange).then(function () { hasChanges = true; refreshLibraryFromServer(page); - }, function() { - require(["toast"], function(toast) { - toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder")); + }, function () { + require(['toast'], function (toast) { + toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder')); }); }); } @@ -41,12 +41,12 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed ApiClient.updateMediaPath(virtualFolder.Name, { Path: path, NetworkPath: networkSharePath - }).then(function() { + }).then(function () { hasChanges = true; refreshLibraryFromServer(page); - }, function() { - require(["toast"], function(toast) { - toast(Globalize.translate("ErrorAddingMediaPathToVirtualFolder")); + }, function () { + require(['toast'], function (toast) { + toast(globalize.translate('ErrorAddingMediaPathToVirtualFolder')); }); }); } @@ -54,20 +54,21 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed function onRemoveClick(btnRemovePath, location) { var button = btnRemovePath; var virtualFolder = currentOptions.library; - require(["confirm"], function(confirm) { + + require(['confirm'], function (confirm) { confirm({ - title: Globalize.translate("HeaderRemoveMediaLocation"), - text: Globalize.translate("MessageConfirmRemoveMediaLocation"), - confirmText: Globalize.translate("ButtonDelete"), - primary: "delete" - }).then(function() { + title: globalize.translate('HeaderRemoveMediaLocation'), + text: globalize.translate('MessageConfirmRemoveMediaLocation'), + confirmText: globalize.translate('ButtonDelete'), + primary: 'delete' + }).then(function () { var refreshAfterChange = currentOptions.refresh; - ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function() { + ApiClient.removeMediaPath(virtualFolder.Name, location, refreshAfterChange).then(function () { hasChanges = true; - refreshLibraryFromServer(dom.parentWithClass(button, "dlg-libraryeditor")); - }, function() { - require(["toast"], function(toast) { - toast(Globalize.translate("DefaultErrorMessage")); + refreshLibraryFromServer(dom.parentWithClass(button, 'dlg-libraryeditor')); + }, function () { + require(['toast'], function (toast) { + toast(globalize.translate('DefaultErrorMessage')); }); }); }); @@ -75,39 +76,48 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed } function onListItemClick(e) { - var listItem = dom.parentWithClass(e.target, "listItem"); + var listItem = dom.parentWithClass(e.target, 'listItem'); + if (listItem) { - var index = parseInt(listItem.getAttribute("data-index")); + var index = parseInt(listItem.getAttribute('data-index')); var pathInfos = (currentOptions.library.LibraryOptions || {}).PathInfos || []; var pathInfo = null == index ? {} : pathInfos[index] || {}; var originalPath = pathInfo.Path || (null == index ? null : currentOptions.library.Locations[index]); - var btnRemovePath = dom.parentWithClass(e.target, "btnRemovePath"); - if (btnRemovePath) return void onRemoveClick(btnRemovePath, originalPath); - showDirectoryBrowser(dom.parentWithClass(listItem, "dlg-libraryeditor"), originalPath, pathInfo.NetworkPath); + var btnRemovePath = dom.parentWithClass(e.target, 'btnRemovePath'); + + if (btnRemovePath) { + onRemoveClick(btnRemovePath, originalPath); + return; + } + + showDirectoryBrowser(dom.parentWithClass(listItem, 'dlg-libraryeditor'), originalPath, pathInfo.NetworkPath); } } function getFolderHtml(pathInfo, index) { - var html = ""; + var html = ''; html += '
'; - html += '
'; + html += '
'; html += '

'; html += pathInfo.Path; - html += "

"; + html += ''; + if (pathInfo.NetworkPath) { - html += '
' + pathInfo.NetworkPath + "
"; + html += '
' + pathInfo.NetworkPath + '
'; } - html += "
"; - html += ''; - html += "
"; + + html += '
'; + html += ''; + html += '
'; return html; } function refreshLibraryFromServer(page) { - ApiClient.getVirtualFolders().then(function(result) { - var library = result.filter(function(f) { - return f.Name === currentOptions.library.Name + ApiClient.getVirtualFolders().then(function (result) { + var library = result.filter(function (f) { + return f.Name === currentOptions.library.Name; })[0]; + if (library) { currentOptions.library = library; renderLibrary(page, currentOptions); @@ -117,52 +127,64 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed function renderLibrary(page, options) { var pathInfos = (options.library.LibraryOptions || {}).PathInfos || []; - pathInfos.length || (pathInfos = options.library.Locations.map(function(p) { - return { - Path: p - } - })); - if (options.library.CollectionType === 'boxsets') { - page.querySelector(".folders").classList.add("hide"); - } else { - page.querySelector(".folders").classList.remove("hide"); + + if (!pathInfos.length) { + pathInfos = options.library.Locations.map(function (p) { + return { + Path: p + }; + }); } - page.querySelector(".folderList").innerHTML = pathInfos.map(getFolderHtml).join(""); + + if (options.library.CollectionType === 'boxsets') { + page.querySelector('.folders').classList.add('hide'); + } else { + page.querySelector('.folders').classList.remove('hide'); + } + + page.querySelector('.folderList').innerHTML = pathInfos.map(getFolderHtml).join(''); } function onAddButtonClick() { - showDirectoryBrowser(dom.parentWithClass(this, "dlg-libraryeditor")); + showDirectoryBrowser(dom.parentWithClass(this, 'dlg-libraryeditor')); } function showDirectoryBrowser(context, originalPath, networkPath) { - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); picker.show({ - enableNetworkSharePath: !0, + enableNetworkSharePath: true, pathReadOnly: null != originalPath, path: originalPath, networkSharePath: networkPath, - callback: function(path, networkSharePath) { - path && (originalPath ? updateMediaLocation(context, originalPath, networkSharePath) : addMediaLocation(context, path, networkSharePath)); + callback: function (path, networkSharePath) { + if (path) { + if (originalPath) { + updateMediaLocation(context, originalPath, networkSharePath); + } else { + addMediaLocation(context, path, networkSharePath); + } + } + picker.close(); } - }) - }) + }); + }); } function onToggleAdvancedChange() { - var dlg = dom.parentWithClass(this, "dlg-libraryeditor"); - libraryoptionseditor.setAdvancedVisible(dlg.querySelector(".libraryOptions"), this.checked) + var dlg = dom.parentWithClass(this, 'dlg-libraryeditor'); + libraryoptionseditor.setAdvancedVisible(dlg.querySelector('.libraryOptions'), this.checked); } function initEditor(dlg, options) { renderLibrary(dlg, options); - dlg.querySelector(".btnAddFolder").addEventListener("click", onAddButtonClick); - dlg.querySelector(".folderList").addEventListener("click", onListItemClick); - dlg.querySelector(".chkAdvanced").addEventListener("change", onToggleAdvancedChange); - dlg.querySelector(".btnSubmit").addEventListener("click", onEditLibrary); - libraryoptionseditor.embed(dlg.querySelector(".libraryOptions"), options.library.CollectionType, options.library.LibraryOptions).then(function() { - onToggleAdvancedChange.call(dlg.querySelector(".chkAdvanced")); + dlg.querySelector('.btnAddFolder').addEventListener('click', onAddButtonClick); + dlg.querySelector('.folderList').addEventListener('click', onListItemClick); + dlg.querySelector('.chkAdvanced').addEventListener('change', onToggleAdvancedChange); + dlg.querySelector('.btnSubmit').addEventListener('click', onEditLibrary); + libraryoptionseditor.embed(dlg.querySelector('.libraryOptions'), options.library.CollectionType, options.library.LibraryOptions).then(function () { + onToggleAdvancedChange.call(dlg.querySelector('.chkAdvanced')); }); } @@ -171,45 +193,45 @@ define(["jQuery", "loading", "dialogHelper", "dom", "components/libraryoptionsed } function editor() { - this.show = function(options) { + this.show = function (options) { var deferred = jQuery.Deferred(); currentOptions = options; currentDeferred = deferred; hasChanges = false; - var xhr = new XMLHttpRequest; - xhr.open("GET", "components/medialibraryeditor/medialibraryeditor.template.html", true); - xhr.onload = function(e) { + var xhr = new XMLHttpRequest(); + xhr.open('GET', 'components/medialibraryeditor/medialibraryeditor.template.html', true); + + xhr.onload = function (e) { var template = this.response; var dlg = dialogHelper.createDialog({ - size: "medium-tall", + size: 'medium-tall', modal: false, removeOnClose: true, scrollY: false }); - dlg.classList.add("dlg-libraryeditor"); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - dlg.classList.add("formDialog"); - dlg.innerHTML = Globalize.translateDocument(template); - dlg.querySelector(".formDialogHeaderTitle").innerHTML = options.library.Name; + dlg.classList.add('dlg-libraryeditor'); + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + dlg.classList.add('formDialog'); + dlg.innerHTML = globalize.translateDocument(template); + dlg.querySelector('.formDialogHeaderTitle').innerHTML = options.library.Name; initEditor(dlg, options); - dlg.addEventListener("close", onDialogClosed); + dlg.addEventListener('close', onDialogClosed); dialogHelper.open(dlg); - dlg.querySelector(".btnCancel").addEventListener("click", function() { + dlg.querySelector('.btnCancel').addEventListener('click', function () { dialogHelper.close(dlg); }); refreshLibraryFromServer(dlg); }; + xhr.send(); return deferred.promise(); - } + }; } var currentDeferred; var currentOptions; - var hasChanges = false; var isCreating = false; - return editor; }); diff --git a/src/components/medialibraryeditor/medialibraryeditor.template.html b/src/components/medialibraryeditor/medialibraryeditor.template.html index dd13df4ca5..6c814cf2dd 100644 --- a/src/components/medialibraryeditor/medialibraryeditor.template.html +++ b/src/components/medialibraryeditor/medialibraryeditor.template.html @@ -1,5 +1,5 @@
- +

@@ -20,7 +20,7 @@

${HeadersFolders}

diff --git a/src/components/metadataeditor/metadataeditor.js b/src/components/metadataeditor/metadataeditor.js index 8843dc159c..e1c1c8001f 100644 --- a/src/components/metadataeditor/metadataeditor.js +++ b/src/components/metadataeditor/metadataeditor.js @@ -142,9 +142,9 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi 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) { + Genres: getListValues(form.querySelector('#listGenres')), + Tags: getListValues(form.querySelector('#listTags')), + Studios: getListValues(form.querySelector('#listStudios')).map(function (element) { return { Name: element }; }), @@ -158,7 +158,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi OfficialRating: form.querySelector('#selectOfficialRating').value, CustomRating: form.querySelector('#selectCustomRating').value, People: currentItem.People, - LockData: form.querySelector("#chkLockData").checked, + LockData: form.querySelector('#chkLockData').checked, LockedFields: Array.prototype.filter.call(form.querySelectorAll('.selectLockedField'), function (c) { return !c.checked; }).map(function (c) { @@ -177,14 +177,14 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi item.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value; item.PreferredMetadataCountryCode = form.querySelector('#selectCountry').value; - if (currentItem.Type === "Person") { + if (currentItem.Type === 'Person') { var placeOfBirth = form.querySelector('#txtPlaceOfBirth').value; item.ProductionLocations = placeOfBirth ? [placeOfBirth] : []; } - if (currentItem.Type === "Series") { + if (currentItem.Type === 'Series') { // 600000000 var seriesRuntime = form.querySelector('#txtSeriesRuntime').value; @@ -356,7 +356,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi form.removeEventListener('submit', onSubmit); form.addEventListener('submit', onSubmit); - context.querySelector("#btnAddPerson").addEventListener('click', function (event, data) { + context.querySelector('#btnAddPerson').addEventListener('click', function (event, data) { editPerson(context, {}, -1); }); @@ -403,7 +403,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi function populateCountries(select, allCountries) { - var html = ""; + var html = ''; html += ""; @@ -411,7 +411,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi var culture = allCountries[i]; - html += ""; + html += "'; } select.innerHTML = html; @@ -419,7 +419,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi function populateLanguages(select, languages) { - var html = ""; + var html = ''; html += ""; @@ -427,7 +427,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi var culture = languages[i]; - html += ""; + html += "'; } select.innerHTML = html; @@ -462,10 +462,15 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi var idInfo = externalIds[i]; - var id = "txt1" + idInfo.Key; + var id = 'txt1' + idInfo.Key; var formatString = idInfo.UrlFormatString || ''; - var labelText = globalize.translate('LabelDynamicExternalId').replace('{0}', idInfo.Name); + var fullName = idInfo.Name; + if (idInfo.Type) { + fullName = idInfo.Name + ' ' + globalize.translate(idInfo.Type); + } + + var labelText = globalize.translate('LabelDynamicExternalId', fullName); html += '
'; html += '
'; @@ -477,7 +482,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi html += '
'; if (formatString) { - html += ''; + html += ''; } html += '
'; @@ -539,37 +544,37 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi hideElement('#fldPath', context); } - if (item.Type === "Series" || item.Type === "Movie" || item.Type === "Trailer") { + if (item.Type === 'Series' || item.Type === 'Movie' || item.Type === 'Trailer') { showElement('#fldOriginalName', context); } else { hideElement('#fldOriginalName', context); } - if (item.Type === "Series") { + if (item.Type === 'Series') { showElement('#fldSeriesRuntime', context); } else { hideElement('#fldSeriesRuntime', context); } - if (item.Type === "Series" || item.Type === "Person") { + if (item.Type === 'Series' || item.Type === 'Person') { showElement('#fldEndDate', context); } else { hideElement('#fldEndDate', context); } - if (item.Type === "MusicAlbum") { + if (item.Type === 'MusicAlbum') { showElement('#albumAssociationMessage', context); } else { hideElement('#albumAssociationMessage', context); } - if (item.Type === "Movie" || item.Type === "Trailer") { + if (item.Type === 'Movie' || item.Type === 'Trailer') { showElement('#fldCriticRating', context); } else { hideElement('#fldCriticRating', context); } - if (item.Type === "Series") { + if (item.Type === 'Series') { showElement('#fldStatus', context); showElement('#fldAirDays', context); showElement('#fldAirTime', context); @@ -579,19 +584,19 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi hideElement('#fldAirTime', context); } - if (item.MediaType === "Video" && item.Type !== "TvChannel") { + if (item.MediaType === 'Video' && item.Type !== 'TvChannel') { showElement('#fld3dFormat', context); } else { hideElement('#fld3dFormat', context); } - if (item.Type === "Audio") { + if (item.Type === 'Audio') { showElement('#fldAlbumArtist', context); } else { hideElement('#fldAlbumArtist', context); } - if (item.Type === "Audio" || item.Type === "MusicVideo") { + if (item.Type === 'Audio' || item.Type === 'MusicVideo') { showElement('#fldArtist', context); showElement('#fldAlbum', context); } else { @@ -599,29 +604,29 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi hideElement('#fldAlbum', context); } - if (item.Type === "Episode" && item.ParentIndexNumber === 0) { + 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 === "MusicGenre" || - item.Type === "TvChannel" || - item.Type === "Book") { + if (item.Type === 'Person' || + item.Type === 'Genre' || + item.Type === 'Studio' || + 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 === "MusicGenre" || item.Type === "TvChannel") { + if (item.Type === 'Person' || item.Type === 'Genre' || item.Type === 'Studio' || item.Type === 'MusicGenre' || item.Type === 'TvChannel') { hideElement('#fldCommunityRating', context); hideElement('#genresCollapsible', context); hideElement('#studiosCollapsible', context); - if (item.Type === "TvChannel") { + if (item.Type === 'TvChannel') { showElement('#fldOfficialRating', context); } else { hideElement('#fldOfficialRating', context); @@ -637,7 +642,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi showElement('#tagsCollapsible', context); - if (item.Type === "TvChannel") { + if (item.Type === 'TvChannel') { hideElement('#metadataSettingsCollapsible', context); hideElement('#fldPremiereDate', context); hideElement('#fldDateAdded', context); @@ -649,39 +654,39 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi showElement('#fldYear', context); } - if (item.Type === "TvChannel") { + if (item.Type === 'TvChannel') { hideElement('.overviewContainer', context); } else { showElement('.overviewContainer', context); } - if (item.Type === "Person") { + if (item.Type === 'Person') { //todo context.querySelector('#txtProductionYear').label(globalize.translate('LabelBirthYear')); - context.querySelector("#txtPremiereDate").label(globalize.translate('LabelBirthDate')); - context.querySelector("#txtEndDate").label(globalize.translate('LabelDeathDate')); + context.querySelector('#txtPremiereDate').label(globalize.translate('LabelBirthDate')); + context.querySelector('#txtEndDate').label(globalize.translate('LabelDeathDate')); showElement('#fldPlaceOfBirth'); } else { context.querySelector('#txtProductionYear').label(globalize.translate('LabelYear')); - context.querySelector("#txtPremiereDate").label(globalize.translate('LabelReleaseDate')); - context.querySelector("#txtEndDate").label(globalize.translate('LabelEndDate')); + context.querySelector('#txtPremiereDate').label(globalize.translate('LabelReleaseDate')); + context.querySelector('#txtEndDate').label(globalize.translate('LabelEndDate')); hideElement('#fldPlaceOfBirth'); } - if (item.MediaType === "Video" && item.Type !== "TvChannel") { + if (item.MediaType === 'Video' && item.Type !== 'TvChannel') { showElement('#fldOriginalAspectRatio'); } else { hideElement('#fldOriginalAspectRatio'); } - if (item.Type === "Audio" || item.Type === "Episode" || item.Type === "Season") { + if (item.Type === 'Audio' || item.Type === 'Episode' || item.Type === 'Season') { showElement('#fldIndexNumber'); - if (item.Type === "Episode") { + if (item.Type === 'Episode') { context.querySelector('#txtIndexNumber').label(globalize.translate('LabelEpisodeNumber')); - } else if (item.Type === "Season") { + } else if (item.Type === 'Season') { context.querySelector('#txtIndexNumber').label(globalize.translate('LabelSeasonNumber')); - } else if (item.Type === "Audio") { + } else if (item.Type === 'Audio') { context.querySelector('#txtIndexNumber').label(globalize.translate('LabelTrackNumber')); } else { context.querySelector('#txtIndexNumber').label(globalize.translate('LabelNumber')); @@ -690,12 +695,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi hideElement('#fldIndexNumber'); } - if (item.Type === "Audio" || item.Type === "Episode") { + if (item.Type === 'Audio' || item.Type === 'Episode') { showElement('#fldParentIndexNumber'); - if (item.Type === "Episode") { + if (item.Type === 'Episode') { context.querySelector('#txtParentIndexNumber').label(globalize.translate('LabelSeasonNumber')); - } else if (item.Type === "Audio") { + } else if (item.Type === 'Audio') { context.querySelector('#txtParentIndexNumber').label(globalize.translate('LabelDiscNumber')); } else { context.querySelector('#txtParentIndexNumber').label(globalize.translate('LabelParentNumber')); @@ -704,12 +709,12 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi hideElement('#fldParentIndexNumber', context); } - if (item.Type === "BoxSet") { + if (item.Type === 'BoxSet') { showElement('#fldDisplayOrder', context); hideElement('.seriesDisplayOrderDescription', context); context.querySelector('#selectDisplayOrder').innerHTML = ''; - } else if (item.Type === "Series") { + } else if (item.Type === 'Series') { showElement('#fldDisplayOrder', context); showElement('.seriesDisplayOrderDescription', context); @@ -726,19 +731,19 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi populateRatings(parentalRatingOptions, select, item.OfficialRating); - select.value = item.OfficialRating || ""; + select.value = item.OfficialRating || ''; select = context.querySelector('#selectCustomRating'); populateRatings(parentalRatingOptions, select, item.CustomRating); - select.value = item.CustomRating || ""; + select.value = item.CustomRating || ''; var selectStatus = context.querySelector('#selectStatus'); populateStatus(selectStatus); - selectStatus.value = item.Status || ""; + selectStatus.value = item.Status || ''; - context.querySelector('#select3dFormat', context).value = item.Video3DFormat || ""; + 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; @@ -754,7 +759,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi populateListView(context.querySelector('#listTags'), item.Tags); var lockData = (item.LockData || false); - var chkLockData = context.querySelector("#chkLockData"); + var chkLockData = context.querySelector('#chkLockData'); chkLockData.checked = lockData; if (chkLockData.checked) { hideElement('.providerSettingsContainer', context); @@ -764,33 +769,29 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi 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('#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('#txtSortName').value = item.ForcedSortName || ''; + context.querySelector('#txtCommunityRating').value = item.CommunityRating || ''; - context.querySelector('#txtCriticRating').value = item.CriticRating || ""; + 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('#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('#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('#selectDisplayOrder').value = item.DisplayOrder || ''; context.querySelector('#txtArtist').value = (item.ArtistItems || []).map(function (a) { return a.Name; @@ -834,17 +835,17 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi context.querySelector('#txtEndDate').value = ''; } - context.querySelector('#txtProductionYear').value = item.ProductionYear || ""; + 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('#txtOriginalAspectRatio').value = item.AspectRatio || ''; - context.querySelector('#selectLanguage').value = item.PreferredMetadataLanguage || ""; - context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || ""; + context.querySelector('#selectLanguage').value = item.PreferredMetadataLanguage || ''; + context.querySelector('#selectCountry').value = item.PreferredMetadataCountryCode || ''; if (item.RunTimeTicks) { @@ -852,13 +853,13 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi context.querySelector('#txtSeriesRuntime').value = Math.round(minutes); } else { - context.querySelector('#txtSeriesRuntime', context).value = ""; + context.querySelector('#txtSeriesRuntime', context).value = ''; } } function populateRatings(allParentalRatings, select, currentValue) { - var html = ""; + var html = ''; html += ""; @@ -888,18 +889,18 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi rating = ratings[i]; - html += ""; + html += "'; } select.innerHTML = html; } function populateStatus(select) { - var html = ""; + var html = ''; html += ""; - html += ""; - html += ""; + html += "'; + html += "'; select.innerHTML = html; } @@ -917,7 +918,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi for (var i = 0; i < items.length; i++) { html += '
'; - html += 'live_tv'; + html += ''; html += '
'; @@ -927,7 +928,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi html += '
'; - html += ''; + html += ''; html += '
'; } @@ -948,7 +949,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi html += '
'; - html += 'person'; + html += ''; html += '
'; html += ''; html += '
'; - html += ''; + html += ''; html += '
'; } @@ -994,30 +995,30 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi lockedFields = lockedFields || []; var lockedFieldsList = [ - { name: globalize.translate('Name'), value: "Name" }, - { name: globalize.translate('Overview'), value: "Overview" }, - { name: globalize.translate('Genres'), value: "Genres" }, - { name: globalize.translate('ParentalRating'), value: "OfficialRating" }, - { name: globalize.translate('People'), value: "Cast" } + { name: globalize.translate('Name'), value: 'Name' }, + { name: globalize.translate('Overview'), value: 'Overview' }, + { name: globalize.translate('Genres'), value: 'Genres' }, + { name: globalize.translate('ParentalRating'), value: 'OfficialRating' }, + { name: globalize.translate('People'), value: 'Cast' } ]; - if (item.Type === "Person") { - lockedFieldsList.push({ name: globalize.translate('BirthLocation'), value: "ProductionLocations" }); + if (item.Type === 'Person') { + lockedFieldsList.push({ name: globalize.translate('BirthLocation'), value: 'ProductionLocations' }); } else { - lockedFieldsList.push({ name: globalize.translate('ProductionLocations'), value: "ProductionLocations" }); + lockedFieldsList.push({ name: globalize.translate('ProductionLocations'), value: 'ProductionLocations' }); } - if (item.Type === "Series") { - lockedFieldsList.push({ name: globalize.translate('Runtime'), value: "Runtime" }); + if (item.Type === 'Series') { + lockedFieldsList.push({ name: globalize.translate('Runtime'), value: 'Runtime' }); } - lockedFieldsList.push({ name: globalize.translate('Studios'), value: "Studios" }); - lockedFieldsList.push({ name: globalize.translate('Tags'), value: "Tags" }); + lockedFieldsList.push({ name: globalize.translate('Studios'), value: 'Studios' }); + lockedFieldsList.push({ name: globalize.translate('Tags'), value: 'Tags' }); var html = ''; - html += "

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

"; - html += "

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

"; + html += '

' + globalize.translate('HeaderEnabledFields') + '

'; + html += '

' + globalize.translate('HeaderEnabledFieldsHelp') + '

'; html += getLockedFieldsHtml(lockedFieldsList, lockedFields); container.innerHTML = html; } @@ -1046,7 +1047,7 @@ define(['itemHelper', 'dom', 'layoutManager', 'dialogHelper', 'datetime', 'loadi setFieldVisibilities(context, item); fillItemInfo(context, item, metadataEditorInfo.ParentalRatingOptions); - if (item.MediaType === "Video" && item.Type !== "Episode" && item.Type !== "TvChannel") { + if (item.MediaType === 'Video' && item.Type !== 'Episode' && item.Type !== 'TvChannel') { showElement('#fldTagline', context); } else { hideElement('#fldTagline', context); diff --git a/src/components/metadataeditor/metadataeditor.template.html b/src/components/metadataeditor/metadataeditor.template.html index d44136c6b6..39894d4f6f 100644 --- a/src/components/metadataeditor/metadataeditor.template.html +++ b/src/components/metadataeditor/metadataeditor.template.html @@ -1,15 +1,15 @@
- +

${Edit}

@@ -184,7 +184,7 @@ ${Genres}
@@ -193,7 +193,7 @@ ${People}
@@ -203,7 +203,7 @@ ${Studios}
@@ -212,7 +212,7 @@ ${Tags}
diff --git a/src/components/metadataeditor/personeditor.js b/src/components/metadataeditor/personeditor.js index 7883cfca1b..9fb6fdec6f 100644 --- a/src/components/metadataeditor/personeditor.js +++ b/src/components/metadataeditor/personeditor.js @@ -96,4 +96,4 @@ define(['dialogHelper', 'layoutManager', 'globalize', 'require', 'paper-icon-but return { show: show }; -}); \ No newline at end of file +}); diff --git a/src/components/metadataeditor/personeditor.template.html b/src/components/metadataeditor/personeditor.template.html index 75b011aa73..40b29767fa 100644 --- a/src/components/metadataeditor/personeditor.template.html +++ b/src/components/metadataeditor/personeditor.template.html @@ -1,5 +1,5 @@
- +

${Edit}

diff --git a/src/components/multidownload.js b/src/components/multidownload.js index a1881b8db9..d11e52de14 100644 --- a/src/components/multidownload.js +++ b/src/components/multidownload.js @@ -63,4 +63,4 @@ define(['browser'], function (browser) { download(url); }); }; -}); \ No newline at end of file +}); diff --git a/src/components/multiselect/multiselect.css b/src/components/multiselect/multiselect.css index 9c2a58cd20..e9c66c57a4 100644 --- a/src/components/multiselect/multiselect.css +++ b/src/components/multiselect/multiselect.css @@ -4,7 +4,7 @@ left: 0; right: 0; top: 0; - background-color: rgba(0, 0, 0, .3); + background-color: rgba(0, 0, 0, 0.3); z-index: 99998; } @@ -13,7 +13,7 @@ top: 0; left: 0; right: 0; - padding: 1em .5em; + padding: 1em 0.5em; display: flex; align-items: center; z-index: 99999; diff --git a/src/components/multiselect/multiselect.js b/src/components/multiselect/multiselect.js index 6b2906cb0a..70a0924bc1 100644 --- a/src/components/multiselect/multiselect.js +++ b/src/components/multiselect/multiselect.js @@ -1,5 +1,5 @@ -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 = []; @@ -15,12 +15,12 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo selectedItems = []; selectedElements = []; - var elems = document.querySelectorAll(".itemSelectionPanel"); + 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.classList.remove('withMultiSelect'); } } } @@ -28,13 +28,13 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo function onItemSelectionPanelClick(e, itemSelectionPanel) { // toggle the checkbox, if it wasn't clicked on - if (!dom.parentWithClass(e.target, "chkItemSelect")) { - var chkItemSelect = itemSelectionPanel.querySelector(".chkItemSelect"); + if (!dom.parentWithClass(e.target, 'chkItemSelect')) { + var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect'); if (chkItemSelect) { - if (chkItemSelect.classList.contains("checkedInitial")) { - chkItemSelect.classList.remove("checkedInitial"); + if (chkItemSelect.classList.contains('checkedInitial')) { + chkItemSelect.classList.remove('checkedInitial'); } else { var newValue = !chkItemSelect.checked; chkItemSelect.checked = newValue; @@ -50,7 +50,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo 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) { @@ -73,7 +73,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo } if (selectedItems.length) { - var itemSelectionCount = document.querySelector(".itemSelectionCount"); + var itemSelectionCount = document.querySelector('.itemSelectionCount'); if (itemSelectionCount) { itemSelectionCount.innerHTML = selectedItems.length; } @@ -88,27 +88,27 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo function showSelection(item, isChecked) { - var itemSelectionPanel = item.querySelector(".itemSelectionPanel"); + var itemSelectionPanel = item.querySelector('.itemSelectionPanel'); if (!itemSelectionPanel) { - itemSelectionPanel = document.createElement("div"); - itemSelectionPanel.classList.add("itemSelectionPanel"); + itemSelectionPanel = document.createElement('div'); + itemSelectionPanel.classList.add('itemSelectionPanel'); - var parent = item.querySelector(".cardBox") || item.querySelector(".cardContent"); - parent.classList.add("withMultiSelect"); + var parent = item.querySelector('.cardBox') || item.querySelector('.cardContent'); + parent.classList.add('withMultiSelect'); parent.appendChild(itemSelectionPanel); - var cssClass = "chkItemSelect"; + 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"; + cssClass += ' checkedInitial'; } - var checkedAttribute = isChecked ? " checked" : ""; + var checkedAttribute = isChecked ? ' checked' : ''; itemSelectionPanel.innerHTML = ''; - var chkItemSelect = itemSelectionPanel.querySelector(".chkItemSelect"); - chkItemSelect.addEventListener("change", onSelectionChange); + var chkItemSelect = itemSelectionPanel.querySelector('.chkItemSelect'); + chkItemSelect.addEventListener('change', onSelectionChange); } } @@ -118,27 +118,27 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo if (!selectionCommandsPanel) { - selectionCommandsPanel = document.createElement("div"); - selectionCommandsPanel.classList.add("selectionCommandsPanel"); + selectionCommandsPanel = document.createElement('div'); + selectionCommandsPanel.classList.add('selectionCommandsPanel'); document.body.appendChild(selectionCommandsPanel); currentSelectionCommandsPanel = selectionCommandsPanel; - var html = ""; + var html = ''; - html += ''; + html += ''; html += '

'; - var moreIcon = "more_horiz"; - html += ''; + const moreIcon = 'more_horiz'; + html += ''; selectionCommandsPanel.innerHTML = html; - selectionCommandsPanel.querySelector(".btnCloseSelectionPanel").addEventListener("click", hideSelections); + selectionCommandsPanel.querySelector('.btnCloseSelectionPanel').addEventListener('click', hideSelections); - var btnSelectionPanelOptions = selectionCommandsPanel.querySelector(".btnSelectionPanelOptions"); + var btnSelectionPanelOptions = selectionCommandsPanel.querySelector('.btnSelectionPanelOptions'); - dom.addEventListener(btnSelectionPanelOptions, "click", showMenuForSelectedItems, { passive: true }); + dom.addEventListener(btnSelectionPanelOptions, 'click', showMenuForSelectedItems, { passive: true }); } } @@ -146,7 +146,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo return new Promise(function (resolve, reject) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert(options).then(resolve, resolve); }); }); @@ -156,15 +156,15 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo return new Promise(function (resolve, reject) { - var msg = globalize.translate("ConfirmDeleteItem"); - var title = globalize.translate("HeaderDeleteItem"); + var msg = globalize.translate('ConfirmDeleteItem'); + var title = globalize.translate('HeaderDeleteItem'); if (itemIds.length > 1) { - msg = globalize.translate("ConfirmDeleteItems"); - title = globalize.translate("HeaderDeleteItems"); + msg = globalize.translate('ConfirmDeleteItems'); + title = globalize.translate('HeaderDeleteItems'); } - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm(msg, title).then(function () { var promises = itemIds.map(function (itemId) { @@ -173,7 +173,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo Promise.all(promises).then(resolve, function () { - alertText(globalize.translate("ErrorDeletingItem")).then(reject, reject); + alertText(globalize.translate('ErrorDeletingItem')).then(reject, reject); }); }, reject); @@ -190,58 +190,58 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo var menuItems = []; menuItems.push({ - name: globalize.translate("AddToCollection"), - id: "addtocollection", - icon: "add" + name: globalize.translate('AddToCollection'), + id: 'addtocollection', + icon: 'add' }); menuItems.push({ - name: globalize.translate("AddToPlaylist"), - id: "playlist", - icon: "playlist_add" + name: globalize.translate('AddToPlaylist'), + id: 'playlist', + icon: 'playlist_add' }); // TODO: Be more dynamic based on what is selected if (user.Policy.EnableContentDeletion) { menuItems.push({ - name: globalize.translate("Delete"), - id: "delete", - icon: "delete" + name: globalize.translate('Delete'), + id: 'delete', + icon: 'delete' }); } - if (user.Policy.EnableContentDownloading && appHost.supports("filedownload")) { + if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) { menuItems.push({ - name: Globalize.translate("ButtonDownload"), - id: "download", - icon: "file_download" + name: globalize.translate('ButtonDownload'), + id: 'download', + icon: 'file_download' }); } if (user.Policy.IsAdministrator) { menuItems.push({ - name: globalize.translate("GroupVersions"), - id: "groupvideos", - icon: "call_merge" + name: globalize.translate('GroupVersions'), + id: 'groupvideos', + icon: 'call_merge' }); } menuItems.push({ - name: globalize.translate("MarkPlayed"), - id: "markplayed", - icon: "check_box" + name: globalize.translate('MarkPlayed'), + id: 'markplayed', + icon: 'check_box' }); menuItems.push({ - name: globalize.translate("MarkUnplayed"), - id: "markunplayed", - icon: "check_box_outline_blank" + name: globalize.translate('MarkUnplayed'), + id: 'markunplayed', + icon: 'check_box_outline_blank' }); menuItems.push({ - name: globalize.translate("RefreshMetadata"), - id: "refresh", - icon: "refresh" + name: globalize.translate('RefreshMetadata'), + id: 'refresh', + icon: 'refresh' }); require(['actionsheet'], function (actionsheet) { @@ -253,8 +253,8 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo var serverId = apiClient.serverInfo().Id; switch (id) { - case "addtocollection": - require(["collectionEditor"], function (collectionEditor) { + case 'addtocollection': + require(['collectionEditor'], function (collectionEditor) { new collectionEditor().show({ items: items, serverId: serverId @@ -263,8 +263,8 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo hideSelections(); dispatchNeedsRefresh(); break; - case "playlist": - require(["playlistEditor"], function (playlistEditor) { + case 'playlist': + require(['playlistEditor'], function (playlistEditor) { new playlistEditor().show({ items: items, serverId: serverId @@ -273,30 +273,30 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo hideSelections(); dispatchNeedsRefresh(); break; - case "delete": + case 'delete': deleteItems(apiClient, items).then(dispatchNeedsRefresh); hideSelections(); dispatchNeedsRefresh(); break; - case "groupvideos": + case 'groupvideos': combineVersions(apiClient, items); break; - case "markplayed": + case 'markplayed': items.forEach(function (itemId) { apiClient.markPlayed(apiClient.getCurrentUserId(), itemId); }); hideSelections(); dispatchNeedsRefresh(); break; - case "markunplayed": + 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 @@ -321,7 +321,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo [].forEach.call(selectedElements, function (i) { - var container = dom.parentWithAttribute(i, "is", "emby-itemscontainer"); + var container = dom.parentWithAttribute(i, 'is', 'emby-itemscontainer'); if (container && elems.indexOf(container) === -1) { elems.push(container); @@ -337,9 +337,9 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo if (selection.length < 2) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert({ - text: globalize.translate("PleaseSelectTwoItems") + text: globalize.translate('PleaseSelectTwoItems') }); }); return; @@ -349,8 +349,8 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo apiClient.ajax({ - type: "POST", - url: apiClient.getUrl("Videos/MergeVersions", { Ids: selection.join(",") }) + type: 'POST', + url: apiClient.getUrl('Videos/MergeVersions', { Ids: selection.join(',') }) }).then(function () { @@ -362,8 +362,8 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo function showSelections(initialCard) { - require(["emby-checkbox"], function () { - var cards = document.querySelectorAll(".card"); + 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]); } @@ -379,9 +379,9 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo if (selectedItems.length) { - var card = dom.parentWithClass(target, "card"); + var card = dom.parentWithClass(target, 'card'); if (card) { - var itemSelectionPanel = card.querySelector(".itemSelectionPanel"); + var itemSelectionPanel = card.querySelector('.itemSelectionPanel'); if (itemSelectionPanel) { return onItemSelectionPanelClick(e, itemSelectionPanel); } @@ -393,7 +393,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo } } - document.addEventListener("viewbeforehide", hideSelections); + document.addEventListener('viewbeforehide', hideSelections); return function (options) { @@ -403,7 +403,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo function onTapHold(e) { - var card = dom.parentWithClass(e.target, "card"); + var card = dom.parentWithClass(e.target, 'card'); if (card) { @@ -440,7 +440,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo var element = touch.target; if (element) { - var card = dom.parentWithClass(element, "card"); + var card = dom.parentWithClass(element, 'card'); if (card) { @@ -509,7 +509,7 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo return; } - var card = dom.parentWithClass(touchTarget, "card"); + var card = dom.parentWithClass(touchTarget, 'card'); touchTarget = null; if (card) { @@ -522,27 +522,27 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo // mobile safari doesn't allow contextmenu override if (browser.touch && !browser.safari) { - element.addEventListener("contextmenu", onTapHold); + element.addEventListener('contextmenu', onTapHold); } else { - dom.addEventListener(element, "touchstart", onTouchStart, { + dom.addEventListener(element, 'touchstart', onTouchStart, { passive: true }); - dom.addEventListener(element, "touchmove", onTouchMove, { + dom.addEventListener(element, 'touchmove', onTouchMove, { passive: true }); - dom.addEventListener(element, "touchend", onTouchEnd, { + dom.addEventListener(element, 'touchend', onTouchEnd, { passive: true }); - dom.addEventListener(element, "touchcancel", onTouchEnd, { + dom.addEventListener(element, 'touchcancel', onTouchEnd, { passive: true }); - dom.addEventListener(element, "mousedown", onMouseDown, { + dom.addEventListener(element, 'mousedown', onMouseDown, { passive: true }); - dom.addEventListener(element, "mouseleave", onMouseOut, { + dom.addEventListener(element, 'mouseleave', onMouseOut, { passive: true }); - dom.addEventListener(element, "mouseup", onMouseOut, { + dom.addEventListener(element, 'mouseup', onMouseOut, { passive: true }); } @@ -551,38 +551,38 @@ define(["browser", "appStorage", "apphost", "loading", "connectionManager", "glo initTapHold(container); if (options.bindOnClick !== false) { - container.addEventListener("click", onContainerClick); + container.addEventListener('click', onContainerClick); } self.onContainerClick = onContainerClick; self.destroy = function () { - container.removeEventListener("click", onContainerClick); - container.removeEventListener("contextmenu", onTapHold); + container.removeEventListener('click', onContainerClick); + container.removeEventListener('contextmenu', onTapHold); var element = container; - dom.removeEventListener(element, "touchstart", onTouchStart, { + dom.removeEventListener(element, 'touchstart', onTouchStart, { passive: true }); - dom.removeEventListener(element, "touchmove", onTouchMove, { + dom.removeEventListener(element, 'touchmove', onTouchMove, { passive: true }); - dom.removeEventListener(element, "touchend", onTouchEnd, { + 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, { + dom.removeEventListener(element, 'mousedown', onMouseDown, { passive: true }); - dom.removeEventListener(element, "mouseleave", onMouseOut, { + dom.removeEventListener(element, 'mouseleave', onMouseOut, { passive: true }); - dom.removeEventListener(element, "mouseup", onMouseOut, { + dom.removeEventListener(element, 'mouseup', onMouseOut, { passive: true }); }; diff --git a/src/components/navdrawer/navdrawer.css b/src/components/navdrawer/navdrawer.css deleted file mode 100644 index 5d63e150d1..0000000000 --- a/src/components/navdrawer/navdrawer.css +++ /dev/null @@ -1,42 +0,0 @@ -.tmla-mask, -.touch-menu-la { - position: fixed; - top: 0; - bottom: 0; - contain: strict -} - -.touch-menu-la { - background-color: #FFF; - will-change: transform; - display: flex; - transition: transform ease-out 40ms, left ease-out 260ms; - z-index: 1099 -} - -.touch-menu-la.transition { - transition: transform ease-out 240ms, left ease-out 260ms -} - -.drawer-open { - box-shadow: 2px 0 12px rgba(0, 0, 0, .4) -} - -.scrollContainer { - flex-grow: 1 -} - -.tmla-mask { - left: 0; - right: 0; - background-color: #000; - opacity: 0; - z-index: 1098; - transition: opacity ease-in-out .38s, visibility ease-in-out .38s; - will-change: opacity; - background-color: rgba(0, 0, 0, .3) -} - -.tmla-mask.backdrop { - opacity: 1 -} \ No newline at end of file diff --git a/src/components/navdrawer/navdrawer.js b/src/components/navdrawer/navdrawer.js deleted file mode 100644 index 69adbd1f5a..0000000000 --- a/src/components/navdrawer/navdrawer.js +++ /dev/null @@ -1,205 +0,0 @@ -define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function(browser, dom) { - "use strict"; - return function(options) { - function getTouches(e) { - return e.changedTouches || e.targetTouches || e.touches; - } - - function onMenuTouchStart(e) { - options.target.classList.remove("transition"); - var touches = getTouches(e); - var touch = touches[0] || {}; - - menuTouchStartX = touch.clientX; - menuTouchStartY = touch.clientY; - menuTouchStartTime = (new Date).getTime(); - } - - function setVelocity(deltaX) { - var time = (new Date).getTime() - (menuTouchStartTime || 0); - velocity = Math.abs(deltaX) / time; - } - - function onMenuTouchMove(e) { - var isOpen = self.visible; - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var endY = touch.clientY || 0; - var deltaX = endX - (menuTouchStartX || 0); - var deltaY = endY - (menuTouchStartY || 0); - setVelocity(deltaX), isOpen && 1 !== dragMode && deltaX > 0 && (dragMode = 2), 0 === dragMode && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5 ? (dragMode = 1, scrollContainer.addEventListener("scroll", disableEvent), self.showMask()) : 0 === dragMode && Math.abs(deltaY) >= 5 && (dragMode = 2), 1 === dragMode && (newPos = currentPos + deltaX, self.changeMenuPos()) - } - - function onMenuTouchEnd(e) { - options.target.classList.add("transition"); - scrollContainer.removeEventListener("scroll", disableEvent); - dragMode = 0; - - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var endY = touch.clientY || 0; - var deltaX = endX - (menuTouchStartX || 0); - var deltaY = endY - (menuTouchStartY || 0); - - currentPos = deltaX; - self.checkMenuState(deltaX, deltaY); - } - - function onEdgeTouchStart(e) { - if (isPeeking) { - onMenuTouchMove(e); - } else { - if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) { - isPeeking = true; - if (e.type === "touchstart") { - dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); - dom.addEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); - } - onMenuTouchStart(e); - } - } - } - - function onEdgeTouchMove(e) { - e.preventDefault(); - e.stopPropagation(); - - onEdgeTouchStart(e); - } - - function onEdgeTouchEnd(e) { - isPeeking && (isPeeking = !1, dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}), onMenuTouchEnd(e)) - } - - function disableEvent(e) { - e.preventDefault(), e.stopPropagation() - } - - function onBackgroundTouchStart(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; - backgroundTouchStartX = touch.clientX, backgroundTouchStartTime = (new Date).getTime() - } - - function onBackgroundTouchMove(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - if (endX <= options.width && self.isVisible) { - countStart++; - var deltaX = endX - (backgroundTouchStartX || 0); - if (1 === countStart && (startPoint = deltaX), deltaX < 0 && 2 !== dragMode) { - dragMode = 1, newPos = deltaX - startPoint + options.width, self.changeMenuPos(); - var time = (new Date).getTime() - (backgroundTouchStartTime || 0); - velocity = Math.abs(deltaX) / time - } - } - e.preventDefault(), e.stopPropagation() - } - - function onBackgroundTouchEnd(e) { - var touches = getTouches(e); - var touch = touches[0] || {}; - var endX = touch.clientX || 0; - var deltaX = endX - (backgroundTouchStartX || 0); - self.checkMenuState(deltaX), countStart = 0 - } - - function onMaskTransitionEnd() { - var classList = mask.classList; - classList.contains("backdrop") || classList.add("hide") - } - var self; - var defaults; - var mask; - var newPos = 0; - var currentPos = 0; - var startPoint = 0; - var countStart = 0; - var velocity = 0; - options.target.classList.add("transition"); - var dragMode = 0; - var scrollContainer = options.target.querySelector(".mainDrawer-scrollContainer"); - scrollContainer.classList.add("scrollY"); - var TouchMenuLA = function() { - self = this, defaults = { - width: 260, - handleSize: 10, - disableMask: !1, - maxMaskOpacity: 0.5 - }, this.isVisible = !1, this.initialize() - }; - TouchMenuLA.prototype.initElements = function() { - options.target.classList.add("touch-menu-la"), options.target.style.width = options.width + "px", options.target.style.left = -options.width + "px", options.disableMask || (mask = document.createElement("div"), mask.className = "tmla-mask hide", document.body.appendChild(mask), dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, { - passive: !0 - })) - }; - var menuTouchStartX; - var menuTouchStartY; - var menuTouchStartTime; - var edgeContainer = document.querySelector(".mainDrawerHandle"); - var isPeeking = false; - TouchMenuLA.prototype.animateToPosition = function(pos) { - requestAnimationFrame(function() { - options.target.style.transform = pos ? "translateX(" + pos + "px)" : "none" - }) - }, TouchMenuLA.prototype.changeMenuPos = function() { - newPos <= options.width && this.animateToPosition(newPos) - }, TouchMenuLA.prototype.clickMaskClose = function() { - mask.addEventListener("click", function() { - self.close() - }) - }, TouchMenuLA.prototype.checkMenuState = function(deltaX, deltaY) { - velocity >= 0.4 ? deltaX >= 0 || Math.abs(deltaY || 0) >= 70 ? self.open() : self.close() : newPos >= 100 ? self.open() : newPos && self.close() - }, TouchMenuLA.prototype.open = function() { - this.animateToPosition(options.width), currentPos = options.width, this.isVisible = !0, options.target.classList.add("drawer-open"), self.showMask(), self.invoke(options.onChange) - }, TouchMenuLA.prototype.close = function() { - this.animateToPosition(0), currentPos = 0, self.isVisible = !1, options.target.classList.remove("drawer-open"), self.hideMask(), self.invoke(options.onChange) - }, TouchMenuLA.prototype.toggle = function() { - self.isVisible ? self.close() : self.open() - }; - var backgroundTouchStartX; - var backgroundTouchStartTime; - TouchMenuLA.prototype.showMask = function() { - mask.classList.remove("hide"), mask.offsetWidth, mask.classList.add("backdrop") - }, TouchMenuLA.prototype.hideMask = function() { - mask.classList.remove("backdrop") - }, TouchMenuLA.prototype.invoke = function(fn) { - fn && fn.apply(self) - }; - var _edgeSwipeEnabled; - return TouchMenuLA.prototype.setEdgeSwipeEnabled = function(enabled) { - options.disableEdgeSwipe || browser.touch && (enabled ? _edgeSwipeEnabled || (_edgeSwipeEnabled = !0, dom.addEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { - passive: !0 - }), dom.addEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { - passive: !0 - }), dom.addEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { - passive: !0 - })) : _edgeSwipeEnabled && (_edgeSwipeEnabled = !1, dom.removeEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { - passive: !0 - }), dom.removeEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { - passive: !0 - }), dom.removeEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { - passive: !0 - }))) - }, TouchMenuLA.prototype.initialize = function() { - options = Object.assign(defaults, options || {}), browser.edge && (options.disableEdgeSwipe = !0), self.initElements(), browser.touch && (dom.addEventListener(options.target, "touchstart", onMenuTouchStart, { - passive: !0 - }), dom.addEventListener(options.target, "touchmove", onMenuTouchMove, { - passive: !0 - }), dom.addEventListener(options.target, "touchend", onMenuTouchEnd, { - passive: !0 - }), dom.addEventListener(options.target, "touchcancel", onMenuTouchEnd, { - passive: !0 - }), dom.addEventListener(mask, "touchstart", onBackgroundTouchStart, { - passive: !0 - }), dom.addEventListener(mask, "touchmove", onBackgroundTouchMove, {}), dom.addEventListener(mask, "touchend", onBackgroundTouchEnd, { - passive: !0 - }), dom.addEventListener(mask, "touchcancel", onBackgroundTouchEnd, { - passive: !0 - })), self.clickMaskClose() - }, new TouchMenuLA - } -}); \ No newline at end of file diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js index 2c3e45b630..3ac891b5e7 100644 --- a/src/components/notifications/notifications.js +++ b/src/components/notifications/notifications.js @@ -5,7 +5,9 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir document.removeEventListener('click', onOneDocumentClick); document.removeEventListener('keydown', onOneDocumentClick); - if (window.Notification) { + // don't request notification permissions if they're already granted or denied + if (window.Notification && window.Notification.permission === 'default') { + /* eslint-disable-next-line compat/compat */ Notification.requestPermission(); } } @@ -26,6 +28,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir } function resetRegistration() { + /* eslint-disable-next-line compat/compat */ var serviceWorker = navigator.serviceWorker; if (serviceWorker) { serviceWorker.ready.then(function (registration) { @@ -94,10 +97,10 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir } var notification = { - title: "New " + item.Type, + title: 'New ' + item.Type, body: body, vibrate: true, - tag: "newItem" + item.Id, + tag: 'newItem' + item.Id, data: { //options: { // url: LibraryBrowser.getHref(item) @@ -112,7 +115,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir notification.icon = apiClient.getScaledImageUrl(item.Id, { width: 80, tag: imageTags.Primary, - type: "Primary" + type: 'Primary' }); } @@ -136,11 +139,11 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir Recursive: true, Limit: 3, - Filters: "IsNotFolder", - SortBy: "DateCreated", - SortOrder: "Descending", + Filters: 'IsNotFolder', + SortBy: 'DateCreated', + SortOrder: 'Descending', Ids: newItems.join(','), - MediaTypes: "Audio,Video", + MediaTypes: 'Audio,Video', EnableTotalRecordCount: false }).then(function (result) { @@ -168,20 +171,20 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir } var notification = { - tag: "install" + installation.Id, + tag: 'install' + installation.Id, data: {} }; if (status === 'completed') { - notification.title = globalize.translate('PackageInstallCompleted').replace('{0}', installation.Name + ' ' + installation.Version); + notification.title = globalize.translate('PackageInstallCompleted', installation.Name, installation.Version); notification.vibrate = true; } else if (status === 'cancelled') { - notification.title = globalize.translate('PackageInstallCancelled').replace('{0}', installation.Name + ' ' + installation.Version); + notification.title = globalize.translate('PackageInstallCancelled', installation.Name, installation.Version); } else if (status === 'failed') { - notification.title = globalize.translate('PackageInstallFailed').replace('{0}', installation.Name + ' ' + installation.Version); + notification.title = globalize.translate('PackageInstallFailed', installation.Name, installation.Version); notification.vibrate = true; } else if (status === 'progress') { - notification.title = globalize.translate('InstallingPackage').replace('{0}', installation.Name + ' ' + installation.Version); + notification.title = globalize.translate('InstallingPackage', installation.Name, installation.Version); notification.actions = [ @@ -213,25 +216,25 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir }); events.on(serverNotifications, 'PackageInstallationCompleted', function (e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "completed"); + showPackageInstallNotification(apiClient, data, 'completed'); }); events.on(serverNotifications, 'PackageInstallationFailed', function (e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "failed"); + showPackageInstallNotification(apiClient, data, 'failed'); }); events.on(serverNotifications, 'PackageInstallationCancelled', function (e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "cancelled"); + showPackageInstallNotification(apiClient, data, 'cancelled'); }); events.on(serverNotifications, 'PackageInstalling', function (e, apiClient, data) { - showPackageInstallNotification(apiClient, data, "progress"); + showPackageInstallNotification(apiClient, data, 'progress'); }); events.on(serverNotifications, 'ServerShuttingDown', function (e, apiClient, data) { var serverId = apiClient.serverInfo().Id; var notification = { - tag: "restart" + serverId, + tag: 'restart' + serverId, title: globalize.translate('ServerNameIsShuttingDown', apiClient.serverInfo().Name) }; showNotification(notification, 0, apiClient); @@ -240,7 +243,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir events.on(serverNotifications, 'ServerRestarting', function (e, apiClient, data) { var serverId = apiClient.serverInfo().Id; var notification = { - tag: "restart" + serverId, + tag: 'restart' + serverId, title: globalize.translate('ServerNameIsRestarting', apiClient.serverInfo().Name) }; showNotification(notification, 0, apiClient); @@ -250,7 +253,7 @@ define(['serverNotifications', 'playbackManager', 'events', 'globalize', 'requir var serverId = apiClient.serverInfo().Id; var notification = { - tag: "restart" + serverId, + tag: 'restart' + serverId, title: globalize.translate('PleaseRestartServerName', apiClient.serverInfo().Name) }; diff --git a/src/components/nowplayingbar/nowplayingbar.css b/src/components/nowplayingbar/nowplayingbar.css index 120a0508a0..b1e77715ff 100644 --- a/src/components/nowplayingbar/nowplayingbar.css +++ b/src/components/nowplayingbar/nowplayingbar.css @@ -16,7 +16,7 @@ } .nowPlayingBar-hidden { - transform: translate3d(0,100%,0); + transform: translate3d(0, 100%, 0); } .nowPlayingBarTop { @@ -28,7 +28,8 @@ justify-content: center; } -.mediaButton, .nowPlayingBarUserDataButtons .btnUserItemRating { +.mediaButton, +.nowPlayingBarUserDataButtons .btnUserItemRating { vertical-align: middle; margin: 0; text-align: center; @@ -62,6 +63,7 @@ .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; flex-grow: 1; @@ -74,7 +76,7 @@ .nowPlayingBarPositionContainer { position: absolute !important; left: 0; - top: -.56em; + top: -0.56em; right: 0; z-index: 1; } @@ -89,7 +91,8 @@ .nowPlayingBarRight { position: relative; - margin: 0 .5em 0 auto; + margin: 0 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: flex; @@ -121,7 +124,6 @@ } @media all and (max-width: 70em) { - .nowPlayingBarRight .nowPlayingBarUserDataButtons { display: none; } @@ -155,13 +157,15 @@ .nowPlayingBarRight .nowPlayingBarVolumeSliderContainer { display: none !important; } + .nowPlayingBarInfoContainer { width: 70%; } } @media all and (max-width: 24em) { - .nowPlayingBar .muteButton, .nowPlayingBar .unmuteButton { + .nowPlayingBar .muteButton, + .nowPlayingBar .unmuteButton { display: none; } } diff --git a/src/components/nowplayingbar/nowplayingbar.js b/src/components/nowplayingbar/nowplayingbar.js index 37a1a32f56..546029a982 100644 --- a/src/components/nowplayingbar/nowplayingbar.js +++ b/src/components/nowplayingbar/nowplayingbar.js @@ -1,4 +1,4 @@ -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) { +define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 'layoutManager', 'playbackManager', 'nowPlayingHelper', 'apphost', 'dom', 'connectionManager', 'itemContextMenu', 'paper-icon-button-light', 'emby-ratingbutton'], function (require, datetime, itemHelper, events, browser, imageLoader, layoutManager, playbackManager, nowPlayingHelper, appHost, dom, connectionManager, itemContextMenu) { 'use strict'; var currentPlayer; @@ -31,7 +31,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', html += '
'; html += '
'; - html += ''; + html += ''; html += '
'; html += '
'; @@ -42,31 +42,31 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', // 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 += '
'; html += '
'; - html += ''; - html += ''; + html += ''; + html += ''; html += '
'; html += '
'; @@ -134,12 +134,10 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } }); - var i; - var length; playPauseButtons = elem.querySelectorAll('.playPauseButton'); - for (i = 0, length = playPauseButtons.length; i < length; i++) { - playPauseButtons[i].addEventListener('click', onPlayPauseClick); - } + playPauseButtons.forEach((button) => { + button.addEventListener('click', onPlayPauseClick); + }); elem.querySelector('.nextTrackButton').addEventListener('click', function () { @@ -155,8 +153,6 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } }); - elem.querySelector('.remoteControlButton').addEventListener('click', showRemoteControl); - toggleRepeatButton = elem.querySelector('.toggleRepeatButton'); toggleRepeatButton.addEventListener('click', function () { @@ -176,7 +172,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } }); - toggleRepeatButtonIcon = toggleRepeatButton.querySelector('i'); + toggleRepeatButtonIcon = toggleRepeatButton.querySelector('.material-icons'); volumeSlider = elem.querySelector('.nowPlayingBarVolumeSlider'); volumeSliderContainer = elem.querySelector('.nowPlayingBarVolumeSliderContainer'); @@ -192,6 +188,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', currentPlayer.setVolume(this.value); } } + volumeSlider.addEventListener('change', setVolume); volumeSlider.addEventListener('mousemove', setVolume); volumeSlider.addEventListener('touchmove', setVolume); @@ -225,8 +222,8 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', elem.addEventListener('click', function (e) { - if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT', 'A'])) { - showRemoteControl(0); + if (!dom.parentWithTag(e.target, ['BUTTON', 'INPUT'])) { + showRemoteControl(); } }); } @@ -282,22 +279,12 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } function updatePlayPauseState(isPaused) { - var i; - var 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'; - } - } + playPauseButtons.forEach((button) => { + const icon = button.querySelector('.material-icons'); + icon.classList.remove('play_arrow', 'pause'); + icon.classList.add(isPaused ? 'play_arrow' : 'pause'); + }); } } @@ -341,15 +328,16 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } function updateRepeatModeDisplay(repeatMode) { + toggleRepeatButtonIcon.classList.remove('repeat', 'repeat_one'); if (repeatMode === 'RepeatAll') { - toggleRepeatButtonIcon.innerHTML = "repeat"; + toggleRepeatButtonIcon.classList.add('repeat'); toggleRepeatButton.classList.add('repeatButton-active'); } else if (repeatMode === 'RepeatOne') { - toggleRepeatButtonIcon.innerHTML = "repeat_one"; + toggleRepeatButtonIcon.classList.add('repeat_one'); toggleRepeatButton.classList.add('repeatButton-active'); } else { - toggleRepeatButtonIcon.innerHTML = "repeat"; + toggleRepeatButtonIcon.classList.add('repeat'); toggleRepeatButton.classList.remove('repeatButton-active'); } } @@ -380,7 +368,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', var timeText = positionTicks == null ? '--:--' : datetime.getDisplayRunningTime(positionTicks); if (runtimeTicks) { - timeText += " / " + datetime.getDisplayRunningTime(runtimeTicks); + timeText += ' / ' + datetime.getDisplayRunningTime(runtimeTicks); } currentTimeElement.innerHTML = timeText; @@ -393,21 +381,14 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', var showMuteButton = true; var showVolumeSlider = true; - var progressElement = volumeSliderContainer.querySelector('.mdl-slider-background-lower'); if (supportedCommands.indexOf('ToggleMute') === -1) { showMuteButton = false; } - if (isMuted) { - muteButton.querySelector('i').innerHTML = 'volume_off'; - } else { - muteButton.querySelector('i').innerHTML = 'volume_up'; - } - - if (progressElement) { - progressElement.style.width = (volumeLevel || 0) + '%'; - } + const muteButtonIcon = muteButton.querySelector('.material-icons'); + muteButtonIcon.classList.remove('volume_off', 'volume_up'); + muteButtonIcon.classList.add(isMuted ? 'volume_off' : 'volume_up'); if (supportedCommands.indexOf('SetVolume') === -1) { showVolumeSlider = false; @@ -439,17 +420,13 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } } - function getTextActionButton(item, text, serverId) { + function getTextActionButton(item, text) { if (!text) { text = itemHelper.getDisplayName(item); } - var html = ''; - - return html; + return `${text}`; } function seriesImageUrl(item, options) { @@ -463,7 +440,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } options = options || {}; - options.type = options.type || "Primary"; + options.type = options.type || 'Primary'; if (options.type === 'Primary') { @@ -501,7 +478,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } options = options || {}; - options.type = options.type || "Primary"; + options.type = options.type || 'Primary'; if (item.ImageTags && item.ImageTags[options.type]) { @@ -527,16 +504,16 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 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"' : ''; if (nowPlayingName.item) { - return '' + getTextActionButton(nowPlayingName.item, nowPlayingName.text, serverId) + '
'; + var nowPlayingText = getTextActionButton(nowPlayingName.item, nowPlayingName.text); + return `
${nowPlayingText}
`; } - return '' + nowPlayingName.text + '
'; + return `
${nowPlayingText}
`; }).join(''); @@ -565,15 +542,25 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', 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 = ''; + var contextButton = document.querySelector('.btnToggleContextMenu'); + var options = { + play: false, + queue: false, + positionTo: contextButton + }; + nowPlayingUserData.innerHTML = ''; + apiClient.getCurrentUser().then(function(user) { + contextButton.addEventListener('click', function () { + itemContextMenu.show(Object.assign({ + item: item, + user: user + }, options )); + }); + }); }); - } } else { nowPlayingUserData.innerHTML = ''; @@ -581,8 +568,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', } function onPlaybackStart(e, state) { - - //console.log('nowplaying event: ' + e.type); + console.debug('nowplaying event: ' + e.type); var player = this; @@ -627,7 +613,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', function onPlaybackStopped(e, state) { - //console.log('nowplaying event: ' + e.type); + console.debug('nowplaying event: ' + e.type); var player = this; if (player.isLocalPlayer) { @@ -653,7 +639,7 @@ define(['require', 'datetime', 'itemHelper', 'events', 'browser', 'imageLoader', function onStateChanged(event, state) { - //console.log('nowplaying event: ' + e.type); + console.debug('nowplaying event: ' + event.type); var player = this; if (!state.NowPlayingItem || layoutManager.tv) { diff --git a/src/components/packagemanager.js b/src/components/packagemanager.js index 03ed1006c1..46f4704522 100644 --- a/src/components/packagemanager.js +++ b/src/components/packagemanager.js @@ -149,4 +149,4 @@ define(['appSettings', 'pluginManager'], function (appSettings, pluginManager) { }; return new PackageManager(); -}); \ No newline at end of file +}); diff --git a/src/components/photoplayer/plugin.js b/src/components/photoplayer/plugin.js index 6629fbfb0f..4dc00809dc 100644 --- a/src/components/photoplayer/plugin.js +++ b/src/components/photoplayer/plugin.js @@ -1,5 +1,5 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackManager', 'appRouter', 'appSettings', 'connectionManager'], function (browser, require, events, appHost, loading, dom, playbackManager, appRouter, appSettings, connectionManager) { - "use strict"; + 'use strict'; function PhotoPlayer() { @@ -21,18 +21,24 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa var index = options.startIndex || 0; - var newSlideShow = new slideshow({ - showTitle: false, - cover: false, - items: options.items, - startIndex: index, - interval: 11000, - interactive: true + var apiClient = connectionManager.currentApiClient(); + + apiClient.getCurrentUser().then(function(result) { + + var newSlideShow = new slideshow({ + showTitle: false, + cover: false, + items: options.items, + startIndex: index, + interval: 11000, + interactive: true, + user: result + }); + + newSlideShow.show(); + + resolve(); }); - - newSlideShow.show(); - - resolve(); }); }); }; @@ -43,4 +49,4 @@ define(['browser', 'require', 'events', 'apphost', 'loading', 'dom', 'playbackMa }; return PhotoPlayer; -}); \ No newline at end of file +}); diff --git a/src/components/playback/autoplaydetect.js b/src/components/playback/autoplaydetect.js deleted file mode 100644 index 3610eef2ab..0000000000 --- a/src/components/playback/autoplaydetect.js +++ /dev/null @@ -1,61 +0,0 @@ -define([], function () { - 'use strict'; - - function supportsHtmlMediaAutoplay() { - - 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/components/playback/brightnessosd.js b/src/components/playback/brightnessosd.js index b2bf9d4106..5ed2b8f81f 100644 --- a/src/components/playback/brightnessosd.js +++ b/src/components/playback/brightnessosd.js @@ -11,7 +11,7 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia function getOsdElementHtml() { var html = ''; - html += 'brightness_high'; + html += ''; html += '
'; @@ -32,7 +32,7 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia elem.classList.add('brightnessOsd'); elem.innerHTML = getOsdElementHtml(); - iconElement = elem.querySelector('i'); + iconElement = elem.querySelector('.material-icons'); progressElement = elem.querySelector('.iconOsdProgressInner'); document.body.appendChild(elem); @@ -98,15 +98,22 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia } } + function setIcon(iconElement, icon) { + iconElement.classList.remove('brightness_high'); + iconElement.classList.remove('brightness_medium'); + iconElement.classList.remove('brightness_low'); + iconElement.classList.add(icon); + } + function updateElementsFromPlayer(brightness) { if (iconElement) { if (brightness >= 80) { - iconElement.innerHTML = 'brightness_high'; + setIcon(iconElement, 'brightness_high'); } else if (brightness >= 20) { - iconElement.innerHTML = 'brightness_medium'; + setIcon(iconElement, 'brightness_medium'); } else { - iconElement.innerHTML = 'brightness_low'; + setIcon(iconElement, 'brightness_low'); } } if (progressElement) { diff --git a/src/components/playback/experimentalwarnings.js b/src/components/playback/experimentalwarnings.js index 17b1af0257..632e38208c 100644 --- a/src/components/playback/experimentalwarnings.js +++ b/src/components/playback/experimentalwarnings.js @@ -1,5 +1,5 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function (connectionManager, globalize, userSettings, appHost) { - "use strict"; + 'use strict'; function getRequirePromise(deps) { @@ -44,24 +44,15 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function ( } function showBlurayMessage() { - - 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 Jellyfin app with native Bluray folder support.'; - return showMessage(message, 'blurayexpirementalinfo', 'nativeblurayplayback'); + return showMessage(globalize.translate('UnsupportedPlayback'), 'blurayexpirementalinfo', 'nativeblurayplayback'); } function showDvdMessage() { - - 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 Jellyfin app with native Dvd folder support.'; - return showMessage(message, 'dvdexpirementalinfo', 'nativedvdplayback'); + return showMessage(globalize.translate('UnsupportedPlayback'), 'dvdexpirementalinfo', 'nativedvdplayback'); } function showIsoMessage() { - - 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 Jellyfin app with native ISO support.'; - return showMessage(message, 'isoexpirementalinfo', 'nativeisoplayback'); + return showMessage(globalize.translate('UnsupportedPlayback'), 'isoexpirementalinfo', 'nativeisoplayback'); } function ExpirementalPlaybackWarnings() { @@ -94,4 +85,4 @@ define(['connectionManager', 'globalize', 'userSettings', 'apphost'], function ( }; return ExpirementalPlaybackWarnings; -}); \ No newline at end of file +}); diff --git a/src/components/playback/iconosd.css b/src/components/playback/iconosd.css index b2c4fca91a..8f197a179e 100644 --- a/src/components/playback/iconosd.css +++ b/src/components/playback/iconosd.css @@ -4,11 +4,11 @@ right: 3%; z-index: 100000; background: #222; - background: rgba(0, 0, 0, .8); + background: rgba(0, 0, 0, 0.8); padding: 1em; color: #fff; backdrop-filter: blur(5px); - border-radius: .25em; + border-radius: 0.25em; transition: opacity 200ms ease-out; } @@ -19,22 +19,22 @@ .iconOsdIcon { font-size: 320%; display: block; - margin: .25em .7em; + margin: 0.25em 0.7em; } .iconOsdProgressOuter { - margin: 1.5em .25em 1em; - height: .35em; + margin: 1.5em 0.25em 1em; + height: 0.35em; background: #222; - border-radius: .25em; + border-radius: 0.25em; } .iconOsdProgressInner { background: #00a4dc; height: 100%; - border-radius: .25em; + border-radius: 0.25em; } .brightnessOsdProgressInner { - background: #FF9800; -} \ No newline at end of file + background: #ff9800; +} diff --git a/src/components/playback/mediasession.js b/src/components/playback/mediasession.js index 7f4b9f519e..2dd10b3484 100644 --- a/src/components/playback/mediasession.js +++ b/src/components/playback/mediasession.js @@ -1,45 +1,28 @@ -define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], function (playbackManager, nowPlayingHelper, events, connectionManager) { - "use strict"; - - // no support for mediaSession - if (!navigator.mediaSession && !window.NativeShell) { - return; - } +import playbackManager from 'playbackManager'; +import nowPlayingHelper from 'nowPlayingHelper'; +import events from 'events'; +import connectionManager from 'connectionManager'; +/* eslint-disable indent */ // Reports media playback to the device for lock screen control - var currentPlayer; - var lastUpdateTime = 0; + let currentPlayer; - function seriesImageUrl(item, options) { + function seriesImageUrl(item, options = {}) { + options.type = options.type || 'Primary'; 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') { + } else if (options.type === 'Primary' && item.SeriesPrimaryImageTag) { + options.tag = item.SeriesPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); + } else if (options.type === 'Thumb') { if (item.SeriesThumbImageTag) { - options.tag = item.SeriesThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); - } - if (item.ParentThumbImageTag) { - + } else if (item.ParentThumbImageTag) { options.tag = item.ParentThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.ParentThumbItemId, options); @@ -49,137 +32,101 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f return null; } - function imageUrl(item, options) { - - options = options || {}; - options.type = options.type || "Primary"; + function imageUrl(item, 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) { - + } else if (item.AlbumId && item.AlbumPrimaryImageTag) { options.tag = item.AlbumPrimaryImageTag; + return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); } return null; } - function pushImageUrl(item, imageOptions, list) { - var url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); + function getImageUrl(item, imageOptions = {}) { + const url = seriesImageUrl(item, imageOptions) || imageUrl(item, imageOptions); if (url) { - var height = imageOptions.height || imageOptions.maxHeight; + const height = imageOptions.height || imageOptions.maxHeight; - list.push({ + return { src: url, sizes: height + 'x' + height - }); + }; + } else { + return null; } } - function getImageUrls(item) { + function getImageUrls(item, imageSizes = [96, 128, 192, 256, 384, 512]) { + const list = []; - var list = []; - - pushImageUrl(item, {height: 96}, list); - pushImageUrl(item, {height: 128}, list); - pushImageUrl(item, {height: 192}, list); - pushImageUrl(item, {height: 256}, list); - pushImageUrl(item, {height: 384}, list); - pushImageUrl(item, {height: 512}, list); + imageSizes.forEach((size) => { + const url = getImageUrl(item, {height: size}); + if (url !== null) { + list.push(url); + } + }); return list; } function updatePlayerState(player, state, eventName) { + // Don't go crazy reporting position changes + if (eventName === 'timeupdate') { + // Only report if this item hasn't been reported yet, or if there's an actual playback change. + // Don't report on simple time updates + return; + } - var item = state.NowPlayingItem; + const item = state.NowPlayingItem; if (!item) { hideMediaControls(); return; } - if (eventName == 'init') { // transform "init" event into "timeupdate" to restraint update rate + if (eventName === 'init') { // transform "init" event into "timeupdate" to restraint update rate eventName = 'timeupdate'; } - var isVideo = item.MediaType === 'Video'; - var isLocalPlayer = player.isLocalPlayer || false; + const isVideo = item.MediaType === 'Video'; + const isLocalPlayer = player.isLocalPlayer || false; // Local players do their own notifications if (isLocalPlayer && isVideo) { return; } - var playState = state.PlayState || {}; + const playState = state.PlayState || {}; + const parts = nowPlayingHelper.getNowPlayingNames(item); + const artist = parts[parts.length - 1].text; + const title = parts.length === 1 ? '' : parts[0].text; - var parts = nowPlayingHelper.getNowPlayingNames(item); - - var artist = parts.length === 1 ? '' : parts[0].text; - var title = parts[parts.length - 1].text; - - // Switch these two around for video - if (isVideo && parts.length > 1) { - var temp = artist; - artist = title; - title = temp; - } - - var albumArtist; - - if (item.AlbumArtists && item.AlbumArtists[0]) { - albumArtist = item.AlbumArtists[0].Name; - } - - var album = item.Album || ''; - var itemId = item.Id; + const album = item.Album || ''; + const itemId = item.Id; // Convert to ms - var duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); - var currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); + const duration = parseInt(item.RunTimeTicks ? (item.RunTimeTicks / 10000) : 0); + const currentTime = parseInt(playState.PositionTicks ? (playState.PositionTicks / 10000) : 0); - var isPaused = playState.IsPaused || false; - var canSeek = playState.CanSeek || false; + const isPaused = playState.IsPaused || false; + const canSeek = playState.CanSeek || false; - var now = new Date().getTime(); - - // Don't go crazy reporting position changes - if (eventName == 'timeupdate' && (now - lastUpdateTime) < 5000) { - // Only report if this item hasn't been reported yet, or if there's an actual playback change. - // Don't report on simple time updates - return; - } - - lastUpdateTime = now; - - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.metadata = new MediaMetadata({ title: title, artist: artist, album: album, - artwork: getImageUrls(item), - albumArtist: albumArtist, - currentTime: currentTime, - duration: duration, - paused: isPaused, - itemId: itemId, - mediaType: item.MediaType + artwork: getImageUrls(item) }); } else { - var imageUrl = []; - pushImageUrl(item, {maxHeight: 400}, imageUrl); - - if (imageUrl.length) { - imageUrl = imageUrl[0].src; - } else { - imageUrl = null; - } + let itemImageUrl = seriesImageUrl(item, { maxHeight: 3000 }) || imageUrl(item, { maxHeight: 3000 }); window.NativeShell.updateMediaSession({ action: eventName, @@ -190,7 +137,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f album: album, duration: duration, position: currentTime, - imageUrl: imageUrl, + imageUrl: itemImageUrl, canSeek: canSeek, isPaused: isPaused }); @@ -198,37 +145,25 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function onGeneralEvent(e) { + const state = playbackManager.getPlayerState(this); - var player = this; - var state = playbackManager.getPlayerState(player); - - updatePlayerState(player, state, e.type); + updatePlayerState(this, state, e.type); } function onStateChanged(e, state) { - - var player = this; - updatePlayerState(player, state, 'statechange'); + updatePlayerState(this, state, 'statechange'); } function onPlaybackStart(e, state) { - - var player = this; - - updatePlayerState(player, state, e.type); + updatePlayerState(this, state, e.type); } - function onPlaybackStopped(e, state) { - - var player = this; - + function onPlaybackStopped() { hideMediaControls(); } function releaseCurrentPlayer() { - if (currentPlayer) { - events.off(currentPlayer, 'playbackstart', onPlaybackStart); events.off(currentPlayer, 'playbackstop', onPlaybackStopped); events.off(currentPlayer, 'unpause', onGeneralEvent); @@ -243,9 +178,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function hideMediaControls() { - lastUpdateTime = 0; - - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.metadata = null; } else { window.NativeShell.hideMediaSession(); @@ -253,7 +186,6 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } function bindToPlayer(player) { - releaseCurrentPlayer(); if (!player) { @@ -262,7 +194,7 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f currentPlayer = player; - var state = playbackManager.getPlayerState(player); + const state = playbackManager.getPlayerState(player); updatePlayerState(player, state, 'init'); events.on(currentPlayer, 'playbackstart', onPlaybackStart); @@ -276,8 +208,8 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f function execute(name) { playbackManager[name](currentPlayer); } - if (navigator.mediaSession) { + if ('mediaSession' in navigator) { navigator.mediaSession.setActionHandler('previoustrack', function () { execute('previousTrack'); }); @@ -304,9 +236,9 @@ define(['playbackManager', 'nowPlayingHelper', 'events', 'connectionManager'], f } events.on(playbackManager, 'playerchange', function () { - bindToPlayer(playbackManager.getCurrentPlayer()); }); bindToPlayer(playbackManager.getCurrentPlayer()); -}); + +/* eslint-enable indent */ diff --git a/src/components/playback/nowplayinghelper.js b/src/components/playback/nowplayinghelper.js index b1af977ab0..9bba23c294 100644 --- a/src/components/playback/nowplayinghelper.js +++ b/src/components/playback/nowplayinghelper.js @@ -18,10 +18,10 @@ define([], function () { if (nowPlayingItem.MediaType === 'Video') { if (nowPlayingItem.IndexNumber != null) { - topText = nowPlayingItem.IndexNumber + " - " + topText; + topText = nowPlayingItem.IndexNumber + ' - ' + topText; } if (nowPlayingItem.ParentIndexNumber != null) { - topText = nowPlayingItem.ParentIndexNumber + "." + topText; + topText = nowPlayingItem.ParentIndexNumber + '.' + topText; } } diff --git a/src/components/playback/playaccessvalidation.js b/src/components/playback/playaccessvalidation.js index 35d8314fc1..5148d2b821 100644 --- a/src/components/playback/playaccessvalidation.js +++ b/src/components/playback/playaccessvalidation.js @@ -1,5 +1,5 @@ define(['connectionManager', 'globalize'], function (connectionManager, globalize) { - "use strict"; + 'use strict'; function getRequirePromise(deps) { return new Promise(function (resolve, reject) { @@ -47,4 +47,4 @@ define(['connectionManager', 'globalize'], function (connectionManager, globaliz }; return PlayAccessValidation; -}); \ No newline at end of file +}); diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index da04a2e13e..dea419c8cc 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1,6 +1,9 @@ -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) { +define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'playQueueManager', 'userSettings', 'globalize', 'connectionManager', 'loading', 'apphost', 'screenfull'], function (events, datetime, appSettings, itemHelper, pluginManager, PlayQueueManager, userSettings, globalize, connectionManager, loading, apphost, screenfull) { 'use strict'; + /** Delay time in ms for reportPlayback logging */ + const reportPlaybackLogDelay = 1e3; + function enableLocalPlaylistManagement(player) { if (player.getPlaylist) { @@ -17,9 +20,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function bindToFullscreenChange(player) { - events.on(fullscreenManager, 'fullscreenchange', function () { - events.trigger(player, 'fullscreenchange'); - }); + if (screenfull.isEnabled) { + screenfull.on('change', function () { + events.trigger(player, 'fullscreenchange'); + }); + } } function triggerPlayerChange(playbackManagerInstance, newPlayer, newTarget, previousPlayer, previousTargetInfo) { @@ -38,6 +43,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla events.trigger(playbackManagerInstance, 'playerchange', [newPlayer, newTarget, previousPlayer]); } + /** Last invoked method */ + let reportPlaybackLastMethod; + + /** Last invoke time of method */ + let reportPlaybackLastTime; + function reportPlayback(playbackManagerInstance, state, player, reportPlaylist, serverId, method, progressEventName) { if (!serverId) { @@ -57,7 +68,14 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla addPlaylistToPlaybackReport(playbackManagerInstance, info, player, serverId); } - //console.log(method + '-' + JSON.stringify(info)); + const now = (new Date).getTime(); + + if (method !== reportPlaybackLastMethod || now - (reportPlaybackLastTime || 0) >= reportPlaybackLogDelay) { + console.debug(method + '-' + JSON.stringify(info)); + reportPlaybackLastMethod = method; + reportPlaybackLastTime = now; + } + var apiClient = connectionManager.getApiClient(serverId); apiClient[method](info); } @@ -110,8 +128,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } else { query.Limit = query.Limit || 300; - query.Fields = "Chapters"; - query.ExcludeLocationTypes = "Virtual"; + query.Fields = 'Chapters'; + query.ExcludeLocationTypes = 'Virtual'; query.EnableTotalRecordCount = false; query.CollapseBoxSetItems = false; @@ -146,7 +164,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla function backdropImageUrl(apiClient, item, options) { options = options || {}; - options.type = options.type || "Backdrop"; + options.type = options.type || 'Backdrop'; // If not resizing, get the original image if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { @@ -203,15 +221,15 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla } function getParam(name, url) { - name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); - var regexS = "[\\?&]" + name + "=([^&#]*)"; - var regex = new RegExp(regexS, "i"); + name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]'); + var regexS = '[\\?&]' + name + '=([^&#]*)'; + var regex = new RegExp(regexS, 'i'); var results = regex.exec(url); if (results == null) { - return ""; + return ''; } else { - return decodeURIComponent(results[1].replace(/\+/g, " ")); + return decodeURIComponent(results[1].replace(/\+/g, ' ')); } } @@ -291,13 +309,11 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla 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 maxAudioBitDepth = condition.Value; + } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioSampleRate') { + return maxAudioSampleRate = condition.Value; + } else if (condition.Condition === 'LessThanEqual' && condition.Property === 'AudioBitrate') { + return maxAudioBitrate = condition.Value; } }); } @@ -598,8 +614,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla url: apiClient.getUrl('LiveStreams/Open', query), type: 'POST', data: JSON.stringify(postData), - contentType: "application/json", - dataType: "json" + contentType: 'application/json', + dataType: 'json' }); } @@ -1024,7 +1040,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla currentTargetInfo = targetInfo; if (targetInfo) { - console.log('Active player: ' + JSON.stringify(targetInfo)); + console.debug('Active player: ' + JSON.stringify(targetInfo)); } if (player && player.isLocalPlayer) { @@ -1111,17 +1127,17 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla var itemType = item.Type; - if (itemType === "PhotoAlbum" || itemType === "MusicGenre" || itemType === "Season" || itemType === "Series" || itemType === "BoxSet" || itemType === "MusicAlbum" || itemType === "MusicArtist" || itemType === "Playlist") { + if (itemType === 'PhotoAlbum' || itemType === 'MusicGenre' || itemType === 'Season' || itemType === 'Series' || itemType === 'BoxSet' || itemType === 'MusicAlbum' || itemType === 'MusicArtist' || itemType === 'Playlist') { return true; } - if (item.LocationType === "Virtual") { - if (itemType !== "Program") { + if (item.LocationType === 'Virtual') { + if (itemType !== 'Program') { return false; } } - if (itemType === "Program") { + if (itemType === 'Program') { if (!item.EndDate || !item.StartDate) { return false; @@ -1518,7 +1534,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.isFullscreen(); } - return fullscreenManager.isFullScreen(); + return screenfull.isFullscreen; }; self.toggleFullscreen = function (player) { @@ -1528,10 +1544,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return player.toggleFulscreen(); } - if (fullscreenManager.isFullScreen()) { - fullscreenManager.exitFullscreen(); - } else { - fullscreenManager.requestFullscreen(); + if (screenfull.isEnabled) { + screenfull.toggle(); } }; @@ -1633,29 +1647,29 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla self.supportSubtitleOffset = function(player) { player = player || self._currentPlayer; return player && 'setSubtitleOffset' in player; - } + }; self.enableShowingSubtitleOffset = function(player) { player = player || self._currentPlayer; player.enableShowingSubtitleOffset(); - } + }; self.disableShowingSubtitleOffset = function(player) { player = player || self._currentPlayer; if (player.disableShowingSubtitleOffset) { player.disableShowingSubtitleOffset(); } - } + }; self.isShowingSubtitleOffsetEnabled = function(player) { player = player || self._currentPlayer; return player.isShowingSubtitleOffsetEnabled(); - } + }; self.isSubtitleStreamExternal = function(index, player) { var stream = getSubtitleStream(player, index); return stream ? getDeliveryMethod(stream) === 'External' : false; - } + }; self.setSubtitleOffset = function (value, player) { player = player || self._currentPlayer; @@ -1669,12 +1683,12 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (player.getSubtitleOffset) { return player.getSubtitleOffset(); } - } + }; self.canHandleOffsetOnCurrentSubtitle = function(player) { var index = self.getSubtitleStreamIndex(player); return index !== -1 && self.isSubtitleStreamExternal(index, player); - } + }; self.seek = function (ticks, player) { @@ -1861,36 +1875,36 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla var queryOptions = options.queryOptions || {}; - if (firstItem.Type === "Program") { + if (firstItem.Type === 'Program') { promise = getItemsForPlayback(serverId, { Ids: firstItem.ChannelId }); - } else if (firstItem.Type === "Playlist") { + } else if (firstItem.Type === 'Playlist') { promise = getItemsForPlayback(serverId, { ParentId: firstItem.Id, SortBy: options.shuffle ? 'Random' : null }); - } else if (firstItem.Type === "MusicArtist") { + } else if (firstItem.Type === 'MusicArtist') { promise = getItemsForPlayback(serverId, { ArtistIds: firstItem.Id, - Filters: "IsNotFolder", + Filters: 'IsNotFolder', Recursive: true, SortBy: options.shuffle ? 'Random' : 'SortName', - MediaTypes: "Audio" + MediaTypes: 'Audio' }); - } else if (firstItem.MediaType === "Photo") { + } else if (firstItem.MediaType === 'Photo') { promise = getItemsForPlayback(serverId, { ParentId: firstItem.ParentId, - Filters: "IsNotFolder", + Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, SortBy: options.shuffle ? 'Random' : 'SortName', - MediaTypes: "Photo,Video", + MediaTypes: 'Photo,Video', Limit: 500 }).then(function (result) { @@ -1911,40 +1925,40 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return Promise.resolve(result); }); - } else if (firstItem.Type === "PhotoAlbum") { + } else if (firstItem.Type === 'PhotoAlbum') { promise = getItemsForPlayback(serverId, { ParentId: firstItem.Id, - Filters: "IsNotFolder", + Filters: 'IsNotFolder', // Setting this to true may cause some incorrect sorting Recursive: false, SortBy: options.shuffle ? 'Random' : 'SortName', - MediaTypes: "Photo,Video", + MediaTypes: 'Photo,Video', Limit: 1000 }); - } else if (firstItem.Type === "MusicGenre") { + } else if (firstItem.Type === 'MusicGenre') { promise = getItemsForPlayback(serverId, { GenreIds: firstItem.Id, - Filters: "IsNotFolder", + Filters: 'IsNotFolder', Recursive: true, SortBy: options.shuffle ? 'Random' : 'SortName', - MediaTypes: "Audio" + MediaTypes: 'Audio' }); } else if (firstItem.IsFolder) { promise = getItemsForPlayback(serverId, mergePlaybackQueries({ ParentId: firstItem.Id, - Filters: "IsNotFolder", + Filters: 'IsNotFolder', Recursive: true, // These are pre-sorted SortBy: options.shuffle ? 'Random' : (['BoxSet'].indexOf(firstItem.Type) === -1 ? 'SortName' : null), - MediaTypes: "Audio,Video" + MediaTypes: 'Audio,Video' }, queryOptions)); - } else if (firstItem.Type === "Episode" && items.length === 1 && getPlayer(firstItem, options).supportsProgress !== false) { + } 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); @@ -1960,7 +1974,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla IsVirtualUnaired: false, IsMissing: false, UserId: apiClient.getCurrentUserId(), - Fields: "Chapters" + Fields: 'Chapters' }).then(function (episodesResult) { @@ -2197,7 +2211,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla return Promise.reject(); } - if (firstItem.MediaType === "Photo") { + if (firstItem.MediaType === 'Photo') { return playPhotos(items, options, user); } @@ -2828,7 +2842,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (newItemInfo) { - console.log('playing next track'); + console.debug('playing next track'); var newItemPlayOptions = newItemInfo.item.playOptions || getDefaultPlayOptions(); @@ -3118,7 +3132,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla // medianotsupported var errorType = error.type; - console.log('playbackmanager playback error type: ' + (errorType || '')); + console.debug('playbackmanager playback error type: ' + (errorType || '')); var streamInfo = error.streamInfo || getPlayerData(player).streamInfo; @@ -3140,7 +3154,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla AllowVideoStreamCopy: false, AllowAudioStreamCopy: currentlyPreventsAudioStreamCopy || currentlyPreventsVideoStreamCopy ? false : null - }, true); + }); return; } @@ -3162,7 +3176,8 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla // User clicked stop or content ended var state = self.getPlayerState(player); - var streamInfo = getPlayerData(player).streamInfo; + var data = getPlayerData(player); + var streamInfo = data.streamInfo; var nextItem = self._playNextAfterEnded ? self._playQueueManager.getNextItemInfo() : null; @@ -3210,6 +3225,9 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla showPlaybackInfoErrorMessage(self, displayErrorCode, nextItem); } else if (nextItem) { self.nextTrack(); + } else { + // Nothing more to play - clear data + data.streamInfo = null; } } @@ -3374,7 +3392,6 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla pluginManager.ofType('mediaplayer').map(initMediaPlayer); function sendProgressUpdate(player, progressEventName, reportPlaylist) { - if (!player) { throw new Error('player cannot be null'); } @@ -3401,7 +3418,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla function getLiveStreamMediaInfo(player, streamInfo, mediaSource, liveStreamId, serverId) { - console.log('getLiveStreamMediaInfo'); + console.debug('getLiveStreamMediaInfo'); streamInfo.lastMediaInfoQuery = new Date().getTime(); @@ -3832,23 +3849,23 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla if (player.isLocalPlayer) { var list = [ - "GoHome", - "GoToSettings", - "VolumeUp", - "VolumeDown", - "Mute", - "Unmute", - "ToggleMute", - "SetVolume", - "SetAudioStreamIndex", - "SetSubtitleStreamIndex", - "SetMaxStreamingBitrate", - "DisplayContent", - "GoToSearch", - "DisplayMessage", - "SetRepeatMode", - "PlayMediaSource", - "PlayTrailers" + 'GoHome', + 'GoToSettings', + 'VolumeUp', + 'VolumeDown', + 'Mute', + 'Unmute', + 'ToggleMute', + 'SetVolume', + 'SetAudioStreamIndex', + 'SetSubtitleStreamIndex', + 'SetMaxStreamingBitrate', + 'DisplayContent', + 'GoToSearch', + 'DisplayMessage', + 'SetRepeatMode', + 'PlayMediaSource', + 'PlayTrailers' ]; if (apphost.supports('fullscreenchange')) { @@ -3961,7 +3978,7 @@ define(['events', 'datetime', 'appSettings', 'itemHelper', 'pluginManager', 'pla }; PlaybackManager.prototype.sendCommand = function (cmd, player) { - console.log('MediaController received command: ' + cmd.Name); + console.debug('MediaController received command: ' + cmd.Name); switch (cmd.Name) { case 'SetRepeatMode': this.setRepeatMode(cmd.Arguments.RepeatMode, player); diff --git a/src/components/playback/playbackorientation.js b/src/components/playback/playbackorientation.js index 3253d8acdf..654ac29848 100644 --- a/src/components/playback/playbackorientation.js +++ b/src/components/playback/playbackorientation.js @@ -1,5 +1,5 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager, layoutManager, events) { - "use strict"; + 'use strict'; var orientationLocked; @@ -9,7 +9,7 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager function onOrientationChangeError(err) { orientationLocked = false; - console.log('error locking orientation: ' + err); + console.error('error locking orientation: ' + err); } events.on(playbackManager, 'playbackstart', function (e, player, state) { @@ -17,6 +17,7 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager var isLocalVideo = player.isLocalPlayer && !player.isExternalPlayer && playbackManager.isPlayingVideo(player); if (isLocalVideo && layoutManager.mobile) { + /* eslint-disable-next-line compat/compat */ var lockOrientation = screen.lockOrientation || screen.mozLockOrientation || screen.msLockOrientation || (screen.orientation && screen.orientation.lock); if (lockOrientation) { @@ -40,16 +41,17 @@ define(['playbackManager', 'layoutManager', 'events'], function (playbackManager if (orientationLocked && !playbackStopInfo.nextMediaType) { + /* eslint-disable-next-line compat/compat */ 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); + console.error('error unlocking orientation: ' + err); } orientationLocked = false; } } }); -}); \ No newline at end of file +}); diff --git a/src/components/playback/playerSelectionMenu.js b/src/components/playback/playerSelectionMenu.js index 97e6e46230..329cc11f92 100644 --- a/src/components/playback/playerSelectionMenu.js +++ b/src/components/playback/playerSelectionMenu.js @@ -99,7 +99,7 @@ define(['appSettings', 'events', 'browser', 'loading', 'playbackManager', 'appRo var name = t.name; if (t.appName && t.appName !== t.name) { - name += " - " + t.appName; + name += ' - ' + t.appName; } return { diff --git a/src/components/playback/playersettingsmenu.js b/src/components/playback/playersettingsmenu.js index 086f98c2d4..b89631f63a 100644 --- a/src/components/playback/playersettingsmenu.js +++ b/src/components/playback/playersettingsmenu.js @@ -4,7 +4,7 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob function showQualityMenu(player, btn) { var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { - return stream.Type === "Video"; + return stream.Type === 'Video'; })[0]; var videoWidth = videoStream ? videoStream.Width : null; @@ -87,7 +87,7 @@ define(['connectionManager', 'actionsheet', 'datetime', 'playbackManager', 'glob var currentMaxBitrate = playbackManager.getMaxStreamingBitrate(player); var videoStream = playbackManager.currentMediaSource(player).MediaStreams.filter(function (stream) { - return stream.Type === "Video"; + return stream.Type === 'Video'; })[0]; var videoWidth = videoStream ? videoStream.Width : null; diff --git a/src/components/playback/playmethodhelper.js b/src/components/playback/playmethodhelper.js index 4e85f87093..75af04035c 100644 --- a/src/components/playback/playmethodhelper.js +++ b/src/components/playback/playmethodhelper.js @@ -21,4 +21,4 @@ define([], function () { return { getDisplayPlayMethod: getDisplayPlayMethod }; -}); \ No newline at end of file +}); diff --git a/src/components/playback/playqueuemanager.js b/src/components/playback/playqueuemanager.js index ed2076a814..565cb6993e 100644 --- a/src/components/playback/playqueuemanager.js +++ b/src/components/playback/playqueuemanager.js @@ -6,7 +6,7 @@ define([], function () { if (!item.PlaylistItemId) { - item.PlaylistItemId = "playlistItem" + currentId; + item.PlaylistItemId = 'playlistItem' + currentId; currentId++; } } @@ -230,4 +230,4 @@ define([], function () { }; return PlayQueueManager; -}); \ No newline at end of file +}); diff --git a/src/components/playback/remotecontrolautoplay.js b/src/components/playback/remotecontrolautoplay.js index d8316b87ef..90a872cc6e 100644 --- a/src/components/playback/remotecontrolautoplay.js +++ b/src/components/playback/remotecontrolautoplay.js @@ -32,16 +32,16 @@ define(['events', 'playbackManager'], function (events, playbackManager) { } if (!oldPlayer.isLocalPlayer) { - console.log('Skipping remote control autoplay because oldPlayer is not a local player'); + console.debug('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'); + console.debug('Skipping remote control autoplay because newPlayer is a local player'); return; } transferPlayback(oldPlayer, newPlayer); }); -}); \ No newline at end of file +}); diff --git a/src/components/playback/volumeosd.js b/src/components/playback/volumeosd.js index b622cc18b1..95a13d769d 100644 --- a/src/components/playback/volumeosd.js +++ b/src/components/playback/volumeosd.js @@ -11,7 +11,7 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia function getOsdElementHtml() { var html = ''; - html += 'volume_up'; + html += ''; html += '
'; @@ -32,7 +32,7 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia elem.classList.add('volumeOsd'); elem.innerHTML = getOsdElementHtml(); - iconElement = elem.querySelector('i'); + iconElement = elem.querySelector('.material-icons'); progressElement = elem.querySelector('.iconOsdProgressInner'); document.body.appendChild(elem); @@ -101,7 +101,8 @@ define(['events', 'playbackManager', 'dom', 'browser', 'css!./iconosd', 'materia function updatePlayerVolumeState(isMuted, volume) { if (iconElement) { - iconElement.innerHTML = isMuted ? 'volume_off' : 'volume_up'; + iconElement.classList.remove('volume_off', 'volume_up'); + iconElement.classList.add(isMuted ? 'volume_off' : 'volume_up'); } if (progressElement) { progressElement.style.width = (volume || 0) + '%'; diff --git a/src/components/playbacksettings/playbacksettings.js b/src/components/playbacksettings/playbacksettings.js index 69915b18bf..259386397d 100644 --- a/src/components/playbacksettings/playbacksettings.js +++ b/src/components/playbacksettings/playbacksettings.js @@ -1,5 +1,5 @@ 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"; + 'use strict'; function fillSkipLengths(select) { @@ -17,15 +17,15 @@ define(['require', 'browser', 'appSettings', 'apphost', 'focusManager', 'quality function populateLanguages(select, languages) { - var html = ""; + var html = ''; - html += ""; + html += "'; for (var i = 0, length = languages.length; i < length; i++) { var culture = languages[i]; - html += ""; + html += "'; } select.innerHTML = html; @@ -154,12 +154,12 @@ define(['require', 'browser', 'appSettings', 'apphost', 'focusManager', 'quality populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures); - context.querySelector('#selectAudioLanguage', context).value = user.Configuration.AudioLanguagePreference || ""; + 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) { + apiClient.getNamedConfiguration('cinemamode').then(function (cinemaConfig) { if (cinemaConfig.EnableIntrosForMovies || cinemaConfig.EnableIntrosForEpisodes) { context.querySelector('.cinemaModeOptions').classList.remove('hide'); @@ -342,4 +342,4 @@ define(['require', 'browser', 'appSettings', 'apphost', 'focusManager', 'quality }; return PlaybackSettings; -}); \ No newline at end of file +}); diff --git a/src/components/playbacksettings/playbacksettings.template.html b/src/components/playbacksettings/playbacksettings.template.html index 06cfe3f3d6..0c8b726a40 100644 --- a/src/components/playbacksettings/playbacksettings.template.html +++ b/src/components/playbacksettings/playbacksettings.template.html @@ -86,4 +86,4 @@ - \ No newline at end of file + diff --git a/src/components/playerstats/playerstats.css b/src/components/playerstats/playerstats.css index b9d6355bd2..dfdf75a2e0 100644 --- a/src/components/playerstats/playerstats.css +++ b/src/components/playerstats/playerstats.css @@ -1,11 +1,10 @@ .playerStats { - background: rgba(28,28,28,0.8); - border-radius: .3em; + background: rgba(28, 28, 28, 0.8); + border-radius: 0.3em; color: #fff; left: 1.5em; position: absolute; top: 5em; - color: #fff; } .playerStats-tv { @@ -23,8 +22,8 @@ .playerStats-closeButton { position: absolute; - top: .25em; - right: .25em; + top: 0.25em; + right: 0.25em; color: #ccc; z-index: 1; } @@ -44,7 +43,7 @@ .playerStats-stat-label { font-weight: 500; - margin: 0 .5em 0 0; + margin: 0 0.5em 0 0; } .playerStats-stat-header { diff --git a/src/components/playerstats/playerstats.js b/src/components/playerstats/playerstats.js index 4179192dd2..c0fb369c6c 100644 --- a/src/components/playerstats/playerstats.js +++ b/src/components/playerstats/playerstats.js @@ -18,7 +18,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (layoutManager.tv) { button = ''; } else { - button = ''; + button = ''; } var contentClass = layoutManager.tv ? 'playerStats-content playerStats-content-tv' : 'playerStats-content'; @@ -132,7 +132,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (videoCodec) { sessionStats.push({ - label: globalize.translate("LabelVideoCodec"), + label: globalize.translate('LabelVideoCodec'), value: session.TranscodingInfo.IsVideoDirect ? (videoCodec.toUpperCase() + ' (direct)') : videoCodec.toUpperCase() }); } @@ -140,7 +140,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (audioCodec) { sessionStats.push({ - label: globalize.translate("LabelAudioCodec"), + label: globalize.translate('LabelAudioCodec'), value: session.TranscodingInfo.IsAudioDirect ? (audioCodec.toUpperCase() + ' (direct)') : audioCodec.toUpperCase() }); } @@ -157,28 +157,28 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (totalBitrate) { sessionStats.push({ - label: globalize.translate("LabelBitrate"), + label: globalize.translate('LabelBitrate'), value: getDisplayBitrate(totalBitrate) }); } if (session.TranscodingInfo.CompletionPercentage) { sessionStats.push({ - label: globalize.translate("LabelTranscodingProgress"), + label: globalize.translate('LabelTranscodingProgress'), value: session.TranscodingInfo.CompletionPercentage.toFixed(1) + '%' }); } if (session.TranscodingInfo.Framerate) { sessionStats.push({ - label: globalize.translate("LabelTranscodingFramerate"), + label: globalize.translate('LabelTranscodingFramerate'), value: session.TranscodingInfo.Framerate + ' fps' }); } if (session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { sessionStats.push({ - label: globalize.translate("LabelReasonForTranscoding"), + label: globalize.translate('LabelReasonForTranscoding'), value: session.TranscodingInfo.TranscodeReasons.map(translateReason).join('
') }); } @@ -216,14 +216,14 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (mediaSource.Container) { sessionStats.push({ - label: globalize.translate("LabelProfileContainer"), + label: globalize.translate('LabelProfileContainer'), value: mediaSource.Container }); } if (mediaFileSize) { sessionStats.push({ - label: globalize.translate("LabelSize"), + label: globalize.translate('LabelSize'), value: getReadableSize(mediaFileSize) }); } @@ -231,7 +231,7 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (totalBitrate) { sessionStats.push({ - label: globalize.translate("LabelBitrate"), + label: globalize.translate('LabelBitrate'), value: getDisplayBitrate(totalBitrate) }); } @@ -267,14 +267,14 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (videoInfos.length) { sessionStats.push({ - label: globalize.translate("LabelVideoCodec"), + label: globalize.translate('LabelVideoCodec'), value: videoInfos.join(' ') }); } if (videoStream.BitRate) { sessionStats.push({ - label: globalize.translate("LabelVideoBitrate"), + label: globalize.translate('LabelVideoBitrate'), value: getDisplayBitrate(videoStream.BitRate) }); } @@ -291,35 +291,35 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth if (audioInfos.length) { sessionStats.push({ - label: globalize.translate("LabelAudioCodec"), + label: globalize.translate('LabelAudioCodec'), value: audioInfos.join(' ') }); } if (audioStream.BitRate) { sessionStats.push({ - label: globalize.translate("LabelAudioBitrate"), + label: globalize.translate('LabelAudioBitrate'), value: getDisplayBitrate(audioStream.BitRate) }); } if (audioChannels) { sessionStats.push({ - label: globalize.translate("LabelAudioChannels"), + label: globalize.translate('LabelAudioChannels'), value: audioChannels }); } if (audioStream.SampleRate) { sessionStats.push({ - label: globalize.translate("LabelAudioSampleRate"), + label: globalize.translate('LabelAudioSampleRate'), value: audioStream.SampleRate + ' Hz' }); } if (audioStream.BitDepth) { sessionStats.push({ - label: globalize.translate("LabelAudioBitDepth"), + label: globalize.translate('LabelAudioBitDepth'), value: audioStream.BitDepth }); } @@ -346,12 +346,12 @@ define(['events', 'globalize', 'playbackManager', 'connectionManager', 'playMeth }; baseCategory.stats.unshift({ - label: globalize.translate("LabelPlayMethod"), + label: globalize.translate('LabelPlayMethod'), value: displayPlayMethod }); baseCategory.stats.unshift({ - label: globalize.translate("LabelPlayer"), + label: globalize.translate('LabelPlayer'), value: player.name }); diff --git a/src/components/playlisteditor/playlisteditor.js b/src/components/playlisteditor/playlisteditor.js index 4738211a5e..56d7142ad3 100644 --- a/src/components/playlisteditor/playlisteditor.js +++ b/src/components/playlisteditor/playlisteditor.js @@ -1,24 +1,10 @@ -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) { +define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', 'connectionManager', 'userSettings', 'appRouter', 'globalize', 'emby-input', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (dom, shell, dialogHelper, loading, layoutManager, playbackManager, connectionManager, userSettings, appRouter, globalize) { 'use strict'; var currentServerId; - function parentWithClass(elem, className) { - - while (!elem.classList || !elem.classList.contains(className)) { - elem = elem.parentNode; - - if (!elem) { - return null; - } - } - - return elem; - } - function onSubmit(e) { - - var panel = parentWithClass(this, 'dialog'); + var panel = dom.parentWithClass(this, 'dialog'); var playlistId = panel.querySelector('#selectPlaylistToAddTo').value; var apiClient = connectionManager.getApiClient(currentServerId); @@ -35,11 +21,9 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } function createPlaylist(apiClient, dlg) { - loading.show(); - var url = apiClient.getUrl("Playlists", { - + var url = apiClient.getUrl('Playlists', { Name: dlg.querySelector('#txtNewPlaylistName').value, Ids: dlg.querySelector('.fldSelectedItemIds').value || '', userId: apiClient.getCurrentUserId() @@ -47,12 +31,10 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', }); apiClient.ajax({ - type: "POST", + type: 'POST', url: url, - dataType: "json" - + dataType: 'json' }).then(function (result) { - loading.hide(); var id = result.Id; @@ -63,16 +45,13 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } function redirectToPlaylist(apiClient, id) { - appRouter.showItem(id, apiClient.serverId()); } function addToPlaylist(apiClient, dlg, id) { - var itemIds = dlg.querySelector('.fldSelectedItemIds').value || ''; if (id === 'queue') { - playbackManager.queue({ serverId: apiClient.serverId(), ids: itemIds.split(',') @@ -84,18 +63,16 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', loading.show(); - var url = apiClient.getUrl("Playlists/" + id + "/Items", { - + var url = apiClient.getUrl('Playlists/' + id + '/Items', { Ids: itemIds, userId: apiClient.getCurrentUserId() }); apiClient.ajax({ - type: "POST", + type: 'POST', url: url }).then(function () { - loading.hide(); dlg.submitted = true; @@ -108,7 +85,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } function populatePlaylists(editorOptions, panel) { - var select = panel.querySelector('#selectPlaylistToAddTo'); loading.hide(); @@ -116,16 +92,14 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', panel.querySelector('.newPlaylistInfo').classList.add('hide'); var options = { - Recursive: true, - IncludeItemTypes: "Playlist", + 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()) { @@ -135,7 +109,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', html += ''; html += result.Items.map(function (i) { - return ''; }); @@ -159,7 +132,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } function getEditorHtml(items) { - var html = ''; html += '
'; @@ -195,7 +167,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } function initEditor(content, options, items) { - content.querySelector('#selectPlaylistToAddTo').addEventListener('change', function () { if (this.value) { content.querySelector('.newPlaylistInfo').classList.add('hide'); @@ -235,7 +206,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } PlaylistEditor.prototype.show = function (options) { - var items = options.items || {}; currentServerId = options.serverId; @@ -258,7 +228,7 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', var title = globalize.translate('HeaderAddToPlaylist'); html += '
'; - html += ''; + html += ''; html += '

'; html += title; html += '

'; @@ -272,7 +242,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', initEditor(dlg, options, items); dlg.querySelector('.btnCancel').addEventListener('click', function () { - dialogHelper.close(dlg); }); @@ -281,7 +250,6 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'playbackManager', } return dialogHelper.open(dlg).then(function () { - if (layoutManager.tv) { centerFocus(dlg.querySelector('.formDialogContent'), false, false); } diff --git a/src/components/playmenu.js b/src/components/playmenu.js index 7225ff94e1..a410da6985 100644 --- a/src/components/playmenu.js +++ b/src/components/playmenu.js @@ -72,4 +72,4 @@ define(['actionsheet', 'datetime', 'playbackManager', 'globalize', 'appSettings' return { show: show }; -}); \ No newline at end of file +}); diff --git a/src/components/pluginManager.js b/src/components/pluginManager.js index ec65e63e65..2126d73b3c 100644 --- a/src/components/pluginManager.js +++ b/src/components/pluginManager.js @@ -27,7 +27,7 @@ define(['events'], function (events) { PluginManager.prototype.loadPlugin = function (url) { - console.log('Loading plugin: ' + url); + console.debug('Loading plugin: ' + url); var instance = this; return new Promise(function (resolve, reject) { @@ -146,4 +146,4 @@ define(['events'], function (events) { }; return new PluginManager(); -}); \ No newline at end of file +}); diff --git a/src/components/polyfills/objectassign.js b/src/components/polyfills/objectassign.js deleted file mode 100644 index bf8d7118a5..0000000000 --- a/src/components/polyfills/objectassign.js +++ /dev/null @@ -1,23 +0,0 @@ -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; - }; - })(); -} diff --git a/src/components/prompt/nativeprompt.js b/src/components/prompt/nativeprompt.js deleted file mode 100644 index b0634bd428..0000000000 --- a/src/components/prompt/nativeprompt.js +++ /dev/null @@ -1,28 +0,0 @@ -define([], function () { - 'use strict'; - - function replaceAll(str, find, replace) { - - 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/components/prompt/prompt.js b/src/components/prompt/prompt.js index 6e8e019c83..a76083cf04 100644 --- a/src/components/prompt/prompt.js +++ b/src/components/prompt/prompt.js @@ -1,6 +1,10 @@ -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) { +define(['browser', 'dialogHelper', 'layoutManager', 'scrollHelper', 'globalize', 'dom', 'require', 'material-icons', 'emby-button', 'paper-icon-button-light', 'emby-input', 'formDialogStyle'], function(browser, dialogHelper, layoutManager, scrollHelper, globalize, dom, require) { 'use strict'; + function replaceAll(str, find, replace) { + return str.split(find).join(replace); + } + function setInputProperties(dlg, options) { var txtInput = dlg.querySelector('#txtInput'); @@ -13,7 +17,6 @@ define(['dialogHelper', 'layoutManager', 'scrollHelper', 'globalize', 'dom', 're } function showDialog(options, template) { - var dialogOptions = { removeOnClose: true, scrollY: false @@ -71,34 +74,49 @@ define(['dialogHelper', 'layoutManager', 'scrollHelper', 'globalize', 'dom', 're 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; - - if (value) { - return value; + if (submitValue) { + return submitValue; } else { return Promise.reject(); } }); } - return function (options) { + if ((browser.tv || browser.xboxOne) && window.confirm) { + return function (options) { + if (typeof options === 'string') { + options = { + label: '', + text: options + }; + } - return new Promise(function (resolve, reject) { - require(['text!./prompt.template.html'], function (template) { + var label = replaceAll(options.label || '', '
', '\n'); + var result = prompt(label, options.text || ''); - if (typeof options === 'string') { - options = { - title: '', - text: options - }; - } - showDialog(options, template).then(resolve, reject); + if (result) { + return Promise.resolve(result); + } else { + return Promise.reject(result); + } + }; + } else { + 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/components/prompt/prompt.template.html b/src/components/prompt/prompt.template.html index b1e7f580f0..981fa9f102 100644 --- a/src/components/prompt/prompt.template.html +++ b/src/components/prompt/prompt.template.html @@ -1,6 +1,6 @@

diff --git a/src/components/qualityoptions.js b/src/components/qualityoptions.js index e46a690e8a..5ad69cb790 100644 --- a/src/components/qualityoptions.js +++ b/src/components/qualityoptions.js @@ -160,4 +160,4 @@ define(['globalize'], function (globalize) { getVideoQualityOptions: getVideoQualityOptions, getAudioQualityOptions: getAudioQualityOptions }; -}); \ No newline at end of file +}); diff --git a/src/components/recordingcreator/recordingbutton.js b/src/components/recordingcreator/recordingbutton.js index a32803e107..c4bfc43010 100644 --- a/src/components/recordingcreator/recordingbutton.js +++ b/src/components/recordingcreator/recordingbutton.js @@ -21,16 +21,25 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom' } } + function setButtonIcon(button, icon) { + var inner = button.querySelector('.material-icons'); + inner.classList.remove('fiber_smart_record'); + inner.classList.remove('fiber_manual_record'); + inner.classList.add(icon); + } + function RecordingButton(options) { this.options = options; + var button = options.button; + + setButtonIcon(button, 'fiber_manual_record'); + 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 = 'fiber_manual_record'; var clickFn = onRecordingButtonClick.bind(this); this.clickFn = clickFn; @@ -80,7 +89,7 @@ define(['globalize', 'connectionManager', 'require', 'loading', 'apphost', 'dom' var options = this.options; var button = options.button; this.item = item; - button.querySelector('i').innerHTML = getIndicatorIcon(item); + setButtonIcon(button, getIndicatorIcon(item)); if (item.TimerId && (item.Status || 'Cancelled') !== 'Cancelled') { button.classList.add('recordingIcon-active'); diff --git a/src/components/recordingcreator/recordingcreator.css b/src/components/recordingcreator/recordingcreator.css index dc1ba9b31a..031d04b860 100644 --- a/src/components/recordingcreator/recordingcreator.css +++ b/src/components/recordingcreator/recordingcreator.css @@ -9,7 +9,7 @@ } .recordingDialog-itemName { - margin-top: .7em; + margin-top: 0.7em; } .recordingDetailsContainer { diff --git a/src/components/recordingcreator/recordingcreator.js b/src/components/recordingcreator/recordingcreator.js index 614d483b21..ae26d0debc 100644 --- a/src/components/recordingcreator/recordingcreator.js +++ b/src/components/recordingcreator/recordingcreator.js @@ -36,14 +36,14 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c if (imageTags.Primary) { return apiClient.getScaledImageUrl(item.Id, { - type: "Primary", + type: 'Primary', maxHeight: imageHeight, tag: item.ImageTags.Primary }); } else if (imageTags.Thumb) { return apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', maxHeight: imageHeight, tag: item.ImageTags.Thumb }); @@ -202,4 +202,4 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c return { show: showEditor }; -}); \ No newline at end of file +}); diff --git a/src/components/recordingcreator/recordingcreator.template.html b/src/components/recordingcreator/recordingcreator.template.html index 2a2840aecc..8d7d75c8f6 100644 --- a/src/components/recordingcreator/recordingcreator.template.html +++ b/src/components/recordingcreator/recordingcreator.template.html @@ -1,5 +1,5 @@
- +

diff --git a/src/components/recordingcreator/recordingeditor.js b/src/components/recordingcreator/recordingeditor.js index 3a1d4ba943..86c731ad26 100644 --- a/src/components/recordingcreator/recordingeditor.js +++ b/src/components/recordingcreator/recordingeditor.js @@ -159,4 +159,4 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c return { show: showEditor }; -}); \ No newline at end of file +}); diff --git a/src/components/recordingcreator/recordingeditor.template.html b/src/components/recordingcreator/recordingeditor.template.html index 6b853704f3..f7a9f98ee6 100644 --- a/src/components/recordingcreator/recordingeditor.template.html +++ b/src/components/recordingcreator/recordingeditor.template.html @@ -1,5 +1,5 @@
- +

${HeaderRecordingOptions}

diff --git a/src/components/recordingcreator/recordingfields.css b/src/components/recordingcreator/recordingfields.css index c8492f5298..db0c7e0692 100644 --- a/src/components/recordingcreator/recordingfields.css +++ b/src/components/recordingcreator/recordingfields.css @@ -4,9 +4,9 @@ } .recordingIcon-active { - color: #cc3333; + color: #c33; } .recordSeriesContainer { - margin-bottom: .8em; -} \ No newline at end of file + margin-bottom: 0.8em; +} diff --git a/src/components/recordingcreator/recordingfields.js b/src/components/recordingcreator/recordingfields.js index 106fec36bf..b4cbdfab0a 100644 --- a/src/components/recordingcreator/recordingfields.js +++ b/src/components/recordingcreator/recordingfields.js @@ -151,7 +151,7 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa var apiClient = connectionManager.getApiClient(options.serverId); var button = dom.parentWithTag(e.target, 'BUTTON'); - var isChecked = !button.querySelector('i').classList.contains('recordingIcon-active'); + var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active'); var hasEnabledTimer = this.TimerId && this.Status !== 'Cancelled'; @@ -191,7 +191,7 @@ define(['globalize', 'connectionManager', 'serverNotifications', 'require', 'loa var apiClient = connectionManager.getApiClient(options.serverId); var button = dom.parentWithTag(e.target, 'BUTTON'); - var isChecked = !button.querySelector('i').classList.contains('recordingIcon-active'); + var isChecked = !button.querySelector('.material-icons').classList.contains('recordingIcon-active'); if (isChecked) { options.parent.querySelector('.recordSeriesContainer').classList.remove('hide'); diff --git a/src/components/recordingcreator/recordingfields.template.html b/src/components/recordingcreator/recordingfields.template.html index 622b0d62e7..25a0c3c30d 100644 --- a/src/components/recordingcreator/recordingfields.template.html +++ b/src/components/recordingcreator/recordingfields.template.html @@ -2,7 +2,7 @@
@@ -14,7 +14,7 @@
diff --git a/src/components/recordingcreator/recordinghelper.js b/src/components/recordingcreator/recordinghelper.js index 4bfd316c73..a071cb2032 100644 --- a/src/components/recordingcreator/recordinghelper.js +++ b/src/components/recordingcreator/recordinghelper.js @@ -214,4 +214,4 @@ define(['globalize', 'loading', 'connectionManager'], function (globalize, loadi cancelTimerWithConfirmation: cancelTimerWithConfirmation, cancelSeriesTimerWithConfirmation: cancelSeriesTimerWithConfirmation }; -}); \ No newline at end of file +}); diff --git a/src/components/recordingcreator/seriesrecordingeditor.js b/src/components/recordingcreator/seriesrecordingeditor.js index 73a98cf5e7..62accd5b63 100644 --- a/src/components/recordingcreator/seriesrecordingeditor.js +++ b/src/components/recordingcreator/seriesrecordingeditor.js @@ -267,4 +267,4 @@ define(['dialogHelper', 'globalize', 'layoutManager', 'mediaInfo', 'apphost', 'c show: showEditor, embed: embed }; -}); \ No newline at end of file +}); diff --git a/src/components/recordingcreator/seriesrecordingeditor.template.html b/src/components/recordingcreator/seriesrecordingeditor.template.html index c2e8ebd0ed..582c1a633c 100644 --- a/src/components/recordingcreator/seriesrecordingeditor.template.html +++ b/src/components/recordingcreator/seriesrecordingeditor.template.html @@ -1,5 +1,5 @@
- +

${HeaderSeriesOptions}

diff --git a/src/components/refreshdialog/refreshdialog.js b/src/components/refreshdialog/refreshdialog.js index 30074b4d0b..3edb725c4a 100644 --- a/src/components/refreshdialog/refreshdialog.js +++ b/src/components/refreshdialog/refreshdialog.js @@ -1,19 +1,6 @@ -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) { +define(['dom', 'shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager', 'appRouter', 'globalize', 'emby-input', 'emby-checkbox', 'paper-icon-button-light', 'emby-select', 'material-icons', 'css!./../formdialog', 'emby-button'], function (dom, shell, dialogHelper, loading, layoutManager, connectionManager, appRouter, globalize) { 'use strict'; - function parentWithClass(elem, className) { - - while (!elem.classList || !elem.classList.contains(className)) { - elem = elem.parentNode; - - if (!elem) { - return null; - } - } - - return elem; - } - function getEditorHtml() { var html = ''; @@ -65,7 +52,7 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager' loading.show(); var instance = this; - var dlg = parentWithClass(e.target, 'dialog'); + var dlg = dom.parentWithClass(e.target, 'dialog'); var options = instance.options; var apiClient = connectionManager.getApiClient(options.serverId); @@ -123,7 +110,7 @@ define(['shell', 'dialogHelper', 'loading', 'layoutManager', 'connectionManager' var title = globalize.translate('RefreshMetadata'); html += '
'; - html += ''; + html += ''; html += '

'; html += title; html += '

'; diff --git a/src/components/remotecontrol/remotecontrol.css b/src/components/remotecontrol/remotecontrol.css index 673f301c1e..073c925339 100644 --- a/src/components/remotecontrol/remotecontrol.css +++ b/src/components/remotecontrol/remotecontrol.css @@ -1,168 +1,649 @@ +.nowPlayingPage { + padding: 5em 0 0 0 !important; +} + .nowPlayingInfoContainer { + display: -webkit-box; + display: -webkit-flex; display: flex; - flex-direction: row + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -webkit-flex-direction: row; + flex-direction: row; } .navigationSection { - text-align: center + text-align: center; +} + +.btnArrowUp { + border-radius: 40% 40% 10% 10%; +} + +.btnArrowLeft { + border-radius: 40% 10% 10% 40%; +} + +.btnArrowRight { + border-radius: 10% 40% 40% 10%; +} + +.btnArrowDown { + border-radius: 10% 10% 40% 40%; +} + +.btnOk { + border-radius: 10%; } .nowPlayingPageTitle { - margin: 0 0 .5em .5em + margin: 0 0 0.5em 0.5em; +} + +.nowPlayingAlbum a, +.nowPlayingArtist a { + font-weight: normal; + text-align: left !important; + color: inherit !important; +} + +.nowPlayingButtonsContainer { + display: flex; +} + +.nowPlayingInfoContainerMedia { + text-align: left; + margin-bottom: 1em; +} + +.nowPlayingPositionSlider { + width: stretch; } .nowPlayingPositionSliderContainer { - margin: .7em 0 .7em 1em + margin: 0.2em 1em 0.2em 1em; + width: 100%; + z-index: 0; } .nowPlayingInfoButtons { + display: -webkit-box; + display: -webkit-flex; display: flex; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; - flex-wrap: wrap + -webkit-flex-wrap: wrap; + flex-wrap: wrap; } .nowPlayingInfoControls, .nowPlayingTime { display: flex; + display: -webkit-box; + display: -webkit-flex; } .nowPlayingPageImageContainer { - width: 20%; - margin-right: .25em; + width: 16%; + margin-right: 1em; position: relative; - flex-shrink: 0 + -webkit-flex-shrink: 0; + flex-shrink: 0; } -@media all and (min-width:50em) { - .nowPlayingPageImageContainer { - width: 16% - } +.nowPlayingPageImageContainerNoAlbum { + width: 100%; + position: relative; +} + +.nowPlayingPageImageContainerNoAlbum button { + cursor: default; +} + +.nowPlayingPageImageContainerNoAlbum::after { + content: ""; + display: block; + padding-bottom: 100%; +} + +.btnPlayPause { + font-size: xx-large; + padding: 0; + margin: 0; } .nowPlayingInfoControls { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; flex-grow: 1; display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; flex-direction: column; - justify-content: center + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; } .nowPlayingPageImage { + display: block; bottom: 0; left: 0; right: 0; + margin: 0 auto; width: 100%; + -webkit-box-shadow: 0 0 1.9vh #000; box-shadow: 0 0 1.9vh #000; - border: .1em solid #222; - user-drag: none; + border: 0.1em solid #222; user-select: none; + -moz-user-select: none; + -webkit-user-drag: none; + -webkit-user-select: none; + -ms-user-select: none; } -@media all and (orientation:portrait) and (max-width:50em) { +.contextMenuList { + padding: 1.5em 0; +} + +.contextMenuList a { + color: inherit !important; +} + +.contextMenuList .material-icons.listItemIcon { + font-size: x-large; +} + +.nowPlayingSecondaryButtons { + 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; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + z-index: 0; +} + +@media all and (min-width: 63em) { + .nowPlayingPage { + padding: 8em 0 0 0 !important; + } + + .nowPlayingSecondaryButtons { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + } + + .nowPlayingPageUserDataButtonsTitle { + display: none !important; + } + + .playlistSectionButton, + .nowPlayingPlaylist, + .nowPlayingContextMenu { + background: unset !important; + } +} + +@media all and (min-width: 80em) { + .nowPlayingPageImageContainer { + margin-right: 0.75em; + } +} + +@media all and (orientation: portrait) and (max-width: 47em) { + .remoteControlContent { + padding-left: 7.3% !important; + padding-right: 7.3% !important; + display: flex; + height: 100%; + flex-direction: column; + } + .nowPlayingInfoContainer { + -webkit-box-orient: vertical !important; + -webkit-box-direction: normal !important; + -webkit-flex-direction: column !important; flex-direction: column !important; - align-items: center + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + width: 100%; + height: calc(100% - 4.2em); } .nowPlayingPageTitle { - text-align: center; - margin: .5em 0 .75em + /* text-align: center; */ + margin: 0; + } + + .nowPlayingAlbum, + .nowPlayingArtist { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .nowPlayingInfoContainerMedia { + text-align: left !important; + width: 80%; } .nowPlayingPositionSliderContainer { - margin: .7em 1em + margin: 0.2em 1em 0.2em 1em; } .nowPlayingInfoButtons { - justify-content: center + /* margin: 1.5em 0 0 0; */ + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + font-size: x-large; + height: 100%; } .nowPlayingPageImageContainer { - width: auto; - margin-right: 0 + width: 100%; + margin: auto auto 0.5em; + } + + .nowPlayingPageImageContainerNoAlbum .cardImageContainer .cardImageIcon { + font-size: 15em; + color: inherit; } .nowPlayingInfoControls { - margin-top: 1em; - max-width: 100% + margin: 0.5em 0 1em 0; + width: 100%; + -webkit-box-pack: start !important; + -webkit-justify-content: start !important; + justify-content: start !important; + } + + .nowPlayingSecondaryButtons { + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + } + + .nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle { + width: 20%; + font-size: large; + } + + .nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button { + padding-top: 0; + padding-right: 0; + margin-right: 0; + float: right; + border-radius: 0; + } + + .nowPlayingInfoButtons .btnRewind { + position: absolute; + left: 0; + margin-left: 0; + padding-left: 7.3%; + font-size: smaller; + } + + .nowPlayingInfoButtons .btnFastForward { + position: absolute; + right: 0; + margin-right: 0; + padding-right: 7.3%; + font-size: smaller; + } + + .paper-icon-button-light:hover { + color: #fff !important; + background-color: transparent !important; + } + + .btnPlayPause { + padding: 0; + margin: 0; + font-size: 1.7em; + } + + .btnPlayPause:hover { + background-color: transparent !important; } .nowPlayingPageImage { + /* width: inherit; */ + overflow-y: hidden; + overflow: hidden; + margin: 0 auto; + } + + .nowPlayingPageImage.nowPlayingPageImageAudio { + width: 100%; + } + + .nowPlayingPageImageContainer.nowPlayingPageImagePoster { + height: 50%; + overflow: hidden; + } + + .nowPlayingPageImageContainer.nowPlayingPageImagePoster img { + height: 100%; width: auto; - height: 36vh + } + + #nowPlayingPage .playlistSection .playlist, + #nowPlayingPage .playlistSection .contextMenu { + position: absolute; + top: 12.2em; + bottom: 4.2em; + overflow: scroll; + padding: 0 1em; + display: inline-block; + left: 0; + right: 0; + z-index: 1000; + } + + .playlistSectionButton { + position: fixed; + bottom: 0; + left: 0; + height: 4.2em; + right: 0; + padding-left: 7.3%; + padding-right: 7.3%; + } + + .playlistSectionButton .btnTogglePlaylist { + font-size: larger; + margin: 0; + padding-left: 0; + } + + .playlistSectionButton .btnSavePlaylist { + margin: 0; + padding-right: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + border-radius: 0; + } + + .playlistSectionButton .btnToggleContextMenu { + font-size: larger; + margin: 0; + padding-right: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + border-radius: 0; + } + + .playlistSectionButton .volumecontrol { + width: 100%; + } + + .remoteControlSection { + margin: 0; + padding: 0 0 4.2em 0; + } + + .nowPlayingButtonsContainer { + display: flex; + height: 100%; + flex-direction: column; } } -@media all and (orientation:portrait) and (max-width:40em) { +@media all and (orientation: landscape) and (max-width: 63em) { + .remoteControlContent { + padding-left: 4.3% !important; + padding-right: 4.3% !important; + display: flex; + height: 100%; + flex-direction: column; + } + + .nowPlayingInfoContainer { + -webkit-box-orient: horizontal !important; + -webkit-box-direction: normal !important; + -webkit-flex-direction: row !important; + flex-direction: row !important; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + width: 100%; + height: calc(100% - 4.2em); + } + + .nowPlayingPageTitle { + /* text-align: center; */ + margin: 0; + } + + .nowPlayingInfoContainerMedia { + text-align: left !important; + width: 80%; + } + + .nowPlayingPositionSliderContainer { + margin: 0.2em 1em 0.2em 1em; + } + + .nowPlayingInfoButtons { + /* margin: 1.5em 0 0 0; */ + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + font-size: x-large; + height: 100%; + } + + .nowPlayingPageImageContainer { + width: 30%; + margin: auto 1em auto auto; + } + + .nowPlayingPageImageContainerNoAlbum .cardImageContainer .cardImageIcon { + font-size: 12em; + color: inherit; + } + + .nowPlayingInfoControls { + margin: 0.5em 0 1em 0; + width: 100%; + -webkit-box-pack: start !important; + -webkit-justify-content: start !important; + justify-content: start !important; + } + + .nowPlayingSecondaryButtons { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: center; + -webkit-justify-content: center; + justify-content: center; + } + + .nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle { + width: 20%; + font-size: large; + } + + .nowPlayingInfoControls .nowPlayingPageUserDataButtonsTitle button { + padding-top: 0; + padding-right: 0; + margin-right: 0; + float: right; + border-radius: 0; + } + + .paper-icon-button-light:hover { + color: #fff !important; + background-color: transparent !important; + } + + .btnPlayPause { + padding: 0; + margin: 0; + font-size: 1.7em; + } + + .btnPlayPause:hover { + background-color: transparent !important; + } + .nowPlayingPageImage { - height: 30vh + /* width: inherit; */ + overflow-y: hidden; + overflow: hidden; + margin: 0 auto; + } + + .nowPlayingPageImage.nowPlayingPageImageAudio { + width: 100%; + } + + .nowPlayingPageImageContainer.nowPlayingPageImagePoster { + height: 100%; + overflow: hidden; + } + + .nowPlayingPageImageContainer.nowPlayingPageImagePoster img { + height: 100%; + width: auto; + } + + #nowPlayingPage .playlistSection .playlist, + #nowPlayingPage .playlistSection .contextMenu { + position: absolute; + top: 7.2em; + bottom: 4.2em; + overflow: scroll; + padding: 0 1em; + display: inline-block; + left: 0; + right: 0; + z-index: 1000; + } + + .playlistSectionButton { + position: fixed; + bottom: 0; + left: 0; + height: 4.2em; + right: 0; + padding-left: 4.3%; + padding-right: 4.3%; + } + + .playlistSectionButton .btnTogglePlaylist { + font-size: larger; + margin: 0; + padding-left: 0; + } + + .playlistSectionButton .btnSavePlaylist { + margin: 0; + padding-right: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + border-radius: 0; + } + + .playlistSectionButton .btnToggleContextMenu { + font-size: larger; + margin: 0; + padding-right: 0; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + -webkit-box-pack: end; + -webkit-justify-content: flex-end; + justify-content: flex-end; + border-radius: 0; + } + + .playlistSectionButton .volumecontrol { + width: 100%; + } + + .remoteControlSection { + margin: 4.2em 0 0 0; + padding: 0 0 4.2em 0; + } + + .nowPlayingButtonsContainer { + display: flex; + height: 100%; + flex-direction: column; } } .nowPlayingTime { display: flex; + -webkit-box-align: center; + -webkit-align-items: center; align-items: center; - margin: 0 1em -} - -.nowPlayingSecondaryButtons { - display: flex; - align-items: center; - flex-wrap: wrap; - justify-content: center -} - -@media all and (min-width:50em) { - .nowPlayingSecondaryButtons { - flex-grow: 1; - justify-content: flex-end - } -} - -@media all and (min-width:80em) { - .nowPlayingPageImageContainer { - margin-right: .75em - } + margin: 0 1em; } .nowPlayingNavButtonContainer { - width: 30em + width: 30em; } -.smallBackdropPosterItem .cardOverlayInner>div { +.smallBackdropPosterItem .cardOverlayInner > div { white-space: nowrap; + -o-text-overflow: ellipsis; text-overflow: ellipsis; - overflow: hidden + overflow: hidden; } .playlistIndexIndicatorImage { + -webkit-background-size: initial initial !important; background-size: initial !important; - background-image: url(assets/img/equalizer.gif) !important; + background-image: url(../../assets/img/equalizer.gif) !important; } .hideVideoButtons .videoButton { - display: none + display: none; } .nowPlayingVolumeSliderContainer { - width: 9em + width: 9em; } -@media all and (max-width:50em) { - .nowPlayingInfoButtons .nowPlayingPageUserDataButtons { - display: none !important +@media all and (max-width: 63em) { + .nowPlayingSecondaryButtons .nowPlayingPageUserDataButtons, + .nowPlayingSecondaryButtons .repeatToggleButton, + .nowPlayingInfoButtons .playlist .listItemMediaInfo, + .nowPlayingInfoButtons .btnStop { + display: none !important; } -} -@media all and (max-width:47em) { - .nowPlayingInfoButtons .repeatToggleButton { - display: none !important - } -} - -@media all and (max-width:34em) { - .nowPlayingInfoButtons .btnNowPlayingFastForward, - .nowPlayingInfoButtons .btnNowPlayingRewind, - .nowPlayingInfoButtons .playlist .listItemMediaInfo { - display: none !important + .navigationSection .collapseContent .material-icons { + font-size: 4em; } } diff --git a/src/components/remotecontrol/remotecontrol.js b/src/components/remotecontrol/remotecontrol.js index 3a48c2dbef..a4f25a774c 100644 --- a/src/components/remotecontrol/remotecontrol.js +++ b/src/components/remotecontrol/remotecontrol.js @@ -1,5 +1,5 @@ -define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageLoader", "playbackManager", "nowPlayingHelper", "events", "connectionManager", "apphost", "globalize", "cardStyle", "emby-itemscontainer", "css!./remotecontrol.css", "emby-ratingbutton"], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize) { - "use strict"; +define(['browser', 'datetime', 'backdrop', 'libraryBrowser', 'listView', 'imageLoader', 'playbackManager', 'nowPlayingHelper', 'events', 'connectionManager', 'apphost', 'globalize', 'layoutManager', 'userSettings', 'cardBuilder', 'cardStyle', 'emby-itemscontainer', 'css!./remotecontrol.css', 'emby-ratingbutton'], function (browser, datetime, backdrop, libraryBrowser, listView, imageLoader, playbackManager, nowPlayingHelper, events, connectionManager, appHost, globalize, layoutManager, userSettings, cardBuilder) { + 'use strict'; function showAudioMenu(context, player, button, item) { var currentIndex = playbackManager.getAudioStreamIndex(player); @@ -17,7 +17,7 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL return menuItem; }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, @@ -45,11 +45,11 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL }); menuItems.unshift({ id: -1, - name: globalize.translate("ButtonOff"), + name: globalize.translate('ButtonOff'), selected: null == currentIndex }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, @@ -63,22 +63,22 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function getNowPlayingNameHtml(nowPlayingItem, includeNonNameInfo) { return nowPlayingHelper.getNowPlayingNames(nowPlayingItem, includeNonNameInfo).map(function (i) { return i.text; - }).join("
"); + }).join('
'); } function seriesImageUrl(item, options) { - if ("Episode" !== item.Type) { + if ('Episode' !== item.Type) { return null; } options = options || {}; - options.type = options.type || "Primary"; - if ("Primary" === options.type && item.SeriesPrimaryImageTag) { + options.type = options.type || 'Primary'; + if ('Primary' === options.type && item.SeriesPrimaryImageTag) { options.tag = item.SeriesPrimaryImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); } - if ("Thumb" === options.type) { + if ('Thumb' === options.type) { if (item.SeriesThumbImageTag) { options.tag = item.SeriesThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); @@ -95,7 +95,7 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function imageUrl(item, options) { options = options || {}; - options.type = options.type || "Primary"; + options.type = options.type || 'Primary'; if (item.ImageTags && item.ImageTags[options.type]) { options.tag = item.ImageTags[options.type]; @@ -110,65 +110,109 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL return null; } - function updateNowPlayingInfo(context, state) { + function updateNowPlayingInfo(context, state, serverId) { var item = state.NowPlayingItem; - var displayName = item ? getNowPlayingNameHtml(item).replace("
", " - ") : ""; - context.querySelector(".nowPlayingPageTitle").innerHTML = displayName; + var displayName = item ? getNowPlayingNameHtml(item).replace('
', ' - ') : ''; + if (typeof item !== 'undefined') { + var nowPlayingServerId = (item.ServerId || serverId); + if (item.Type == 'Audio' || item.MediaStreams[0].Type == 'Audio') { + var songName = item.Name; + if (item.Album != null && item.Artists != null) { + var albumName = item.Album; + var artistName; + if (item.ArtistItems != null) { + artistName = item.ArtistItems[0].Name; + context.querySelector('.nowPlayingAlbum').innerHTML = '${albumName}`; + context.querySelector('.nowPlayingArtist').innerHTML = '${artistName}`; + context.querySelector('.contextMenuAlbum').innerHTML = ' ` + globalize.translate('ViewAlbum') + ''; + context.querySelector('.contextMenuArtist').innerHTML = ' ` + globalize.translate('ViewArtist') + ''; + } else { + artistName = item.Artists; + context.querySelector('.nowPlayingAlbum').innerHTML = albumName; + context.querySelector('.nowPlayingArtist').innerHTML = artistName; + } + } + context.querySelector('.nowPlayingSongName').innerHTML = songName; + } else if (item.Type == 'Episode') { + if (item.SeasonName != null) { + var seasonName = item.SeasonName; + context.querySelector('.nowPlayingSeason').innerHTML = '${seasonName}`; + } + if (item.SeriesName != null) { + var seriesName = item.SeriesName; + if (item.SeriesId !=null) { + context.querySelector('.nowPlayingSerie').innerHTML = '${seriesName}`; + } else { + context.querySelector('.nowPlayingSerie').innerHTML = seriesName; + } + } + context.querySelector('.nowPlayingEpisode').innerHTML = item.Name; + } else { + context.querySelector('.nowPlayingPageTitle').innerHTML = displayName; + } - if (displayName.length > 0) { - context.querySelector(".nowPlayingPageTitle").classList.remove("hide"); - } else { - context.querySelector(".nowPlayingPageTitle").classList.add("hide"); - } + if (displayName.length > 0 && item.Type != 'Audio' && item.Type != 'Episode') { + context.querySelector('.nowPlayingPageTitle').classList.remove('hide'); + } else { + context.querySelector('.nowPlayingPageTitle').classList.add('hide'); + } - var url = item ? seriesImageUrl(item, { - maxHeight: 300 - }) || imageUrl(item, { - maxHeight: 300 - }) : null; + var url = item ? seriesImageUrl(item, { + maxHeight: 300 * 2 + }) || imageUrl(item, { + maxHeight: 300 * 2 + }) : null; - console.log("updateNowPlayingInfo"); - setImageUrl(context, url); - if (item) { - backdrop.setBackdrops([item]); - var apiClient = connectionManager.getApiClient(item.ServerId); - apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) { - var userData = fullItem.UserData || {}; - var likes = null == userData.Likes ? "" : userData.Likes; - context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = ''; - }); - } else { - backdrop.clear(); - context.querySelector(".nowPlayingPageUserDataButtons").innerHTML = ""; + console.debug('updateNowPlayingInfo'); + setImageUrl(context, state, url); + if (item) { + backdrop.setBackdrops([item]); + var apiClient = connectionManager.getApiClient(item.ServerId); + apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (fullItem) { + var userData = fullItem.UserData || {}; + var likes = null == userData.Likes ? '' : userData.Likes; + context.querySelector('.nowPlayingPageUserDataButtonsTitle').innerHTML = ''; + context.querySelector('.nowPlayingPageUserDataButtons').innerHTML = ''; + }); + } else { + backdrop.clear(); + context.querySelector('.nowPlayingPageUserDataButtons').innerHTML = ''; + } } } - function setImageUrl(context, url) { + function setImageUrl(context, state, url) { currentImgUrl = url; - var imgContainer = context.querySelector(".nowPlayingPageImageContainer"); + var item = state.NowPlayingItem; + var imgContainer = context.querySelector('.nowPlayingPageImageContainer'); if (url) { imgContainer.innerHTML = ''; - imgContainer.classList.remove("hide"); + if (item.Type == 'Audio') { + context.querySelector('.nowPlayingPageImage').classList.add('nowPlayingPageImageAudio'); + context.querySelector('.nowPlayingPageImageContainer').classList.remove('nowPlayingPageImageAudio'); + } else { + context.querySelector('.nowPlayingPageImageContainer').classList.add('nowPlayingPageImagePoster'); + context.querySelector('.nowPlayingPageImage').classList.remove('nowPlayingPageImageAudio'); + } } else { - imgContainer.classList.add("hide"); - imgContainer.innerHTML = ""; + imgContainer.innerHTML = '
'; } } function buttonVisible(btn, enabled) { if (enabled) { - btn.classList.remove("hide"); + btn.classList.remove('hide'); } else { - btn.classList.add("hide"); + btn.classList.add('hide'); } } function updateSupportedCommands(context, commands) { - var all = context.querySelectorAll(".btnCommand"); + var all = context.querySelectorAll('.btnCommand'); for (var i = 0, length = all.length; i < length; i++) { - var enableButton = -1 !== commands.indexOf(all[i].getAttribute("data-command")); + var enableButton = -1 !== commands.indexOf(all[i].getAttribute('data-command')); all[i].disabled = !enableButton; } } @@ -178,16 +222,16 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function toggleRepeat(player) { if (player) { switch (playbackManager.getRepeatMode(player)) { - case "RepeatNone": - playbackManager.setRepeatMode("RepeatAll", player); + case 'RepeatNone': + playbackManager.setRepeatMode('RepeatAll', player); break; - case "RepeatAll": - playbackManager.setRepeatMode("RepeatOne", player); + case 'RepeatAll': + playbackManager.setRepeatMode('RepeatOne', player); break; - case "RepeatOne": - playbackManager.setRepeatMode("RepeatNone", player); + case 'RepeatOne': + playbackManager.setRepeatMode('RepeatNone', player); } } } @@ -199,45 +243,46 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL var supportedCommands = playerInfo.supportedCommands; currentPlayerSupportedCommands = supportedCommands; var playState = state.PlayState || {}; - buttonVisible(context.querySelector(".btnToggleFullscreen"), item && "Video" == item.MediaType && -1 != supportedCommands.indexOf("ToggleFullscreen")); + var isSupportedCommands = supportedCommands.includes('DisplayMessage') || supportedCommands.includes('SendString') || supportedCommands.includes('Select'); + buttonVisible(context.querySelector('.btnToggleFullscreen'), item && 'Video' == item.MediaType && supportedCommands.includes('ToggleFullscreen')); updateAudioTracksDisplay(player, context); updateSubtitleTracksDisplay(player, context); - if (-1 != supportedCommands.indexOf("DisplayMessage") && !currentPlayer.isLocalPlayer) { - context.querySelector(".sendMessageSection").classList.remove("hide"); + if (supportedCommands.includes('DisplayMessage') && !currentPlayer.isLocalPlayer) { + context.querySelector('.sendMessageSection').classList.remove('hide'); } else { - context.querySelector(".sendMessageSection").classList.add("hide"); + context.querySelector('.sendMessageSection').classList.add('hide'); } - if (-1 != supportedCommands.indexOf("SendString") && !currentPlayer.isLocalPlayer) { - context.querySelector(".sendTextSection").classList.remove("hide"); + if (supportedCommands.includes('SendString') && !currentPlayer.isLocalPlayer) { + context.querySelector('.sendTextSection').classList.remove('hide'); } else { - context.querySelector(".sendTextSection").classList.add("hide"); + context.querySelector('.sendTextSection').classList.add('hide'); } - if (!currentPlayer.isLocalPlayer) { - context.querySelector(".navigationSection").classList.remove("hide"); + if (supportedCommands.includes('Select') && !currentPlayer.isLocalPlayer) { + context.querySelector('.navigationSection').classList.remove('hide'); } else { - context.querySelector(".navigationSection").classList.add("hide"); + context.querySelector('.navigationSection').classList.add('hide'); } - buttonVisible(context.querySelector(".btnArrowUp"), -1 != supportedCommands.indexOf("MoveUp")); - buttonVisible(context.querySelector(".btnArrowLeft"), -1 != supportedCommands.indexOf("MoveDown")); - buttonVisible(context.querySelector(".btnArrowRight"), -1 != supportedCommands.indexOf("MoveRight")); - buttonVisible(context.querySelector(".btnArrowDown"), -1 != supportedCommands.indexOf("MoveLeft")); - buttonVisible(context.querySelector(".btnOk"), -1 != supportedCommands.indexOf("Select")); - buttonVisible(context.querySelector(".btnBack"), -1 != supportedCommands.indexOf("Back")); - buttonVisible(context.querySelector(".btnContextMenu"), -1 != supportedCommands.indexOf("ToggleContextMenu")); - buttonVisible(context.querySelector(".btnShowSearch"), -1 != supportedCommands.indexOf("GoToSearch")); - buttonVisible(context.querySelector(".bthShowSettings"), -1 != supportedCommands.indexOf("GoToSettings")); - buttonVisible(context.querySelector(".btnGoHome"), -1 != supportedCommands.indexOf("GoHome")); + if (isSupportedCommands && !currentPlayer.isLocalPlayer) { + context.querySelector('.remoteControlSection').classList.remove('hide'); + } else { + context.querySelector('.remoteControlSection').classList.add('hide'); + } - buttonVisible(context.querySelector(".btnStop"), null != item); - buttonVisible(context.querySelector(".btnNextTrack"), null != item); - buttonVisible(context.querySelector(".btnPreviousTrack"), null != item); - buttonVisible(context.querySelector(".btnRewind"), null != item); - buttonVisible(context.querySelector(".btnFastForward"), null != item); - var positionSlider = context.querySelector(".nowPlayingPositionSlider"); + buttonVisible(context.querySelector('.btnStop'), null != item); + buttonVisible(context.querySelector('.btnNextTrack'), null != item); + buttonVisible(context.querySelector('.btnPreviousTrack'), null != item); + buttonVisible(context.querySelector('.btnRewind'), null != item); + buttonVisible(context.querySelector('.btnFastForward'), null != item); + var positionSlider = context.querySelector('.nowPlayingPositionSlider'); + + if (positionSlider && item && item.RunTimeTicks) { + positionSlider.setKeyboardSteps(userSettings.skipBackLength() * 1000000 / item.RunTimeTicks, + userSettings.skipForwardLength() * 1000000 / item.RunTimeTicks); + } if (positionSlider && !positionSlider.dragging) { positionSlider.disabled = !playState.CanSeek; @@ -249,10 +294,10 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL updateTimeDisplay(playState.PositionTicks, item ? item.RunTimeTicks : null); updatePlayerVolumeState(context, playState.IsMuted, playState.VolumeLevel); - if (item && "Video" == item.MediaType) { - context.classList.remove("hideVideoButtons"); + if (item && 'Video' == item.MediaType) { + context.classList.remove('hideVideoButtons'); } else { - context.classList.add("hideVideoButtons"); + context.classList.add('hideVideoButtons'); } updateRepeatModeDisplay(playState.RepeatMode); @@ -261,27 +306,27 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function updateAudioTracksDisplay(player, context) { var supportedCommands = currentPlayerSupportedCommands; - buttonVisible(context.querySelector(".btnAudioTracks"), playbackManager.audioTracks(player).length > 1 && -1 != supportedCommands.indexOf("SetAudioStreamIndex")); + buttonVisible(context.querySelector('.btnAudioTracks'), playbackManager.audioTracks(player).length > 1 && -1 != supportedCommands.indexOf('SetAudioStreamIndex')); } function updateSubtitleTracksDisplay(player, context) { var supportedCommands = currentPlayerSupportedCommands; - buttonVisible(context.querySelector(".btnSubtitles"), playbackManager.subtitleTracks(player).length && -1 != supportedCommands.indexOf("SetSubtitleStreamIndex")); + buttonVisible(context.querySelector('.btnSubtitles'), playbackManager.subtitleTracks(player).length && -1 != supportedCommands.indexOf('SetSubtitleStreamIndex')); } function updateRepeatModeDisplay(repeatMode) { var context = dlg; - var toggleRepeatButton = context.querySelector(".repeatToggleButton"); + var toggleRepeatButton = context.querySelector('.repeatToggleButton'); - if ("RepeatAll" == repeatMode) { - toggleRepeatButton.innerHTML = "repeat"; - toggleRepeatButton.classList.add("repeatButton-active"); - } else if ("RepeatOne" == repeatMode) { - toggleRepeatButton.innerHTML = "repeat_one"; - toggleRepeatButton.classList.add("repeatButton-active"); + if ('RepeatAll' == repeatMode) { + toggleRepeatButton.innerHTML = ""; + toggleRepeatButton.classList.add('repeatButton-active'); + } else if ('RepeatOne' == repeatMode) { + toggleRepeatButton.innerHTML = ""; + toggleRepeatButton.classList.add('repeatButton-active'); } else { - toggleRepeatButton.innerHTML = "repeat"; - toggleRepeatButton.classList.remove("repeatButton-active"); + toggleRepeatButton.innerHTML = ""; + toggleRepeatButton.classList.remove('repeatButton-active'); } } @@ -290,48 +335,47 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL var supportedCommands = currentPlayerSupportedCommands; var showMuteButton = true; var showVolumeSlider = true; - var volumeSlider = view.querySelector('.nowPlayingVolumeSliderContainer'); - var progressElement = volumeSlider.querySelector('.mdl-slider-background-lower'); - if (-1 === supportedCommands.indexOf("Mute")) { + if (-1 === supportedCommands.indexOf('Mute')) { showMuteButton = false; } - if (-1 === supportedCommands.indexOf("SetVolume")) { + if (-1 === supportedCommands.indexOf('SetVolume')) { showVolumeSlider = false; } - if (currentPlayer.isLocalPlayer && appHost.supports("physicalvolumecontrol")) { + if (currentPlayer.isLocalPlayer && appHost.supports('physicalvolumecontrol')) { showMuteButton = false; showVolumeSlider = false; } + const buttonMute = view.querySelector('.buttonMute'); + const buttonMuteIcon = buttonMute.querySelector('.material-icons'); + + buttonMuteIcon.classList.remove('volume_off', 'volume_up'); + if (isMuted) { - view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute")); - view.querySelector(".buttonMute i").innerHTML = "volume_off"; + buttonMute.setAttribute('title', globalize.translate('Unmute')); + buttonMuteIcon.classList.add('volume_off'); } else { - view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute")); - view.querySelector(".buttonMute i").innerHTML = "volume_up"; - } - - if (progressElement) { - progressElement.style.width = (volumeLevel || 0) + '%'; + buttonMute.setAttribute('title', globalize.translate('Mute')); + buttonMuteIcon.classList.add('volume_up'); } if (showMuteButton) { - view.querySelector(".buttonMute").classList.remove("hide"); + buttonMute.classList.remove('hide'); } else { - view.querySelector(".buttonMute").classList.add("hide"); + buttonMute.classList.add('hide'); } - var nowPlayingVolumeSlider = context.querySelector(".nowPlayingVolumeSlider"); - var nowPlayingVolumeSliderContainer = context.querySelector(".nowPlayingVolumeSliderContainer"); + var nowPlayingVolumeSlider = context.querySelector('.nowPlayingVolumeSlider'); + var nowPlayingVolumeSliderContainer = context.querySelector('.nowPlayingVolumeSliderContainer'); if (nowPlayingVolumeSlider) { if (showVolumeSlider) { - nowPlayingVolumeSliderContainer.classList.remove("hide"); + nowPlayingVolumeSliderContainer.classList.remove('hide'); } else { - nowPlayingVolumeSliderContainer.classList.add("hide"); + nowPlayingVolumeSliderContainer.classList.add('hide'); } if (!nowPlayingVolumeSlider.dragging) { @@ -342,14 +386,18 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function updatePlayPauseState(isPaused, isActive) { var context = dlg; - var btnPlayPause = context.querySelector(".btnPlayPause"); - btnPlayPause.querySelector("i").innerHTML = isPaused ? "play_arrow" : "pause"; + var btnPlayPause = context.querySelector('.btnPlayPause'); + const btnPlayPauseIcon = btnPlayPause.querySelector('.material-icons'); + + btnPlayPauseIcon.classList.remove('play_circle_filled', 'pause_circle_filled'); + btnPlayPauseIcon.classList.add(isPaused ? 'play_circle_filled' : 'pause_circle_filled'); + buttonVisible(btnPlayPause, isActive); } function updateTimeDisplay(positionTicks, runtimeTicks) { var context = dlg; - var positionSlider = context.querySelector(".nowPlayingPositionSlider"); + var positionSlider = context.querySelector('.nowPlayingPositionSlider'); if (positionSlider && !positionSlider.dragging) { if (runtimeTicks) { @@ -361,8 +409,8 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL } } - context.querySelector(".positionTime").innerHTML = null == positionTicks ? "--:--" : datetime.getDisplayRunningTime(positionTicks); - context.querySelector(".runtime").innerHTML = null != runtimeTicks ? datetime.getDisplayRunningTime(runtimeTicks) : "--:--"; + context.querySelector('.positionTime').innerHTML = null == positionTicks ? '--:--' : datetime.getDisplayRunningTime(positionTicks); + context.querySelector('.runtime').innerHTML = null != runtimeTicks ? datetime.getDisplayRunningTime(runtimeTicks) : '--:--'; } function getPlaylistItems(player) { @@ -371,27 +419,27 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function loadPlaylist(context, player) { getPlaylistItems(player).then(function (items) { - var html = ""; + var html = ''; html += listView.getListViewHtml({ items: items, smallIcon: true, - action: "setplaylistindex", + action: 'setplaylistindex', enableUserDataButtons: false, rightButtons: [{ - icon: "remove_circle_outline", - title: globalize.translate("ButtonRemove"), - id: "remove" + icon: 'remove_circle_outline', + title: globalize.translate('ButtonRemove'), + id: 'remove' }], dragHandle: true }); if (items.length) { - context.querySelector(".playlistSection").classList.remove("hide"); + context.querySelector('.btnTogglePlaylist').classList.remove('hide'); } else { - context.querySelector(".playlistSection").classList.add("hide"); + context.querySelector('.btnTogglePlaylist').classList.add('hide'); } - var itemsContainer = context.querySelector(".playlist"); + var itemsContainer = context.querySelector('.playlist'); itemsContainer.innerHTML = html; var playlistItemId = playbackManager.getCurrentPlaylistItemId(player); @@ -399,17 +447,20 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL var img = itemsContainer.querySelector('.listItem[data-playlistItemId="' + playlistItemId + '"] .listItemImage'); if (img) { - img.classList.remove("lazy"); - img.classList.add("playlistIndexIndicatorImage"); + img.classList.remove('lazy'); + img.classList.add('playlistIndexIndicatorImage'); } } imageLoader.lazyChildren(itemsContainer); + context.querySelector('.playlist').classList.add('hide'); + context.querySelector('.contextMenu').classList.add('hide'); + context.querySelector('.btnSavePlaylist').classList.add('hide'); }); } function onPlaybackStart(e, state) { - console.log("remotecontrol event: " + e.type); + console.debug('remotecontrol event: ' + e.type); var player = this; onStateChanged.call(player, e, state); } @@ -437,7 +488,7 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL } function onPlaybackStopped(e, state) { - console.log("remotecontrol event: " + e.type); + console.debug('remotecontrol event: ' + e.type); var player = this; if (!state.NextMediaType) { @@ -477,16 +528,16 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL var player = currentPlayer; if (player) { - events.off(player, "playbackstart", onPlaybackStart); - events.off(player, "statechange", onStateChanged); - events.off(player, "repeatmodechange", onRepeatModeChange); - events.off(player, "playlistitemremove", onPlaylistUpdate); - events.off(player, "playlistitemmove", onPlaylistUpdate); - 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); + events.off(player, 'playbackstart', onPlaybackStart); + events.off(player, 'statechange', onStateChanged); + events.off(player, 'repeatmodechange', onRepeatModeChange); + events.off(player, 'playlistitemremove', onPlaylistUpdate); + events.off(player, 'playlistitemmove', onPlaylistUpdate); + 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; } } @@ -495,18 +546,18 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL if (releaseCurrentPlayer(), currentPlayer = player, player) { var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { - type: "init" + type: 'init' }, state); - events.on(player, "playbackstart", onPlaybackStart); - events.on(player, "statechange", onStateChanged); - events.on(player, "repeatmodechange", onRepeatModeChange); - events.on(player, "playlistitemremove", onPlaylistItemRemoved); - events.on(player, "playlistitemmove", onPlaylistUpdate); - 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); + events.on(player, 'playbackstart', onPlaybackStart); + events.on(player, 'statechange', onStateChanged); + events.on(player, 'repeatmodechange', onRepeatModeChange); + events.on(player, 'playlistitemremove', onPlaylistItemRemoved); + events.on(player, 'playlistitemmove', onPlaylistUpdate); + 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 playerInfo = playbackManager.getPlayerInfo(); var supportedCommands = playerInfo.supportedCommands; currentPlayerSupportedCommands = supportedCommands; @@ -516,11 +567,11 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function onBtnCommandClick() { if (currentPlayer) { - if (this.classList.contains("repeatToggleButton")) { + if (this.classList.contains('repeatToggleButton')) { toggleRepeat(currentPlayer); } else { playbackManager.sendCommand({ - Name: this.getAttribute("data-command") + Name: this.getAttribute('data-command') }, currentPlayer); } } @@ -535,7 +586,7 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL } function savePlaylist() { - require(["playlistEditor"], function (playlistEditor) { + require(['playlistEditor'], function (playlistEditor) { getSaveablePlaylistItems().then(function (items) { var serverId = items.length ? items[0].ServerId : ApiClient.serverId(); new playlistEditor().show({ @@ -544,67 +595,67 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL }), serverId: serverId, enableAddToPlayQueue: false, - defaultValue: "new" + defaultValue: 'new' }); }); }); } function bindEvents(context) { - var btnCommand = context.querySelectorAll(".btnCommand"); + var btnCommand = context.querySelectorAll('.btnCommand'); for (var i = 0, length = btnCommand.length; i < length; i++) { - btnCommand[i].addEventListener("click", onBtnCommandClick); + btnCommand[i].addEventListener('click', onBtnCommandClick); } - context.querySelector(".btnToggleFullscreen").addEventListener("click", function (e) { + context.querySelector('.btnToggleFullscreen').addEventListener('click', function (e) { if (currentPlayer) { playbackManager.sendCommand({ - Name: e.target.getAttribute("data-command") + Name: e.target.getAttribute('data-command') }, currentPlayer); } }); - context.querySelector(".btnAudioTracks").addEventListener("click", function (e) { + context.querySelector('.btnAudioTracks').addEventListener('click', function (e) { if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) { showAudioMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem); } }); - context.querySelector(".btnSubtitles").addEventListener("click", function (e) { + context.querySelector('.btnSubtitles').addEventListener('click', function (e) { if (currentPlayer && lastPlayerState && lastPlayerState.NowPlayingItem) { showSubtitleMenu(context, currentPlayer, e.target, lastPlayerState.NowPlayingItem); } }); - context.querySelector(".btnStop").addEventListener("click", function () { + context.querySelector('.btnStop').addEventListener('click', function () { if (currentPlayer) { playbackManager.stop(currentPlayer); } }); - context.querySelector(".btnPlayPause").addEventListener("click", function () { + context.querySelector('.btnPlayPause').addEventListener('click', function () { if (currentPlayer) { playbackManager.playPause(currentPlayer); } }); - context.querySelector(".btnNextTrack").addEventListener("click", function () { + context.querySelector('.btnNextTrack').addEventListener('click', function () { if (currentPlayer) { playbackManager.nextTrack(currentPlayer); } }); - context.querySelector(".btnRewind").addEventListener("click", function () { + context.querySelector('.btnRewind').addEventListener('click', function () { if (currentPlayer) { playbackManager.rewind(currentPlayer); } }); - context.querySelector(".btnFastForward").addEventListener("click", function () { + context.querySelector('.btnFastForward').addEventListener('click', function () { if (currentPlayer) { playbackManager.fastForward(currentPlayer); } }); - context.querySelector(".btnPreviousTrack").addEventListener("click", function () { + context.querySelector('.btnPreviousTrack').addEventListener('click', function () { if (currentPlayer) { playbackManager.previousTrack(currentPlayer); } }); - context.querySelector(".nowPlayingPositionSlider").addEventListener("change", function () { + context.querySelector('.nowPlayingPositionSlider').addEventListener('change', function () { var value = this.value; if (currentPlayer) { @@ -613,11 +664,11 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL } }); - context.querySelector(".nowPlayingPositionSlider").getBubbleText = function (value) { + context.querySelector('.nowPlayingPositionSlider').getBubbleText = function (value) { var state = lastPlayerState; if (!state || !state.NowPlayingItem || !currentRuntimeTicks) { - return "--:--"; + return '--:--'; } var ticks = currentRuntimeTicks; @@ -626,28 +677,47 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL return datetime.getDisplayRunningTime(ticks); }; - context.querySelector(".nowPlayingVolumeSlider").addEventListener("change", function () { + function setVolume() { playbackManager.setVolume(this.value, currentPlayer); - }); - context.querySelector(".nowPlayingVolumeSlider").addEventListener("mousemove", function () { - playbackManager.setVolume(this.value, currentPlayer); - }); - context.querySelector(".nowPlayingVolumeSlider").addEventListener("touchmove", function () { - playbackManager.setVolume(this.value, currentPlayer); - }); - context.querySelector(".buttonMute").addEventListener("click", function () { + } + + context.querySelector('.nowPlayingVolumeSlider').addEventListener('change', setVolume); + context.querySelector('.nowPlayingVolumeSlider').addEventListener('mousemove', setVolume); + context.querySelector('.nowPlayingVolumeSlider').addEventListener('touchmove', setVolume); + context.querySelector('.buttonMute').addEventListener('click', function () { playbackManager.toggleMute(currentPlayer); }); - var playlistContainer = context.querySelector(".playlist"); - playlistContainer.addEventListener("action-remove", function (e) { + var playlistContainer = context.querySelector('.playlist'); + playlistContainer.addEventListener('action-remove', function (e) { playbackManager.removeFromPlaylist([e.detail.playlistItemId], currentPlayer); }); - playlistContainer.addEventListener("itemdrop", function (e) { + playlistContainer.addEventListener('itemdrop', function (e) { var newIndex = e.detail.newIndex; var playlistItemId = e.detail.playlistItemId; playbackManager.movePlaylistItem(playlistItemId, newIndex, currentPlayer); }); - context.querySelector(".btnSavePlaylist").addEventListener("click", savePlaylist); + context.querySelector('.btnSavePlaylist').addEventListener('click', savePlaylist); + context.querySelector('.btnTogglePlaylist').addEventListener('click', function () { + if (context.querySelector('.playlist').classList.contains('hide')) { + context.querySelector('.playlist').classList.remove('hide'); + context.querySelector('.btnSavePlaylist').classList.remove('hide'); + context.querySelector('.contextMenu').classList.add('hide'); + context.querySelector('.volumecontrol').classList.add('hide'); + } else { + context.querySelector('.playlist').classList.add('hide'); + context.querySelector('.btnSavePlaylist').classList.add('hide'); + context.querySelector('.volumecontrol').classList.remove('hide'); + } + }); + context.querySelector('.btnToggleContextMenu').addEventListener('click', function () { + if (context.querySelector('.contextMenu').classList.contains('hide')) { + context.querySelector('.contextMenu').classList.remove('hide'); + context.querySelector('.btnSavePlaylist').classList.add('hide'); + context.querySelector('.playlist').classList.add('hide'); + } else { + context.querySelector('.contextMenu').classList.add('hide'); + } + }); } function onPlayerChange() { @@ -657,16 +727,16 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function onMessageSubmit(e) { var form = e.target; playbackManager.sendCommand({ - Name: "DisplayMessage", + Name: 'DisplayMessage', Arguments: { - Header: form.querySelector("#txtMessageTitle").value, - Text: form.querySelector("#txtMessageText", form).value + Header: form.querySelector('#txtMessageTitle').value, + Text: form.querySelector('#txtMessageText', form).value } }, currentPlayer); - form.querySelector("input").value = ""; + form.querySelector('input').value = ''; - require(["toast"], function (toast) { - toast("Message sent."); + require(['toast'], function (toast) { + toast('Message sent.'); }); e.preventDefault(); @@ -677,15 +747,15 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL function onSendStringSubmit(e) { var form = e.target; playbackManager.sendCommand({ - Name: "SendString", + Name: 'SendString', Arguments: { - String: form.querySelector("#txtTypeText", form).value + String: form.querySelector('#txtTypeText', form).value } }, currentPlayer); - form.querySelector("input").value = ""; + form.querySelector('input').value = ''; - require(["toast"], function (toast) { - toast("Text sent."); + require(['toast'], function (toast) { + toast('Text sent.'); }); e.preventDefault(); @@ -694,15 +764,33 @@ define(["browser", "datetime", "backdrop", "libraryBrowser", "listView", "imageL } function init(ownerView, context) { + let contextmenuHtml = ``; + let volumecontrolHtml = '
'; + volumecontrolHtml += ``; + volumecontrolHtml += '
'; + volumecontrolHtml += '
'; + if (!layoutManager.mobile) { + context.querySelector('.nowPlayingSecondaryButtons').innerHTML += volumecontrolHtml; + context.querySelector('.playlistSectionButton').innerHTML += contextmenuHtml; + } else { + context.querySelector('.playlistSectionButton').innerHTML += volumecontrolHtml + contextmenuHtml; + } + bindEvents(context); - context.querySelector(".sendMessageForm").addEventListener("submit", onMessageSubmit); - context.querySelector(".typeTextForm").addEventListener("submit", onSendStringSubmit); - events.on(playbackManager, "playerchange", onPlayerChange); + context.querySelector('.sendMessageForm').addEventListener('submit', onMessageSubmit); + context.querySelector('.typeTextForm').addEventListener('submit', onSendStringSubmit); + events.on(playbackManager, 'playerchange', onPlayerChange); + + if (layoutManager.tv) { + var positionSlider = context.querySelector('.nowPlayingPositionSlider'); + positionSlider.classList.add('focusable'); + positionSlider.enableKeyboardDragging(); + } } function onDialogClosed(e) { releaseCurrentPlayer(); - events.off(playbackManager, "playerchange", onPlayerChange); + events.off(playbackManager, 'playerchange', onPlayerChange); lastPlayerState = null; } diff --git a/src/components/sanitizefilename.js b/src/components/sanitizefilename.js index d422a95533..de7b1a0782 100644 --- a/src/components/sanitizefilename.js +++ b/src/components/sanitizefilename.js @@ -1,95 +1,90 @@ // From https://github.com/parshap/node-sanitize-filename -define([], function () { - 'use strict'; +const illegalRe = /[\/\?<>\\:\*\|":]/g; +// eslint-disable-next-line no-control-regex +const controlRe = /[\x00-\x1f\x80-\x9f]/g; +const reservedRe = /^\.+$/; +const windowsReservedRe = /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\..*)?$/i; +const windowsTrailingRe = /[\. ]+$/; - 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 >= 0xd800 && codePoint <= 0xdbff; +} - function isHighSurrogate(codePoint) { - return codePoint >= 0xd800 && codePoint <= 0xdbff; +function isLowSurrogate(codePoint) { + return codePoint >= 0xdc00 && codePoint <= 0xdfff; +} + +function getByteLength(string) { + if (typeof string !== 'string') { + throw new Error('Input must be string'); } - function isLowSurrogate(codePoint) { - return codePoint >= 0xdc00 && codePoint <= 0xdfff; - } - - function getByteLength(string) { - 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) { + const charLength = string.length; + let byteLength = 0; + let codePoint = null; + let prevCodePoint = null; + for (let 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 if (codePoint >= 0x80 && codePoint <= 0x7ff) { - byteLength += 2; - } else if (codePoint >= 0x800 && codePoint <= 0xffff) { + } else { byteLength += 3; } - prevCodePoint = codePoint; + } else if (codePoint <= 0x7f) { + byteLength += 1; + } else if (codePoint >= 0x80 && codePoint <= 0x7ff) { + byteLength += 2; + } else if (codePoint >= 0x800 && codePoint <= 0xffff) { + byteLength += 3; } - - return byteLength; + prevCodePoint = codePoint; } - function truncate(string, byteLength) { - if (typeof string !== "string") { - throw new Error("Input must be string"); - } + return byteLength; +} - 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; +function truncate(string, byteLength) { + if (typeof string !== 'string') { + throw new Error('Input must be string'); } - return { - 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); + const charLength = string.length; + let curByteLength = 0; + let codePoint; + let segment; + + for (let 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]; } - }; -}); \ No newline at end of file + + 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; +} + +export function sanitize(input, replacement) { + const sanitized = input + .replace(illegalRe, replacement) + .replace(controlRe, replacement) + .replace(reservedRe, replacement) + .replace(windowsReservedRe, replacement) + .replace(windowsTrailingRe, replacement); + return truncate(sanitized, 255); +} diff --git a/src/components/scrollManager.js b/src/components/scrollManager.js index 9f7035d528..f7bd41ff8b 100644 --- a/src/components/scrollManager.js +++ b/src/components/scrollManager.js @@ -1,38 +1,47 @@ -define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManager) { - "use strict"; +/* eslint-disable indent */ + +/** + * Module for controlling scroll behavior. + * @module components/scrollManager + */ + +import dom from 'dom'; +import browser from 'browser'; +import layoutManager from 'layoutManager'; /** * Scroll time in ms. */ - var ScrollTime = 270; + const ScrollTime = 270; /** * Epsilon for comparing values. */ - var Epsilon = 1e-6; + const Epsilon = 1e-6; // FIXME: Need to scroll to top of page to fully show the top menu. This can be solved by some marker of top most elements or their containers /** * Returns minimum vertical scroll. * Scroll less than that value will be zeroed. * - * @return {number} minimum vertical scroll + * @return {number} Minimum vertical scroll. */ function minimumScrollY() { - var topMenu = document.querySelector(".headerTop"); + const topMenu = document.querySelector('.headerTop'); if (topMenu) { return topMenu.clientHeight; } return 0; } - var supportsSmoothScroll = "scrollBehavior" in document.documentElement.style; + const supportsSmoothScroll = 'scrollBehavior' in document.documentElement.style; - var supportsScrollToOptions = false; + let supportsScrollToOptions = false; try { - var elem = document.createElement("div"); + const elem = document.createElement('div'); - var opts = Object.defineProperty({}, "behavior", { + const opts = Object.defineProperty({}, 'behavior', { + // eslint-disable-next-line getter-return get: function () { supportsScrollToOptions = true; } @@ -40,16 +49,16 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage elem.scrollTo(opts); } catch (e) { - console.log("error checking ScrollToOptions support"); + console.error('error checking ScrollToOptions support'); } /** * Returns value clamped by range [min, max]. * - * @param {number} value clamped value - * @param {number} min begining of range - * @param {number} max ending of range - * @return {number} clamped value + * @param {number} value - Clamped value. + * @param {number} min - Begining of range. + * @param {number} max - Ending of range. + * @return {number} Clamped value. */ function clamp(value, min, max) { return value <= min ? min : value >= max ? max : value; @@ -59,15 +68,15 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage * Returns the required delta to fit range 1 into range 2. * In case of range 1 is bigger than range 2 returns delta to fit most out of range part. * - * @param {number} begin1 begining of range 1 - * @param {number} end1 ending of range 1 - * @param {number} begin2 begining of range 2 - * @param {number} end2 ending of range 2 - * @return {number} delta: <0 move range1 to the left, >0 - to the right + * @param {number} begin1 - Begining of range 1. + * @param {number} end1 - Ending of range 1. + * @param {number} begin2 - Begining of range 2. + * @param {number} end2 - Ending of range 2. + * @return {number} Delta: <0 move range1 to the left, >0 - to the right. */ function fitRange(begin1, end1, begin2, end2) { - var delta1 = begin1 - begin2; - var delta2 = end2 - end1; + const delta1 = begin1 - begin2; + const delta2 = end2 - end1; if (delta1 < 0 && delta1 < delta2) { return -delta1; } else if (delta2 < 0) { @@ -79,13 +88,21 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Ease value. * - * @param {number} t value in range [0, 1] - * @return {number} eased value in range [0, 1] + * @param {number} t - Value in range [0, 1]. + * @return {number} Eased value in range [0, 1]. */ function ease(t) { return t*(2 - t); // easeOutQuad === ease-out } + /** + * @typedef {Object} Rect + * @property {number} left - X coordinate of top-left corner. + * @property {number} top - Y coordinate of top-left corner. + * @property {number} width - Width. + * @property {number} height - Height. + */ + /** * Document scroll wrapper helps to unify scrolling and fix issues of some browsers. * @@ -99,41 +116,68 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage * * Tizen 5 Browser/Native: scrolls documentElement (and window); has a document.scrollingElement */ - function DocumentScroller() { - } - - DocumentScroller.prototype = { + class DocumentScroller { + /** + * Horizontal scroll position. + * @type {number} + */ get scrollLeft() { return window.pageXOffset; - }, + } + set scrollLeft(val) { window.scroll(val, window.pageYOffset); - }, + } + /** + * Vertical scroll position. + * @type {number} + */ get scrollTop() { return window.pageYOffset; - }, + } + set scrollTop(val) { window.scroll(window.pageXOffset, val); - }, + } + /** + * Horizontal scroll size (scroll width). + * @type {number} + */ get scrollWidth() { return Math.max(document.documentElement.scrollWidth, document.body.scrollWidth); - }, + } + /** + * Vertical scroll size (scroll height). + * @type {number} + */ get scrollHeight() { return Math.max(document.documentElement.scrollHeight, document.body.scrollHeight); - }, + } + /** + * Horizontal client size (client width). + * @type {number} + */ get clientWidth() { return Math.min(document.documentElement.clientWidth, document.body.clientWidth); - }, + } + /** + * Vertical client size (client height). + * @type {number} + */ get clientHeight() { return Math.min(document.documentElement.clientHeight, document.body.clientHeight); - }, + } - getBoundingClientRect: function() { + /** + * Returns bounding client rect. + * @return {Rect} Bounding client rect. + */ + getBoundingClientRect() { // Make valid viewport coordinates: documentElement.getBoundingClientRect returns rect of entire document relative to viewport return { left: 0, @@ -141,28 +185,47 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage width: this.clientWidth, height: this.clientHeight }; - }, + } - scrollTo: function() { + /** + * Scrolls window. + * @param {...mixed} args See window.scrollTo. + */ + scrollTo() { window.scrollTo.apply(window, arguments); } - }; - - var documentScroller = new DocumentScroller(); + } /** - * Returns parent element that can be scrolled. If no such, returns documentElement. + * Default (document) scroller. + */ + const documentScroller = new DocumentScroller(); + + /** + * Returns parent element that can be scrolled. If no such, returns document scroller. * - * @param {HTMLElement} element element for which parent is being searched - * @param {boolean} vertical search for vertical scrollable parent + * @param {HTMLElement} element - Element for which parent is being searched. + * @param {boolean} vertical - Search for vertical scrollable parent. + * @param {HTMLElement|DocumentScroller} Parent element that can be scrolled or document scroller. */ function getScrollableParent(element, vertical) { if (element) { - var parent = element.parentElement; + let nameScroll = 'scrollWidth'; + let nameClient = 'clientWidth'; + let nameClass = 'scrollX'; + + if (vertical) { + nameScroll = 'scrollHeight'; + nameClient = 'clientHeight'; + nameClass = 'scrollY'; + } + + let parent = element.parentElement; while (parent) { - if ((!vertical && parent.scrollWidth > parent.clientWidth && parent.classList.contains("scrollX")) || - (vertical && parent.scrollHeight > parent.clientHeight && parent.classList.contains("scrollY"))) { + // Skip 'emby-scroller' because it scrolls by itself + if (!parent.classList.contains('emby-scroller') && + parent[nameScroll] > parent[nameClient] && parent.classList.contains(nameClass)) { return parent; } @@ -175,20 +238,20 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * @typedef {Object} ScrollerData - * @property {number} scrollPos current scroll position - * @property {number} scrollSize scroll size - * @property {number} clientSize client size + * @property {number} scrollPos - Current scroll position. + * @property {number} scrollSize - Scroll size. + * @property {number} clientSize - Client size. */ /** - * Returns scroll data for specified orientation. + * Returns scroller data for specified orientation. * - * @param {HTMLElement} scroller scroller - * @param {boolean} vertical vertical scroll data - * @return {ScrollerData} scroll data + * @param {HTMLElement} scroller - Scroller. + * @param {boolean} vertical - Vertical scroller data. + * @return {ScrollerData} Scroller data. */ function getScrollerData(scroller, vertical) { - var data = {}; + let data = {}; if (!vertical) { data.scrollPos = scroller.scrollLeft; @@ -206,14 +269,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Returns position of child of scroller for specified orientation. * - * @param {HTMLElement} scroller scroller - * @param {HTMLElement} element child of scroller - * @param {boolean} vertical vertical scroll - * @return {number} child position + * @param {HTMLElement} scroller - Scroller. + * @param {HTMLElement} element - Child of scroller. + * @param {boolean} vertical - Vertical scroll. + * @return {number} Child position. */ function getScrollerChildPos(scroller, element, vertical) { - var elementRect = element.getBoundingClientRect(); - var scrollerRect = scroller.getBoundingClientRect(); + const elementRect = element.getBoundingClientRect(); + const scrollerRect = scroller.getBoundingClientRect(); if (!vertical) { return scroller.scrollLeft + elementRect.left - scrollerRect.left; @@ -225,21 +288,21 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Returns scroll position for element. * - * @param {ScrollerData} scrollerData scroller data - * @param {number} elementPos child element position - * @param {number} elementSize child element size - * @param {boolean} centered scroll to center - * @return {number} scroll position + * @param {ScrollerData} scrollerData - Scroller data. + * @param {number} elementPos - Child element position. + * @param {number} elementSize - Child element size. + * @param {boolean} centered - Scroll to center. + * @return {number} Scroll position. */ function calcScroll(scrollerData, elementPos, elementSize, centered) { - var maxScroll = scrollerData.scrollSize - scrollerData.clientSize; + const maxScroll = scrollerData.scrollSize - scrollerData.clientSize; - var scroll; + let scroll; if (centered) { scroll = elementPos + (elementSize - scrollerData.clientSize) / 2; } else { - var delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1); + const delta = fitRange(elementPos, elementPos + elementSize - 1, scrollerData.scrollPos, scrollerData.scrollPos + scrollerData.clientSize - 1); scroll = scrollerData.scrollPos - delta; } @@ -249,19 +312,19 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Calls scrollTo function in proper way. * - * @param {HTMLElement} scroller scroller - * @param {ScrollToOptions} options scroll options + * @param {HTMLElement} scroller - Scroller. + * @param {ScrollToOptions} options - Scroll options. */ function scrollToHelper(scroller, options) { - if ("scrollTo" in scroller) { + if ('scrollTo' in scroller) { if (!supportsScrollToOptions) { - var scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft); - var scrollY = (options.top !== undefined ? options.top : scroller.scrollTop); + const scrollX = (options.left !== undefined ? options.left : scroller.scrollLeft); + const scrollY = (options.top !== undefined ? options.top : scroller.scrollTop); scroller.scrollTo(scrollX, scrollY); } else { scroller.scrollTo(options); } - } else if ("scrollLeft" in scroller) { + } else if ('scrollLeft' in scroller) { if (options.left !== undefined) { scroller.scrollLeft = options.left; } @@ -274,14 +337,14 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Performs built-in scroll. * - * @param {HTMLElement} xScroller horizontal scroller - * @param {number} scrollX horizontal coordinate - * @param {HTMLElement} yScroller vertical scroller - * @param {number} scrollY vertical coordinate - * @param {boolean} smooth smooth scrolling + * @param {HTMLElement} xScroller - Horizontal scroller. + * @param {number} scrollX - Horizontal coordinate. + * @param {HTMLElement} yScroller - Vertical scroller. + * @param {number} scrollY - Vertical coordinate. + * @param {boolean} smooth - Smooth scrolling. */ function builtinScroll(xScroller, scrollX, yScroller, scrollY, smooth) { - var scrollBehavior = smooth ? "smooth" : "instant"; + const scrollBehavior = smooth ? 'smooth' : 'instant'; if (xScroller !== yScroller) { scrollToHelper(xScroller, {left: scrollX, behavior: scrollBehavior}); @@ -291,7 +354,10 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage } } - var scrollTimer; + /** + * Requested frame for animated scroll. + */ + let scrollTimer; /** * Resets scroll timer to stop scrolling. @@ -304,29 +370,29 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Performs animated scroll. * - * @param {HTMLElement} xScroller horizontal scroller - * @param {number} scrollX horizontal coordinate - * @param {HTMLElement} yScroller vertical scroller - * @param {number} scrollY vertical coordinate + * @param {HTMLElement} xScroller - Horizontal scroller. + * @param {number} scrollX - Horizontal coordinate. + * @param {HTMLElement} yScroller - Vertical scroller. + * @param {number} scrollY - Vertical coordinate. */ function animateScroll(xScroller, scrollX, yScroller, scrollY) { - var ox = xScroller.scrollLeft; - var oy = yScroller.scrollTop; - var dx = scrollX - ox; - var dy = scrollY - oy; + const ox = xScroller.scrollLeft; + const oy = yScroller.scrollTop; + const dx = scrollX - ox; + const dy = scrollY - oy; if (Math.abs(dx) < Epsilon && Math.abs(dy) < Epsilon) { return; } - var start; + let start; function scrollAnim(currentTimestamp) { start = start || currentTimestamp; - var k = Math.min(1, (currentTimestamp - start) / ScrollTime); + let k = Math.min(1, (currentTimestamp - start) / ScrollTime); if (k === 1) { resetScrollTimer(); @@ -336,8 +402,8 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage k = ease(k); - var x = ox + dx*k; - var y = oy + dy*k; + const x = ox + dx*k; + const y = oy + dy*k; builtinScroll(xScroller, x, yScroller, y, false); @@ -350,11 +416,11 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Performs scroll. * - * @param {HTMLElement} xScroller horizontal scroller - * @param {number} scrollX horizontal coordinate - * @param {HTMLElement} yScroller vertical scroller - * @param {number} scrollY vertical coordinate - * @param {boolean} smooth smooth scrolling + * @param {HTMLElement} xScroller - Horizontal scroller. + * @param {number} scrollX - Horizontal coordinate. + * @param {HTMLElement} yScroller - Vertical scroller. + * @param {number} scrollY - Vertical coordinate. + * @param {boolean} smooth - Smooth scrolling. */ function doScroll(xScroller, scrollX, yScroller, scrollY, smooth) { @@ -391,39 +457,26 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Returns true if scroll manager is enabled. */ - var isEnabled = function() { - - if (!layoutManager.tv) { - return false; - } - - if (browser.tizen) { - return true; - } - - if (browser.web0s) { - return true; - } - - return false; - }; + export function isEnabled() { + return layoutManager.tv; + } /** * Scrolls the document to a given position. * - * @param {number} scrollX horizontal coordinate - * @param {number} scrollY vertical coordinate - * @param {boolean} [smooth=false] smooth scrolling + * @param {number} scrollX - Horizontal coordinate. + * @param {number} scrollY - Vertical coordinate. + * @param {boolean} [smooth=false] - Smooth scrolling. */ - var scrollTo = function(scrollX, scrollY, smooth) { + export function scrollTo(scrollX, scrollY, smooth) { smooth = !!smooth; // Scroller is document itself by default - var scroller = getScrollableParent(null, false); + const scroller = getScrollableParent(null, false); - var xScrollerData = getScrollerData(scroller, false); - var yScrollerData = getScrollerData(scroller, true); + const xScrollerData = getScrollerData(scroller, false); + const yScrollerData = getScrollerData(scroller, true); scrollX = clamp(Math.round(scrollX), 0, xScrollerData.scrollSize - xScrollerData.clientSize); scrollY = clamp(Math.round(scrollY), 0, yScrollerData.scrollSize - yScrollerData.clientSize); @@ -434,39 +487,39 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage /** * Scrolls the document to a given element. * - * @param {HTMLElement} element target element of scroll task - * @param {boolean} [smooth=false] smooth scrolling + * @param {HTMLElement} element - Target element of scroll task. + * @param {boolean} [smooth=false] - Smooth scrolling. */ - var scrollToElement = function(element, smooth) { + export function scrollToElement(element, smooth) { smooth = !!smooth; - var scrollCenterX = true; - var scrollCenterY = true; + let scrollCenterX = true; + let scrollCenterY = true; - var offsetParent = element.offsetParent; + const offsetParent = element.offsetParent; // In Firefox offsetParent.offsetParent is BODY - var isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === "fixed"); + const isFixed = offsetParent && (!offsetParent.offsetParent || window.getComputedStyle(offsetParent).position === 'fixed'); // Scroll fixed elements to nearest edge (or do not scroll at all) if (isFixed) { scrollCenterX = scrollCenterY = false; } - var xScroller = getScrollableParent(element, false); - var yScroller = getScrollableParent(element, true); + const xScroller = getScrollableParent(element, false); + const yScroller = getScrollableParent(element, true); - var elementRect = element.getBoundingClientRect(); + const elementRect = element.getBoundingClientRect(); - var xScrollerData = getScrollerData(xScroller, false); - var yScrollerData = getScrollerData(yScroller, true); + const xScrollerData = getScrollerData(xScroller, false); + const yScrollerData = getScrollerData(yScroller, true); - var xPos = getScrollerChildPos(xScroller, element, false); - var yPos = getScrollerChildPos(yScroller, element, true); + const xPos = getScrollerChildPos(xScroller, element, false); + const yPos = getScrollerChildPos(yScroller, element, true); - var scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX); - var scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY); + const scrollX = calcScroll(xScrollerData, xPos, elementRect.width, scrollCenterX); + let scrollY = calcScroll(yScrollerData, yPos, elementRect.height, scrollCenterY); // HACK: Scroll to top for top menu because it is hidden // FIXME: Need a marker to scroll top/bottom @@ -484,16 +537,17 @@ define(["dom", "browser", "layoutManager"], function (dom, browser, layoutManage } if (isEnabled()) { - dom.addEventListener(window, "focusin", function(e) { + dom.addEventListener(window, 'focusin', function(e) { setTimeout(function() { scrollToElement(e.target, useSmoothScroll()); }, 0); }, {capture: true}); } - return { - isEnabled: isEnabled, - scrollTo: scrollTo, - scrollToElement: scrollToElement - }; -}); +/* eslint-enable indent */ + +export default { + isEnabled: isEnabled, + scrollTo: scrollTo, + scrollToElement: scrollToElement +}; diff --git a/src/components/scrollhelper.js b/src/components/scrollhelper.js index 6280dc5062..1a36594026 100644 --- a/src/components/scrollhelper.js +++ b/src/components/scrollhelper.js @@ -134,4 +134,4 @@ define(['focusManager', 'dom', 'scrollStyles'], function (focusManager, dom) { toCenter: toCenter, toStart: toStart }; -}); \ No newline at end of file +}); diff --git a/src/components/search/searchfields.css b/src/components/search/searchfields.css index 01981ed998..08d8515c86 100644 --- a/src/components/search/searchfields.css +++ b/src/components/search/searchfields.css @@ -4,8 +4,8 @@ } .searchfields-icon { - margin-bottom: .1em; - margin-right: .25em; + margin-bottom: 0.1em; + margin-right: 0.25em; font-size: 2em; align-self: flex-end; } diff --git a/src/components/search/searchfields.js b/src/components/search/searchfields.js index 912acfc41c..53ab187a81 100644 --- a/src/components/search/searchfields.js +++ b/src/components/search/searchfields.js @@ -121,4 +121,4 @@ define(['layoutManager', 'globalize', 'require', 'events', 'browser', 'alphaPick }; return SearchFields; -}); \ No newline at end of file +}); diff --git a/src/components/search/searchfields.template.html b/src/components/search/searchfields.template.html index bad808cb7e..7da5e240c5 100644 --- a/src/components/search/searchfields.template.html +++ b/src/components/search/searchfields.template.html @@ -1,5 +1,5 @@
- search +
diff --git a/src/components/search/searchresults.js b/src/components/search/searchresults.js index 02f1feefe1..d4de2349a4 100644 --- a/src/components/search/searchresults.js +++ b/src/components/search/searchresults.js @@ -5,8 +5,8 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', var options = { - SortBy: "IsFavoriteOrLiked,Random", - IncludeItemTypes: "Movie,Series,MusicArtist", + SortBy: 'IsFavoriteOrLiked,Random', + IncludeItemTypes: 'Movie,Series,MusicArtist', Limit: 20, Recursive: true, ImageTypeLimit: 0, @@ -165,7 +165,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "LiveTvProgram", + IncludeItemTypes: 'LiveTvProgram', IsMovie: true, IsKids: false, IsNews: false @@ -194,7 +194,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Movie" + IncludeItemTypes: 'Movie' }, context, '.movieResults', { @@ -212,7 +212,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Series" + IncludeItemTypes: 'Series' }, context, '.seriesResults', { @@ -231,7 +231,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "LiveTvProgram", + IncludeItemTypes: 'LiveTvProgram', IsSeries: true, IsSports: false, IsKids: false, @@ -262,7 +262,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Episode" + IncludeItemTypes: 'Episode' }, context, '.episodeResults', { @@ -363,7 +363,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "LiveTvProgram", + IncludeItemTypes: 'LiveTvProgram', IsMovie: instance.options.collectionType === 'livetv' ? false : null, IsSeries: instance.options.collectionType === 'livetv' ? false : null, IsSports: instance.options.collectionType === 'livetv' ? false : null, @@ -394,8 +394,8 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - MediaTypes: "Video", - ExcludeItemTypes: "Movie,Episode" + MediaTypes: 'Video', + ExcludeItemTypes: 'Movie,Episode' }, context, '.videoResults', { @@ -439,7 +439,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "MusicAlbum" + IncludeItemTypes: 'MusicAlbum' }, context, '.albumResults', { @@ -456,7 +456,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Audio" + IncludeItemTypes: 'Audio' }, context, '.songResults', { @@ -475,7 +475,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - MediaTypes: "Photo" + MediaTypes: 'Photo' }, context, '.photoResults', { @@ -492,7 +492,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "PhotoAlbum" + IncludeItemTypes: 'PhotoAlbum' }, context, '.photoAlbumResults', { @@ -508,7 +508,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Book" + IncludeItemTypes: 'Book' }, context, '.bookResults', { @@ -525,7 +525,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "AudioBook" + IncludeItemTypes: 'AudioBook' }, context, '.audioBookResults', { @@ -541,7 +541,7 @@ define(['layoutManager', 'globalize', 'require', 'events', 'connectionManager', IncludeGenres: false, IncludeStudios: false, IncludeArtists: false, - IncludeItemTypes: "Playlist" + IncludeItemTypes: 'Playlist' }, context, '.playlistResults', { diff --git a/src/components/search/searchresults.template.html b/src/components/search/searchresults.template.html index a9fa232fbc..1deecaca6c 100644 --- a/src/components/search/searchresults.template.html +++ b/src/components/search/searchresults.template.html @@ -11,7 +11,7 @@

${Movies}

-
+
@@ -19,7 +19,7 @@

${Shows}

-
+
@@ -27,7 +27,7 @@

${Episodes}

-
+
@@ -35,7 +35,7 @@

${Sports}

-
+
@@ -43,7 +43,7 @@

${Kids}

-
+
@@ -51,7 +51,7 @@

${News}

-
+
@@ -59,7 +59,7 @@

${Programs}

-
+
@@ -67,7 +67,7 @@

${Videos}

-
+
@@ -75,7 +75,7 @@

${Playlists}

-
+
@@ -83,7 +83,7 @@

${Artists}

-
+
@@ -91,7 +91,7 @@

${Albums}

-
+
@@ -99,7 +99,7 @@

${Songs}

-
+
@@ -107,7 +107,7 @@

${HeaderPhotoAlbums}

-
+
@@ -115,7 +115,7 @@

${Photos}

-
+
@@ -123,7 +123,7 @@

${HeaderAudioBooks}

-
+
@@ -131,7 +131,7 @@

${Books}

-
+
@@ -139,7 +139,7 @@

${People}

-
+
-
\ No newline at end of file +
diff --git a/src/components/serverNotifications/serverNotifications.js b/src/components/serverNotifications.js similarity index 85% rename from src/components/serverNotifications/serverNotifications.js rename to src/components/serverNotifications.js index 1941881b7a..e60f98475b 100644 --- a/src/components/serverNotifications/serverNotifications.js +++ b/src/components/serverNotifications.js @@ -33,7 +33,7 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus } function processGeneralCommand(cmd, apiClient) { - console.log('Received command: ' + cmd.Name); + console.debug('Received command: ' + cmd.Name); switch (cmd.Name) { case 'Select': inputManager.trigger('select'); @@ -133,7 +133,7 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus focusManager.sendText(cmd.Arguments.String); break; default: - console.log('processGeneralCommand does not recognize: ' + cmd.Name); + console.debug('processGeneralCommand does not recognize: ' + cmd.Name); break; } @@ -142,12 +142,12 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus function onMessageReceived(e, msg) { var apiClient = this; - if (msg.MessageType === "Play") { + if (msg.MessageType === 'Play') { notifyApp(); var serverId = apiClient.serverInfo().Id; - if (msg.Data.PlayCommand === "PlayNext") { + if (msg.Data.PlayCommand === 'PlayNext') { playbackManager.queueNext({ ids: msg.Data.ItemIds, serverId: serverId }); - } else if (msg.Data.PlayCommand === "PlayLast") { + } else if (msg.Data.PlayCommand === 'PlayLast') { playbackManager.queue({ ids: msg.Data.ItemIds, serverId: serverId }); } else { playbackManager.play({ @@ -160,7 +160,7 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus serverId: serverId }); } - } else if (msg.MessageType === "Playstate") { + } else if (msg.MessageType === 'Playstate') { if (msg.Data.Command === 'Stop') { inputManager.trigger('stop'); } else if (msg.Data.Command === 'Pause') { @@ -178,10 +178,10 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus } else { notifyApp(); } - } else if (msg.MessageType === "GeneralCommand") { + } else if (msg.MessageType === 'GeneralCommand') { var cmd = msg.Data; processGeneralCommand(cmd, apiClient); - } else if (msg.MessageType === "UserDataChanged") { + } 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]]); @@ -191,36 +191,14 @@ define(['connectionManager', 'playbackManager', 'events', 'inputManager', 'focus events.trigger(serverNotifications, msg.MessageType, [apiClient, msg.Data]); } } - function bindEvents(apiClient) { - events.off(apiClient, "message", onMessageReceived); - events.on(apiClient, "message", onMessageReceived); - } - - function enableNativeGamepadKeyMapping() { - if (window.navigator && "string" == typeof window.navigator.gamepadInputEmulation) { - window.navigator.gamepadInputEmulation = "keyboard"; - return true; - } - - return false; - } - - function isGamepadSupported() { - return "ongamepadconnected" in window || navigator.getGamepads || navigator.webkitGetGamepads; + events.off(apiClient, 'message', onMessageReceived); + events.on(apiClient, 'message', onMessageReceived); } connectionManager.getApiClients().forEach(bindEvents); - events.on(connectionManager, 'apiclientcreated', function (e, newApiClient) { bindEvents(newApiClient); }); - - if (!enableNativeGamepadKeyMapping() && isGamepadSupported()) { - require(["components/serverNotifications/gamepadtokey"]); - } - - require(["components/serverNotifications/mouseManager"]); - return serverNotifications; }); diff --git a/src/components/serverRestartDialog.js b/src/components/serverRestartDialog.js index 4c20183b2a..4c52d5f01b 100644 --- a/src/components/serverRestartDialog.js +++ b/src/components/serverRestartDialog.js @@ -12,7 +12,7 @@ define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelp } // 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) { + apiClient.getJSON(apiClient.getUrl('System/Info')).then(function (info) { // If this is back to false, the restart completed if (!info.IsShuttingDown) { @@ -155,4 +155,4 @@ define(['loading', 'events', 'dialogHelper', 'dom', 'layoutManager', 'scrollHelp }; return ServerRestartDialog; -}); \ No newline at end of file +}); diff --git a/src/components/serviceworker/notifications.js b/src/components/serviceworker/notifications.js index 9c5be840bf..5f96d01a4d 100644 --- a/src/components/serviceworker/notifications.js +++ b/src/components/serviceworker/notifications.js @@ -1,3 +1,4 @@ +/* eslint-env serviceworker */ (function () { 'use strict'; @@ -19,7 +20,7 @@ case 'restart': return apiClient.restartServer(); default: - clients.openWindow("/"); + clients.openWindow('/'); return Promise.resolve(); } }); @@ -34,11 +35,11 @@ var action = event.action; if (!action) { - clients.openWindow("/"); + clients.openWindow('/'); event.waitUntil(Promise.resolve()); return; } event.waitUntil(executeAction(action, data, serverId)); }, false); -})(); \ No newline at end of file +})(); diff --git a/src/components/sessionplayer.js b/src/components/sessionplayer.js index adcaab2674..489b57493d 100644 --- a/src/components/sessionplayer.js +++ b/src/components/sessionplayer.js @@ -79,7 +79,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'] instance.isUpdating = true; var apiClient = getCurrentApiClient(instance); - apiClient.sendMessage("SessionsStop"); + apiClient.sendMessage('SessionsStop'); if (instance.pollInterval) { clearInterval(instance.pollInterval); instance.pollInterval = null; @@ -158,7 +158,7 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'] instance.isUpdating = true; var apiClient = getCurrentApiClient(instance); - apiClient.sendMessage("SessionsStart", "100,800"); + apiClient.sendMessage('SessionsStart', '100,800'); if (instance.pollInterval) { clearInterval(instance.pollInterval); instance.pollInterval = null; @@ -549,4 +549,4 @@ define(['playbackManager', 'events', 'serverNotifications', 'connectionManager'] }; return SessionPlayer; -}); \ No newline at end of file +}); diff --git a/src/components/shell.js b/src/components/shell.js index 534a57b027..4f1aa0c8de 100644 --- a/src/components/shell.js +++ b/src/components/shell.js @@ -10,12 +10,6 @@ define([], function () { } }, - canExec: false, - exec: function (options) { - // options.path - // options.arguments - return Promise.reject(); - }, enableFullscreen: function () { if (window.NativeShell) { window.NativeShell.enableFullscreen(); @@ -27,4 +21,4 @@ define([], function () { } } }; -}); \ No newline at end of file +}); diff --git a/src/components/shortcuts.js b/src/components/shortcuts.js index 9d2b1847e5..ab606ab1d2 100644 --- a/src/components/shortcuts.js +++ b/src/components/shortcuts.js @@ -425,4 +425,4 @@ define(['playbackManager', 'inputManager', 'connectionManager', 'appRouter', 'gl getShortcutAttributesHtml: getShortcutAttributesHtml }; -}); \ No newline at end of file +}); diff --git a/src/components/skinManager.js b/src/components/skinManager.js index 06125e947a..871b6d999f 100644 --- a/src/components/skinManager.js +++ b/src/components/skinManager.js @@ -24,28 +24,25 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr function getThemes() { return [{ - name: "Apple TV", - id: "appletv" + name: 'Apple TV', + id: 'appletv' }, { - name: "Blue Radiance", - id: "blueradiance" + name: 'Blue Radiance', + id: 'blueradiance' }, { - name: "Dark", - id: "dark", + name: 'Dark', + id: 'dark', isDefault: true, isDefaultServerDashboard: true }, { - name: "Emby", - id: "emby" + name: 'Light', + id: 'light' }, { - name: "Light", - id: "light" + name: 'Purple Haze', + id: 'purplehaze' }, { - name: "Purple Haze", - id: "purple-haze" - }, { - name: "Windows Media Center", - id: "wmc" + name: 'Windows Media Center', + id: 'wmc' }]; } @@ -94,12 +91,12 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr function onThemeLoaded() { document.documentElement.classList.remove('preload'); try { - var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue("background-color"); + var color = getComputedStyle(document.querySelector('.skinHeader')).getPropertyValue('background-color'); if (color) { appHost.setThemeColor(color); } } catch (err) { - console.log('Error setting theme color: ' + err); + console.error('error setting theme color: ' + err); } } @@ -119,8 +116,8 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr var linkUrl = info.stylesheetPath; unloadTheme(); - var link = document.createElement('link'); + var link = document.createElement('link'); link.setAttribute('rel', 'stylesheet'); link.setAttribute('type', 'text/css'); link.onload = function () { @@ -165,6 +162,7 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr function playSound(path, volume) { lastSound = new Date().getTime(); require(['howler'], function (howler) { + /* globals Howl */ try { var sound = new Howl({ src: [path], @@ -173,7 +171,7 @@ define(['apphost', 'userSettings', 'browser', 'events', 'pluginManager', 'backdr sound.play(); currentSound = sound; } catch (err) { - console.log('Error playing sound: ' + err); + console.error('error playing sound: ' + err); } }); } diff --git a/src/components/slideshow/slideshow.js b/src/components/slideshow/slideshow.js index a5acd042b3..4716135ceb 100644 --- a/src/components/slideshow/slideshow.js +++ b/src/components/slideshow/slideshow.js @@ -1,17 +1,26 @@ -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) { +/** + * Image viewer component + * @module components/slideshow/slideshow + */ +define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'focusManager', 'browser', 'apphost', 'css!./style', 'material-icons', 'paper-icon-button-light'], function (dialogHelper, inputManager, connectionManager, layoutManager, focusManager, browser, appHost) { 'use strict'; + /** + * Retrieves an item's image URL from the API. + * @param {object|string} item - Item used to generate the image URL. + * @param {object} options - Options of the image. + * @param {object} apiClient - API client instance used to retrieve the image. + * @returns {null|string} URL of the item's image. + */ function getImageUrl(item, options, apiClient) { - options = options || {}; - options.type = options.type || "Primary"; + 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); } @@ -27,10 +36,16 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f return null; } + /** + * Retrieves a backdrop's image URL from the API. + * @param {object} item - Item used to generate the image URL. + * @param {object} options - Options of the image. + * @param {object} apiClient - API client instance used to retrieve the image. + * @returns {null|string} URL of the item's backdrop. + */ function getBackdropImageUrl(item, options, apiClient) { - options = options || {}; - options.type = options.type || "Backdrop"; + options.type = options.type || 'Backdrop'; // If not resizing, get the original image if (!options.maxWidth && !options.width && !options.maxHeight && !options.height) { @@ -46,60 +61,78 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f return null; } - function getImgUrl(item, original) { - + /** + * Dispatches a request for an item's image to its respective handler. + * @param {object} item - Item used to generate the image URL. + * @returns {string} URL of the item's image. + */ + function getImgUrl(item, user) { 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) { + if (item.MediaType === 'Photo' && user && user.Policy.EnableContentDownloading) { return apiClient.getItemDownloadUrl(item.Id); } - imageOptions.type = "Primary"; + imageOptions.type = 'Primary'; return getImageUrl(item, imageOptions, apiClient); } } + /** + * Generates a button using the specified icon, classes and properties. + * @param {string} icon - Name of the material icon on the button + * @param {string} cssClass - CSS classes to assign to the button + * @param {boolean} canFocus - Flag to set the tabindex attribute on the button to -1. + * @param {boolean} autoFocus - Flag to set the autofocus attribute on the button. + * @returns {string} The HTML markup of the button. + */ function getIcon(icon, cssClass, canFocus, autoFocus) { - var tabIndex = canFocus ? '' : ' tabindex="-1"'; autoFocus = autoFocus ? ' autofocus' : ''; - return ''; + return ''; } + /** + * Sets the viewport meta tag to enable or disable scaling by the user. + * @param {boolean} scalable - Flag to set the scalability of the viewport. + */ function setUserScalable(scalable) { - try { appHost.setUserScalable(scalable); } catch (err) { - console.log('error in appHost.setUserScalable: ' + err); + console.error('error in appHost.setUserScalable: ' + err); } } return function (options) { - var self = this; + /** Initialized instance of Swiper. */ var swiperInstance; - var dlg; - var currentTimeout; - var currentIntervalMs; + /** Initialized instance of the dialog containing the Swiper instance. */ + var dialog; + /** Options of the slideshow components */ var currentOptions; - var currentIndex; + /** ID of the timeout used to hide the OSD. */ + var hideTimeout; + /** Last coordinates of the mouse pointer. */ + var lastMouseMoveData; + /** Visibility status of the OSD. */ + var _osdOpen = false; - // small hack since this is not possible anyway - if (browser.chromecast) { - options.interactive = false; - } + // Use autoplay on Chromecast since it is non-interactive. + if (browser.chromecast) options.interactive = false; + /** + * Creates the HTML markup for the dialog and the OSD. + * @param {Object} options - Options used to create the dialog and slideshow. + */ function createElements(options) { + currentOptions = options; - dlg = dialogHelper.createDialog({ + dialog = dialogHelper.createDialog({ exitAnimationDuration: options.interactive ? 400 : 800, size: 'fullscreen', autoFocus: false, @@ -108,23 +141,21 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f removeOnClose: true }); - dlg.classList.add('slideshowDialog'); + dialog.classList.add('slideshowDialog'); var html = ''; - if (options.interactive) { + html += '
'; + if (options.interactive && !layoutManager.tv) { var actionButtonsOnTop = layoutManager.mobile; - 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')) { + if (appHost.supports('filedownload') && options.user && options.user.Policy.EnableContentDownloading) { html += getIcon('file_download', 'btnDownload slideshowButton', true); } if (appHost.supports('sharing')) { @@ -137,8 +168,8 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f if (!actionButtonsOnTop) { html += '
'; - html += getIcon('pause', 'btnSlideshowPause slideshowButton', true, true); - if (appHost.supports('filedownload')) { + html += getIcon('play_arrow', 'btnSlideshowPause slideshowButton', true, true); + if (appHost.supports('filedownload') && options.user && options.user.Policy.EnableContentDownloading) { html += getIcon('file_download', 'btnDownload slideshowButton', true); } if (appHost.supports('sharing')) { @@ -148,33 +179,28 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f html += '
'; } - html += '
'; - } else { html += '

'; } - dlg.innerHTML = html; + dialog.innerHTML = html; - if (options.interactive) { - dlg.querySelector('.btnSlideshowExit').addEventListener('click', function (e) { - - dialogHelper.close(dlg); + if (options.interactive && !layoutManager.tv) { + dialog.querySelector('.btnSlideshowExit').addEventListener('click', function (e) { + dialogHelper.close(dialog); }); - dlg.querySelector('.btnSlideshowNext').addEventListener('click', nextImage); - dlg.querySelector('.btnSlideshowPrevious').addEventListener('click', previousImage); - var btnPause = dlg.querySelector('.btnSlideshowPause'); + var btnPause = dialog.querySelector('.btnSlideshowPause'); if (btnPause) { btnPause.addEventListener('click', playPause); } - var btnDownload = dlg.querySelector('.btnDownload'); + var btnDownload = dialog.querySelector('.btnDownload'); if (btnDownload) { btnDownload.addEventListener('click', download); } - var btnShare = dlg.querySelector('.btnShare'); + var btnShare = dialog.querySelector('.btnShare'); if (btnShare) { btnShare.addEventListener('click', share); } @@ -182,60 +208,111 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f setUserScalable(true); - dialogHelper.open(dlg).then(function () { - + dialogHelper.open(dialog).then(function () { setUserScalable(false); - stopInterval(); }); inputManager.on(window, onInputCommand); document.addEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove); - dlg.addEventListener('close', onDialogClosed); + dialog.addEventListener('close', onDialogClosed); - if (options.interactive) { - loadSwiper(dlg); + loadSwiper(dialog, options); + } + + /** + * Handles OSD changes when the autoplay is started. + */ + function onAutoplayStart() { + var btnSlideshowPause = dialog.querySelector('.btnSlideshowPause .material-icons'); + if (btnSlideshowPause) { + btnSlideshowPause.classList.replace('play_arrow', 'pause'); } } - function loadSwiper(dlg) { + /** + * Handles OSD changes when the autoplay is stopped. + */ + function onAutoplayStop() { + var btnSlideshowPause = dialog.querySelector('.btnSlideshowPause .material-icons'); + if (btnSlideshowPause) { + btnSlideshowPause.classList.replace('pause', 'play_arrow'); + } + } + /** + * Initializes the Swiper instance and binds the relevant events. + * @param {HTMLElement} dialog - Element containing the dialog. + * @param {Object} options - Options used to initialize the Swiper instance. + */ + function loadSwiper(dialog, options) { + var slides; if (currentOptions.slides) { - dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.slides.map(getSwiperSlideHtmlFromSlide).join(''); + slides = currentOptions.slides; } else { - dlg.querySelector('.swiper-wrapper').innerHTML = currentOptions.items.map(getSwiperSlideHtmlFromItem).join(''); + slides = currentOptions.items; } require(['swiper'], function (Swiper) { - - swiperInstance = new Swiper(dlg.querySelector('.slideshowSwiperContainer'), { - // Optional parameters + swiperInstance = new Swiper(dialog.querySelector('.slideshowSwiperContainer'), { 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, + // Loop is disabled due to the virtual slides option not supporting it. + loop: false, + zoom: { + minRatio: 1, + toggle: true, + containerClass: 'slider-zoom-container' + }, + autoplay: !options.interactive, + keyboard: { + enabled: true + }, + preloadImages: true, + slidesPerView: 1, + slidesPerColumn: 1, initialSlide: options.startIndex || 0, - speed: 240 + speed: 240, + navigation: { + nextEl: '.btnSlideshowNext', + prevEl: '.btnSlideshowPrevious' + }, + // Virtual slides reduce memory consumption for large libraries while allowing preloading of images; + virtual: { + slides: slides, + cache: true, + renderSlide: getSwiperSlideHtml, + addSlidesBefore: 1, + addSlidesAfter: 1 + } }); - if (layoutManager.mobile) { - pause(); - } else { - play(); - } + swiperInstance.on('autoplayStart', onAutoplayStart); + swiperInstance.on('autoplayStop', onAutoplayStop); }); } - function getSwiperSlideHtmlFromItem(item) { + /** + * Renders the HTML markup of a slide for an item or a slide. + * @param {Object} item - The item used to render the slide. + * @param {number} index - The index of the item in the Swiper instance. + * @returns {string} The HTML markup of the slide. + */ + function getSwiperSlideHtml(item, index) { + if (currentOptions.slides) { + return getSwiperSlideHtmlFromSlide(item); + } else { + return getSwiperSlideHtmlFromItem(item); + } + } + /** + * Renders the HTML markup of a slide for an item. + * @param {Object} item - Item used to generate the slide. + * @returns {string} The HTML markup of the slide. + */ + function getSwiperSlideHtmlFromItem(item) { return getSwiperSlideHtmlFromSlide({ - imageUrl: getImgUrl(item), - originalImage: getImgUrl(item, true), + originalImage: getImgUrl(item, currentOptions.user), //title: item.Name, //description: item.Overview Id: item.Id, @@ -243,11 +320,17 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f }); } + /** + * Renders the HTML markup of a slide for a slide object. + * @param {Object} item - Slide object used to generate the slide. + * @returns {string} The HTML markup of the slide. + */ function getSwiperSlideHtmlFromSlide(item) { - var html = ''; - html += '
'; - html += ''; + html += '
'; + html += '
'; + html += ''; + html += '
'; if (item.title || item.subtitle) { html += '
'; html += '
'; @@ -269,42 +352,18 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f return html; } - function previousImage() { - if (swiperInstance) { - swiperInstance.slidePrev(); - } else { - stopInterval(); - showNextImage(currentIndex - 1); - } - } - - function nextImage() { - if (swiperInstance) { - - if (options.loop === false) { - - if (swiperInstance.activeIndex >= swiperInstance.slides.length - 1) { - dialogHelper.close(dlg); - return; - } - } - - swiperInstance.slideNext(); - } else { - stopInterval(); - showNextImage(currentIndex + 1); - } - } - + /** + * Fetches the information of the currently displayed slide. + * @returns {null|{itemId: string, shareUrl: string, serverId: string, url: string}} Object containing the information of the currently displayed slide. + */ function getCurrentImageInfo() { - if (swiperInstance) { var slide = document.querySelector('.swiper-slide-active'); if (slide) { return { url: slide.getAttribute('data-original'), - shareUrl: slide.getAttribute('data-imageurl'), + shareUrl: slide.getAttribute('data-original'), itemId: slide.getAttribute('data-itemid'), serverId: slide.getAttribute('data-serverid') }; @@ -315,8 +374,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f } } + /** + * Starts a download for the currently displayed slide. + */ function download() { - var imageInfo = getCurrentImageInfo(); require(['fileDownloader'], function (fileDownloader) { @@ -324,8 +385,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f }); } + /** + * Shares the currently displayed slide using the browser's built-in sharing feature. + */ function share() { - var imageInfo = getCurrentImageInfo(); navigator.share({ @@ -333,29 +396,29 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f }); } + /** + * Starts the autoplay feature of the Swiper instance. + */ function play() { - - var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i'); - if (btnSlideshowPause) { - btnSlideshowPause.innerHTML = "pause"; + if (swiperInstance.autoplay) { + swiperInstance.autoplay.start(); } - - swiperInstance.startAutoplay(); } + /** + * Pauses the autoplay feature of the Swiper instance; + */ function pause() { - - var btnSlideshowPause = dlg.querySelector('.btnSlideshowPause i'); - if (btnSlideshowPause) { - btnSlideshowPause.innerHTML = "play_arrow"; + if (swiperInstance.autoplay) { + swiperInstance.autoplay.stop(); } - - swiperInstance.stopAutoplay(); } + /** + * Toggles the autoplay feature of the Swiper instance. + */ function playPause() { - - var paused = dlg.querySelector('.btnSlideshowPause i').innerHTML !== "pause"; + var paused = !dialog.querySelector('.btnSlideshowPause .material-icons').classList.contains('pause'); if (paused) { play(); } else { @@ -363,8 +426,10 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f } } + /** + * Closes the dialog and destroys the Swiper instance. + */ function onDialogClosed() { - var swiper = swiperInstance; if (swiper) { swiper.destroy(true, true); @@ -375,53 +440,38 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f document.removeEventListener((window.PointerEvent ? 'pointermove' : 'mousemove'), onPointerMove); } - function startInterval(options) { - - currentOptions = options; - - stopInterval(); - createElements(options); - - if (!options.interactive) { - currentIntervalMs = options.interval || 11000; - showNextImage(options.startIndex || 0, true); - } - } - - var _osdOpen = false; - - function isOsdOpen() { - return _osdOpen; - } - - function getOsdBottom() { - return dlg.querySelector('.slideshowBottomBar'); - } - + /** + * Shows the OSD. + */ function showOsd() { - - var bottom = getOsdBottom(); + var bottom = dialog.querySelector('.slideshowBottomBar'); if (bottom) { slideUpToShow(bottom); startHideTimer(); } } + /** + * Hides the OSD. + */ function hideOsd() { - - var bottom = getOsdBottom(); + var bottom = dialog.querySelector('.slideshowBottomBar'); if (bottom) { slideDownToHide(bottom); } } - var hideTimeout; - + /** + * Starts the timer used to automatically hide the OSD. + */ function startHideTimer() { stopHideTimer(); - hideTimeout = setTimeout(hideOsd, 4000); + hideTimeout = setTimeout(hideOsd, 3000); } + /** + * Stops the timer used to automatically hide the OSD. + */ function stopHideTimer() { if (hideTimeout) { clearTimeout(hideTimeout); @@ -429,71 +479,76 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f } } - function slideUpToShow(elem) { - - if (!elem.classList.contains('hide')) { + /** + * Shows the OSD by sliding it into view. + * @param {HTMLElement} element - Element containing the OSD. + */ + function slideUpToShow(element) { + if (!element.classList.contains('hide')) { return; } _osdOpen = true; - elem.classList.remove('hide'); + element.classList.remove('hide'); var onFinish = function () { - focusManager.focus(elem.querySelector('.btnSlideshowPause')); + focusManager.focus(element.querySelector('.btnSlideshowPause')); }; - if (!elem.animate) { + if (!element.animate) { onFinish(); return; } requestAnimationFrame(function () { - var keyframes = [ - { transform: 'translate3d(0,' + elem.offsetHeight + 'px,0)', opacity: '.3', offset: 0 }, + { transform: 'translate3d(0,' + element.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; + element.animate(keyframes, timing).onfinish = onFinish; }); } - function slideDownToHide(elem) { - - if (elem.classList.contains('hide')) { + /** + * Hides the OSD by sliding it out of view. + * @param {HTMLElement} element - Element containing the OSD. + */ + function slideDownToHide(element) { + if (element.classList.contains('hide')) { return; } var onFinish = function () { - elem.classList.add('hide'); + element.classList.add('hide'); _osdOpen = false; }; - if (!elem.animate) { + if (!element.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 } + { transform: 'translate3d(0,' + element.offsetHeight + 'px,0)', opacity: '.3', offset: 1 } ]; var timing = { duration: 300, iterations: 1, easing: 'ease-out' }; - elem.animate(keyframes, timing).onfinish = onFinish; + element.animate(keyframes, timing).onfinish = onFinish; }); } - var lastMouseMoveData; - - function onPointerMove(e) { - - var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'); + /** + * Shows the OSD when moving the mouse pointer or touching the screen. + * @param {Event} event - Pointer movement event. + */ + function onPointerMove(event) { + var pointerType = event.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'); if (pointerType === 'mouse') { - var eventX = e.screenX || 0; - var eventY = e.screenY || 0; + var eventX = event.screenX || 0; + var eventY = event.screenY || 0; var obj = lastMouseMoveData; if (!obj) { @@ -516,127 +571,47 @@ define(['dialogHelper', 'inputManager', 'connectionManager', 'layoutManager', 'f } } - function onInputCommand(e) { - - switch (e.detail.command) { - - case 'left': - if (!isOsdOpen()) { - e.preventDefault(); - e.stopPropagation(); - previousImage(); - } - break; - case 'right': - if (!isOsdOpen()) { - e.preventDefault(); - e.stopPropagation(); - nextImage(); - } - break; + /** + * Dispatches keyboard inputs to their proper handlers. + * @param {Event} event - Keyboard input event. + */ + function onInputCommand(event) { + switch (event.detail.command) { case 'up': case 'down': case 'select': case 'menu': case 'info': - case 'play': - case 'playpause': - case 'pause': showOsd(); break; + case 'play': + play(); + break; + case 'pause': + pause(); + break; + case 'playpause': + playPause(); + break; default: break; } } - function showNextImage(index, skipPreload) { - - 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 (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() { - if (currentTimeout) { - clearTimeout(currentTimeout); - currentTimeout = null; - } - } - + /** + * Shows the slideshow component. + */ self.show = function () { - startInterval(options); + createElements(options); }; + /** + * Hides the slideshow element. + */ self.hide = function () { - - var dialog = dlg; if (dialog) { - dialogHelper.close(dialog); } }; }; -}); \ No newline at end of file +}); diff --git a/src/components/slideshow/style.css b/src/components/slideshow/style.css index 1167a972c8..f1fea508d7 100644 --- a/src/components/slideshow/style.css +++ b/src/components/slideshow/style.css @@ -3,11 +3,14 @@ background: #000; } -.slideshowSwiperContainer, .swiper-wrapper, .swiper-slide { +.slideshowSwiperContainer, +.swiper-wrapper, +.swiper-slide { background: #000; } -.slideshowImage, .slideshowSwiperContainer { +.slideshowImage, +.slideshowSwiperContainer { position: fixed; top: 0; right: 0; @@ -27,48 +30,48 @@ .slideshowImageText { position: fixed; - bottom: .25em; - right: .5em; + bottom: 0.25em; + right: 0.5em; color: #fff; z-index: 1002; 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 { - width: auto; - height: auto; - max-width: 100%; max-height: 100%; - transform: translate(-50%, -50%); - position: absolute; - left: 50%; - top: 50%; + max-width: 100%; + display: flex; + justify-content: center; + align-items: center; + text-align: center; + margin: auto; } .slideshowButtonIcon { color: #fff; - opacity: .7; + opacity: 0.7; } .btnSlideshowPrevious { - left: .5vh; + left: 0.5vh; top: 45vh; z-index: 1002; position: absolute; } .btnSlideshowNext { - right: .5vh; + right: 0.5vh; top: 45vh; z-index: 1002; position: absolute; } .topActionButtons { - right: .5vh; - top: .5vh; + right: 0.5vh; + top: 0.5vh; z-index: 1002; position: absolute; } @@ -78,9 +81,9 @@ left: 0; bottom: 0; right: 0; - background-color: rgba(0, 0, 0, .7); + background-color: rgba(0, 0, 0, 0.7); color: #fff; - padding: .5%; + padding: 0.5%; display: flex; flex-direction: row; align-items: center; @@ -92,9 +95,9 @@ left: 0; top: 0; right: 0; - background-color: rgba(0, 0, 0, .7); + background-color: rgba(0, 0, 0, 0.7); color: #fff; - padding: .5%; + padding: 0.5%; display: flex; flex-direction: row; align-items: center; @@ -118,16 +121,27 @@ .slideTextInner { margin: 0 auto; max-width: 60%; - background: rgba(0,0,0,.8); + background: rgba(0, 0, 0, 0.8); display: inline-block; - padding: .5em 1em; - border-radius: .25em; + padding: 0.5em 1em; + border-radius: 0.25em; } .slideTitle { - margin: 0 0 .25em; + margin: 0 0 0.25em; } .slideSubtitle { color: #ccc; } + +.swiper-slide { + display: flex; + flex-direction: column; +} + +.slider-zoom-container { + margin: auto; + max-height: 100%; + max-width: 100%; +} diff --git a/src/components/sortmenu/sortmenu.js b/src/components/sortmenu/sortmenu.js index d4f75a0806..9950afb89a 100644 --- a/src/components/sortmenu/sortmenu.js +++ b/src/components/sortmenu/sortmenu.js @@ -66,7 +66,7 @@ define(['require', 'dom', 'focusManager', 'dialogHelper', 'loading', 'layoutMana var html = ''; html += '
'; - html += ''; + html += ''; html += '

${Sort}

'; html += '
'; diff --git a/src/components/sortmenu/sortmenu.template.html b/src/components/sortmenu/sortmenu.template.html index 3f523c2959..da7da98371 100644 --- a/src/components/sortmenu/sortmenu.template.html +++ b/src/components/sortmenu/sortmenu.template.html @@ -19,4 +19,4 @@
-
\ No newline at end of file +
diff --git a/src/components/subtitleeditor/subtitleeditor.css b/src/components/subtitleeditor/subtitleeditor.css index a97b20b38a..08e6faffba 100644 --- a/src/components/subtitleeditor/subtitleeditor.css +++ b/src/components/subtitleeditor/subtitleeditor.css @@ -1,3 +1,3 @@ .originalSubtitleFileLabel { margin-right: 1em; -} \ No newline at end of file +} diff --git a/src/components/subtitleeditor/subtitleeditor.js b/src/components/subtitleeditor/subtitleeditor.js index 964aa81789..e9bcc0bfca 100644 --- a/src/components/subtitleeditor/subtitleeditor.js +++ b/src/components/subtitleeditor/subtitleeditor.js @@ -48,7 +48,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', var apiClient = connectionManager.getApiClient(currentItem.ServerId); apiClient.ajax({ - type: "POST", + type: 'POST', url: apiClient.getUrl(url) }).then(function () { @@ -87,7 +87,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', apiClient.ajax({ - type: "DELETE", + type: 'DELETE', url: apiClient.getUrl(url) }).then(function () { @@ -132,7 +132,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', itemHtml += '<' + tagName + ' class="' + className + '" data-index="' + s.Index + '">'; - itemHtml += 'closed_caption'; + itemHtml += ''; itemHtml += '
'; @@ -149,7 +149,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', if (!layoutManager.tv) { if (s.Path) { - itemHtml += ''; + itemHtml += ''; } } @@ -232,11 +232,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', html += '
'; } html += '

' + provider + '

'; - if (layoutManager.tv) { - html += '
'; - } else { - html += '
'; - } + html += '
'; lastProvider = provider; } @@ -248,7 +244,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', html += '<' + tagName + ' class="' + className + '" data-subid="' + result.Id + '">'; - html += 'closed_caption'; + html += ''; var bodyClass = result.Comment || result.IsHashMatch ? 'three-line' : 'two-line'; @@ -281,7 +277,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', html += '
'; if (!layoutManager.tv) { - html += ''; + html += ''; } html += ''; @@ -397,7 +393,7 @@ define(['dialogHelper', 'require', 'layoutManager', 'globalize', 'userSettings', var items = []; items.push({ - name: Globalize.translate('Download'), + name: globalize.translate('Download'), id: 'download' }); diff --git a/src/components/subtitleeditor/subtitleeditor.template.html b/src/components/subtitleeditor/subtitleeditor.template.html index dc8ae25701..7471972f59 100644 --- a/src/components/subtitleeditor/subtitleeditor.template.html +++ b/src/components/subtitleeditor/subtitleeditor.template.html @@ -1,9 +1,8 @@
- +

${Subtitles}

- info${Help} - + ${Help}
@@ -18,7 +17,7 @@
- +
diff --git a/src/components/subtitlesettings/subtitleappearancehelper.js b/src/components/subtitlesettings/subtitleappearancehelper.js index 8a40bd134b..bec8156aca 100644 --- a/src/components/subtitlesettings/subtitleappearancehelper.js +++ b/src/components/subtitlesettings/subtitleappearancehelper.js @@ -1,5 +1,5 @@ define([], function () { - "use strict"; + 'use strict'; function getTextStyles(settings, isCue) { @@ -156,4 +156,4 @@ define([], function () { getStyles: getStyles, applyStyles: applyStyles }; -}); \ No newline at end of file +}); diff --git a/src/components/subtitlesettings/subtitlesettings.js b/src/components/subtitlesettings/subtitlesettings.js index 669b26d271..d728360d05 100644 --- a/src/components/subtitlesettings/subtitlesettings.js +++ b/src/components/subtitlesettings/subtitlesettings.js @@ -1,24 +1,19 @@ 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"; + 'use strict'; function populateLanguages(select, languages) { + var html = ''; - var html = ""; - - html += ""; - + html += "'; for (var i = 0, length = languages.length; i < length; i++) { - var culture = languages[i]; - - html += ""; + html += "'; } select.innerHTML = html; } function getSubtitleAppearanceObject(context) { - var appearanceSettings = {}; appearanceSettings.textSize = context.querySelector('#selectTextSize').value; @@ -42,8 +37,8 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi populateLanguages(selectSubtitleLanguage, allCultures); - selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || ""; - context.querySelector('#selectSubtitlePlaybackMode').value = user.Configuration.SubtitleMode || ""; + selectSubtitleLanguage.value = user.Configuration.SubtitleLanguagePreference || ''; + context.querySelector('#selectSubtitlePlaybackMode').value = user.Configuration.SubtitleMode || ''; context.querySelector('#selectSubtitlePlaybackMode').dispatchEvent(new CustomEvent('change', {})); @@ -102,14 +97,12 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi } function onSubmit(e) { - 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); }); @@ -118,6 +111,7 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi if (e) { e.preventDefault(); } + return false; } @@ -197,9 +191,7 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi 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); @@ -214,9 +206,8 @@ define(['require', 'globalize', 'appSettings', 'apphost', 'focusManager', 'loadi }; SubtitleSettings.prototype.destroy = function () { - this.options = null; }; return SubtitleSettings; -}); \ No newline at end of file +}); diff --git a/src/components/subtitlesettings/subtitlesettings.template.html b/src/components/subtitlesettings/subtitlesettings.template.html index a6ec43d8fa..716296a257 100644 --- a/src/components/subtitlesettings/subtitlesettings.template.html +++ b/src/components/subtitlesettings/subtitlesettings.template.html @@ -1,7 +1,5 @@
-
-

${Subtitles}

@@ -9,6 +7,7 @@
+
@@ -34,7 +34,6 @@
-

${HeaderSubtitleAppearance}

@@ -61,6 +60,7 @@
+
+
+
+
-
\ No newline at end of file +
diff --git a/src/components/tabbedview/itemstab.js b/src/components/tabbedview/itemstab.js index 33eddb6ec5..884cfa2015 100644 --- a/src/components/tabbedview/itemstab.js +++ b/src/components/tabbedview/itemstab.js @@ -104,24 +104,17 @@ define(['playbackManager', 'userSettings', 'alphaPicker', 'alphaNumericShortcuts } function showSortMenu() { - var instance = this; - require(['sortMenu'], function (SortMenu) { - new SortMenu().show({ - settingsKey: instance.getSettingsKey(), settings: instance.getSortValues(), onChange: instance.itemsContainer.refreshItems.bind(instance.itemsContainer), serverId: instance.params.serverId, sortOptions: instance.getSortMenuOptions() - }).then(function () { - updateSortText(instance); updateAlphaPickerState(instance); - instance.itemsContainer.refreshItems(); }); }); @@ -188,7 +181,8 @@ define(['playbackManager', 'userSettings', 'alphaPicker', 'alphaNumericShortcuts return; } - btnSortIcon.innerHTML = values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward'; + btnSortIcon.classList.remove('arrow_downward', 'arrow_upward'); + btnSortIcon.classList.add(values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward'); } function bindAll(elems, eventName, fn) { diff --git a/src/components/tabbedview/tabbedview.js b/src/components/tabbedview/tabbedview.js index 33f1c6e6cc..a67e8e0fa1 100644 --- a/src/components/tabbedview/tabbedview.js +++ b/src/components/tabbedview/tabbedview.js @@ -120,4 +120,4 @@ define(['backdrop', 'mainTabsManager', 'layoutManager', 'emby-tabs'], function ( }; return TabbedView; -}); \ No newline at end of file +}); diff --git a/src/components/thememediaplayer.js b/src/components/thememediaplayer.js index a8298fad37..94012ba823 100644 --- a/src/components/thememediaplayer.js +++ b/src/components/thememediaplayer.js @@ -108,4 +108,4 @@ define(['playbackManager', 'userSettings', 'connectionManager'], function (playb // } //}); -}); \ No newline at end of file +}); diff --git a/src/components/toast/toast.css b/src/components/toast/toast.css index 09d89abca5..28d6cb52fc 100644 --- a/src/components/toast/toast.css +++ b/src/components/toast/toast.css @@ -3,9 +3,9 @@ min-width: 20em; box-sizing: border-box; box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); - border-radius: .15em; + border-radius: 0.15em; cursor: default; - transition: transform .3s ease-out; + transition: transform 0.3s ease-out; min-height: initial; padding: 1em 1.5em; bottom: 1em; diff --git a/src/components/toast/toast.js b/src/components/toast/toast.js index d8ac404764..7b8e49e4d2 100644 --- a/src/components/toast/toast.js +++ b/src/components/toast/toast.js @@ -26,7 +26,7 @@ define(['css!./toast'], function () { }; } - var elem = document.createElement("div"); + var elem = document.createElement('div'); elem.classList.add('toast'); elem.innerHTML = options.text; @@ -39,4 +39,4 @@ define(['css!./toast'], function () { }, 300); }; -}); \ No newline at end of file +}); diff --git a/src/components/touchhelper.js b/src/components/touchhelper.js index 0f6d34aace..97455fc969 100644 --- a/src/components/touchhelper.js +++ b/src/components/touchhelper.js @@ -168,4 +168,4 @@ define(['dom', 'events'], function (dom, events) { }; return TouchHelper; -}); \ No newline at end of file +}); diff --git a/src/components/tunerpicker.js b/src/components/tunerpicker.js index 3882f2e85a..e7c92851a4 100644 --- a/src/components/tunerpicker.js +++ b/src/components/tunerpicker.js @@ -1,38 +1,38 @@ -define(["dialogHelper", "dom", "layoutManager", "connectionManager", "globalize", "loading", "browser", "material-icons", "formDialogStyle", "emby-button", "emby-itemscontainer", "cardStyle"], function (dialogHelper, dom, layoutManager, connectionManager, globalize, loading, browser) { - "use strict"; +define(['dialogHelper', 'dom', 'layoutManager', 'connectionManager', 'globalize', 'loading', 'browser', 'focusManager', 'scrollHelper', 'material-icons', 'formDialogStyle', 'emby-button', 'emby-itemscontainer', 'cardStyle'], function (dialogHelper, dom, layoutManager, connectionManager, globalize, loading, browser, focusManager, scrollHelper) { + 'use strict'; var enableFocusTransform = !browser.slow && !browser.edge; function getEditorHtml() { - var html = ""; + var html = ''; html += '
'; html += '
'; html += '
'; - html += "

" + globalize.translate("DetectingDevices") + "...

"; - html += "

" + globalize.translate("MessagePleaseWait") + "

"; - html += "
"; - html += '

' + globalize.translate("HeaderNewDevices") + "

"; + html += '

' + globalize.translate('DetectingDevices') + '...

'; + html += '

' + globalize.translate('MessagePleaseWait') + '

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

' + globalize.translate('HeaderNewDevices') + '

'; html += '
'; - html += "
"; - html += "
"; - return html += "
"; + html += '
'; + html += '
'; + return html += '
'; } function getDeviceHtml(device) { var padderClass; - var html = ""; - var cssClass = "card scalableCard"; - var cardBoxCssClass = "cardBox visualCardBox"; - cssClass += " backdropCard backdropCard-scalable"; - padderClass = "cardPadder-backdrop"; + var html = ''; + var cssClass = 'card scalableCard'; + var cardBoxCssClass = 'cardBox visualCardBox'; + cssClass += ' backdropCard backdropCard-scalable'; + padderClass = 'cardPadder-backdrop'; // TODO move card creation code to Card component if (layoutManager.tv) { - cssClass += " show-focus"; + cssClass += ' show-focus'; if (enableFocusTransform) { - cssClass += " show-animation"; + cssClass += ' show-animation'; } } @@ -41,56 +41,56 @@ define(["dialogHelper", "dom", "layoutManager", "connectionManager", "globalize" html += '
'; html += '
'; html += '
'; - html += '
dvr
'; - html += "
"; - html += "
"; + html += '
'; + html += '
'; + html += '
'; html += '
'; - html += '
' + getTunerName(device.Type) + "
"; - html += '
' + device.FriendlyName + "
"; + html += '
' + getTunerName(device.Type) + '
'; + html += '
' + device.FriendlyName + '
'; html += '
'; - html += device.Url || " "; - html += "
"; - html += "
"; - html += "
"; - return html += ""; + html += device.Url || ' '; + html += '
'; + html += '
'; + html += '
'; + return html += ''; } function getTunerName(providerId) { switch (providerId = providerId.toLowerCase()) { - case "m3u": - return "M3U"; + case 'm3u': + return 'M3U'; - case "hdhomerun": - return "HDHomerun"; + case 'hdhomerun': + return 'HDHomerun'; - case "hauppauge": - return "Hauppauge"; + case 'hauppauge': + return 'Hauppauge'; - case "satip": - return "DVB"; + case 'satip': + return 'DVB'; default: - return "Unknown"; + return 'Unknown'; } } function renderDevices(view, devices) { var i; var length; - var html = ""; + var html = ''; for (i = 0, length = devices.length; i < length; i++) { html += getDeviceHtml(devices[i]); } if (devices.length) { - view.querySelector(".devicesHeader").classList.remove("hide"); + view.querySelector('.devicesHeader').classList.remove('hide'); } else { - html = "


" + globalize.translate("NoNewDevicesFound") + "

"; - view.querySelector(".devicesHeader").classList.add("hide"); + html = '


' + globalize.translate('NoNewDevicesFound') + '

'; + view.querySelector('.devicesHeader').classList.add('hide'); } - var elem = view.querySelector(".results"); + var elem = view.querySelector('.results'); elem.innerHTML = html; if (layoutManager.tv) { @@ -100,13 +100,13 @@ define(["dialogHelper", "dom", "layoutManager", "connectionManager", "globalize" function discoverDevices(view, apiClient) { loading.show(); - view.querySelector(".loadingContent").classList.remove("hide"); - return ApiClient.getJSON(ApiClient.getUrl("LiveTv/Tuners/Discvover", { + view.querySelector('.loadingContent').classList.remove('hide'); + return ApiClient.getJSON(ApiClient.getUrl('LiveTv/Tuners/Discvover', { NewDevicesOnly: true })).then(function (devices) { currentDevices = devices; renderDevices(view, devices); - view.querySelector(".loadingContent").classList.add("hide"); + view.querySelector('.loadingContent').classList.add('hide'); loading.hide(); }); } @@ -119,31 +119,31 @@ define(["dialogHelper", "dom", "layoutManager", "connectionManager", "globalize" }; if (layoutManager.tv) { - dialogOptions.size = "fullscreen"; + dialogOptions.size = 'fullscreen'; } else { - dialogOptions.size = "small"; + dialogOptions.size = 'small'; } var dlg = dialogHelper.createDialog(dialogOptions); - dlg.classList.add("formDialog"); - var html = ""; + dlg.classList.add('formDialog'); + var html = ''; html += '
'; - html += ''; + html += ''; html += '

'; - html += globalize.translate("HeaderLiveTvTunerSetup"); - html += "

"; - html += "
"; + html += globalize.translate('HeaderLiveTvTunerSetup'); + html += ''; + html += '
'; html += getEditorHtml(); dlg.innerHTML = html; - dlg.querySelector(".btnCancel").addEventListener("click", function () { + dlg.querySelector('.btnCancel').addEventListener('click', function () { dialogHelper.close(dlg); }); var deviceResult; - dlg.querySelector(".results").addEventListener("click", function (e) { - var tunerCard = dom.parentWithClass(e.target, "card"); + dlg.querySelector('.results').addEventListener('click', function (e) { + var tunerCard = dom.parentWithClass(e.target, 'card'); if (tunerCard) { - var deviceId = tunerCard.getAttribute("data-id"); + var deviceId = tunerCard.getAttribute('data-id'); deviceResult = currentDevices.filter(function (d) { return d.DeviceId === deviceId; })[0]; @@ -152,14 +152,14 @@ define(["dialogHelper", "dom", "layoutManager", "connectionManager", "globalize" }); if (layoutManager.tv) { - centerFocus(dlg.querySelector(".formDialogContent"), false, true); + scrollHelper.centerFocus.on(dlg.querySelector('.formDialogContent'), false); } var apiClient = connectionManager.getApiClient(options.serverId); discoverDevices(dlg, apiClient); if (layoutManager.tv) { - centerFocus(dlg.querySelector(".formDialogContent"), false, false); + scrollHelper.centerFocus.off(dlg.querySelector('.formDialogContent'), false); } return dialogHelper.open(dlg).then(function () { diff --git a/src/components/tvproviders/schedulesdirect.js b/src/components/tvproviders/schedulesdirect.js index a1265e7cc9..be1cdf575b 100644 --- a/src/components/tvproviders/schedulesdirect.js +++ b/src/components/tvproviders/schedulesdirect.js @@ -1,31 +1,31 @@ -define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "emby-select", "emby-button", "flexStyles"], function ($, loading) { - "use strict"; +define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'listViewStyle', 'emby-input', 'emby-select', 'emby-button', 'flexStyles'], function ($, loading, globalize) { + 'use strict'; return function (page, providerId, options) { function reload() { loading.show(); - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { var info = config.ListingProviders.filter(function (i) { return i.Id === providerId; })[0] || {}; listingsId = info.ListingsId; - $("#selectListing", page).val(info.ListingsId || ""); - page.querySelector(".txtUser").value = info.Username || ""; - page.querySelector(".txtPass").value = ""; - page.querySelector(".txtZipCode").value = info.ZipCode || ""; + $('#selectListing', page).val(info.ListingsId || ''); + page.querySelector('.txtUser').value = info.Username || ''; + page.querySelector('.txtPass').value = ''; + page.querySelector('.txtZipCode').value = info.ZipCode || ''; if (info.Username && info.Password) { - page.querySelector(".listingsSection").classList.remove("hide"); + page.querySelector('.listingsSection').classList.remove('hide'); } else { - page.querySelector(".listingsSection").classList.add("hide"); + page.querySelector('.listingsSection').classList.add('hide'); } - page.querySelector(".chkAllTuners").checked = info.EnableAllTuners; + page.querySelector('.chkAllTuners').checked = info.EnableAllTuners; if (info.EnableAllTuners) { - page.querySelector(".selectTunersSection").classList.add("hide"); + page.querySelector('.selectTunersSection').classList.add('hide'); } else { - page.querySelector(".selectTunersSection").classList.remove("hide"); + page.querySelector('.selectTunersSection').classList.remove('hide'); } setCountry(info); @@ -34,7 +34,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em } function setCountry(info) { - ApiClient.getJSON(ApiClient.getUrl("LiveTv/ListingProviders/SchedulesDirect/Countries")).then(function (result) { + ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/SchedulesDirect/Countries')).then(function (result) { var i; var length; var countryList = []; @@ -42,7 +42,7 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em for (var region in result) { var countries = result[region]; - if (countries.length && "ZZZ" !== region) { + if (countries.length && 'ZZZ' !== region) { for (i = 0, length = countries.length; i < length; i++) { countryList.push({ name: countries[i].fullName, @@ -63,13 +63,13 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em return 0; }); - $("#selectCountry", page).html(countryList.map(function (c) { - return '"; - }).join("")).val(info.Country || ""); - $(page.querySelector(".txtZipCode")).trigger("change"); + $('#selectCountry', page).html(countryList.map(function (c) { + return ''; + }).join('')).val(info.Country || ''); + $(page.querySelector('.txtZipCode')).trigger('change'); }, function () { // ApiClient.getJSON() error handler Dashboard.alert({ - message: Globalize.translate("ErrorGettingTvLineups") + message: globalize.translate('ErrorGettingTvLineups') }); }); loading.hide(); @@ -77,11 +77,11 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em function sha256(str) { if (!self.TextEncoder) { - return Promise.resolve(""); + return Promise.resolve(''); } - var buffer = new TextEncoder("utf-8").encode(str); - return crypto.subtle.digest("SHA-256", buffer).then(function (hash) { + var buffer = new TextEncoder('utf-8').encode(str); + return crypto.subtle.digest('SHA-256', buffer).then(function (hash) { return hex(hash); }); } @@ -93,22 +93,22 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em for (var i = 0; i < view.byteLength; i += 4) { var value = view.getUint32(i); var stringValue = value.toString(16); - var paddedValue = ("00000000" + stringValue).slice(-"00000000".length); + var paddedValue = ('00000000' + stringValue).slice(-'00000000'.length); hexCodes.push(paddedValue); } - return hexCodes.join(""); + return hexCodes.join(''); } function submitLoginForm() { loading.show(); - sha256(page.querySelector(".txtPass").value).then(function (passwordHash) { + sha256(page.querySelector('.txtPass').value).then(function (passwordHash) { var info = { - Type: "SchedulesDirect", - Username: page.querySelector(".txtUser").value, + Type: 'SchedulesDirect', + Username: page.querySelector('.txtUser').value, EnableAllTuners: true, Password: passwordHash, - Pw: page.querySelector(".txtPass").value + Pw: page.querySelector('.txtPass').value }; var id = providerId; @@ -117,56 +117,56 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em } ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/ListingProviders", { + type: 'POST', + url: ApiClient.getUrl('LiveTv/ListingProviders', { ValidateLogin: true }), data: JSON.stringify(info), - contentType: "application/json", - dataType: "json" + contentType: 'application/json', + dataType: 'json' }).then(function (result) { Dashboard.processServerConfigurationUpdateResult(); providerId = result.Id; reload(); }, function () { Dashboard.alert({ // ApiClient.ajax() error handler - message: Globalize.translate("ErrorSavingTvProvider") + message: globalize.translate('ErrorSavingTvProvider') }); }); }); } function submitListingsForm() { - var selectedListingsId = $("#selectListing", page).val(); + var selectedListingsId = $('#selectListing', page).val(); if (!selectedListingsId) { return void Dashboard.alert({ - message: Globalize.translate("ErrorPleaseSelectLineup") + message: globalize.translate('ErrorPleaseSelectLineup') }); } loading.show(); var id = providerId; - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { var info = config.ListingProviders.filter(function (i) { return i.Id === id; })[0]; - info.ZipCode = page.querySelector(".txtZipCode").value; - info.Country = $("#selectCountry", page).val(); + info.ZipCode = page.querySelector('.txtZipCode').value; + info.Country = $('#selectCountry', page).val(); info.ListingsId = selectedListingsId; - info.EnableAllTuners = page.querySelector(".chkAllTuners").checked; - info.EnabledTuners = info.EnableAllTuners ? [] : $(".chkTuner", page).get().filter(function (i) { + info.EnableAllTuners = page.querySelector('.chkAllTuners').checked; + info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (i) { return i.checked; }).map(function (i) { - return i.getAttribute("data-id"); + return i.getAttribute('data-id'); }); ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/ListingProviders", { + type: 'POST', + url: ApiClient.getUrl('LiveTv/ListingProviders', { ValidateListings: true }), data: JSON.stringify(info), - contentType: "application/json" + contentType: 'application/json' }).then(function (result) { loading.hide(); @@ -174,11 +174,11 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em Dashboard.processServerConfigurationUpdateResult(); } - Events.trigger(self, "submitted"); + Events.trigger(self, 'submitted'); }, function () { loading.hide(); Dashboard.alert({ - message: Globalize.translate("ErrorAddingListingsToSchedulesDirect") + message: globalize.translate('ErrorAddingListingsToSchedulesDirect') }); }); }); @@ -186,115 +186,111 @@ define(["jQuery", "loading", "emby-checkbox", "listViewStyle", "emby-input", "em function refreshListings(value) { if (!value) { - return void $("#selectListing", page).html(""); + return void $('#selectListing', page).html(''); } loading.show(); ApiClient.ajax({ - type: "GET", - url: ApiClient.getUrl("LiveTv/ListingProviders/Lineups", { + type: 'GET', + url: ApiClient.getUrl('LiveTv/ListingProviders/Lineups', { Id: providerId, Location: value, - Country: $("#selectCountry", page).val() + Country: $('#selectCountry', page).val() }), - dataType: "json" + dataType: 'json' }).then(function (result) { - $("#selectListing", page).html(result.map(function (o) { - return '"; + $('#selectListing', page).html(result.map(function (o) { + return ''; })); if (listingsId) { - $("#selectListing", page).val(listingsId); + $('#selectListing', page).val(listingsId); } loading.hide(); }, function (result) { Dashboard.alert({ - message: Globalize.translate("ErrorGettingTvLineups") + message: globalize.translate('ErrorGettingTvLineups') }); - refreshListings(""); + refreshListings(''); loading.hide(); }); } function getTunerName(providerId) { switch (providerId = providerId.toLowerCase()) { - case "m3u": - return "M3U Playlist"; - case "hdhomerun": - return "HDHomerun"; - case "satip": - return "DVB"; + case 'm3u': + return 'M3U Playlist'; + case 'hdhomerun': + return 'HDHomerun'; + case 'satip': + return 'DVB'; default: - return "Unknown"; + return 'Unknown'; } } function refreshTunerDevices(page, providerInfo, devices) { - var html = ""; + var html = ''; for (var i = 0, length = devices.length; i < length; i++) { var device = devices[i]; html += '
'; var enabledTuners = providerInfo.EnabledTuners || []; var isChecked = providerInfo.EnableAllTuners || -1 !== enabledTuners.indexOf(device.Id); - var checkedAttribute = isChecked ? " checked" : ""; - html += '"; + var checkedAttribute = isChecked ? ' checked' : ''; + html += ''; html += '
'; html += '
'; html += device.FriendlyName || getTunerName(device.Type); - html += "
"; + html += '
'; html += '
'; html += device.Url; - html += "
"; - html += "
"; - html += "
"; + html += '
'; + html += '
'; + html += '
'; } - page.querySelector(".tunerList").innerHTML = html; + page.querySelector('.tunerList').innerHTML = html; } var listingsId; var self = this; self.submit = function () { - page.querySelector(".btnSubmitListingsContainer").click(); + page.querySelector('.btnSubmitListingsContainer').click(); }; self.init = function () { options = options || {}; - if (options.showCancelButton) { - page.querySelector(".btnCancel").classList.remove("hide"); - } else { - page.querySelector(".btnCancel").classList.add("hide"); - } + // Only hide the buttons if explicitly set to false; default to showing if undefined or null + // FIXME: rename this option to clarify logic + var hideCancelButton = options.showCancelButton === false; + page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton); - if (options.showSubmitButton) { - page.querySelector(".btnSubmitListings").classList.remove("hide"); - } else { - page.querySelector(".btnSubmitListings").classList.add("hide"); - } + var hideSubmitButton = options.showSubmitButton === false; + page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton); - $(".formLogin", page).on("submit", function () { + $('.formLogin', page).on('submit', function () { submitLoginForm(); return false; }); - $(".formListings", page).on("submit", function () { + $('.formListings', page).on('submit', function () { submitListingsForm(); return false; }); - $(".txtZipCode", page).on("change", function () { + $('.txtZipCode', page).on('change', function () { refreshListings(this.value); }); - page.querySelector(".chkAllTuners").addEventListener("change", function (e) { + page.querySelector('.chkAllTuners').addEventListener('change', function (e) { if (e.target.checked) { - page.querySelector(".selectTunersSection").classList.add("hide"); + page.querySelector('.selectTunersSection').classList.add('hide'); } else { - page.querySelector(".selectTunersSection").classList.remove("hide"); + page.querySelector('.selectTunersSection').classList.remove('hide'); } }); - $(".createAccountHelp", page).html(Globalize.translate("MessageCreateAccountAt", 'http://www.schedulesdirect.org')); + $('.createAccountHelp', page).html(globalize.translate('MessageCreateAccountAt', 'http://www.schedulesdirect.org')); reload(); }; }; diff --git a/src/components/tvproviders/schedulesdirect.template.html b/src/components/tvproviders/schedulesdirect.template.html index da593ef569..abe19b50f5 100644 --- a/src/components/tvproviders/schedulesdirect.template.html +++ b/src/components/tvproviders/schedulesdirect.template.html @@ -1,7 +1,7 @@

Schedules Direct

- ${Help} + ${Help}

@@ -70,4 +70,4 @@
-
\ No newline at end of file +
diff --git a/src/components/tvproviders/xmltv.js b/src/components/tvproviders/xmltv.js index a86a1e1099..4c39b14430 100644 --- a/src/components/tvproviders/xmltv.js +++ b/src/components/tvproviders/xmltv.js @@ -1,5 +1,5 @@ -define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "paper-icon-button-light"], function ($, loading) { - "use strict"; +define(['jQuery', 'loading', 'globalize', 'emby-checkbox', 'emby-input', 'listViewStyle', 'paper-icon-button-light'], function ($, loading, globalize) { + 'use strict'; return function (page, providerId, options) { function getListingProvider(config, id) { @@ -15,26 +15,26 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa return getListingProvider(); } - return ApiClient.getJSON(ApiClient.getUrl("LiveTv/ListingProviders/Default")); + return ApiClient.getJSON(ApiClient.getUrl('LiveTv/ListingProviders/Default')); } function reload() { loading.show(); - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { getListingProvider(config, providerId).then(function (info) { - page.querySelector(".txtPath").value = info.Path || ""; - page.querySelector(".txtKids").value = (info.KidsCategories || []).join("|"); - page.querySelector(".txtNews").value = (info.NewsCategories || []).join("|"); - page.querySelector(".txtSports").value = (info.SportsCategories || []).join("|"); - page.querySelector(".txtMovies").value = (info.MovieCategories || []).join("|"); - page.querySelector(".txtMoviePrefix").value = info.MoviePrefix || ""; - page.querySelector(".txtUserAgent").value = info.UserAgent || ""; - page.querySelector(".chkAllTuners").checked = info.EnableAllTuners; + page.querySelector('.txtPath').value = info.Path || ''; + page.querySelector('.txtKids').value = (info.KidsCategories || []).join('|'); + page.querySelector('.txtNews').value = (info.NewsCategories || []).join('|'); + page.querySelector('.txtSports').value = (info.SportsCategories || []).join('|'); + page.querySelector('.txtMovies').value = (info.MovieCategories || []).join('|'); + page.querySelector('.txtMoviePrefix').value = info.MoviePrefix || ''; + page.querySelector('.txtUserAgent').value = info.UserAgent || ''; + page.querySelector('.chkAllTuners').checked = info.EnableAllTuners; - if (page.querySelector(".chkAllTuners").checked) { - page.querySelector(".selectTunersSection").classList.add("hide"); + if (page.querySelector('.chkAllTuners').checked) { + page.querySelector('.selectTunersSection').classList.add('hide'); } else { - page.querySelector(".selectTunersSection").classList.remove("hide"); + page.querySelector('.selectTunersSection').classList.remove('hide'); } refreshTunerDevices(page, info, config.TunerHosts); @@ -47,7 +47,7 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa var value = txtInput.value; if (value) { - return value.split("|"); + return value.split('|'); } return []; @@ -56,31 +56,31 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa function submitListingsForm() { loading.show(); var id = providerId; - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { var info = config.ListingProviders.filter(function (provider) { return provider.Id === id; })[0] || {}; - info.Type = "xmltv"; - info.Path = page.querySelector(".txtPath").value; - info.MoviePrefix = page.querySelector(".txtMoviePrefix").value || null; - info.UserAgent = page.querySelector(".txtUserAgent").value || null; - info.MovieCategories = getCategories(page.querySelector(".txtMovies")); - info.KidsCategories = getCategories(page.querySelector(".txtKids")); - info.NewsCategories = getCategories(page.querySelector(".txtNews")); - info.SportsCategories = getCategories(page.querySelector(".txtSports")); - info.EnableAllTuners = page.querySelector(".chkAllTuners").checked; - info.EnabledTuners = info.EnableAllTuners ? [] : $(".chkTuner", page).get().filter(function (tuner) { + info.Type = 'xmltv'; + info.Path = page.querySelector('.txtPath').value; + info.MoviePrefix = page.querySelector('.txtMoviePrefix').value || null; + info.UserAgent = page.querySelector('.txtUserAgent').value || null; + info.MovieCategories = getCategories(page.querySelector('.txtMovies')); + info.KidsCategories = getCategories(page.querySelector('.txtKids')); + info.NewsCategories = getCategories(page.querySelector('.txtNews')); + info.SportsCategories = getCategories(page.querySelector('.txtSports')); + info.EnableAllTuners = page.querySelector('.chkAllTuners').checked; + info.EnabledTuners = info.EnableAllTuners ? [] : $('.chkTuner', page).get().filter(function (tuner) { return tuner.checked; }).map(function (tuner) { - return tuner.getAttribute("data-id"); + return tuner.getAttribute('data-id'); }); ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/ListingProviders", { + type: 'POST', + url: ApiClient.getUrl('LiveTv/ListingProviders', { ValidateListings: true }), data: JSON.stringify(info), - contentType: "application/json" + contentType: 'application/json' }).then(function (result) { loading.hide(); @@ -88,11 +88,11 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa Dashboard.processServerConfigurationUpdateResult(); } - Events.trigger(self, "submitted"); + Events.trigger(self, 'submitted'); }, function () { loading.hide(); Dashboard.alert({ - message: Globalize.translate("ErrorAddingXmlTvFile") + message: globalize.translate('ErrorAddingXmlTvFile') }); }); }); @@ -100,51 +100,51 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa function getTunerName(providerId) { switch (providerId = providerId.toLowerCase()) { - case "m3u": - return "M3U Playlist"; - case "hdhomerun": - return "HDHomerun"; - case "satip": - return "DVB"; + case 'm3u': + return 'M3U Playlist'; + case 'hdhomerun': + return 'HDHomerun'; + case 'satip': + return 'DVB'; default: - return "Unknown"; + return 'Unknown'; } } function refreshTunerDevices(page, providerInfo, devices) { - var html = ""; + var html = ''; for (var i = 0, length = devices.length; i < length; i++) { var device = devices[i]; html += '
'; var enabledTuners = providerInfo.EnabledTuners || []; var isChecked = providerInfo.EnableAllTuners || -1 !== enabledTuners.indexOf(device.Id); - var checkedAttribute = isChecked ? " checked" : ""; - html += '"; + var checkedAttribute = isChecked ? ' checked' : ''; + html += ''; html += '
'; html += '
'; html += device.FriendlyName || getTunerName(device.Type); - html += "
"; + html += '
'; html += '
'; html += device.Url; - html += "
"; - html += "
"; - html += "
"; + html += '
'; + html += '
'; + html += '
'; } - page.querySelector(".tunerList").innerHTML = html; + page.querySelector('.tunerList').innerHTML = html; } function onSelectPathClick(e) { - var page = $(e.target).parents(".xmltvForm")[0]; + var page = $(e.target).parents('.xmltvForm')[0]; - require(["directorybrowser"], function (directoryBrowser) { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ includeFiles: true, callback: function (path) { if (path) { - var txtPath = page.querySelector(".txtPath"); + var txtPath = page.querySelector('.txtPath'); txtPath.value = path; txtPath.focus(); } @@ -157,34 +157,30 @@ define(["jQuery", "loading", "emby-checkbox", "emby-input", "listViewStyle", "pa var self = this; self.submit = function () { - page.querySelector(".btnSubmitListings").click(); + page.querySelector('.btnSubmitListings').click(); }; self.init = function () { options = options || {}; - if (false !== options.showCancelButton) { - page.querySelector(".btnCancel").classList.remove("hide"); - } else { - page.querySelector(".btnCancel").classList.add("hide"); - } + // Only hide the buttons if explicitly set to false; default to showing if undefined or null + // FIXME: rename this option to clarify logic + var hideCancelButton = options.showCancelButton === false; + page.querySelector('.btnCancel').classList.toggle('hide', hideCancelButton); - if (false !== options.showSubmitButton) { - page.querySelector(".btnSubmitListings").classList.remove("hide"); - } else { - page.querySelector(".btnSubmitListings").classList.add("hide"); - } + var hideSubmitButton = options.showSubmitButton === false; + page.querySelector('.btnSubmitListings').classList.toggle('hide', hideSubmitButton); - $("form", page).on("submit", function () { + $('form', page).on('submit', function () { submitListingsForm(); return false; }); - page.querySelector("#btnSelectPath").addEventListener("click", onSelectPathClick); - page.querySelector(".chkAllTuners").addEventListener("change", function (evt) { + page.querySelector('#btnSelectPath').addEventListener('click', onSelectPathClick); + page.querySelector('.chkAllTuners').addEventListener('change', function (evt) { if (evt.target.checked) { - page.querySelector(".selectTunersSection").classList.add("hide"); + page.querySelector('.selectTunersSection').classList.add('hide'); } else { - page.querySelector(".selectTunersSection").classList.remove("hide"); + page.querySelector('.selectTunersSection').classList.remove('hide'); } }); reload(); diff --git a/src/components/tvproviders/xmltv.template.html b/src/components/tvproviders/xmltv.template.html index 288c1ebe85..72c29904b3 100644 --- a/src/components/tvproviders/xmltv.template.html +++ b/src/components/tvproviders/xmltv.template.html @@ -1,7 +1,7 @@

Xml TV

- ${Help} + ${Help}
@@ -12,7 +12,7 @@
- +
${XmlTvPathHelp}
diff --git a/src/components/upnextdialog/upnextdialog.css b/src/components/upnextdialog/upnextdialog.css index 784c79cbb7..05e3b10f57 100644 --- a/src/components/upnextdialog/upnextdialog.css +++ b/src/components/upnextdialog/upnextdialog.css @@ -11,6 +11,7 @@ background-color: rgba(0, 0, 0, 0.7); color: #fff; user-select: none; + -webkit-touch-callout: none; } .upNextDialog-hidden { @@ -27,7 +28,7 @@ position: relative; margin-right: 1em; flex-shrink: 0; - margin-bottom: .5em; + margin-bottom: 0.5em; } .upNextDialog-button { @@ -36,7 +37,6 @@ } @media all and (orientation: landscape) { - .upNextDialog { flex-direction: row; } @@ -63,7 +63,11 @@ height: auto; width: 100%; box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); - border: 0; user-drag: none; + border: 0; user-select: none; + -moz-user-select: none; + -webkit-user-drag: none; + -webkit-user-select: none; + -ms-user-select: none; } diff --git a/src/components/upnextdialog/upnextdialog.js b/src/components/upnextdialog/upnextdialog.js index 80e7d807bd..3e9c9f9c5e 100644 --- a/src/components/upnextdialog/upnextdialog.js +++ b/src/components/upnextdialog/upnextdialog.js @@ -10,7 +10,7 @@ define(['dom', 'playbackManager', 'connectionManager', 'events', 'mediaInfo', 'l } options = options || {}; - options.type = options.type || "Primary"; + options.type = options.type || 'Primary'; if (options.type === 'Primary') { @@ -44,7 +44,7 @@ define(['dom', 'playbackManager', 'connectionManager', 'events', 'mediaInfo', 'l function imageUrl(item, options) { options = options || {}; - options.type = options.type || "Primary"; + options.type = options.type || 'Primary'; if (item.ImageTags && item.ImageTags[options.type]) { @@ -131,7 +131,7 @@ define(['dom', 'playbackManager', 'connectionManager', 'events', 'mediaInfo', 'l var secondsRemaining = Math.max(Math.round(getTimeRemainingMs(instance) / 1000), 0); - console.log('up next seconds remaining: ' + secondsRemaining); + console.debug('up next seconds remaining: ' + secondsRemaining); var timeText = '' + globalize.translate('HeaderSecondsValue', secondsRemaining) + ''; @@ -332,4 +332,4 @@ define(['dom', 'playbackManager', 'connectionManager', 'events', 'mediaInfo', 'l }; return UpNextDialog; -}); \ No newline at end of file +}); diff --git a/src/components/userdatabuttons/userdatabuttons.css b/src/components/userdatabuttons/userdatabuttons.css index 0138631734..f93f47ffcc 100644 --- a/src/components/userdatabuttons/userdatabuttons.css +++ b/src/components/userdatabuttons/userdatabuttons.css @@ -1,3 +1,3 @@ .btnUserDataOn { - color: #cc3333 !important; -} \ No newline at end of file + color: #c33 !important; +} diff --git a/src/components/userdatabuttons/userdatabuttons.js b/src/components/userdatabuttons/userdatabuttons.js index 1c00e50caf..86b9902133 100644 --- a/src/components/userdatabuttons/userdatabuttons.js +++ b/src/components/userdatabuttons/userdatabuttons.js @@ -28,9 +28,9 @@ define(['connectionManager', 'globalize', 'dom', 'itemHelper', 'paper-icon-butto iconCssClass = ''; } - iconCssClass += 'md-icon'; + iconCssClass += 'material-icons'; - return ''; + return ''; } function onContainerClick(e) { @@ -90,10 +90,10 @@ define(['connectionManager', 'globalize', 'dom', 'itemHelper', 'paper-icon-butto return html; } - var btnCssClass = "btnUserData"; + var btnCssClass = 'btnUserData'; if (cssClass) { - btnCssClass += " " + cssClass; + btnCssClass += ' ' + cssClass; } var iconCssClass = options.iconCssClass; diff --git a/src/components/usersettings/usersettings.js b/src/components/usersettings/usersettings.js deleted file mode 100644 index 6b3dc90d49..0000000000 --- a/src/components/usersettings/usersettings.js +++ /dev/null @@ -1,5 +0,0 @@ -define(['userSettingsBuilder'], function (userSettingsBuilder) { - 'use strict'; - - return new userSettingsBuilder(); -}); \ No newline at end of file diff --git a/src/components/viewContainer.js b/src/components/viewContainer.js index 607e7029d1..6c83e4a3ba 100644 --- a/src/components/viewContainer.js +++ b/src/components/viewContainer.js @@ -1,16 +1,16 @@ -define(["browser", "dom", "layoutManager", "css!components/viewManager/viewContainer"], function (browser, dom, layoutManager) { - "use strict"; +define(['browser', 'dom', 'layoutManager', 'css!components/viewManager/viewContainer'], function (browser, dom, layoutManager) { + 'use strict'; function setControllerClass(view, options) { if (options.controllerFactory) { return Promise.resolve(); } - var controllerUrl = view.getAttribute("data-controller"); + var controllerUrl = view.getAttribute('data-controller'); if (controllerUrl) { - if (0 === controllerUrl.indexOf("__plugin/")) { - controllerUrl = controllerUrl.substring("__plugin/".length); + if (0 === controllerUrl.indexOf('__plugin/')) { + controllerUrl = controllerUrl.substring('__plugin/'.length); } controllerUrl = Dashboard.getConfigurationResourceUrl(controllerUrl); @@ -38,21 +38,21 @@ define(["browser", "dom", "layoutManager", "css!components/viewManager/viewConta pageIndex = 0; } - var isPluginpage = -1 !== options.url.toLowerCase().indexOf("/configurationpage"); + var isPluginpage = -1 !== options.url.toLowerCase().indexOf('/configurationpage'); var newViewInfo = normalizeNewView(options, isPluginpage); var newView = newViewInfo.elem; var modulesToLoad = []; if (isPluginpage) { - modulesToLoad.push("legacyDashboard"); + modulesToLoad.push('legacyDashboard'); } if (newViewInfo.hasjQuerySelect) { - modulesToLoad.push("legacySelectMenu"); + modulesToLoad.push('legacySelectMenu'); } if (newViewInfo.hasjQueryChecked) { - modulesToLoad.push("fnchecked"); + modulesToLoad.push('fnchecked'); } return new Promise(function (resolve) { @@ -65,12 +65,12 @@ define(["browser", "dom", "layoutManager", "css!components/viewManager/viewConta var view = newView; - if ("string" == typeof view) { - view = document.createElement("div"); + if ('string' == typeof view) { + view = document.createElement('div'); view.innerHTML = newView; } - view.classList.add("mainAnimatedPage"); + view.classList.add('mainAnimatedPage'); if (currentPage) { if (newViewInfo.hasScript && window.$) { @@ -88,17 +88,17 @@ define(["browser", "dom", "layoutManager", "css!components/viewManager/viewConta } if (options.type) { - view.setAttribute("data-type", options.type); + view.setAttribute('data-type', options.type); } var properties = []; if (options.fullscreen) { - properties.push("fullscreen"); + properties.push('fullscreen'); } if (properties.length) { - view.setAttribute("data-properties", properties.join(",")); + view.setAttribute('data-properties', properties.join(',')); } allPages[pageIndex] = view; @@ -133,11 +133,11 @@ define(["browser", "dom", "layoutManager", "css!components/viewManager/viewConta function parseHtml(html, hasScript) { if (hasScript) { - html = replaceAll(html, "\x3c!----\x3e", "<\/script>"); + html = replaceAll(html, '\x3c!----\x3e', '<\/script>'); } - var wrapper = document.createElement("div"); + var wrapper = document.createElement('div'); wrapper.innerHTML = html; return wrapper.querySelector('div[data-role="page"]'); } @@ -149,11 +149,11 @@ define(["browser", "dom", "layoutManager", "css!components/viewManager/viewConta return viewHtml; } - var hasScript = -1 !== viewHtml.indexOf("
-
\ No newline at end of file +
diff --git a/src/components/visibleinviewport.js b/src/components/visibleinviewport.js deleted file mode 100644 index 3768740175..0000000000 --- a/src/components/visibleinviewport.js +++ /dev/null @@ -1,41 +0,0 @@ -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) { - - thresholdX = thresholdX || 0; - thresholdY = thresholdY || 0; - - if (!elem.getBoundingClientRect) { - return true; - } - - var windowSize = dom.getWindowSize(); - - var vpWidth = windowSize.innerWidth; - var vpHeight = windowSize.innerHeight; - - // Use this native browser method, if available. - var rec = elem.getBoundingClientRect(); - var tViz = rec.top >= 0 && rec.top < vpHeight + thresholdY; - var bViz = rec.bottom > 0 && rec.bottom <= vpHeight + thresholdY; - var lViz = rec.left >= 0 && rec.left < vpWidth + thresholdX; - var rViz = rec.right > 0 && rec.right <= vpWidth + thresholdX; - var vVisible = partial ? tViz || bViz : tViz && bViz; - var hVisible = partial ? lViz || rViz : lViz && rViz; - - return vVisible && hVisible; - } - - return visibleInViewport; -}); \ No newline at end of file diff --git a/src/components/youtubeplayer/plugin.js b/src/components/youtubeplayer/plugin.js index a2478cd3f4..5b5e1b1a3c 100644 --- a/src/components/youtubeplayer/plugin.js +++ b/src/components/youtubeplayer/plugin.js @@ -1,5 +1,6 @@ define(['require', 'events', 'browser', 'appRouter', 'loading'], function (require, events, browser, appRouter, loading) { - "use strict"; + 'use strict'; + /* globals YT */ function zoomIn(elem, iterations) { var keyframes = [ @@ -181,7 +182,7 @@ define(['require', 'events', 'browser', 'appRouter', 'loading'], function (requi if (!window.YT) { var tag = document.createElement('script'); - tag.src = "https://www.youtube.com/iframe_api"; + tag.src = 'https://www.youtube.com/iframe_api'; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); } else { @@ -405,4 +406,4 @@ define(['require', 'events', 'browser', 'appRouter', 'loading'], function (requi }; return YoutubePlayer; -}); \ No newline at end of file +}); diff --git a/src/components/youtubeplayer/style.css b/src/components/youtubeplayer/style.css index 8c59a541cf..1328e6f3d5 100644 --- a/src/components/youtubeplayer/style.css +++ b/src/components/youtubeplayer/style.css @@ -9,13 +9,13 @@ align-items: center; } - .youtubePlayerContainer.onTop { - z-index: 1000; - } +.youtubePlayerContainer.onTop { + z-index: 1000; +} - .youtubePlayerContainer video { - margin: 0 !important; - padding: 0 !important; - width: 100%; - height: 100%; - } \ No newline at end of file +.youtubePlayerContainer video { + margin: 0 !important; + padding: 0 !important; + width: 100%; + height: 100%; +} diff --git a/src/config.template.json b/src/config.template.json new file mode 100644 index 0000000000..1e79270943 --- /dev/null +++ b/src/config.template.json @@ -0,0 +1,3 @@ +{ + "multiserver": true +} diff --git a/src/controllers/apikeys.js b/src/controllers/apikeys.js deleted file mode 100644 index 448ffa29a7..0000000000 --- a/src/controllers/apikeys.js +++ /dev/null @@ -1,83 +0,0 @@ -define(["datetime", "loading", "libraryMenu", "dom", "globalize", "emby-button"], function (datetime, loading, libraryMenu, dom, globalize) { - "use strict"; - - function revoke(page, key) { - require(["confirm"], function (confirm) { - confirm(globalize.translate("MessageConfirmRevokeApiKey"), globalize.translate("HeaderConfirmRevokeApiKey")).then(function () { - loading.show(); - ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("Auth/Keys/" + key) - }).then(function () { - loadData(page); - }); - }); - }); - } - - function renderKeys(page, keys) { - var rows = keys.map(function (item) { - var html = ""; - html += '
'; - html += '"; - html += '"; - html += '"; - html += '"; - return html += ""; - }).join(""); - page.querySelector(".resultBody").innerHTML = rows; - loading.hide(); - } - - function loadData(page) { - loading.show(); - ApiClient.getJSON(ApiClient.getUrl("Auth/Keys")).then(function (result) { - renderKeys(page, result.Items); - }); - } - - function showNewKeyPrompt(page) { - require(["prompt"], function (prompt) { - prompt({ - title: globalize.translate("HeaderNewApiKey"), - label: globalize.translate("LabelAppName"), - description: globalize.translate("LabelAppNameExample") - }).then(function (value) { - ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("Auth/Keys", { - App: value - }) - }).then(function () { - loadData(page); - }); - }); - }); - } - - pageIdOn("pageinit", "apiKeysPage", function () { - var page = this; - page.querySelector(".btnNewKey").addEventListener("click", function () { - showNewKeyPrompt(page); - }); - page.querySelector(".tblApiKeys").addEventListener("click", function (e) { - var btnRevoke = dom.parentWithClass(e.target, "btnRevoke"); - - if (btnRevoke) { - revoke(page, btnRevoke.getAttribute("data-token")); - } - }); - }); - pageIdOn("pagebeforeshow", "apiKeysPage", function () { - loadData(this); - }); -}); diff --git a/src/controllers/auth/addserver.js b/src/controllers/auth/addserver.js index a55ba3066c..622d19082e 100644 --- a/src/controllers/auth/addserver.js +++ b/src/controllers/auth/addserver.js @@ -1,52 +1,52 @@ -define(["appSettings", "loading", "browser", "emby-button"], function(appSettings, loading, browser) { - "use strict"; +define(['appSettings', 'loading', 'browser', 'globalize', 'emby-button'], function(appSettings, loading, browser, globalize) { + 'use strict'; function handleConnectionResult(page, result) { loading.hide(); switch (result.State) { - case "SignedIn": + case 'SignedIn': var apiClient = result.ApiClient; Dashboard.onServerChanged(apiClient.getCurrentUserId(), apiClient.accessToken(), apiClient); - Dashboard.navigate("home.html"); + Dashboard.navigate('home.html'); break; - case "ServerSignIn": - Dashboard.navigate("login.html?serverid=" + result.Servers[0].Id, false, "none"); + case 'ServerSignIn': + Dashboard.navigate('login.html?serverid=' + result.Servers[0].Id, false, 'none'); break; - case "ServerSelection": - Dashboard.navigate("selectserver.html", false, "none"); + case 'ServerSelection': + Dashboard.navigate('selectserver.html', false, 'none'); break; - case "ServerUpdateNeeded": + case 'ServerUpdateNeeded': Dashboard.alert({ - message: Globalize.translate("ServerUpdateNeeded", 'https://github.com/jellyfin/jellyfin') + message: globalize.translate('ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin') }); break; - case "Unavailable": + case 'Unavailable': Dashboard.alert({ - message: Globalize.translate("MessageUnableToConnectToServer"), - title: Globalize.translate("HeaderConnectionFailure") + message: globalize.translate('MessageUnableToConnectToServer'), + title: globalize.translate('HeaderConnectionFailure') }); } } function submitServer(page) { loading.show(); - var host = page.querySelector("#txtServerHost").value; + var host = page.querySelector('#txtServerHost').value; ConnectionManager.connectToAddress(host, { enableAutoLogin: appSettings.enableAutoLogin() }).then(function(result) { handleConnectionResult(page, result); }, function() { handleConnectionResult(page, { - State: "Unavailable" + State: 'Unavailable' }); }); } return function(view, params) { - view.querySelector(".addServerForm").addEventListener("submit", onServerSubmit); - view.querySelector(".btnCancel").addEventListener("click", goBack); + view.querySelector('.addServerForm').addEventListener('submit', onServerSubmit); + view.querySelector('.btnCancel').addEventListener('click', goBack); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(view); }); @@ -57,7 +57,7 @@ define(["appSettings", "loading", "browser", "emby-button"], function(appSetting } function goBack() { - require(["appRouter"], function(appRouter) { + require(['appRouter'], function(appRouter) { appRouter.back(); }); } diff --git a/src/controllers/auth/forgotpassword.js b/src/controllers/auth/forgotpassword.js index e0f8ea4ef8..3756bf814d 100644 --- a/src/controllers/auth/forgotpassword.js +++ b/src/controllers/auth/forgotpassword.js @@ -1,34 +1,34 @@ -define([], function () { - "use strict"; +define(['globalize'], function (globalize) { + 'use strict'; function processForgotPasswordResult(result) { - if ("ContactAdmin" == result.Action) { + if ('ContactAdmin' == result.Action) { return void Dashboard.alert({ - message: Globalize.translate("MessageContactAdminToResetPassword"), - title: Globalize.translate("HeaderForgotPassword") + message: globalize.translate('MessageContactAdminToResetPassword'), + title: globalize.translate('HeaderForgotPassword') }); } - if ("InNetworkRequired" == result.Action) { + if ('InNetworkRequired' == result.Action) { return void Dashboard.alert({ - message: Globalize.translate("MessageForgotPasswordInNetworkRequired"), - title: Globalize.translate("HeaderForgotPassword") + message: globalize.translate('MessageForgotPasswordInNetworkRequired'), + title: globalize.translate('HeaderForgotPassword') }); } - if ("PinCode" == result.Action) { - var msg = Globalize.translate("MessageForgotPasswordFileCreated"); - msg += "
"; - msg += "
"; - msg += "Enter PIN here to finish Password Reset
"; - msg += "
"; + if ('PinCode' == result.Action) { + var msg = globalize.translate('MessageForgotPasswordFileCreated'); + msg += '
'; + msg += '
'; + msg += 'Enter PIN here to finish Password Reset
'; + msg += '
'; msg += result.PinFile; - msg += "
"; + msg += '
'; return void Dashboard.alert({ message: msg, - title: Globalize.translate("HeaderForgotPassword"), + title: globalize.translate('HeaderForgotPassword'), callback: function () { - Dashboard.navigate("forgotpasswordpin.html"); + Dashboard.navigate('forgotpasswordpin.html'); } }); } @@ -37,17 +37,17 @@ define([], function () { return function (view, params) { function onSubmit(e) { ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("Users/ForgotPassword"), - dataType: "json", + type: 'POST', + url: ApiClient.getUrl('Users/ForgotPassword'), + dataType: 'json', data: { - EnteredUsername: view.querySelector("#txtName").value + EnteredUsername: view.querySelector('#txtName').value } }).then(processForgotPasswordResult); e.preventDefault(); return false; } - view.querySelector("form").addEventListener("submit", onSubmit); + view.querySelector('form').addEventListener('submit', onSubmit); }; }); diff --git a/src/controllers/auth/forgotpasswordpin.js b/src/controllers/auth/forgotpasswordpin.js index 47b1c899b9..2a51890d2f 100644 --- a/src/controllers/auth/forgotpasswordpin.js +++ b/src/controllers/auth/forgotpasswordpin.js @@ -1,41 +1,41 @@ -define([], function () { - "use strict"; +define(['globalize'], function (globalize) { + 'use strict'; function processForgotPasswordResult(result) { if (result.Success) { - var msg = Globalize.translate("MessagePasswordResetForUsers"); - msg += "
"; - msg += "
"; - msg += result.UsersReset.join("
"); + var msg = globalize.translate('MessagePasswordResetForUsers'); + msg += '
'; + msg += '
'; + msg += result.UsersReset.join('
'); return void Dashboard.alert({ message: msg, - title: Globalize.translate("HeaderPasswordReset"), + title: globalize.translate('HeaderPasswordReset'), callback: function () { - window.location.href = "index.html"; + window.location.href = 'index.html'; } }); } Dashboard.alert({ - message: Globalize.translate("MessageInvalidForgotPasswordPin"), - title: Globalize.translate("HeaderPasswordReset") + message: globalize.translate('MessageInvalidForgotPasswordPin'), + title: globalize.translate('HeaderPasswordReset') }); } return function (view, params) { function onSubmit(e) { ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("Users/ForgotPassword/Pin"), - dataType: "json", + type: 'POST', + url: ApiClient.getUrl('Users/ForgotPassword/Pin'), + dataType: 'json', data: { - Pin: view.querySelector("#txtPin").value + Pin: view.querySelector('#txtPin').value } }).then(processForgotPasswordResult); e.preventDefault(); return false; } - view.querySelector("form").addEventListener("submit", onSubmit); + view.querySelector('form').addEventListener('submit', onSubmit); }; }); diff --git a/src/controllers/auth/login.js b/src/controllers/auth/login.js index 54fb6ce5e9..c0c37e27d6 100644 --- a/src/controllers/auth/login.js +++ b/src/controllers/auth/login.js @@ -1,44 +1,64 @@ -define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layoutManager", "browser", "cardStyle", "emby-checkbox"], function(appHost, appSettings, dom, connectionManager, loading, layoutManager, browser) { - "use strict"; +define(['apphost', 'appSettings', 'dom', 'connectionManager', 'loading', 'layoutManager', 'browser', 'globalize', 'cardStyle', 'emby-checkbox'], function (appHost, appSettings, dom, connectionManager, loading, layoutManager, browser, globalize) { + 'use strict'; var enableFocusTransform = !browser.slow && !browser.edge; function authenticateUserByName(page, apiClient, username, password) { loading.show(); - apiClient.authenticateUserByName(username, password).then(function(result) { + apiClient.authenticateUserByName(username, password).then(function (result) { var user = result.User; - var serverId = getParameterByName("serverid"); - var newUrl = user.Policy.IsAdministrator && !serverId ? "dashboard.html" : "home.html"; + var serverId = getParameterByName('serverid'); + var newUrl; + + if (user.Policy.IsAdministrator && !serverId) { + newUrl = 'dashboard.html'; + } else { + newUrl = 'home.html'; + } + loading.hide(); Dashboard.onServerChanged(user.Id, result.AccessToken, apiClient); Dashboard.navigate(newUrl); - }, function(response) { - page.querySelector("#txtManualName").value = ""; - page.querySelector("#txtManualPassword").value = ""; + }, function (response) { + page.querySelector('#txtManualName').value = ''; + page.querySelector('#txtManualPassword').value = ''; loading.hide(); - if (response.status === 401) { - require(["toast"], function(toast) { - toast(Globalize.translate("MessageInvalidUser")); + + const UnauthorizedOrForbidden = [401, 403]; + if (UnauthorizedOrForbidden.includes(response.status)) { + require(['toast'], function (toast) { + const messageKey = response.status === 401 ? 'MessageInvalidUser' : 'MessageUnauthorizedUser'; + toast(globalize.translate(messageKey)); }); } else { Dashboard.alert({ - message: Globalize.translate("MessageUnableToConnectToServer"), - title: Globalize.translate("HeaderConnectionFailure") + message: globalize.translate('MessageUnableToConnectToServer'), + title: globalize.translate('HeaderConnectionFailure') }); } }); } function showManualForm(context, showCancel, focusPassword) { - context.querySelector(".chkRememberLogin").checked = appSettings.enableAutoLogin(); - context.querySelector(".manualLoginForm").classList.remove("hide"); - context.querySelector(".visualLoginForm").classList.add("hide"); - context.querySelector(".btnManual").classList.add("hide"); - focusPassword ? context.querySelector("#txtManualPassword").focus() : context.querySelector("#txtManualName").focus(); - showCancel ? context.querySelector(".btnCancel").classList.remove("hide") : context.querySelector(".btnCancel").classList.add("hide"); + context.querySelector('.chkRememberLogin').checked = appSettings.enableAutoLogin(); + context.querySelector('.manualLoginForm').classList.remove('hide'); + context.querySelector('.visualLoginForm').classList.add('hide'); + context.querySelector('.btnManual').classList.add('hide'); + + if (focusPassword) { + context.querySelector('#txtManualPassword').focus(); + } else { + context.querySelector('#txtManualName').focus(); + } + + if (showCancel) { + context.querySelector('.btnCancel').classList.remove('hide'); + } else { + context.querySelector('.btnCancel').classList.add('hide'); + } } - var metroColors = ["#6FBD45", "#4BB3DD", "#4164A5", "#E12026", "#800080", "#E1B222", "#008040", "#0094FF", "#FF00C7", "#FF870F", "#7F0037"]; + var metroColors = ['#6FBD45', '#4BB3DD', '#4164A5', '#E12026', '#800080', '#E1B222', '#008040', '#0094FF', '#FF00C7', '#FF870F', '#7F0037']; function getRandomMetroColor() { var index = Math.floor(Math.random() * (metroColors.length - 1)); @@ -49,140 +69,151 @@ define(["apphost", "appSettings", "dom", "connectionManager", "loading", "layout if (str) { var character = String(str.substr(0, 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 metroColors[index]; } + return getRandomMetroColor(); } function loadUserList(context, apiClient, users) { - var html = ""; + var html = ''; + for (var i = 0; i < users.length; i++) { var user = users[i]; // TODO move card creation code to Card component - - var cssClass = "card squareCard scalableCard squareCard-scalable"; + var cssClass = 'card squareCard scalableCard squareCard-scalable'; if (layoutManager.tv) { - cssClass += " show-focus"; + cssClass += ' show-focus'; if (enableFocusTransform) { - cssClass += " show-animation"; + cssClass += ' show-animation'; } } - var cardBoxCssClass = "cardBox cardBox-bottompadded"; - + var cardBoxCssClass = 'cardBox cardBox-bottompadded'; html += '"; + html += '
' + user.Name + '
'; + html += ''; + html += ''; + html += ''; } - context.querySelector("#divUsers").innerHTML = html; + + context.querySelector('#divUsers').innerHTML = html; } - return function(view, params) { + return function (view, params) { function getApiClient() { var serverId = params.serverid; - return serverId ? connectionManager.getOrCreateApiClient(serverId) : ApiClient; + + if (serverId) { + return connectionManager.getOrCreateApiClient(serverId); + } + + return ApiClient; } function showVisualForm() { - view.querySelector(".visualLoginForm").classList.remove("hide"); - view.querySelector(".manualLoginForm").classList.add("hide"); - view.querySelector(".btnManual").classList.remove("hide"); + view.querySelector('.visualLoginForm').classList.remove('hide'); + view.querySelector('.manualLoginForm').classList.add('hide'); + view.querySelector('.btnManual').classList.remove('hide'); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(view); }); } - view.querySelector("#divUsers").addEventListener("click", function(e) { - var card = dom.parentWithClass(e.target, "card"); - var cardContent = card ? card.querySelector(".cardContent") : null; + view.querySelector('#divUsers').addEventListener('click', function (e) { + var card = dom.parentWithClass(e.target, 'card'); + var cardContent = card ? card.querySelector('.cardContent') : null; + if (cardContent) { var context = view; - var id = cardContent.getAttribute("data-userid"); - var name = cardContent.getAttribute("data-username"); - var haspw = cardContent.getAttribute("data-haspw"); + var id = cardContent.getAttribute('data-userid'); + var name = cardContent.getAttribute('data-username'); + var haspw = cardContent.getAttribute('data-haspw'); + if (id === 'manual') { - context.querySelector("#txtManualName").value = ""; + context.querySelector('#txtManualName').value = ''; showManualForm(context, true); } else if (haspw == 'false') { - authenticateUserByName(context, getApiClient(), name, ""); + authenticateUserByName(context, getApiClient(), name, ''); } else { - context.querySelector("#txtManualName").value = name; - context.querySelector("#txtManualPassword").value = ""; + context.querySelector('#txtManualName').value = name; + context.querySelector('#txtManualPassword').value = ''; showManualForm(context, true, true); } } }); - - view.querySelector(".manualLoginForm").addEventListener("submit", function(e) { - appSettings.enableAutoLogin(view.querySelector(".chkRememberLogin").checked); + view.querySelector('.manualLoginForm').addEventListener('submit', function (e) { + appSettings.enableAutoLogin(view.querySelector('.chkRememberLogin').checked); var apiClient = getApiClient(); - authenticateUserByName(view, apiClient, view.querySelector("#txtManualName").value, view.querySelector("#txtManualPassword").value); + authenticateUserByName(view, apiClient, view.querySelector('#txtManualName').value, view.querySelector('#txtManualPassword').value); e.preventDefault(); return false; }); - - view.querySelector(".btnForgotPassword").addEventListener("click", function() { - Dashboard.navigate("forgotpassword.html"); + view.querySelector('.btnForgotPassword').addEventListener('click', function () { + Dashboard.navigate('forgotpassword.html'); }); - - view.querySelector(".btnCancel").addEventListener("click", showVisualForm); - - view.querySelector(".btnManual").addEventListener("click", function() { - view.querySelector("#txtManualName").value = ""; + view.querySelector('.btnCancel').addEventListener('click', showVisualForm); + view.querySelector('.btnManual').addEventListener('click', function () { + view.querySelector('#txtManualName').value = ''; showManualForm(view, true); }); - - view.addEventListener("viewshow", function(e) { + view.querySelector('.btnSelectServer').addEventListener('click', function () { + Dashboard.selectServer(); + }); + view.addEventListener('viewshow', function (e) { loading.show(); + if (!appHost.supports('multiserver')) { - view.querySelector(".btnSelectServer").classList.add("hide"); + view.querySelector('.btnSelectServer').classList.add('hide'); } + var apiClient = getApiClient(); - apiClient.getPublicUsers().then(function(users) { + apiClient.getPublicUsers().then(function (users) { if (users.length) { showVisualForm(); loadUserList(view, apiClient, users); } else { - view.querySelector("#txtManualName").value = ""; + view.querySelector('#txtManualName').value = ''; showManualForm(view, false, false); } - }).catch().then(function() { + }).catch().then(function () { loading.hide(); }); - - apiClient.getJSON(apiClient.getUrl("Branding/Configuration")).then(function(options) { - view.querySelector(".disclaimer").textContent = options.LoginDisclaimer || ""; + apiClient.getJSON(apiClient.getUrl('Branding/Configuration')).then(function (options) { + view.querySelector('.disclaimer').textContent = options.LoginDisclaimer || ''; }); }); - } + }; }); diff --git a/src/controllers/auth/selectserver.js b/src/controllers/auth/selectserver.js index b0ee5673e0..ba88313484 100644 --- a/src/controllers/auth/selectserver.js +++ b/src/controllers/auth/selectserver.js @@ -1,5 +1,5 @@ -define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focusManager", "connectionManager", "globalize", "actionsheet", "dom", "browser", "material-icons", "flexStyles", "emby-scroller", "emby-itemscontainer", "cardStyle", "emby-button"], function (loading, appRouter, layoutManager, appSettings, appHost, focusManager, connectionManager, globalize, actionSheet, dom, browser) { - "use strict"; +define(['loading', 'appRouter', 'layoutManager', 'appSettings', 'apphost', 'focusManager', 'connectionManager', 'globalize', 'actionsheet', 'dom', 'browser', 'material-icons', 'flexStyles', 'emby-scroller', 'emby-itemscontainer', 'cardStyle', 'emby-button'], function (loading, appRouter, layoutManager, appSettings, appHost, focusManager, connectionManager, globalize, actionSheet, dom, browser) { + 'use strict'; var enableFocusTransform = !browser.slow && !browser.edge; @@ -8,8 +8,8 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu return { name: server.Name, showIcon: true, - icon: "cast", - cardType: "", + icon: 'cast', + cardType: '', id: server.Id, server: server }; @@ -18,28 +18,28 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu var cardImageContainer; if (item.showIcon) { - cardImageContainer = '' + item.icon + ""; + cardImageContainer = ''; } else { cardImageContainer = '
'; } // TODO move card creation code to Card component - var cssClass = "card overflowSquareCard loginSquareCard scalableCard overflowSquareCard-scalable"; + var cssClass = 'card overflowSquareCard loginSquareCard scalableCard overflowSquareCard-scalable'; if (layoutManager.tv) { - cssClass += " show-focus"; + cssClass += ' show-focus'; if (enableFocusTransform) { - cssClass += " show-animation"; + cssClass += ' show-animation'; } } - var cardBoxCssClass = "cardBox"; + var cardBoxCssClass = 'cardBox'; var innerOpening = '
'; var cardContainer = ''; - cardContainer += ''; return cardContainer; - }).join(""); - var itemsContainer = view.querySelector(".servers"); + }).join(''); + var itemsContainer = view.querySelector('.servers'); if (!items.length) { - html = '

' + globalize.translate("MessageNoServersAvailable") + "

"; + html = '

' + globalize.translate('MessageNoServersAvailable') + '

'; } itemsContainer.innerHTML = html; @@ -66,20 +66,20 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu } function updatePageStyle(view, params) { - if (params.showuser == "1") { - view.classList.add("libraryPage"); - view.classList.remove("standalonePage"); - view.classList.add("noSecondaryNavPage"); + if (params.showuser == '1') { + view.classList.add('libraryPage'); + view.classList.remove('standalonePage'); + view.classList.add('noSecondaryNavPage'); } else { - view.classList.add("standalonePage"); - view.classList.remove("libraryPage"); - view.classList.remove("noSecondaryNavPage"); + view.classList.add('standalonePage'); + view.classList.remove('libraryPage'); + view.classList.remove('noSecondaryNavPage'); } } function showGeneralError() { loading.hide(); - alertText(globalize.translate("DefaultErrorMessage")); + alertText(globalize.translate('DefaultErrorMessage')); } function alertText(text) { @@ -89,13 +89,13 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu } function alertTextWithOptions(options) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert(options); }); } function showServerConnectionFailure() { - alertText(globalize.translate("MessageUnableToConnectToServer"), globalize.translate("HeaderConnectionFailure")); + alertText(globalize.translate('MessageUnableToConnectToServer')); } return function (view, params) { @@ -108,20 +108,20 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu var apiClient = result.ApiClient; switch (result.State) { - case "SignedIn": + case 'SignedIn': Dashboard.onServerChanged(apiClient.getCurrentUserId(), apiClient.accessToken(), apiClient); - Dashboard.navigate("home.html"); + Dashboard.navigate('home.html'); break; - case "ServerSignIn": + case 'ServerSignIn': Dashboard.onServerChanged(null, null, apiClient); - Dashboard.navigate("login.html?serverid=" + result.Servers[0].Id); + Dashboard.navigate('login.html?serverid=' + result.Servers[0].Id); break; - case "ServerUpdateNeeded": + case 'ServerUpdateNeeded': alertTextWithOptions({ - text: globalize.translate("core#ServerUpdateNeeded", "https://github.com/jellyfin/jellyfin"), - html: globalize.translate("core#ServerUpdateNeeded", 'https://github.com/jellyfin/jellyfin') + text: globalize.translate('core#ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin'), + html: globalize.translate('core#ServerUpdateNeeded', 'https://github.com/jellyfin/jellyfin') }); break; @@ -142,23 +142,23 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu function onServerClick(server) { var menuItems = []; menuItems.push({ - name: globalize.translate("Connect"), - id: "connect" + name: globalize.translate('Connect'), + id: 'connect' }); menuItems.push({ - name: globalize.translate("Delete"), - id: "delete" + name: globalize.translate('Delete'), + id: 'delete' }); actionSheet.show({ items: menuItems, title: server.Name }).then(function (id) { switch (id) { - case "connect": + case 'connect': connectToServer(server); break; - case "delete": + case 'delete': deleteServer(server); } }); @@ -180,7 +180,7 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu var servers; updatePageStyle(view, params); - view.addEventListener("viewshow", function (e) { + view.addEventListener('viewshow', function (e) { var isRestored = e.detail.isRestored; appRouter.setTitle(null); @@ -188,16 +188,16 @@ define(["loading", "appRouter", "layoutManager", "appSettings", "apphost", "focu loadServers(); } }); - view.querySelector(".servers").addEventListener("click", function (e) { - var card = dom.parentWithClass(e.target, "card"); + view.querySelector('.servers').addEventListener('click', function (e) { + var card = dom.parentWithClass(e.target, 'card'); if (card) { - var url = card.getAttribute("data-url"); + var url = card.getAttribute('data-url'); if (url) { appRouter.show(url); } else { - var id = card.getAttribute("data-id"); + var id = card.getAttribute('data-id'); onServerClick(servers.filter(function (s) { return s.Id === id; })[0]); diff --git a/src/controllers/dashboard/apikeys.js b/src/controllers/dashboard/apikeys.js new file mode 100644 index 0000000000..f43bfd0329 --- /dev/null +++ b/src/controllers/dashboard/apikeys.js @@ -0,0 +1,83 @@ +define(['datetime', 'loading', 'libraryMenu', 'dom', 'globalize', 'emby-button'], function (datetime, loading, libraryMenu, dom, globalize) { + 'use strict'; + + function revoke(page, key) { + require(['confirm'], function (confirm) { + confirm(globalize.translate('MessageConfirmRevokeApiKey'), globalize.translate('HeaderConfirmRevokeApiKey')).then(function () { + loading.show(); + ApiClient.ajax({ + type: 'DELETE', + url: ApiClient.getUrl('Auth/Keys/' + key) + }).then(function () { + loadData(page); + }); + }); + }); + } + + function renderKeys(page, keys) { + var rows = keys.map(function (item) { + var html = ''; + html += '
'; + html += ''; + html += ''; + html += ''; + html += ''; + return html += ''; + }).join(''); + page.querySelector('.resultBody').innerHTML = rows; + loading.hide(); + } + + function loadData(page) { + loading.show(); + ApiClient.getJSON(ApiClient.getUrl('Auth/Keys')).then(function (result) { + renderKeys(page, result.Items); + }); + } + + function showNewKeyPrompt(page) { + require(['prompt'], function (prompt) { + prompt({ + title: globalize.translate('HeaderNewApiKey'), + label: globalize.translate('LabelAppName'), + description: globalize.translate('LabelAppNameExample') + }).then(function (value) { + ApiClient.ajax({ + type: 'POST', + url: ApiClient.getUrl('Auth/Keys', { + App: value + }) + }).then(function () { + loadData(page); + }); + }); + }); + } + + pageIdOn('pageinit', 'apiKeysPage', function () { + var page = this; + page.querySelector('.btnNewKey').addEventListener('click', function () { + showNewKeyPrompt(page); + }); + page.querySelector('.tblApiKeys').addEventListener('click', function (e) { + var btnRevoke = dom.parentWithClass(e.target, 'btnRevoke'); + + if (btnRevoke) { + revoke(page, btnRevoke.getAttribute('data-token')); + } + }); + }); + pageIdOn('pagebeforeshow', 'apiKeysPage', function () { + loadData(this); + }); +}); diff --git a/src/controllers/dashboard/dashboard.js b/src/controllers/dashboard/dashboard.js index 63c6f3226b..1256f60074 100644 --- a/src/controllers/dashboard/dashboard.js +++ b/src/controllers/dashboard/dashboard.js @@ -1,24 +1,24 @@ -define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globalize", "loading", "connectionManager", "playMethodHelper", "cardBuilder", "imageLoader", "components/activitylog", "scripts/imagehelper", "indicators", "humanedate", "listViewStyle", "emby-button", "flexStyles", "emby-button", "emby-itemscontainer"], function (datetime, events, itemHelper, serverNotifications, dom, globalize, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper, indicators) { - "use strict"; +define(['datetime', 'events', 'itemHelper', 'serverNotifications', 'dom', 'globalize', 'date-fns', 'dfnshelper', 'loading', 'connectionManager', 'playMethodHelper', 'cardBuilder', 'imageLoader', 'components/activitylog', 'scripts/imagehelper', 'indicators', 'listViewStyle', 'emby-button', 'flexStyles', 'emby-button', 'emby-itemscontainer'], function (datetime, events, itemHelper, serverNotifications, dom, globalize, datefns, dfnshelper, loading, connectionManager, playMethodHelper, cardBuilder, imageLoader, ActivityLog, imageHelper, indicators) { + 'use strict'; function showPlaybackInfo(btn, session) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { var title; var text = []; var displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); - if (displayPlayMethod === "DirectStream") { - title = globalize.translate("DirectStreaming"); - text.push(globalize.translate("DirectStreamHelp1")); - text.push("
"); - text.push(globalize.translate("DirectStreamHelp2")); - } else if (displayPlayMethod === "Transcode") { - title = globalize.translate("Transcoding"); - text.push(globalize.translate("MediaIsBeingConverted")); + if (displayPlayMethod === 'DirectStream') { + title = globalize.translate('DirectStreaming'); + text.push(globalize.translate('DirectStreamHelp1')); + text.push('
'); + text.push(globalize.translate('DirectStreamHelp2')); + } else if (displayPlayMethod === 'Transcode') { + title = globalize.translate('Transcoding'); + text.push(globalize.translate('MediaIsBeingConverted')); if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { - text.push("
"); - text.push(globalize.translate("LabelReasonForTranscoding")); + text.push('
'); + text.push(globalize.translate('LabelReasonForTranscoding')); session.TranscodingInfo.TranscodeReasons.forEach(function (transcodeReason) { text.push(globalize.translate(transcodeReason)); }); @@ -26,18 +26,18 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } alert({ - text: text.join("
"), + text: text.join('
'), title: title }); }); } function showSendMessageForm(btn, session) { - require(["prompt"], function (prompt) { + require(['prompt'], function (prompt) { prompt({ - title: globalize.translate("HeaderSendMessage"), - label: globalize.translate("LabelMessageText"), - confirmText: globalize.translate("ButtonSend") + title: globalize.translate('HeaderSendMessage'), + label: globalize.translate('LabelMessageText'), + confirmText: globalize.translate('ButtonSend') }).then(function (text) { if (text) { connectionManager.getApiClient(session.ServerId).sendMessageCommand(session.Id, { @@ -50,20 +50,20 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } function showOptionsMenu(btn, session) { - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { var menuItems = []; if (session.ServerId && session.DeviceId !== connectionManager.deviceId()) { menuItems.push({ - name: globalize.translate("SendMessage"), - id: "sendmessage" + name: globalize.translate('SendMessage'), + id: 'sendmessage' }); } if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length) { menuItems.push({ - name: globalize.translate("ViewPlaybackInfo"), - id: "transcodinginfo" + name: globalize.translate('ViewPlaybackInfo'), + id: 'transcodinginfo' }); } @@ -72,11 +72,11 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa positionTo: btn }).then(function (id) { switch (id) { - case "sendmessage": + case 'sendmessage': showSendMessageForm(btn, session); break; - case "transcodinginfo": + case 'transcodinginfo': showPlaybackInfo(btn, session); } }); @@ -84,28 +84,28 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } function onActiveDevicesClick(evt) { - var btn = dom.parentWithClass(evt.target, "sessionCardButton"); + var btn = dom.parentWithClass(evt.target, 'sessionCardButton'); if (btn) { - var card = dom.parentWithClass(btn, "card"); + var card = dom.parentWithClass(btn, 'card'); if (card) { var sessionId = card.id; var session = (DashboardPage.sessionsList || []).filter(function (dashboardSession) { - return "session" + dashboardSession.Id === sessionId; + return 'session' + dashboardSession.Id === sessionId; })[0]; if (session) { - if (btn.classList.contains("btnCardOptions")) { + if (btn.classList.contains('btnCardOptions')) { showOptionsMenu(btn, session); - } else if (btn.classList.contains("btnSessionInfo")) { + } else if (btn.classList.contains('btnSessionInfo')) { showPlaybackInfo(btn, session); - } else if (btn.classList.contains("btnSessionSendMessage")) { + } else if (btn.classList.contains('btnSessionSendMessage')) { showSendMessageForm(btn, session); - } else if (btn.classList.contains("btnSessionStop")) { - connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, "Stop"); - } else if (btn.classList.contains("btnSessionPlayPause") && session.PlayState) { - connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, "PlayPause"); + } else if (btn.classList.contains('btnSessionStop')) { + connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, 'Stop'); + } else if (btn.classList.contains('btnSessionPlayPause') && session.PlayState) { + connectionManager.getApiClient(session.ServerId).sendPlayStateCommand(session.Id, 'PlayPause'); } } } @@ -135,31 +135,31 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa apiClient.getLiveTvRecordings({ UserId: Dashboard.getCurrentUserId(), IsInProgress: true, - Fields: "CanDelete,PrimaryImageAspectRatio", + Fields: 'CanDelete,PrimaryImageAspectRatio', EnableTotalRecordCount: false, - EnableImageTypes: "Primary,Thumb,Backdrop" + EnableImageTypes: 'Primary,Thumb,Backdrop' }).then(function (result) { - var itemsContainer = view.querySelector(".activeRecordingItems"); + var itemsContainer = view.querySelector('.activeRecordingItems'); if (!result.Items.length) { - view.querySelector(".activeRecordingsSection").classList.add("hide"); - return void(itemsContainer.innerHTML = ""); + view.querySelector('.activeRecordingsSection').classList.add('hide'); + return void(itemsContainer.innerHTML = ''); } - view.querySelector(".activeRecordingsSection").classList.remove("hide"); + view.querySelector('.activeRecordingsSection').classList.remove('hide'); itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, - shape: "auto", - defaultShape: "backdrop", + shape: 'auto', + defaultShape: 'backdrop', showTitle: true, showParentTitle: true, coverImage: true, cardLayout: false, centerText: true, - preferThumb: "auto", + preferThumb: 'auto', overlayText: false, overlayMoreButton: true, - action: "none", + action: 'none', centerPlayButton: true }); imageLoader.lazyChildren(itemsContainer); @@ -168,28 +168,28 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa function reloadSystemInfo(view, apiClient) { apiClient.getSystemInfo().then(function (systemInfo) { - view.querySelector("#serverName").innerHTML = globalize.translate("DashboardServerName", systemInfo.ServerName); - var localizedVersion = globalize.translate("DashboardVersionNumber", systemInfo.Version); + view.querySelector('#serverName').innerHTML = globalize.translate('DashboardServerName', systemInfo.ServerName); + var localizedVersion = globalize.translate('DashboardVersionNumber', systemInfo.Version); - if (systemInfo.SystemUpdateLevel !== "Release") { - localizedVersion += " " + systemInfo.SystemUpdateLevel; + if (systemInfo.SystemUpdateLevel !== 'Release') { + localizedVersion += ' ' + systemInfo.SystemUpdateLevel; } - view.querySelector("#versionNumber").innerHTML = localizedVersion; - view.querySelector("#operatingSystem").innerHTML = globalize.translate("DashboardOperatingSystem", systemInfo.OperatingSystem); - view.querySelector("#architecture").innerHTML = globalize.translate("DashboardArchitecture", systemInfo.SystemArchitecture); + view.querySelector('#versionNumber').innerHTML = localizedVersion; + view.querySelector('#operatingSystem').innerHTML = globalize.translate('DashboardOperatingSystem', systemInfo.OperatingSystem); + view.querySelector('#architecture').innerHTML = globalize.translate('DashboardArchitecture', systemInfo.SystemArchitecture); if (systemInfo.CanSelfRestart) { - view.querySelector("#btnRestartServer").classList.remove("hide"); + view.querySelector('#btnRestartServer').classList.remove('hide'); } else { - view.querySelector("#btnRestartServer").classList.add("hide"); + view.querySelector('#btnRestartServer').classList.add('hide'); } - view.querySelector("#cachePath").innerHTML = systemInfo.CachePath; - view.querySelector("#logPath").innerHTML = systemInfo.LogPath; - view.querySelector("#transcodePath").innerHTML = systemInfo.TranscodingTempPath; - view.querySelector("#metadataPath").innerHTML = systemInfo.InternalMetadataPath; - view.querySelector("#webPath").innerHTML = systemInfo.WebPath; + view.querySelector('#cachePath').innerHTML = systemInfo.CachePath; + view.querySelector('#logPath').innerHTML = systemInfo.LogPath; + view.querySelector('#transcodePath').innerHTML = systemInfo.TranscodingTempPath; + view.querySelector('#metadataPath').innerHTML = systemInfo.InternalMetadataPath; + view.querySelector('#webPath').innerHTML = systemInfo.WebPath; }); } @@ -211,25 +211,25 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } function renderActiveConnections(view, sessions) { - var html = ""; + var html = ''; DashboardPage.sessionsList = sessions; - var parentElement = view.querySelector(".activeDevices"); - var cardElem = parentElement.querySelector(".card"); + var parentElement = view.querySelector('.activeDevices'); + var cardElem = parentElement.querySelector('.card'); if (cardElem) { - cardElem.classList.add("deadSession"); + cardElem.classList.add('deadSession'); } for (var i = 0, length = sessions.length; i < length; i++) { var session = sessions[i]; - var rowId = "session" + session.Id; - var elem = view.querySelector("#" + rowId); + var rowId = 'session' + session.Id; + var elem = view.querySelector('#' + rowId); if (elem) { DashboardPage.updateSession(elem, session); } else { var nowPlayingItem = session.NowPlayingItem; - var className = "scalableCard card activeSession backdropCard backdropCard-scalable"; + var className = 'scalableCard card activeSession backdropCard backdropCard-scalable'; html += '
'; html += '
'; html += '
'; @@ -253,13 +253,13 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } html += '
'; - html += '
' + session.DeviceName + "
"; - html += '
' + DashboardPage.getAppSecondaryText(session) + "
"; - html += "
"; - html += "
"; + html += '
' + session.DeviceName + '
'; + html += '
' + DashboardPage.getAppSecondaryText(session) + '
'; + html += '
'; + html += '
'; if (session.TranscodingInfo && session.TranscodingInfo.Framerate) { - html += '
' + session.TranscodingInfo.Framerate + " fps
"; + html += '
' + session.TranscodingInfo.Framerate + ' fps
'; } else { html += '
'; } @@ -268,66 +268,73 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa var nowPlayingName = DashboardPage.getNowPlayingName(session); html += '
'; html += nowPlayingName.html; - html += "
"; - html += '
' + DashboardPage.getSessionNowPlayingTime(session) + "
"; + html += ''; + html += '
' + DashboardPage.getSessionNowPlayingTime(session) + '
'; html += ''; if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { var percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks; html += indicators.getProgressHtml(percent, { - containerClass: "playbackProgress" + containerClass: 'playbackProgress' }); } else { // need to leave the element in just in case the device starts playback html += indicators.getProgressHtml(0, { - containerClass: "playbackProgress hide" + containerClass: 'playbackProgress hide' }); } if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { var percent = session.TranscodingInfo.CompletionPercentage.toFixed(1); html += indicators.getProgressHtml(percent, { - containerClass: "transcodingProgress" + containerClass: 'transcodingProgress' }); } else { // same issue as playbackProgress element above html += indicators.getProgressHtml(0, { - containerClass: "transcodingProgress hide" + containerClass: 'transcodingProgress hide' }); } - html += ""; - html += ""; - html += ""; + html += ''; + html += ''; + html += ''; html += '
'; html += '
'; - var btnCssClass; - btnCssClass = session.ServerId && session.NowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== connectionManager.deviceId() ? "" : " hide"; - html += ''; - html += ''; - btnCssClass = session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length ? "" : " hide"; - html += ''; - btnCssClass = session.ServerId && -1 !== session.SupportedCommands.indexOf("DisplayMessage") && session.DeviceId !== connectionManager.deviceId() ? "" : " hide"; - html += ''; - html += "
"; + + var btnCssClass = session.ServerId && session.NowPlayingItem && session.SupportsRemoteControl ? '' : ' hide'; + const playIcon = session.PlayState.IsPaused ? 'pause' : 'play_arrow'; + + html += ''; + html += ''; + + btnCssClass = session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo.TranscodeReasons.length ? '' : ' hide'; + html += ''; + + btnCssClass = session.ServerId && -1 !== session.SupportedCommands.indexOf('DisplayMessage') && session.DeviceId !== connectionManager.deviceId() ? '' : ' hide'; + html += ''; + html += '
'; + html += '
'; html += DashboardPage.getSessionNowPlayingStreamInfo(session); - html += "
"; + html += ''; + html += '
'; var userImage = DashboardPage.getUserImage(session); html += userImage ? '
" : '
'; html += '
'; html += DashboardPage.getUsersHtml(session); - html += "
"; - html += "
"; - html += ""; - html += ""; - html += ""; + + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; } } - parentElement.insertAdjacentHTML("beforeend", html); - var deadSessionElem = parentElement.querySelector(".deadSession"); + parentElement.insertAdjacentHTML('beforeend', html); + var deadSessionElem = parentElement.querySelector('.deadSession'); if (deadSessionElem) { deadSessionElem.parentNode.removeChild(deadSessionElem); @@ -335,9 +342,9 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } function renderRunningTasks(view, tasks) { - var html = ""; + var html = ''; tasks = tasks.filter(function (task) { - if ("Idle" != task.State) { + if ('Idle' != task.State) { return !task.IsHidden; } @@ -345,59 +352,59 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }); if (tasks.length) { - view.querySelector(".runningTasksContainer").classList.remove("hide"); + view.querySelector('.runningTasksContainer').classList.remove('hide'); } else { - view.querySelector(".runningTasksContainer").classList.add("hide"); + view.querySelector('.runningTasksContainer').classList.add('hide'); } for (var i = 0, length = tasks.length; i < length; i++) { var task = tasks[i]; - html += "

"; - html += task.Name + "
"; + html += '

'; + html += task.Name + '
'; - if (task.State === "Running") { + if (task.State === 'Running') { var progress = (task.CurrentProgressPercentage || 0).toFixed(1); html += ''; - html += progress + "%"; - html += ""; - html += "" + progress + "%"; - html += ''; - } else if (task.State === "Cancelling") { - html += '' + globalize.translate("LabelStopping") + ""; + html += progress + '%'; + html += ''; + html += "" + progress + '%'; + html += ''; + } else if (task.State === 'Cancelling') { + html += '' + globalize.translate('LabelStopping') + ''; } - html += "

"; + html += '

'; } - view.querySelector("#divRunningTasks").innerHTML = html; + view.querySelector('#divRunningTasks').innerHTML = html; } window.DashboardPage = { startInterval: function (apiClient) { - apiClient.sendMessage("SessionsStart", "0,1500"); - apiClient.sendMessage("ScheduledTasksInfoStart", "0,1000"); + apiClient.sendMessage('SessionsStart', '0,1500'); + apiClient.sendMessage('ScheduledTasksInfoStart', '0,1000'); }, stopInterval: function (apiClient) { - apiClient.sendMessage("SessionsStop"); - apiClient.sendMessage("ScheduledTasksInfoStop"); + apiClient.sendMessage('SessionsStop'); + apiClient.sendMessage('ScheduledTasksInfoStop'); }, getSessionNowPlayingStreamInfo: function (session) { - var html = ""; + var html = ''; var showTranscodingInfo = false; var displayPlayMethod = playMethodHelper.getDisplayPlayMethod(session); - if (displayPlayMethod === "DirectStream") { - html += globalize.translate("DirectStreaming"); - } else if (displayPlayMethod === "Transcode") { - html += globalize.translate("Transcoding"); + if (displayPlayMethod === 'DirectStream') { + html += globalize.translate('DirectStreaming'); + } else if (displayPlayMethod === 'Transcode') { + html += globalize.translate('Transcoding'); if (session.TranscodingInfo && session.TranscodingInfo.Framerate) { - html += " (" + session.TranscodingInfo.Framerate + " fps)"; + html += ' (' + session.TranscodingInfo.Framerate + ' fps)'; } showTranscodingInfo = true; - } else if (displayPlayMethod === "DirectPlay") { - html += globalize.translate("DirectPlaying"); + } else if (displayPlayMethod === 'DirectPlay') { + html += globalize.translate('DirectPlaying'); } if (showTranscodingInfo) { @@ -406,9 +413,9 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa if (session.TranscodingInfo) { if (session.TranscodingInfo.Bitrate) { if (session.TranscodingInfo.Bitrate > 1e6) { - line.push((session.TranscodingInfo.Bitrate / 1e6).toFixed(1) + " Mbps"); + line.push((session.TranscodingInfo.Bitrate / 1e6).toFixed(1) + ' Mbps'); } else { - line.push(Math.floor(session.TranscodingInfo.Bitrate / 1e3) + " Kbps"); + line.push(Math.floor(session.TranscodingInfo.Bitrate / 1e3) + ' Kbps'); } } @@ -426,7 +433,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } if (line.length) { - html += " - " + line.join(" "); + html += ' - ' + line.join(' '); } } @@ -434,42 +441,43 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }, getSessionNowPlayingTime: function (session) { var nowPlayingItem = session.NowPlayingItem; - var html = ""; + var html = ''; if (nowPlayingItem) { if (session.PlayState.PositionTicks) { html += datetime.getDisplayRunningTime(session.PlayState.PositionTicks); } else { - html += "0:00"; + html += '0:00'; } - html += " / "; + html += ' / '; if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { html += datetime.getDisplayRunningTime(nowPlayingItem.RunTimeTicks); } else { - html += "0:00"; + html += '0:00'; } } return html; }, getAppSecondaryText: function (session) { - return session.Client + " " + session.ApplicationVersion; + return session.Client + ' ' + session.ApplicationVersion; }, getNowPlayingName: function (session) { - var imgUrl = ""; + var imgUrl = ''; var nowPlayingItem = session.NowPlayingItem; - + // FIXME: It seems that, sometimes, server sends date in the future, so date-fns displays messages like 'in less than a minute'. We should fix + // how dates are returned by the server when the session is active and show something like 'Active now', instead of past/future sentences if (!nowPlayingItem) { return { - html: "Last seen " + humaneDate(session.LastActivityDate), + html: globalize.translate('LastSeen', datefns.formatDistanceToNow(Date.parse(session.LastActivityDate), dfnshelper.localeWithSuffix)), image: imgUrl }; } var topText = itemHelper.getDisplayName(nowPlayingItem); - var bottomText = ""; + var bottomText = ''; if (nowPlayingItem.Artists && nowPlayingItem.Artists.length) { bottomText = topText; @@ -488,14 +496,14 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa tag: nowPlayingItem.ImageTags.Logo, maxHeight: 24, maxWidth: 130, - type: "Logo" + type: 'Logo' }); } else if (nowPlayingItem.ParentLogoImageTag) { imgUrl = ApiClient.getScaledImageUrl(nowPlayingItem.ParentLogoItemId, { tag: nowPlayingItem.ParentLogoImageTag, maxHeight: 24, maxWidth: 130, - type: "Logo" + type: 'Logo' }); } @@ -504,7 +512,7 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } return { - html: bottomText ? topText + "
" + bottomText : topText, + html: bottomText ? topText + '
' + bottomText : topText, image: imgUrl }; }, @@ -519,106 +527,104 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa html.push(session.AdditionalUsers[i].UserName); } - return html.join(", "); + return html.join(', '); }, getUserImage: function (session) { if (session.UserId && session.UserPrimaryImageTag) { return ApiClient.getUserImageUrl(session.UserId, { tag: session.UserPrimaryImageTag, - type: "Primary" + type: 'Primary' }); } return null; }, updateSession: function (row, session) { - row.classList.remove("deadSession"); + row.classList.remove('deadSession'); var nowPlayingItem = session.NowPlayingItem; if (nowPlayingItem) { - row.classList.add("playingSession"); + row.classList.add('playingSession'); } else { - row.classList.remove("playingSession"); + row.classList.remove('playingSession'); } - if (session.ServerId && -1 !== session.SupportedCommands.indexOf("DisplayMessage") && session.DeviceId !== connectionManager.deviceId()) { - row.querySelector(".btnSessionSendMessage").classList.remove("hide"); + if (session.ServerId && -1 !== session.SupportedCommands.indexOf('DisplayMessage') && session.DeviceId !== connectionManager.deviceId()) { + row.querySelector('.btnSessionSendMessage').classList.remove('hide'); } else { - row.querySelector(".btnSessionSendMessage").classList.add("hide"); + row.querySelector('.btnSessionSendMessage').classList.add('hide'); } if (session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons && session.TranscodingInfo && session.TranscodingInfo.TranscodeReasons.length) { - row.querySelector(".btnSessionInfo").classList.remove("hide"); + row.querySelector('.btnSessionInfo').classList.remove('hide'); } else { - row.querySelector(".btnSessionInfo").classList.add("hide"); + row.querySelector('.btnSessionInfo').classList.add('hide'); } - var btnSessionPlayPause = row.querySelector(".btnSessionPlayPause"); + var btnSessionPlayPause = row.querySelector('.btnSessionPlayPause'); if (session.ServerId && nowPlayingItem && session.SupportsRemoteControl && session.DeviceId !== connectionManager.deviceId()) { - btnSessionPlayPause.classList.remove("hide"); - row.querySelector(".btnSessionStop").classList.remove("hide"); + btnSessionPlayPause.classList.remove('hide'); + row.querySelector('.btnSessionStop').classList.remove('hide'); } else { - btnSessionPlayPause.classList.add("hide"); - row.querySelector(".btnSessionStop").classList.add("hide"); + btnSessionPlayPause.classList.add('hide'); + row.querySelector('.btnSessionStop').classList.add('hide'); } - if (session.PlayState && session.PlayState.IsPaused) { - btnSessionPlayPause.querySelector("i").innerHTML = "play_arrow"; - } else { - btnSessionPlayPause.querySelector("i").innerHTML = "pause"; - } + const btnSessionPlayPauseIcon = btnSessionPlayPause.querySelector('.material-icons'); + btnSessionPlayPauseIcon.classList.remove('play_arrow', 'pause'); + btnSessionPlayPauseIcon.classList.add(session.PlayState && session.PlayState.IsPaused ? 'play_arrow' : 'pause'); - row.querySelector(".sessionNowPlayingStreamInfo").innerHTML = DashboardPage.getSessionNowPlayingStreamInfo(session); - row.querySelector(".sessionNowPlayingTime").innerHTML = DashboardPage.getSessionNowPlayingTime(session); - row.querySelector(".sessionUserName").innerHTML = DashboardPage.getUsersHtml(session); - row.querySelector(".sessionAppSecondaryText").innerHTML = DashboardPage.getAppSecondaryText(session); - row.querySelector(".sessionTranscodingFramerate").innerHTML = session.TranscodingInfo && session.TranscodingInfo.Framerate ? session.TranscodingInfo.Framerate + " fps" : ""; + row.querySelector('.sessionNowPlayingStreamInfo').innerHTML = DashboardPage.getSessionNowPlayingStreamInfo(session); + row.querySelector('.sessionNowPlayingTime').innerHTML = DashboardPage.getSessionNowPlayingTime(session); + row.querySelector('.sessionUserName').innerHTML = DashboardPage.getUsersHtml(session); + row.querySelector('.sessionAppSecondaryText').innerHTML = DashboardPage.getAppSecondaryText(session); + row.querySelector('.sessionTranscodingFramerate').innerHTML = session.TranscodingInfo && session.TranscodingInfo.Framerate ? session.TranscodingInfo.Framerate + ' fps' : ''; var nowPlayingName = DashboardPage.getNowPlayingName(session); - var nowPlayingInfoElem = row.querySelector(".sessionNowPlayingInfo"); + var nowPlayingInfoElem = row.querySelector('.sessionNowPlayingInfo'); - if (!(nowPlayingName.image && nowPlayingName.image == nowPlayingInfoElem.getAttribute("data-imgsrc"))) { + if (!(nowPlayingName.image && nowPlayingName.image == nowPlayingInfoElem.getAttribute('data-imgsrc'))) { nowPlayingInfoElem.innerHTML = nowPlayingName.html; - nowPlayingInfoElem.setAttribute("data-imgsrc", nowPlayingName.image || ""); + nowPlayingInfoElem.setAttribute('data-imgsrc', nowPlayingName.image || ''); } - var playbackProgressElem = row.querySelector(".playbackProgress"); + var playbackProgressElem = row.querySelector('.playbackProgress'); if (nowPlayingItem && nowPlayingItem.RunTimeTicks) { var percent = 100 * (session.PlayState.PositionTicks || 0) / nowPlayingItem.RunTimeTicks; playbackProgressElem.outerHTML = indicators.getProgressHtml(percent, { - containerClass: "playbackProgress" + containerClass: 'playbackProgress' }); } else { playbackProgressElem.outerHTML = indicators.getProgressHtml(0, { - containerClass: "playbackProgress hide" + containerClass: 'playbackProgress hide' }); } - var transcodingProgress = row.querySelector(".transcodingProgress"); + var transcodingProgress = row.querySelector('.transcodingProgress'); if (session.TranscodingInfo && session.TranscodingInfo.CompletionPercentage) { var percent = session.TranscodingInfo.CompletionPercentage.toFixed(1); transcodingProgress.outerHTML = indicators.getProgressHtml(percent, { - containerClass: "transcodingProgress" + containerClass: 'transcodingProgress' }); } else { transcodingProgress.outerHTML = indicators.getProgressHtml(0, { - containerClass: "transcodingProgress hide" + containerClass: 'transcodingProgress hide' }); } - var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || ""; - var imgElem = row.querySelector(".sessionNowPlayingContent"); + var imgUrl = DashboardPage.getNowPlayingImageUrl(nowPlayingItem) || ''; + var imgElem = row.querySelector('.sessionNowPlayingContent'); - if (imgUrl != imgElem.getAttribute("data-src")) { - imgElem.style.backgroundImage = imgUrl ? "url('" + imgUrl + "')" : ""; - imgElem.setAttribute("data-src", imgUrl); + if (imgUrl != imgElem.getAttribute('data-src')) { + imgElem.style.backgroundImage = imgUrl ? "url('" + imgUrl + "')" : ''; + imgElem.setAttribute('data-src', imgUrl); if (imgUrl) { - imgElem.classList.add("sessionNowPlayingContent-withbackground"); + imgElem.classList.add('sessionNowPlayingContent-withbackground'); } else { - imgElem.classList.remove("sessionNowPlayingContent-withbackground"); + imgElem.classList.remove('sessionNowPlayingContent-withbackground'); } } }, @@ -627,23 +633,28 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa return ""; }, getNowPlayingImageUrl: function (item) { + /* Screen width is multiplied by 0.2, as the there is currently no way to get the width of + elements that aren't created yet. */ if (item && item.BackdropImageTags && item.BackdropImageTags.length) { return ApiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Backdrop', tag: item.BackdropImageTags[0] }); } if (item && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { return ApiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Backdrop', tag: item.ParentBackdropImageTags[0] }); } if (item && item.BackdropImageTag) { return ApiClient.getScaledImageUrl(item.BackdropItemId, { - type: "Backdrop", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Backdrop', tag: item.BackdropImageTag }); } @@ -652,81 +663,87 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa if (item && imageTags.Thumb) { return ApiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Thumb', tag: imageTags.Thumb }); } if (item && item.ParentThumbImageTag) { return ApiClient.getScaledImageUrl(item.ParentThumbItemId, { - type: "Thumb", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Thumb', tag: item.ParentThumbImageTag }); } if (item && item.ThumbImageTag) { return ApiClient.getScaledImageUrl(item.ThumbItemId, { - type: "Thumb", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Thumb', tag: item.ThumbImageTag }); } if (item && imageTags.Primary) { return ApiClient.getScaledImageUrl(item.Id, { - type: "Primary", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Primary', tag: imageTags.Primary }); } if (item && item.PrimaryImageTag) { return ApiClient.getScaledImageUrl(item.PrimaryImageItemId, { - type: "Primary", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Primary', tag: item.PrimaryImageTag }); } if (item && item.AlbumPrimaryImageTag) { return ApiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", + maxWidth: Math.round(dom.getScreenWidth() * 0.20), + type: 'Primary', tag: item.AlbumPrimaryImageTag }); } return null; }, - systemUpdateTaskKey: "SystemUpdateTask", + systemUpdateTaskKey: 'SystemUpdateTask', stopTask: function (btn, id) { - var page = dom.parentWithClass(btn, "page"); + var page = dom.parentWithClass(btn, 'page'); ApiClient.stopScheduledTask(id).then(function () { pollForInfo(page, ApiClient); }); }, restart: function (btn) { - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ - title: globalize.translate("HeaderRestart"), - text: globalize.translate("MessageConfirmRestart"), - confirmText: globalize.translate("ButtonRestart"), - primary: "delete" + title: globalize.translate('HeaderRestart'), + text: globalize.translate('MessageConfirmRestart'), + confirmText: globalize.translate('ButtonRestart'), + primary: 'delete' }).then(function () { - var page = dom.parentWithClass(btn, "page"); - page.querySelector("#btnRestartServer").disabled = true; - page.querySelector("#btnShutdown").disabled = true; + var page = dom.parentWithClass(btn, 'page'); + page.querySelector('#btnRestartServer').disabled = true; + page.querySelector('#btnShutdown').disabled = true; ApiClient.restartServer(); }); }); }, shutdown: function (btn) { - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ - title: globalize.translate("HeaderShutdown"), - text: globalize.translate("MessageConfirmShutdown"), - confirmText: globalize.translate("ButtonShutdown"), - primary: "delete" + title: globalize.translate('HeaderShutdown'), + text: globalize.translate('MessageConfirmShutdown'), + confirmText: globalize.translate('ButtonShutdown'), + primary: 'delete' }).then(function () { - var page = dom.parentWithClass(btn, "page"); - page.querySelector("#btnRestartServer").disabled = true; - page.querySelector("#btnShutdown").disabled = true; + var page = dom.parentWithClass(btn, 'page'); + page.querySelector('#btnRestartServer').disabled = true; + page.querySelector('#btnShutdown').disabled = true; ApiClient.shutdownServer(); }); }); @@ -734,21 +751,15 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa }; return function (view, params) { function onRestartRequired(evt, apiClient) { - if (apiClient.serverId() === serverId) { - renderHasPendingRestart(view, apiClient, true); - } + console.debug('onRestartRequired not implemented', evt, apiClient); } function onServerShuttingDown(evt, apiClient) { - if (apiClient.serverId() === serverId) { - renderHasPendingRestart(view, apiClient, true); - } + console.debug('onServerShuttingDown not implemented', evt, apiClient); } function onServerRestarting(evt, apiClient) { - if (apiClient.serverId() === serverId) { - renderHasPendingRestart(view, apiClient, true); - } + console.debug('onServerRestarting not implemented', evt, apiClient); } function onPackageInstalling(evt, apiClient) { @@ -778,8 +789,8 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa } var serverId = ApiClient.serverId(); - view.querySelector(".activeDevices").addEventListener("click", onActiveDevicesClick); - view.addEventListener("viewshow", function () { + view.querySelector('.activeDevices').addEventListener('click', onActiveDevicesClick); + view.addEventListener('viewshow', function () { var page = this; var apiClient = ApiClient; @@ -787,28 +798,28 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa loading.show(); pollForInfo(page, apiClient); DashboardPage.startInterval(apiClient); - events.on(serverNotifications, "RestartRequired", onRestartRequired); - events.on(serverNotifications, "ServerShuttingDown", onServerShuttingDown); - events.on(serverNotifications, "ServerRestarting", onServerRestarting); - events.on(serverNotifications, "PackageInstalling", onPackageInstalling); - events.on(serverNotifications, "PackageInstallationCompleted", onPackageInstallationCompleted); - events.on(serverNotifications, "Sessions", onSessionsUpdate); - events.on(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + events.on(serverNotifications, 'RestartRequired', onRestartRequired); + events.on(serverNotifications, 'ServerShuttingDown', onServerShuttingDown); + events.on(serverNotifications, 'ServerRestarting', onServerRestarting); + events.on(serverNotifications, 'PackageInstalling', onPackageInstalling); + events.on(serverNotifications, 'PackageInstallationCompleted', onPackageInstallationCompleted); + events.on(serverNotifications, 'Sessions', onSessionsUpdate); + events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); DashboardPage.lastAppUpdateCheck = null; reloadSystemInfo(page, ApiClient); if (!page.userActivityLog) { page.userActivityLog = new ActivityLog({ serverId: ApiClient.serverId(), - element: page.querySelector(".userActivityItems") + element: page.querySelector('.userActivityItems') }); } - if (ApiClient.isMinServerVersion("3.4.1.25")) { + if (ApiClient.isMinServerVersion('3.4.1.25')) { if (!page.serverActivityLog) { page.serverActivityLog = new ActivityLog({ serverId: ApiClient.serverId(), - element: page.querySelector(".serverActivityItems") + element: page.querySelector('.serverActivityItems') }); } } @@ -817,21 +828,21 @@ define(["datetime", "events", "itemHelper", "serverNotifications", "dom", "globa loading.hide(); } }); - view.addEventListener("viewbeforehide", function () { + view.addEventListener('viewbeforehide', function () { var apiClient = ApiClient; - events.off(serverNotifications, "RestartRequired", onRestartRequired); - events.off(serverNotifications, "ServerShuttingDown", onServerShuttingDown); - events.off(serverNotifications, "ServerRestarting", onServerRestarting); - events.off(serverNotifications, "PackageInstalling", onPackageInstalling); - events.off(serverNotifications, "PackageInstallationCompleted", onPackageInstallationCompleted); - events.off(serverNotifications, "Sessions", onSessionsUpdate); - events.off(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + events.off(serverNotifications, 'RestartRequired', onRestartRequired); + events.off(serverNotifications, 'ServerShuttingDown', onServerShuttingDown); + events.off(serverNotifications, 'ServerRestarting', onServerRestarting); + events.off(serverNotifications, 'PackageInstalling', onPackageInstalling); + events.off(serverNotifications, 'PackageInstallationCompleted', onPackageInstallationCompleted); + events.off(serverNotifications, 'Sessions', onSessionsUpdate); + events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); if (apiClient) { DashboardPage.stopInterval(apiClient); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { var page = this; var userActivityLog = page.userActivityLog; diff --git a/src/controllers/dashboard/devices/device.js b/src/controllers/dashboard/devices/device.js new file mode 100644 index 0000000000..9ff3f5902e --- /dev/null +++ b/src/controllers/dashboard/devices/device.js @@ -0,0 +1,50 @@ +define(['loading', 'libraryMenu', 'dom', 'emby-input', 'emby-button'], function (loading, libraryMenu, dom) { + 'use strict'; + + function load(page, device, deviceOptions) { + page.querySelector('#txtCustomName', page).value = deviceOptions.CustomName || ''; + page.querySelector('.reportedName', page).innerHTML = device.Name || ''; + } + + function loadData() { + var page = this; + loading.show(); + var id = getParameterByName('id'); + var promise1 = ApiClient.getJSON(ApiClient.getUrl('Devices/Info', { + Id: id + })); + var promise2 = ApiClient.getJSON(ApiClient.getUrl('Devices/Options', { + Id: id + })); + Promise.all([promise1, promise2]).then(function (responses) { + load(page, responses[0], responses[1]); + loading.hide(); + }); + } + + function save(page) { + var id = getParameterByName('id'); + ApiClient.ajax({ + url: ApiClient.getUrl('Devices/Options', { + Id: id + }), + type: 'POST', + data: JSON.stringify({ + CustomName: page.querySelector('#txtCustomName').value + }), + contentType: 'application/json' + }).then(Dashboard.processServerConfigurationUpdateResult); + } + + function onSubmit(e) { + var form = this; + save(dom.parentWithClass(form, 'page')); + e.preventDefault(); + return false; + } + + return function (view, params) { + view.querySelector('form').addEventListener('submit', onSubmit); + view.addEventListener('viewshow', loadData); + }; +}); diff --git a/src/controllers/devices.js b/src/controllers/dashboard/devices/devices.js similarity index 54% rename from src/controllers/devices.js rename to src/controllers/dashboard/devices/devices.js index 4c8c37eedc..da65ef6219 100644 --- a/src/controllers/devices.js +++ b/src/controllers/dashboard/devices/devices.js @@ -1,24 +1,24 @@ -define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "humanedate", "emby-button", "emby-itemscontainer", "cardStyle"], function (loading, dom, libraryMenu, globalize, imageHelper) { - "use strict"; +define(['loading', 'dom', 'libraryMenu', 'globalize', 'scripts/imagehelper', 'date-fns', 'dfnshelper', 'emby-button', 'emby-itemscontainer', 'cardStyle'], function (loading, dom, libraryMenu, globalize, imageHelper, datefns, dfnshelper) { + 'use strict'; function canDelete(deviceId) { return deviceId !== ApiClient.deviceId(); } function deleteDevice(page, id) { - var msg = globalize.translate("DeleteDeviceConfirmation"); + var msg = globalize.translate('DeleteDeviceConfirmation'); - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ text: msg, - title: globalize.translate("HeaderDeleteDevice"), - confirmText: globalize.translate("ButtonDelete"), - primary: "delete" + title: globalize.translate('HeaderDeleteDevice'), + confirmText: globalize.translate('ButtonDelete'), + primary: 'delete' }).then(function () { loading.show(); ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("Devices", { + type: 'DELETE', + url: ApiClient.getUrl('Devices', { Id: id }) }).then(function () { @@ -33,31 +33,31 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu if (canEdit) { menuItems.push({ - name: globalize.translate("Edit"), - id: "open", - icon: "mode_edit" + name: globalize.translate('Edit'), + id: 'open', + icon: 'mode_edit' }); } if (canDelete(deviceId)) { menuItems.push({ - name: globalize.translate("Delete"), - id: "delete", - icon: "delete" + name: globalize.translate('Delete'), + id: 'delete', + icon: 'delete' }); } - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: btn, callback: function (id) { switch (id) { - case "open": - Dashboard.navigate("device.html?id=" + deviceId); + case 'open': + Dashboard.navigate('device.html?id=' + deviceId); break; - case "delete": + case 'delete': deleteDevice(view, deviceId); } } @@ -66,74 +66,74 @@ define(["loading", "dom", "libraryMenu", "globalize", "scripts/imagehelper", "hu } function load(page, devices) { - var html = ""; + var html = ''; html += devices.map(function (device) { - var deviceHtml = ""; + var deviceHtml = ''; deviceHtml += "'; deviceHtml += '
'; if (canEdit || canDelete(device.Id)) { deviceHtml += '
'; - deviceHtml += ''; - deviceHtml += "
"; + deviceHtml += ''; + deviceHtml += '
'; } deviceHtml += "
"; deviceHtml += device.Name; - deviceHtml += "
"; + deviceHtml += ''; deviceHtml += "
"; - deviceHtml += device.AppName + " " + device.AppVersion; - deviceHtml += "
"; + deviceHtml += device.AppName + ' ' + device.AppVersion; + deviceHtml += ''; deviceHtml += "
"; if (device.LastUserName) { deviceHtml += device.LastUserName; - deviceHtml += ", " + humaneDate(device.DateLastActivity); + deviceHtml += ', ' + datefns.formatDistanceToNow(Date.parse(device.DateLastActivity), dfnshelper.localeWithSuffix); } - deviceHtml += " "; - deviceHtml += "
"; - deviceHtml += ""; - deviceHtml += ""; - deviceHtml += ""; + deviceHtml += ' '; + deviceHtml += ''; + deviceHtml += ''; + deviceHtml += ''; + deviceHtml += ''; return deviceHtml; - }).join(""); - page.querySelector(".devicesList").innerHTML = html; + }).join(''); + page.querySelector('.devicesList').innerHTML = html; } function loadData(page) { loading.show(); - ApiClient.getJSON(ApiClient.getUrl("Devices")).then(function (result) { + ApiClient.getJSON(ApiClient.getUrl('Devices')).then(function (result) { load(page, result.Items); loading.hide(); }); } - var canEdit = ApiClient.isMinServerVersion("3.4.1.31"); + var canEdit = ApiClient.isMinServerVersion('3.4.1.31'); return function (view, params) { - view.querySelector(".devicesList").addEventListener("click", function (e) { - var btnDeviceMenu = dom.parentWithClass(e.target, "btnDeviceMenu"); + view.querySelector('.devicesList').addEventListener('click', function (e) { + var btnDeviceMenu = dom.parentWithClass(e.target, 'btnDeviceMenu'); if (btnDeviceMenu) { - showDeviceMenu(view, btnDeviceMenu, btnDeviceMenu.getAttribute("data-id")); + showDeviceMenu(view, btnDeviceMenu, btnDeviceMenu.getAttribute('data-id')); } }); - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { loadData(this); }); }; diff --git a/src/controllers/dashboard/dlna/dlnaprofile.js b/src/controllers/dashboard/dlna/dlnaprofile.js new file mode 100644 index 0000000000..3fe238c8ad --- /dev/null +++ b/src/controllers/dashboard/dlna/dlnaprofile.js @@ -0,0 +1,829 @@ +define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-select', 'emby-button', 'emby-input', 'emby-checkbox', 'listViewStyle', 'emby-button'], function ($, loading, globalize) { + 'use strict'; + + function loadProfile(page) { + loading.show(); + var promise1 = getProfile(); + var promise2 = ApiClient.getUsers(); + Promise.all([promise1, promise2]).then(function (responses) { + currentProfile = responses[0]; + renderProfile(page, currentProfile, responses[1]); + loading.hide(); + }); + } + + function getProfile() { + var id = getParameterByName('id'); + var url = id ? 'Dlna/Profiles/' + id : 'Dlna/Profiles/Default'; + return ApiClient.getJSON(ApiClient.getUrl(url)); + } + + function renderProfile(page, profile, users) { + $('#txtName', page).val(profile.Name); + $('.chkMediaType', page).each(function () { + this.checked = -1 != (profile.SupportedMediaTypes || '').split(',').indexOf(this.getAttribute('data-value')); + }); + $('#chkEnableAlbumArtInDidl', page).checked(profile.EnableAlbumArtInDidl); + $('#chkEnableSingleImageLimit', page).checked(profile.EnableSingleAlbumArtLimit); + renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []); + var idInfo = profile.Identification || {}; + renderIdentificationHeaders(page, idInfo.Headers || []); + renderSubtitleProfiles(page, profile.SubtitleProfiles || []); + $('#txtInfoFriendlyName', page).val(profile.FriendlyName || ''); + $('#txtInfoModelName', page).val(profile.ModelName || ''); + $('#txtInfoModelNumber', page).val(profile.ModelNumber || ''); + $('#txtInfoModelDescription', page).val(profile.ModelDescription || ''); + $('#txtInfoModelUrl', page).val(profile.ModelUrl || ''); + $('#txtInfoManufacturer', page).val(profile.Manufacturer || ''); + $('#txtInfoManufacturerUrl', page).val(profile.ManufacturerUrl || ''); + $('#txtInfoSerialNumber', page).val(profile.SerialNumber || ''); + $('#txtIdFriendlyName', page).val(idInfo.FriendlyName || ''); + $('#txtIdModelName', page).val(idInfo.ModelName || ''); + $('#txtIdModelNumber', page).val(idInfo.ModelNumber || ''); + $('#txtIdModelDescription', page).val(idInfo.ModelDescription || ''); + $('#txtIdModelUrl', page).val(idInfo.ModelUrl || ''); + $('#txtIdManufacturer', page).val(idInfo.Manufacturer || ''); + $('#txtIdManufacturerUrl', page).val(idInfo.ManufacturerUrl || ''); + $('#txtIdSerialNumber', page).val(idInfo.SerialNumber || ''); + $('#txtIdDeviceDescription', page).val(idInfo.DeviceDescription || ''); + $('#txtAlbumArtPn', page).val(profile.AlbumArtPn || ''); + $('#txtAlbumArtMaxWidth', page).val(profile.MaxAlbumArtWidth || ''); + $('#txtAlbumArtMaxHeight', page).val(profile.MaxAlbumArtHeight || ''); + $('#txtIconMaxWidth', page).val(profile.MaxIconWidth || ''); + $('#txtIconMaxHeight', page).val(profile.MaxIconHeight || ''); + $('#chkIgnoreTranscodeByteRangeRequests', page).checked(profile.IgnoreTranscodeByteRangeRequests); + $('#txtMaxAllowedBitrate', page).val(profile.MaxStreamingBitrate || ''); + $('#txtMusicStreamingTranscodingBitrate', page).val(profile.MusicStreamingTranscodingBitrate || ''); + $('#chkRequiresPlainFolders', page).checked(profile.RequiresPlainFolders); + $('#chkRequiresPlainVideoItems', page).checked(profile.RequiresPlainVideoItems); + $('#txtProtocolInfo', page).val(profile.ProtocolInfo || ''); + $('#txtXDlnaCap', page).val(profile.XDlnaCap || ''); + $('#txtXDlnaDoc', page).val(profile.XDlnaDoc || ''); + $('#txtSonyAggregationFlags', page).val(profile.SonyAggregationFlags || ''); + profile.DirectPlayProfiles = profile.DirectPlayProfiles || []; + profile.TranscodingProfiles = profile.TranscodingProfiles || []; + profile.ContainerProfiles = profile.ContainerProfiles || []; + profile.CodecProfiles = profile.CodecProfiles || []; + profile.ResponseProfiles = profile.ResponseProfiles || []; + var usersHtml = '' + users.map(function (u) { + return ''; + }).join(''); + $('#selectUser', page).html(usersHtml).val(profile.UserId || ''); + renderSubProfiles(page, profile); + } + + function renderIdentificationHeaders(page, headers) { + var index = 0; + var html = '
' + headers.map(function (h) { + var li = '
'; + li += ''; + li += '
'; + li += '

' + h.Name + ': ' + (h.Value || '') + '

'; + li += '
' + (h.Match || '') + '
'; + li += '
'; + li += ''; + li += '
'; + index++; + return li; + }).join('') + '
'; + var elem = $('.httpHeaderIdentificationList', page).html(html).trigger('create'); + $('.btnDeleteIdentificationHeader', elem).on('click', function () { + var itemIndex = parseInt(this.getAttribute('data-index')); + currentProfile.Identification.Headers.splice(itemIndex, 1); + renderIdentificationHeaders(page, currentProfile.Identification.Headers); + }); + } + + function openPopup(elem) { + elem.classList.remove('hide'); + } + + function closePopup(elem) { + elem.classList.add('hide'); + } + + function editIdentificationHeader(page, header) { + isSubProfileNew = null == header; + header = header || {}; + currentSubProfile = header; + var popup = $('#identificationHeaderPopup', page); + $('#txtIdentificationHeaderName', popup).val(header.Name || ''); + $('#txtIdentificationHeaderValue', popup).val(header.Value || ''); + $('#selectMatchType', popup).val(header.Match || 'Equals'); + openPopup(popup[0]); + } + + function saveIdentificationHeader(page) { + currentSubProfile.Name = $('#txtIdentificationHeaderName', page).val(); + currentSubProfile.Value = $('#txtIdentificationHeaderValue', page).val(); + currentSubProfile.Match = $('#selectMatchType', page).val(); + + if (isSubProfileNew) { + currentProfile.Identification = currentProfile.Identification || {}; + currentProfile.Identification.Headers = currentProfile.Identification.Headers || []; + currentProfile.Identification.Headers.push(currentSubProfile); + } + + renderIdentificationHeaders(page, currentProfile.Identification.Headers); + currentSubProfile = null; + closePopup($('#identificationHeaderPopup', page)[0]); + } + + function renderXmlDocumentAttributes(page, attribute) { + var html = '
' + attribute.map(function (h) { + var li = '
'; + li += ''; + li += '
'; + li += '

' + h.Name + ' = ' + (h.Value || '') + '

'; + li += '
'; + li += ''; + return li += '
'; + }).join('') + '
'; + var elem = $('.xmlDocumentAttributeList', page).html(html).trigger('create'); + $('.btnDeleteXmlAttribute', elem).on('click', function () { + var itemIndex = parseInt(this.getAttribute('data-index')); + currentProfile.XmlRootAttributes.splice(itemIndex, 1); + renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes); + }); + } + + function editXmlDocumentAttribute(page, attribute) { + isSubProfileNew = null == attribute; + attribute = attribute || {}; + currentSubProfile = attribute; + var popup = $('#xmlAttributePopup', page); + $('#txtXmlAttributeName', popup).val(attribute.Name || ''); + $('#txtXmlAttributeValue', popup).val(attribute.Value || ''); + openPopup(popup[0]); + } + + function saveXmlDocumentAttribute(page) { + currentSubProfile.Name = $('#txtXmlAttributeName', page).val(); + currentSubProfile.Value = $('#txtXmlAttributeValue', page).val(); + + if (isSubProfileNew) { + currentProfile.XmlRootAttributes.push(currentSubProfile); + } + + renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes); + currentSubProfile = null; + closePopup($('#xmlAttributePopup', page)[0]); + } + + function renderSubtitleProfiles(page, profiles) { + var index = 0; + var html = '
' + profiles.map(function (h) { + var li = '
'; + li += ''; + li += '
'; + li += '

' + (h.Format || '') + '

'; + li += '
'; + li += ''; + li += '
'; + index++; + return li; + }).join('') + '
'; + var elem = $('.subtitleProfileList', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var itemIndex = parseInt(this.getAttribute('data-index')); + currentProfile.SubtitleProfiles.splice(itemIndex, 1); + renderSubtitleProfiles(page, currentProfile.SubtitleProfiles); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var itemIndex = parseInt(this.getAttribute('data-index')); + editSubtitleProfile(page, currentProfile.SubtitleProfiles[itemIndex]); + }); + } + + function editSubtitleProfile(page, profile) { + isSubProfileNew = null == profile; + profile = profile || {}; + currentSubProfile = profile; + var popup = $('#subtitleProfilePopup', page); + $('#txtSubtitleProfileFormat', popup).val(profile.Format || ''); + $('#selectSubtitleProfileMethod', popup).val(profile.Method || ''); + $('#selectSubtitleProfileDidlMode', popup).val(profile.DidlMode || ''); + openPopup(popup[0]); + } + + function saveSubtitleProfile(page) { + currentSubProfile.Format = $('#txtSubtitleProfileFormat', page).val(); + currentSubProfile.Method = $('#selectSubtitleProfileMethod', page).val(); + currentSubProfile.DidlMode = $('#selectSubtitleProfileDidlMode', page).val(); + + if (isSubProfileNew) { + currentProfile.SubtitleProfiles.push(currentSubProfile); + } + + renderSubtitleProfiles(page, currentProfile.SubtitleProfiles); + currentSubProfile = null; + closePopup($('#subtitleProfilePopup', page)[0]); + } + + function renderSubProfiles(page, profile) { + renderDirectPlayProfiles(page, profile.DirectPlayProfiles); + renderTranscodingProfiles(page, profile.TranscodingProfiles); + renderContainerProfiles(page, profile.ContainerProfiles); + renderCodecProfiles(page, profile.CodecProfiles); + renderResponseProfiles(page, profile.ResponseProfiles); + } + + function saveDirectPlayProfile(page) { + currentSubProfile.Type = $('#selectDirectPlayProfileType', page).val(); + currentSubProfile.Container = $('#txtDirectPlayContainer', page).val(); + currentSubProfile.AudioCodec = $('#txtDirectPlayAudioCodec', page).val(); + currentSubProfile.VideoCodec = $('#txtDirectPlayVideoCodec', page).val(); + + if (isSubProfileNew) { + currentProfile.DirectPlayProfiles.push(currentSubProfile); + } + + renderSubProfiles(page, currentProfile); + currentSubProfile = null; + closePopup($('#popupEditDirectPlayProfile', page)[0]); + } + + function renderDirectPlayProfiles(page, profiles) { + var html = ''; + html += ''; + var elem = $('.directPlayProfiles', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var index = this.getAttribute('data-profileindex'); + deleteDirectPlayProfile(page, index); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var index = parseInt(this.getAttribute('data-profileindex')); + editDirectPlayProfile(page, currentProfile.DirectPlayProfiles[index]); + }); + } + + function deleteDirectPlayProfile(page, index) { + currentProfile.DirectPlayProfiles.splice(index, 1); + renderDirectPlayProfiles(page, currentProfile.DirectPlayProfiles); + } + + function editDirectPlayProfile(page, directPlayProfile) { + isSubProfileNew = null == directPlayProfile; + directPlayProfile = directPlayProfile || {}; + currentSubProfile = directPlayProfile; + var popup = $('#popupEditDirectPlayProfile', page); + $('#selectDirectPlayProfileType', popup).val(directPlayProfile.Type || 'Video').trigger('change'); + $('#txtDirectPlayContainer', popup).val(directPlayProfile.Container || ''); + $('#txtDirectPlayAudioCodec', popup).val(directPlayProfile.AudioCodec || ''); + $('#txtDirectPlayVideoCodec', popup).val(directPlayProfile.VideoCodec || ''); + openPopup(popup[0]); + } + + function renderTranscodingProfiles(page, profiles) { + var html = ''; + html += ''; + var elem = $('.transcodingProfiles', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var index = this.getAttribute('data-profileindex'); + deleteTranscodingProfile(page, index); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var index = parseInt(this.getAttribute('data-profileindex')); + editTranscodingProfile(page, currentProfile.TranscodingProfiles[index]); + }); + } + + function editTranscodingProfile(page, transcodingProfile) { + isSubProfileNew = null == transcodingProfile; + transcodingProfile = transcodingProfile || {}; + currentSubProfile = transcodingProfile; + var popup = $('#transcodingProfilePopup', page); + $('#selectTranscodingProfileType', popup).val(transcodingProfile.Type || 'Video').trigger('change'); + $('#txtTranscodingContainer', popup).val(transcodingProfile.Container || ''); + $('#txtTranscodingAudioCodec', popup).val(transcodingProfile.AudioCodec || ''); + $('#txtTranscodingVideoCodec', popup).val(transcodingProfile.VideoCodec || ''); + $('#selectTranscodingProtocol', popup).val(transcodingProfile.Protocol || 'Http'); + $('#chkEnableMpegtsM2TsMode', popup).checked(transcodingProfile.EnableMpegtsM2TsMode || false); + $('#chkEstimateContentLength', popup).checked(transcodingProfile.EstimateContentLength || false); + $('#chkReportByteRangeRequests', popup).checked('Bytes' == transcodingProfile.TranscodeSeekInfo); + $('.radioTabButton:first', popup).trigger('click'); + openPopup(popup[0]); + } + + function deleteTranscodingProfile(page, index) { + currentProfile.TranscodingProfiles.splice(index, 1); + renderTranscodingProfiles(page, currentProfile.TranscodingProfiles); + } + + function saveTranscodingProfile(page) { + currentSubProfile.Type = $('#selectTranscodingProfileType', page).val(); + currentSubProfile.Container = $('#txtTranscodingContainer', page).val(); + currentSubProfile.AudioCodec = $('#txtTranscodingAudioCodec', page).val(); + currentSubProfile.VideoCodec = $('#txtTranscodingVideoCodec', page).val(); + currentSubProfile.Protocol = $('#selectTranscodingProtocol', page).val(); + currentSubProfile.Context = 'Streaming'; + currentSubProfile.EnableMpegtsM2TsMode = $('#chkEnableMpegtsM2TsMode', page).checked(); + currentSubProfile.EstimateContentLength = $('#chkEstimateContentLength', page).checked(); + currentSubProfile.TranscodeSeekInfo = $('#chkReportByteRangeRequests', page).checked() ? 'Bytes' : 'Auto'; + + if (isSubProfileNew) { + currentProfile.TranscodingProfiles.push(currentSubProfile); + } + + renderSubProfiles(page, currentProfile); + currentSubProfile = null; + closePopup($('#transcodingProfilePopup', page)[0]); + } + + function renderContainerProfiles(page, profiles) { + var html = ''; + html += ''; + var elem = $('.containerProfiles', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var index = this.getAttribute('data-profileindex'); + deleteContainerProfile(page, index); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var index = parseInt(this.getAttribute('data-profileindex')); + editContainerProfile(page, currentProfile.ContainerProfiles[index]); + }); + } + + function deleteContainerProfile(page, index) { + currentProfile.ContainerProfiles.splice(index, 1); + renderContainerProfiles(page, currentProfile.ContainerProfiles); + } + + function editContainerProfile(page, containerProfile) { + isSubProfileNew = null == containerProfile; + containerProfile = containerProfile || {}; + currentSubProfile = containerProfile; + var popup = $('#containerProfilePopup', page); + $('#selectContainerProfileType', popup).val(containerProfile.Type || 'Video').trigger('change'); + $('#txtContainerProfileContainer', popup).val(containerProfile.Container || ''); + $('.radioTabButton:first', popup).trigger('click'); + openPopup(popup[0]); + } + + function saveContainerProfile(page) { + currentSubProfile.Type = $('#selectContainerProfileType', page).val(); + currentSubProfile.Container = $('#txtContainerProfileContainer', page).val(); + + if (isSubProfileNew) { + currentProfile.ContainerProfiles.push(currentSubProfile); + } + + renderSubProfiles(page, currentProfile); + currentSubProfile = null; + closePopup($('#containerProfilePopup', page)[0]); + } + + function renderCodecProfiles(page, profiles) { + var html = ''; + html += ''; + var elem = $('.codecProfiles', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var index = this.getAttribute('data-profileindex'); + deleteCodecProfile(page, index); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var index = parseInt(this.getAttribute('data-profileindex')); + editCodecProfile(page, currentProfile.CodecProfiles[index]); + }); + } + + function deleteCodecProfile(page, index) { + currentProfile.CodecProfiles.splice(index, 1); + renderCodecProfiles(page, currentProfile.CodecProfiles); + } + + function editCodecProfile(page, codecProfile) { + isSubProfileNew = null == codecProfile; + codecProfile = codecProfile || {}; + currentSubProfile = codecProfile; + var popup = $('#codecProfilePopup', page); + $('#selectCodecProfileType', popup).val(codecProfile.Type || 'Video').trigger('change'); + $('#txtCodecProfileCodec', popup).val(codecProfile.Codec || ''); + $('.radioTabButton:first', popup).trigger('click'); + openPopup(popup[0]); + } + + function saveCodecProfile(page) { + currentSubProfile.Type = $('#selectCodecProfileType', page).val(); + currentSubProfile.Codec = $('#txtCodecProfileCodec', page).val(); + + if (isSubProfileNew) { + currentProfile.CodecProfiles.push(currentSubProfile); + } + + renderSubProfiles(page, currentProfile); + currentSubProfile = null; + closePopup($('#codecProfilePopup', page)[0]); + } + + function renderResponseProfiles(page, profiles) { + var html = ''; + html += ''; + var elem = $('.mediaProfiles', page).html(html).trigger('create'); + $('.btnDeleteProfile', elem).on('click', function () { + var index = this.getAttribute('data-profileindex'); + deleteResponseProfile(page, index); + }); + $('.lnkEditSubProfile', elem).on('click', function () { + var index = parseInt(this.getAttribute('data-profileindex')); + editResponseProfile(page, currentProfile.ResponseProfiles[index]); + }); + } + + function deleteResponseProfile(page, index) { + currentProfile.ResponseProfiles.splice(index, 1); + renderResponseProfiles(page, currentProfile.ResponseProfiles); + } + + function editResponseProfile(page, responseProfile) { + isSubProfileNew = null == responseProfile; + responseProfile = responseProfile || {}; + currentSubProfile = responseProfile; + var popup = $('#responseProfilePopup', page); + $('#selectResponseProfileType', popup).val(responseProfile.Type || 'Video').trigger('change'); + $('#txtResponseProfileContainer', popup).val(responseProfile.Container || ''); + $('#txtResponseProfileAudioCodec', popup).val(responseProfile.AudioCodec || ''); + $('#txtResponseProfileVideoCodec', popup).val(responseProfile.VideoCodec || ''); + $('.radioTabButton:first', popup).trigger('click'); + openPopup(popup[0]); + } + + function saveResponseProfile(page) { + currentSubProfile.Type = $('#selectResponseProfileType', page).val(); + currentSubProfile.Container = $('#txtResponseProfileContainer', page).val(); + currentSubProfile.AudioCodec = $('#txtResponseProfileAudioCodec', page).val(); + currentSubProfile.VideoCodec = $('#txtResponseProfileVideoCodec', page).val(); + + if (isSubProfileNew) { + currentProfile.ResponseProfiles.push(currentSubProfile); + } + + renderSubProfiles(page, currentProfile); + currentSubProfile = null; + closePopup($('#responseProfilePopup', page)[0]); + } + + function saveProfile(page, profile) { + updateProfile(page, profile); + var id = getParameterByName('id'); + + if (id) { + ApiClient.ajax({ + type: 'POST', + url: ApiClient.getUrl('Dlna/Profiles/' + id), + data: JSON.stringify(profile), + contentType: 'application/json' + }).then(function () { + require(['toast'], function (toast) { + toast('Settings saved.'); + }); + }, Dashboard.processErrorResponse); + } else { + ApiClient.ajax({ + type: 'POST', + url: ApiClient.getUrl('Dlna/Profiles'), + data: JSON.stringify(profile), + contentType: 'application/json' + }).then(function () { + Dashboard.navigate('dlnaprofiles.html'); + }, Dashboard.processErrorResponse); + } + + loading.hide(); + } + + function updateProfile(page, profile) { + profile.Name = $('#txtName', page).val(); + profile.EnableAlbumArtInDidl = $('#chkEnableAlbumArtInDidl', page).checked(); + profile.EnableSingleAlbumArtLimit = $('#chkEnableSingleImageLimit', page).checked(); + profile.SupportedMediaTypes = $('.chkMediaType:checked', page).get().map(function (c) { + return c.getAttribute('data-value'); + }).join(','); + profile.Identification = profile.Identification || {}; + profile.FriendlyName = $('#txtInfoFriendlyName', page).val(); + profile.ModelName = $('#txtInfoModelName', page).val(); + profile.ModelNumber = $('#txtInfoModelNumber', page).val(); + profile.ModelDescription = $('#txtInfoModelDescription', page).val(); + profile.ModelUrl = $('#txtInfoModelUrl', page).val(); + profile.Manufacturer = $('#txtInfoManufacturer', page).val(); + profile.ManufacturerUrl = $('#txtInfoManufacturerUrl', page).val(); + profile.SerialNumber = $('#txtInfoSerialNumber', page).val(); + profile.Identification.FriendlyName = $('#txtIdFriendlyName', page).val(); + profile.Identification.ModelName = $('#txtIdModelName', page).val(); + profile.Identification.ModelNumber = $('#txtIdModelNumber', page).val(); + profile.Identification.ModelDescription = $('#txtIdModelDescription', page).val(); + profile.Identification.ModelUrl = $('#txtIdModelUrl', page).val(); + profile.Identification.Manufacturer = $('#txtIdManufacturer', page).val(); + profile.Identification.ManufacturerUrl = $('#txtIdManufacturerUrl', page).val(); + profile.Identification.SerialNumber = $('#txtIdSerialNumber', page).val(); + profile.Identification.DeviceDescription = $('#txtIdDeviceDescription', page).val(); + profile.AlbumArtPn = $('#txtAlbumArtPn', page).val(); + profile.MaxAlbumArtWidth = $('#txtAlbumArtMaxWidth', page).val(); + profile.MaxAlbumArtHeight = $('#txtAlbumArtMaxHeight', page).val(); + profile.MaxIconWidth = $('#txtIconMaxWidth', page).val(); + profile.MaxIconHeight = $('#txtIconMaxHeight', page).val(); + profile.RequiresPlainFolders = $('#chkRequiresPlainFolders', page).checked(); + profile.RequiresPlainVideoItems = $('#chkRequiresPlainVideoItems', page).checked(); + profile.IgnoreTranscodeByteRangeRequests = $('#chkIgnoreTranscodeByteRangeRequests', page).checked(); + profile.MaxStreamingBitrate = $('#txtMaxAllowedBitrate', page).val(); + profile.MusicStreamingTranscodingBitrate = $('#txtMusicStreamingTranscodingBitrate', page).val(); + profile.ProtocolInfo = $('#txtProtocolInfo', page).val(); + profile.XDlnaCap = $('#txtXDlnaCap', page).val(); + profile.XDlnaDoc = $('#txtXDlnaDoc', page).val(); + profile.SonyAggregationFlags = $('#txtSonyAggregationFlags', page).val(); + profile.UserId = $('#selectUser', page).val(); + } + + var currentProfile; + var currentSubProfile; + var isSubProfileNew; + var allText = globalize.translate('LabelAll'); + + $(document).on('pageinit', '#dlnaProfilePage', function () { + var page = this; + $('.radioTabButton', page).on('click', function () { + $(this).siblings().removeClass('ui-btn-active'); + $(this).addClass('ui-btn-active'); + var value = 'A' == this.tagName ? this.getAttribute('data-value') : this.value; + var elem = $('.' + value, page); + elem.siblings('.tabContent').hide(); + elem.show(); + }); + $('#selectDirectPlayProfileType', page).on('change', function () { + if ('Video' == this.value) { + $('#fldDirectPlayVideoCodec', page).show(); + } else { + $('#fldDirectPlayVideoCodec', page).hide(); + } + + if ('Photo' == this.value) { + $('#fldDirectPlayAudioCodec', page).hide(); + } else { + $('#fldDirectPlayAudioCodec', page).show(); + } + }); + $('#selectTranscodingProfileType', page).on('change', function () { + if ('Video' == this.value) { + $('#fldTranscodingVideoCodec', page).show(); + $('#fldTranscodingProtocol', page).show(); + $('#fldEnableMpegtsM2TsMode', page).show(); + } else { + $('#fldTranscodingVideoCodec', page).hide(); + $('#fldTranscodingProtocol', page).hide(); + $('#fldEnableMpegtsM2TsMode', page).hide(); + } + + if ('Photo' == this.value) { + $('#fldTranscodingAudioCodec', page).hide(); + $('#fldEstimateContentLength', page).hide(); + $('#fldReportByteRangeRequests', page).hide(); + } else { + $('#fldTranscodingAudioCodec', page).show(); + $('#fldEstimateContentLength', page).show(); + $('#fldReportByteRangeRequests', page).show(); + } + }); + $('#selectResponseProfileType', page).on('change', function () { + if ('Video' == this.value) { + $('#fldResponseProfileVideoCodec', page).show(); + } else { + $('#fldResponseProfileVideoCodec', page).hide(); + } + + if ('Photo' == this.value) { + $('#fldResponseProfileAudioCodec', page).hide(); + } else { + $('#fldResponseProfileAudioCodec', page).show(); + } + }); + $('.btnAddDirectPlayProfile', page).on('click', function () { + editDirectPlayProfile(page); + }); + $('.btnAddTranscodingProfile', page).on('click', function () { + editTranscodingProfile(page); + }); + $('.btnAddContainerProfile', page).on('click', function () { + editContainerProfile(page); + }); + $('.btnAddCodecProfile', page).on('click', function () { + editCodecProfile(page); + }); + $('.btnAddResponseProfile', page).on('click', function () { + editResponseProfile(page); + }); + $('.btnAddIdentificationHttpHeader', page).on('click', function () { + editIdentificationHeader(page); + }); + $('.btnAddXmlDocumentAttribute', page).on('click', function () { + editXmlDocumentAttribute(page); + }); + $('.btnAddSubtitleProfile', page).on('click', function () { + editSubtitleProfile(page); + }); + $('.dlnaProfileForm').off('submit', DlnaProfilePage.onSubmit).on('submit', DlnaProfilePage.onSubmit); + $('.editDirectPlayProfileForm').off('submit', DlnaProfilePage.onDirectPlayFormSubmit).on('submit', DlnaProfilePage.onDirectPlayFormSubmit); + $('.transcodingProfileForm').off('submit', DlnaProfilePage.onTranscodingProfileFormSubmit).on('submit', DlnaProfilePage.onTranscodingProfileFormSubmit); + $('.containerProfileForm').off('submit', DlnaProfilePage.onContainerProfileFormSubmit).on('submit', DlnaProfilePage.onContainerProfileFormSubmit); + $('.codecProfileForm').off('submit', DlnaProfilePage.onCodecProfileFormSubmit).on('submit', DlnaProfilePage.onCodecProfileFormSubmit); + $('.editResponseProfileForm').off('submit', DlnaProfilePage.onResponseProfileFormSubmit).on('submit', DlnaProfilePage.onResponseProfileFormSubmit); + $('.identificationHeaderForm').off('submit', DlnaProfilePage.onIdentificationHeaderFormSubmit).on('submit', DlnaProfilePage.onIdentificationHeaderFormSubmit); + $('.xmlAttributeForm').off('submit', DlnaProfilePage.onXmlAttributeFormSubmit).on('submit', DlnaProfilePage.onXmlAttributeFormSubmit); + $('.subtitleProfileForm').off('submit', DlnaProfilePage.onSubtitleProfileFormSubmit).on('submit', DlnaProfilePage.onSubtitleProfileFormSubmit); + }).on('pageshow', '#dlnaProfilePage', function () { + var page = this; + $('#radioInfo', page).trigger('click'); + loadProfile(page); + }); + window.DlnaProfilePage = { + onSubmit: function () { + loading.show(); + saveProfile($(this).parents('.page'), currentProfile); + return false; + }, + onDirectPlayFormSubmit: function () { + saveDirectPlayProfile($(this).parents('.page')); + return false; + }, + onTranscodingProfileFormSubmit: function () { + saveTranscodingProfile($(this).parents('.page')); + return false; + }, + onContainerProfileFormSubmit: function () { + saveContainerProfile($(this).parents('.page')); + return false; + }, + onCodecProfileFormSubmit: function () { + saveCodecProfile($(this).parents('.page')); + return false; + }, + onResponseProfileFormSubmit: function () { + saveResponseProfile($(this).parents('.page')); + return false; + }, + onIdentificationHeaderFormSubmit: function () { + saveIdentificationHeader($(this).parents('.page')); + return false; + }, + onXmlAttributeFormSubmit: function () { + saveXmlDocumentAttribute($(this).parents('.page')); + return false; + }, + onSubtitleProfileFormSubmit: function () { + saveSubtitleProfile($(this).parents('.page')); + return false; + } + }; +}); diff --git a/src/controllers/dashboard/dlna/dlnaprofiles.js b/src/controllers/dashboard/dlna/dlnaprofiles.js new file mode 100644 index 0000000000..fb4caadeb9 --- /dev/null +++ b/src/controllers/dashboard/dlna/dlnaprofiles.js @@ -0,0 +1,89 @@ +define(['jQuery', 'globalize', 'loading', 'libraryMenu', 'listViewStyle', 'emby-button'], function ($, globalize, loading, libraryMenu) { + 'use strict'; + + function loadProfiles(page) { + loading.show(); + ApiClient.getJSON(ApiClient.getUrl('Dlna/ProfileInfos')).then(function (result) { + renderUserProfiles(page, result); + renderSystemProfiles(page, result); + loading.hide(); + }); + } + + function renderUserProfiles(page, profiles) { + renderProfiles(page, page.querySelector('.customProfiles'), profiles.filter(function (p) { + return 'User' == p.Type; + })); + } + + function renderSystemProfiles(page, profiles) { + renderProfiles(page, page.querySelector('.systemProfiles'), profiles.filter(function (p) { + return 'System' == p.Type; + })); + } + + function renderProfiles(page, element, profiles) { + var html = ''; + + if (profiles.length) { + html += '
'; + } + + for (var i = 0, length = profiles.length; i < length; i++) { + var profile = profiles[i]; + html += '
'; + html += ''; + html += ''; + + if ('User' == profile.Type) { + html += ''; + } + + html += '
'; + } + + if (profiles.length) { + html += '
'; + } + + element.innerHTML = html; + $('.btnDeleteProfile', element).on('click', function () { + var id = this.getAttribute('data-profileid'); + deleteProfile(page, id); + }); + } + + function deleteProfile(page, id) { + require(['confirm'], function (confirm) { + confirm(globalize.translate('MessageConfirmProfileDeletion'), globalize.translate('HeaderConfirmProfileDeletion')).then(function () { + loading.show(); + ApiClient.ajax({ + type: 'DELETE', + url: ApiClient.getUrl('Dlna/Profiles/' + id) + }).then(function () { + loading.hide(); + loadProfiles(page); + }); + }); + }); + } + + function getTabs() { + return [{ + href: 'dlnasettings.html', + name: globalize.translate('TabSettings') + }, { + href: 'dlnaprofiles.html', + name: globalize.translate('TabProfiles') + }]; + } + + $(document).on('pageshow', '#dlnaProfilesPage', function () { + libraryMenu.setTabs('dlna', 1, getTabs); + loadProfiles(this); + }); +}); diff --git a/src/controllers/dashboard/dlna/dlnasettings.js b/src/controllers/dashboard/dlna/dlnasettings.js new file mode 100644 index 0000000000..a818002d01 --- /dev/null +++ b/src/controllers/dashboard/dlna/dlnasettings.js @@ -0,0 +1,56 @@ +define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { + 'use strict'; + + function loadPage(page, config, users) { + page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo; + page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog; + $('#txtClientDiscoveryInterval', page).val(config.ClientDiscoveryIntervalSeconds); + $('#chkEnableServer', page).checked(config.EnableServer); + $('#chkBlastAliveMessages', page).checked(config.BlastAliveMessages); + $('#txtBlastInterval', page).val(config.BlastAliveMessageIntervalSeconds); + var usersHtml = users.map(function (u) { + return ''; + }).join(''); + $('#selectUser', page).html(usersHtml).val(config.DefaultUserId || ''); + loading.hide(); + } + + function onSubmit() { + loading.show(); + var form = this; + ApiClient.getNamedConfiguration('dlna').then(function (config) { + config.EnablePlayTo = form.querySelector('#chkEnablePlayTo').checked; + config.EnableDebugLog = form.querySelector('#chkEnableDlnaDebugLogging').checked; + config.ClientDiscoveryIntervalSeconds = $('#txtClientDiscoveryInterval', form).val(); + config.EnableServer = $('#chkEnableServer', form).checked(); + config.BlastAliveMessages = $('#chkBlastAliveMessages', form).checked(); + config.BlastAliveMessageIntervalSeconds = $('#txtBlastInterval', form).val(); + config.DefaultUserId = $('#selectUser', form).val(); + ApiClient.updateNamedConfiguration('dlna', config).then(Dashboard.processServerConfigurationUpdateResult); + }); + return false; + } + + function getTabs() { + return [{ + href: 'dlnasettings.html', + name: globalize.translate('TabSettings') + }, { + href: 'dlnaprofiles.html', + name: globalize.translate('TabProfiles') + }]; + } + + $(document).on('pageinit', '#dlnaSettingsPage', function () { + $('.dlnaSettingsForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#dlnaSettingsPage', function () { + libraryMenu.setTabs('dlna', 0, getTabs); + loading.show(); + var page = this; + var promise1 = ApiClient.getNamedConfiguration('dlna'); + var promise2 = ApiClient.getUsers(); + Promise.all([promise1, promise2]).then(function (responses) { + loadPage(page, responses[0], responses[1]); + }); + }); +}); diff --git a/src/controllers/dashboard/encodingsettings.js b/src/controllers/dashboard/encodingsettings.js new file mode 100644 index 0000000000..65f4e4401d --- /dev/null +++ b/src/controllers/dashboard/encodingsettings.js @@ -0,0 +1,191 @@ +define(['jQuery', 'loading', 'globalize', 'dom', 'libraryMenu'], function ($, loading, globalize, dom, libraryMenu) { + 'use strict'; + + function loadPage(page, config, systemInfo) { + Array.prototype.forEach.call(page.querySelectorAll('.chkDecodeCodec'), function (c) { + c.checked = -1 !== (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute('data-codec')); + }); + page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding; + $('#selectVideoDecoder', page).val(config.HardwareAccelerationType); + $('#selectThreadCount', page).val(config.EncodingThreadCount); + $('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost); + page.querySelector('.txtEncoderPath').value = config.EncoderAppPathDisplay || ''; + $('#txtTranscodingTempPath', page).val(systemInfo.TranscodingTempPath || ''); + $('#txtVaapiDevice', page).val(config.VaapiDevice || ''); + page.querySelector('#selectEncoderPreset').value = config.EncoderPreset || ''; + page.querySelector('#txtH264Crf').value = config.H264Crf || ''; + page.querySelector('#selectDeinterlaceMethod').value = config.DeinterlaceMethod || ''; + page.querySelector('#chkEnableSubtitleExtraction').checked = config.EnableSubtitleExtraction || false; + page.querySelector('#chkEnableThrottling').checked = config.EnableThrottling || false; + page.querySelector('#selectVideoDecoder').dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + loading.hide(); + } + + function onSaveEncodingPathFailure(response) { + loading.hide(); + var msg = ''; + msg = globalize.translate('FFmpegSavePathNotFound'); + + require(['alert'], function (alert) { + alert(msg); + }); + } + + function updateEncoder(form) { + return ApiClient.getSystemInfo().then(function (systemInfo) { + return ApiClient.ajax({ + url: ApiClient.getUrl('System/MediaEncoder/Path'), + type: 'POST', + data: { + Path: form.querySelector('.txtEncoderPath').value, + PathType: 'Custom' + } + }).then(Dashboard.processServerConfigurationUpdateResult, onSaveEncodingPathFailure); + }); + } + + function onSubmit() { + var form = this; + + var onDecoderConfirmed = function () { + loading.show(); + ApiClient.getNamedConfiguration('encoding').then(function (config) { + config.DownMixAudioBoost = $('#txtDownMixAudioBoost', form).val(); + config.TranscodingTempPath = $('#txtTranscodingTempPath', form).val(); + config.EncodingThreadCount = $('#selectThreadCount', form).val(); + config.HardwareAccelerationType = $('#selectVideoDecoder', form).val(); + config.VaapiDevice = $('#txtVaapiDevice', form).val(); + config.EncoderPreset = form.querySelector('#selectEncoderPreset').value; + config.H264Crf = parseInt(form.querySelector('#txtH264Crf').value || '0'); + config.DeinterlaceMethod = form.querySelector('#selectDeinterlaceMethod').value; + config.EnableSubtitleExtraction = form.querySelector('#chkEnableSubtitleExtraction').checked; + config.EnableThrottling = form.querySelector('#chkEnableThrottling').checked; + config.HardwareDecodingCodecs = Array.prototype.map.call(Array.prototype.filter.call(form.querySelectorAll('.chkDecodeCodec'), function (c) { + return c.checked; + }), function (c) { + return c.getAttribute('data-codec'); + }); + config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked; + ApiClient.updateNamedConfiguration('encoding', config).then(function () { + updateEncoder(form); + }, function () { + require(['alert'], function (alert) { + alert(globalize.translate('DefaultErrorMessage')); + }); + + Dashboard.processServerConfigurationUpdateResult(); + }); + }); + }; + + if ($('#selectVideoDecoder', form).val()) { + require(['alert'], function (alert) { + alert({ + title: globalize.translate('TitleHardwareAcceleration'), + text: globalize.translate('HardwareAccelerationWarning') + }).then(onDecoderConfirmed); + }); + } else { + onDecoderConfirmed(); + } + + return false; + } + + function setDecodingCodecsVisible(context, value) { + value = value || ''; + var any; + Array.prototype.forEach.call(context.querySelectorAll('.chkDecodeCodec'), function (c) { + if (-1 === c.getAttribute('data-types').split(',').indexOf(value)) { + dom.parentWithTag(c, 'LABEL').classList.add('hide'); + } else { + dom.parentWithTag(c, 'LABEL').classList.remove('hide'); + any = true; + } + }); + + if (any) { + context.querySelector('.decodingCodecsList').classList.remove('hide'); + } else { + context.querySelector('.decodingCodecsList').classList.add('hide'); + } + } + + function getTabs() { + return [{ + href: 'encodingsettings.html', + name: globalize.translate('Transcoding') + }, { + href: 'playbackconfiguration.html', + name: globalize.translate('TabResumeSettings') + }, { + href: 'streamingsettings.html', + name: globalize.translate('TabStreaming') + }]; + } + + $(document).on('pageinit', '#encodingSettingsPage', function () { + var page = this; + page.querySelector('#selectVideoDecoder').addEventListener('change', function () { + if ('vaapi' == this.value) { + page.querySelector('.fldVaapiDevice').classList.remove('hide'); + page.querySelector('#txtVaapiDevice').setAttribute('required', 'required'); + } else { + page.querySelector('.fldVaapiDevice').classList.add('hide'); + page.querySelector('#txtVaapiDevice').removeAttribute('required'); + } + + if (this.value) { + page.querySelector('.hardwareAccelerationOptions').classList.remove('hide'); + } else { + page.querySelector('.hardwareAccelerationOptions').classList.add('hide'); + } + + setDecodingCodecsVisible(page, this.value); + }); + $('#btnSelectEncoderPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); + picker.show({ + includeFiles: true, + callback: function (path) { + if (path) { + $('.txtEncoderPath', page).val(path); + } + + picker.close(); + } + }); + }); + }); + $('#btnSelectTranscodingTempPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); + picker.show({ + callback: function (path) { + if (path) { + $('#txtTranscodingTempPath', page).val(path); + } + + picker.close(); + }, + validateWriteable: true, + header: globalize.translate('HeaderSelectTranscodingPath'), + instruction: globalize.translate('HeaderSelectTranscodingPathHelp') + }); + }); + }); + $('.encodingSettingsForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#encodingSettingsPage', function () { + loading.show(); + libraryMenu.setTabs('playback', 0, getTabs); + var page = this; + ApiClient.getNamedConfiguration('encoding').then(function (config) { + ApiClient.getSystemInfo().then(function (systemInfo) { + loadPage(page, config, systemInfo); + }); + }); + }); +}); diff --git a/src/controllers/dashboard/general.js b/src/controllers/dashboard/general.js index c37e5e9a46..98ca260f21 100644 --- a/src/controllers/dashboard/general.js +++ b/src/controllers/dashboard/general.js @@ -1,131 +1,130 @@ -define(["jQuery", "loading", "fnchecked", "emby-checkbox", "emby-textarea", "emby-input", "emby-select", "emby-button"], function($, loading) { - "use strict"; +define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox', 'emby-textarea', 'emby-input', 'emby-select', 'emby-button'], function ($, loading, globalize) { + 'use strict'; function loadPage(page, config, languageOptions, systemInfo) { - page.querySelector("#txtServerName").value = systemInfo.ServerName; - $("#chkAutoRunWebApp", page).checked(config.AutoRunWebApp); + page.querySelector('#txtServerName').value = systemInfo.ServerName; + $('#chkAutoRunWebApp', page).checked(config.AutoRunWebApp); + if (systemInfo.CanLaunchWebBrowser) { - page.querySelector("#fldAutoRunWebApp").classList.remove("hide"); + page.querySelector('#fldAutoRunWebApp').classList.remove('hide'); } else { - page.querySelector("#fldAutoRunWebApp").classList.add("hide"); + page.querySelector('#fldAutoRunWebApp').classList.add('hide'); } - page.querySelector("#txtCachePath").value = systemInfo.CachePath || ""; - $("#txtMetadataPath", page).val(systemInfo.InternalMetadataPath || ""); - $("#txtMetadataNetworkPath", page).val(systemInfo.MetadataNetworkPath || ""); - $("#selectLocalizationLanguage", page).html(languageOptions.map(function(language) { - return '" + + page.querySelector('#txtCachePath').value = systemInfo.CachePath || ''; + $('#txtMetadataPath', page).val(systemInfo.InternalMetadataPath || ''); + $('#txtMetadataNetworkPath', page).val(systemInfo.MetadataNetworkPath || ''); + $('#selectLocalizationLanguage', page).html(languageOptions.map(function (language) { + return ''; })).val(config.UICulture); currentLanguage = config.UICulture; - if (systemInfo.CanSelfUpdate) { - page.querySelector(".fldAutomaticUpdates").classList.remove("hide"); - } else { - page.querySelector(".fldAutomaticUpdates").classList.add("hide"); - } - $("#chkEnableAutomaticServerUpdates", page).checked(config.EnableAutoUpdate); - $("#chkEnableAutomaticRestart", page).checked(config.EnableAutomaticRestart); - if (systemInfo.CanSelfRestart) { - page.querySelector("#fldEnableAutomaticRestart").classList.remove("hide"); - } else { - page.querySelector("#fldEnableAutomaticRestart").classList.add("hide"); - } if (systemInfo.CanSelfRestart || systemInfo.CanSelfUpdate) { - $(".autoUpdatesContainer", page).removeClass("hide"); + $('.autoUpdatesContainer', page).removeClass('hide'); } else { - $(".autoUpdatesContainer", page).addClass("hide"); + $('.autoUpdatesContainer', page).addClass('hide'); } + loading.hide(); } function onSubmit() { loading.show(); var form = this; - $(form).parents(".page"); - return ApiClient.getServerConfiguration().then(function(config) { - config.ServerName = $("#txtServerName", form).val(); - config.UICulture = $("#selectLocalizationLanguage", form).val(); - config.CachePath = form.querySelector("#txtCachePath").value; - config.MetadataPath = $("#txtMetadataPath", form).val(); - config.MetadataNetworkPath = $("#txtMetadataNetworkPath", form).val(); - var requiresReload = (config.UICulture !== currentLanguage); - config.AutoRunWebApp = $("#chkAutoRunWebApp", form).checked(); - config.EnableAutomaticRestart = $("#chkEnableAutomaticRestart", form).checked(); - config.EnableAutoUpdate = $("#chkEnableAutomaticServerUpdates", form).checked(); + $(form).parents('.page'); + ApiClient.getServerConfiguration().then(function (config) { + config.ServerName = $('#txtServerName', form).val(); + config.UICulture = $('#selectLocalizationLanguage', form).val(); + config.CachePath = form.querySelector('#txtCachePath').value; + config.MetadataPath = $('#txtMetadataPath', form).val(); + config.MetadataNetworkPath = $('#txtMetadataNetworkPath', form).val(); + var requiresReload = config.UICulture !== currentLanguage; + config.AutoRunWebApp = $('#chkAutoRunWebApp', form).checked(); ApiClient.updateServerConfiguration(config).then(function() { ApiClient.getNamedConfiguration(brandingConfigKey).then(function(brandingConfig) { - brandingConfig.LoginDisclaimer = form.querySelector("#txtLoginDisclaimer").value; - brandingConfig.CustomCss = form.querySelector("#txtCustomCss").value; + brandingConfig.LoginDisclaimer = form.querySelector('#txtLoginDisclaimer').value; + brandingConfig.CustomCss = form.querySelector('#txtCustomCss').value; + if (currentBrandingOptions && brandingConfig.CustomCss !== currentBrandingOptions.CustomCss) { requiresReload = true; } - ApiClient.updateNamedConfiguration(brandingConfigKey, brandingConfig).then(function() { + + ApiClient.updateNamedConfiguration(brandingConfigKey, brandingConfig).then(function () { Dashboard.processServerConfigurationUpdateResult(); + if (requiresReload && !AppInfo.isNativeApp) { window.location.reload(true); } }); - }) - }) - }), !1 + }); + }, function () { + require(['alert'], function (alert) { + alert(globalize.translate('DefaultErrorMessage')); + }); + + Dashboard.processServerConfigurationUpdateResult(); + }); + }); + return false; } var currentBrandingOptions; var currentLanguage; - var brandingConfigKey = "branding"; - - return function(view, params) { - $("#btnSelectCachePath", view).on("click.selectDirectory", function() { - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; - picker.show({ - callback: function(path) { - if (path) { - view.querySelector("#txtCachePath").value = path; - } - picker.close(); - }, - validateWriteable: true, - header: Globalize.translate("HeaderSelectServerCachePath"), - instruction: Globalize.translate("HeaderSelectServerCachePathHelp") - }) - }) - }); - - $("#btnSelectMetadataPath", view).on("click.selectDirectory", function() { - require(["directorybrowser"], function(directoryBrowser) { + var brandingConfigKey = 'branding'; + return function (view, params) { + $('#btnSelectCachePath', view).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ - path: $("#txtMetadataPath", view).val(), - networkSharePath: $("#txtMetadataNetworkPath", view).val(), - callback: function(path, networkPath) { + callback: function (path) { if (path) { - $("#txtMetadataPath", view).val(path); - } - if (networkPath) { - $("#txtMetadataNetworkPath", view).val(networkPath); + view.querySelector('#txtCachePath').value = path; } + picker.close(); }, validateWriteable: true, - header: Globalize.translate("HeaderSelectMetadataPath"), - instruction: Globalize.translate("HeaderSelectMetadataPathHelp"), - enableNetworkSharePath: true - }) - }) + header: globalize.translate('HeaderSelectServerCachePath'), + instruction: globalize.translate('HeaderSelectServerCachePathHelp') + }); + }); }); + $('#btnSelectMetadataPath', view).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); + picker.show({ + path: $('#txtMetadataPath', view).val(), + networkSharePath: $('#txtMetadataNetworkPath', view).val(), + callback: function (path, networkPath) { + if (path) { + $('#txtMetadataPath', view).val(path); + } - $(".dashboardGeneralForm", view).off("submit", onSubmit).on("submit", onSubmit); - view.addEventListener("viewshow", function() { + if (networkPath) { + $('#txtMetadataNetworkPath', view).val(networkPath); + } + + picker.close(); + }, + validateWriteable: true, + header: globalize.translate('HeaderSelectMetadataPath'), + instruction: globalize.translate('HeaderSelectMetadataPathHelp'), + enableNetworkSharePath: true + }); + }); + }); + $('.dashboardGeneralForm', view).off('submit', onSubmit).on('submit', onSubmit); + view.addEventListener('viewshow', function () { var promiseConfig = ApiClient.getServerConfiguration(); - var promiseLanguageOptions = ApiClient.getJSON(ApiClient.getUrl("Localization/Options")); + var promiseLanguageOptions = ApiClient.getJSON(ApiClient.getUrl('Localization/Options')); var promiseSystemInfo = ApiClient.getSystemInfo(); - Promise.all([promiseConfig, promiseLanguageOptions, promiseSystemInfo]).then(function(responses) { + Promise.all([promiseConfig, promiseLanguageOptions, promiseSystemInfo]).then(function (responses) { loadPage(view, responses[0], responses[1], responses[2]); }); - ApiClient.getNamedConfiguration(brandingConfigKey).then(function(config) { + ApiClient.getNamedConfiguration(brandingConfigKey).then(function (config) { currentBrandingOptions = config; - view.querySelector("#txtLoginDisclaimer").value = config.LoginDisclaimer || ""; - view.querySelector("#txtCustomCss").value = config.CustomCss || ""; + view.querySelector('#txtLoginDisclaimer').value = config.LoginDisclaimer || ''; + view.querySelector('#txtCustomCss').value = config.CustomCss || ''; }); }); - } + }; }); diff --git a/src/controllers/dashboard/librarydisplay.js b/src/controllers/dashboard/librarydisplay.js new file mode 100644 index 0000000000..a820c37528 --- /dev/null +++ b/src/controllers/dashboard/librarydisplay.js @@ -0,0 +1,67 @@ +define(['globalize', 'loading', 'libraryMenu', 'emby-checkbox', 'emby-button', 'emby-button'], function(globalize, loading, libraryMenu) { + 'use strict'; + + function getTabs() { + return [{ + href: 'library.html', + name: globalize.translate('HeaderLibraries') + }, { + href: 'librarydisplay.html', + name: globalize.translate('TabDisplay') + }, { + href: 'metadataimages.html', + name: globalize.translate('TabMetadata') + }, { + href: 'metadatanfo.html', + name: globalize.translate('TabNfoSettings') + }]; + } + + return function(view, params) { + function loadData() { + ApiClient.getServerConfiguration().then(function(config) { + view.querySelector('.chkFolderView').checked = config.EnableFolderView; + view.querySelector('.chkGroupMoviesIntoCollections').checked = config.EnableGroupingIntoCollections; + view.querySelector('.chkDisplaySpecialsWithinSeasons').checked = config.DisplaySpecialsWithinSeasons; + view.querySelector('.chkExternalContentInSuggestions').checked = config.EnableExternalContentInSuggestions; + view.querySelector('#chkSaveMetadataHidden').checked = config.SaveMetadataHidden; + }); + ApiClient.getNamedConfiguration('metadata').then(function(metadata) { + view.querySelector('#selectDateAdded').selectedIndex = metadata.UseFileCreationTimeForDateAdded ? 1 : 0; + }); + } + + view.querySelector('form').addEventListener('submit', function(e) { + loading.show(); + var form = this; + ApiClient.getServerConfiguration().then(function(config) { + config.EnableFolderView = form.querySelector('.chkFolderView').checked; + config.EnableGroupingIntoCollections = form.querySelector('.chkGroupMoviesIntoCollections').checked; + config.DisplaySpecialsWithinSeasons = form.querySelector('.chkDisplaySpecialsWithinSeasons').checked; + config.EnableExternalContentInSuggestions = form.querySelector('.chkExternalContentInSuggestions').checked; + config.SaveMetadataHidden = form.querySelector('#chkSaveMetadataHidden').checked; + ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); + }); + ApiClient.getNamedConfiguration('metadata').then(function(config) { + config.UseFileCreationTimeForDateAdded = '1' === $('#selectDateAdded', form).val(); + ApiClient.updateNamedConfiguration('metadata', config); + }); + + e.preventDefault(); + loading.hide(); + return false; + }); + + view.addEventListener('viewshow', function() { + libraryMenu.setTabs('librarysetup', 1, getTabs); + loadData(); + ApiClient.getSystemInfo().then(function(info) { + if ('Windows' === info.OperatingSystem) { + view.querySelector('.fldSaveMetadataHidden').classList.remove('hide'); + } else { + view.querySelector('.fldSaveMetadataHidden').classList.add('hide'); + } + }); + }); + }; +}); diff --git a/src/controllers/dashboard/logs.js b/src/controllers/dashboard/logs.js index f5866f344c..e0b000a130 100644 --- a/src/controllers/dashboard/logs.js +++ b/src/controllers/dashboard/logs.js @@ -1,33 +1,33 @@ -define(["datetime", "loading", "apphost", "listViewStyle", "emby-button", "flexStyles"], function(datetime, loading, appHost) { - "use strict"; +define(['datetime', 'loading', 'apphost', 'listViewStyle', 'emby-button', 'flexStyles'], function(datetime, loading, appHost) { + 'use strict'; return function(view, params) { - view.addEventListener("viewbeforeshow", function() { + view.addEventListener('viewbeforeshow', function() { loading.show(); var apiClient = ApiClient; - apiClient.getJSON(apiClient.getUrl("System/Logs")).then(function(logs) { - var html = ""; + apiClient.getJSON(apiClient.getUrl('System/Logs')).then(function(logs) { + var html = ''; html += '
'; html += logs.map(function(log) { - var logUrl = apiClient.getUrl("System/Logs/Log", { + var logUrl = apiClient.getUrl('System/Logs/Log', { name: log.Name }); - logUrl += "&api_key=" + apiClient.accessToken(); - var logHtml = ""; + logUrl += '&api_key=' + apiClient.accessToken(); + var logHtml = ''; logHtml += ''; logHtml += '
'; - logHtml += "

" + log.Name + "

"; + logHtml += "

" + log.Name + '

'; var date = datetime.parseISO8601Date(log.DateModified, true); var text = datetime.toLocaleDateString(date); - text += " " + datetime.getDisplayTime(date); - logHtml += '
' + text + "
"; - logHtml += "
"; - logHtml += "
"; + text += ' ' + datetime.getDisplayTime(date); + logHtml += '
' + text + '
'; + logHtml += '
'; + logHtml += ''; return logHtml; - }).join(""); - html += ""; - view.querySelector(".serverLogs").innerHTML = html; + }).join(''); + html += ''; + view.querySelector('.serverLogs').innerHTML = html; loading.hide(); }); }); - } -}); \ No newline at end of file + }; +}); diff --git a/src/controllers/medialibrarypage.js b/src/controllers/dashboard/medialibrarypage.js similarity index 57% rename from src/controllers/medialibrarypage.js rename to src/controllers/dashboard/medialibrarypage.js index 543acf31da..0788fa4cad 100644 --- a/src/controllers/medialibrarypage.js +++ b/src/controllers/dashboard/medialibrarypage.js @@ -1,8 +1,8 @@ -define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "globalize", "dom", "indicators", "scripts/imagehelper", "cardStyle", "emby-itemrefreshindicator"], function ($, appHost, taskButton, loading, libraryMenu, globalize, dom, indicators, imageHelper) { - "use strict"; +define(['jQuery', 'apphost', 'scripts/taskbutton', 'loading', 'libraryMenu', 'globalize', 'dom', 'indicators', 'scripts/imagehelper', 'cardStyle', 'emby-itemrefreshindicator'], function ($, appHost, taskButton, loading, libraryMenu, globalize, dom, indicators, imageHelper) { + 'use strict'; function addVirtualFolder(page) { - require(["medialibrarycreator"], function (medialibrarycreator) { + require(['medialibrarycreator'], function (medialibrarycreator) { new medialibrarycreator().show({ collectionTypeOptions: getCollectionTypeOptions().filter(function (f) { return !f.hidden; @@ -17,7 +17,7 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function editVirtualFolder(page, virtualFolder) { - require(["medialibraryeditor"], function (medialibraryeditor) { + require(['medialibraryeditor'], function (medialibraryeditor) { new medialibraryeditor().show({ refresh: shouldRefreshLibraryAfterChanges(page), library: virtualFolder @@ -30,14 +30,14 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function deleteVirtualFolder(page, virtualFolder) { - var msg = globalize.translate("MessageAreYouSureYouWishToRemoveMediaFolder"); + var msg = globalize.translate('MessageAreYouSureYouWishToRemoveMediaFolder'); if (virtualFolder.Locations.length) { - msg += "

" + globalize.translate("MessageTheFollowingLocationWillBeRemovedFromLibrary") + "

"; - msg += virtualFolder.Locations.join("
"); + msg += '

' + globalize.translate('MessageTheFollowingLocationWillBeRemovedFromLibrary') + '

'; + msg += virtualFolder.Locations.join('
'); } - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ text: msg, @@ -55,20 +55,20 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function refreshVirtualFolder(page, virtualFolder) { - require(["refreshDialog"], function (refreshDialog) { + require(['refreshDialog'], function (refreshDialog) { new refreshDialog({ itemIds: [virtualFolder.ItemId], serverId: ApiClient.serverId(), - mode: "scan" + mode: 'scan' }).show(); }); } function renameVirtualFolder(page, virtualFolder) { - require(["prompt"], function (prompt) { + require(['prompt'], function (prompt) { prompt({ - label: globalize.translate("LabelNewName"), - confirmText: globalize.translate("ButtonRename") + label: globalize.translate('LabelNewName'), + confirmText: globalize.translate('ButtonRename') }).then(function (newName) { if (newName && newName != virtualFolder.Name) { var refreshAfterChange = shouldRefreshLibraryAfterChanges(page); @@ -81,59 +81,59 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function showCardMenu(page, elem, virtualFolders) { - var card = dom.parentWithClass(elem, "card"); - var index = parseInt(card.getAttribute("data-index")); + var card = dom.parentWithClass(elem, 'card'); + var index = parseInt(card.getAttribute('data-index')); var virtualFolder = virtualFolders[index]; var menuItems = []; menuItems.push({ - name: globalize.translate("ButtonEditImages"), - id: "editimages", - icon: "photo" + name: globalize.translate('ButtonEditImages'), + id: 'editimages', + icon: 'photo' }); menuItems.push({ - name: globalize.translate("ManageLibrary"), - id: "edit", - icon: "folder_open" + name: globalize.translate('ManageLibrary'), + id: 'edit', + icon: 'folder_open' }); menuItems.push({ - name: globalize.translate("ButtonRemove"), - id: "delete", - icon: "delete" + name: globalize.translate('ButtonRemove'), + id: 'delete', + icon: 'delete' }); menuItems.push({ - name: globalize.translate("ButtonRename"), - id: "rename", - icon: "mode_edit" + name: globalize.translate('ButtonRename'), + id: 'rename', + icon: 'mode_edit' }); menuItems.push({ - name: globalize.translate("ScanLibrary"), - id: "refresh", - icon: "refresh" + name: globalize.translate('ScanLibrary'), + id: 'refresh', + icon: 'refresh' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: elem, callback: function (resultId) { switch (resultId) { - case "edit": + case 'edit': editVirtualFolder(page, virtualFolder); break; - case "editimages": + case 'editimages': editImages(page, virtualFolder); break; - case "rename": + case 'rename': renameVirtualFolder(page, virtualFolder); break; - case "delete": + case 'delete': deleteVirtualFolder(page, virtualFolder); break; - case "refresh": + case 'refresh': refreshVirtualFolder(page, virtualFolder); } } @@ -149,14 +149,14 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function shouldRefreshLibraryAfterChanges(page) { - return "mediaLibraryPage" === page.id; + return 'mediaLibraryPage' === page.id; } function reloadVirtualFolders(page, virtualFolders) { - var html = ""; + var html = ''; virtualFolders.push({ - Name: globalize.translate("ButtonAddMediaLibrary"), - icon: "add_circle", + Name: globalize.translate('ButtonAddMediaLibrary'), + icon: 'add_circle', Locations: [], showType: false, showLocations: false, @@ -169,19 +169,19 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl html += getVirtualFolderHtml(page, virtualFolder, i); } - var divVirtualFolders = page.querySelector("#divVirtualFolders"); + var divVirtualFolders = page.querySelector('#divVirtualFolders'); divVirtualFolders.innerHTML = html; - divVirtualFolders.classList.add("itemsContainer"); - divVirtualFolders.classList.add("vertical-wrap"); - $(".btnCardMenu", divVirtualFolders).on("click", function () { + divVirtualFolders.classList.add('itemsContainer'); + divVirtualFolders.classList.add('vertical-wrap'); + $('.btnCardMenu', divVirtualFolders).on('click', function () { showCardMenu(page, this, virtualFolders); }); - divVirtualFolders.querySelector(".addLibrary").addEventListener("click", function () { + divVirtualFolders.querySelector('.addLibrary').addEventListener('click', function () { addVirtualFolder(page); }); - $(".editLibrary", divVirtualFolders).on("click", function () { - var card = $(this).parents(".card")[0]; - var index = parseInt(card.getAttribute("data-index")); + $('.editLibrary', divVirtualFolders).on('click', function () { + var card = $(this).parents('.card')[0]; + var index = parseInt(card.getAttribute('data-index')); var virtualFolder = virtualFolders[index]; if (virtualFolder.ItemId) { @@ -192,7 +192,7 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function editImages(page, virtualFolder) { - require(["imageEditor"], function (imageEditor) { + require(['imageEditor'], function (imageEditor) { imageEditor.show({ itemId: virtualFolder.ItemId, serverId: ApiClient.serverId() @@ -203,48 +203,48 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl } function getLink(text, url) { - return globalize.translate(text, '', ""); + return globalize.translate(text, '', ''); } function getCollectionTypeOptions() { return [{ - name: "", - value: "" + name: '', + value: '' }, { - name: globalize.translate("FolderTypeMovies"), - value: "movies", - message: getLink("MovieLibraryHelp", "https://docs.jellyfin.org/general/server/media/movies.html") + name: globalize.translate('FolderTypeMovies'), + value: 'movies', + message: getLink('MovieLibraryHelp', 'https://docs.jellyfin.org/general/server/media/movies.html') }, { - name: globalize.translate("FolderTypeMusic"), - value: "music", - message: getLink("MusicLibraryHelp", "https://docs.jellyfin.org/general/server/media/music.html") + name: globalize.translate('FolderTypeMusic'), + value: 'music', + message: getLink('MusicLibraryHelp', 'https://docs.jellyfin.org/general/server/media/music.html') }, { - name: globalize.translate("FolderTypeTvShows"), - value: "tvshows", - message: getLink("TvLibraryHelp", "https://docs.jellyfin.org/general/server/media/shows.html") + name: globalize.translate('FolderTypeTvShows'), + value: 'tvshows', + message: getLink('TvLibraryHelp', 'https://docs.jellyfin.org/general/server/media/shows.html') }, { - name: globalize.translate("FolderTypeBooks"), - value: "books", - message: getLink("BookLibraryHelp", "https://docs.jellyfin.org/general/server/media/books.html") + name: globalize.translate('FolderTypeBooks'), + value: 'books', + message: getLink('BookLibraryHelp', 'https://docs.jellyfin.org/general/server/media/books.html') }, { - name: globalize.translate("OptionHomeVideos"), - value: "homevideos" + name: globalize.translate('OptionHomeVideos'), + value: 'homevideos' }, { - name: globalize.translate("FolderTypeMusicVideos"), - value: "musicvideos" + name: globalize.translate('FolderTypeMusicVideos'), + value: 'musicvideos' }, { - name: globalize.translate("FolderTypeUnset"), - value: "mixed", - message: globalize.translate("MessageUnsetContentHelp") + name: globalize.translate('FolderTypeUnset'), + value: 'mixed', + message: globalize.translate('MessageUnsetContentHelp') }]; } function getVirtualFolderHtml(page, virtualFolder, index) { - var html = ""; - var style = ""; + var html = ''; + var style = ''; - if (page.classList.contains("wizardPage")) { - style += "min-width:33.3%;"; + if (page.classList.contains('wizardPage')) { + style += 'min-width:33.3%;'; } html += '
'; @@ -252,11 +252,12 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl html += '
'; html += '
'; html += '
'; - var imgUrl = ""; + var imgUrl = ''; if (virtualFolder.PrimaryImageItemId) { imgUrl = ApiClient.getScaledImageUrl(virtualFolder.PrimaryImageItemId, { - type: "Primary" + maxWidth: Math.round(dom.getScreenWidth() * 0.40), + type: 'Primary' }); } @@ -267,124 +268,124 @@ define(["jQuery", "apphost", "scripts/taskbutton", "loading", "libraryMenu", "gl hasCardImageContainer = true; } else if (!virtualFolder.showNameWithIcon) { html += '
'; - html += '' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + ""; + html += ''; hasCardImageContainer = true; } if (hasCardImageContainer) { html += '
'; - html += '
'; - html += "
"; - html += "
"; + html += '
'; + html += '
'; + html += '
'; } if (!imgUrl && virtualFolder.showNameWithIcon) { html += '

'; - html += '' + (virtualFolder.icon || imageHelper.getLibraryIcon(virtualFolder.CollectionType)) + ""; + html += ''; if (virtualFolder.showNameWithIcon) { html += '
'; html += virtualFolder.Name; - html += "
"; + html += '

'; } - html += ""; + html += ''; } - html += ""; - html += ""; + html += ''; + html += ''; html += '
'; // always show menu unless explicitly hidden if (virtualFolder.showMenu !== false) { html += '
'; - html += ''; - html += "
"; + html += ''; + html += '
'; } html += "
"; if (virtualFolder.showNameWithIcon) { - html += " "; + html += ' '; } else { html += virtualFolder.Name; } - html += "
"; + html += ''; var typeName = getCollectionTypeOptions().filter(function (t) { return t.value == virtualFolder.CollectionType; })[0]; - typeName = typeName ? typeName.name : globalize.translate("FolderTypeUnset"); + typeName = typeName ? typeName.name : globalize.translate('FolderTypeUnset'); html += "
"; if (virtualFolder.showType === false) { - html += " "; + html += ' '; } else { html += typeName; } - html += "
"; + html += ''; if (virtualFolder.showLocations === false) { html += "
"; - html += " "; - html += "
"; + html += ' '; + html += ''; } else if (virtualFolder.Locations.length && virtualFolder.Locations.length === 1) { html += "
"; html += virtualFolder.Locations[0]; - html += "
"; + html += ''; } else { html += "
"; - html += globalize.translate("NumLocationsValue", virtualFolder.Locations.length); - html += "
"; + html += globalize.translate('NumLocationsValue', virtualFolder.Locations.length); + html += ''; } - html += ""; - html += ""; - html += ""; + html += ''; + html += ''; + html += ''; return html; } function getTabs() { return [{ - href: "library.html", - name: globalize.translate("HeaderLibraries") + href: 'library.html', + name: globalize.translate('HeaderLibraries') }, { - href: "librarydisplay.html", - name: globalize.translate("TabDisplay") + href: 'librarydisplay.html', + name: globalize.translate('TabDisplay') }, { - href: "metadataimages.html", - name: globalize.translate("TabMetadata") + href: 'metadataimages.html', + name: globalize.translate('TabMetadata') }, { - href: "metadatanfo.html", - name: globalize.translate("TabNfoSettings") + href: 'metadatanfo.html', + name: globalize.translate('TabNfoSettings') }]; } window.WizardLibraryPage = { next: function () { - Dashboard.navigate("wizardsettings.html"); + Dashboard.navigate('wizardsettings.html'); } }; - pageClassOn("pageshow", "mediaLibraryPage", function () { + pageClassOn('pageshow', 'mediaLibraryPage', function () { reloadLibrary(this); }); - pageIdOn("pageshow", "mediaLibraryPage", function () { - libraryMenu.setTabs("librarysetup", 0, getTabs); + pageIdOn('pageshow', 'mediaLibraryPage', function () { + libraryMenu.setTabs('librarysetup', 0, getTabs); var page = this; taskButton({ - mode: "on", - progressElem: page.querySelector(".refreshProgress"), - taskKey: "RefreshLibrary", - button: page.querySelector(".btnRefresh") + mode: 'on', + progressElem: page.querySelector('.refreshProgress'), + taskKey: 'RefreshLibrary', + button: page.querySelector('.btnRefresh') }); }); - pageIdOn("pagebeforehide", "mediaLibraryPage", function () { + pageIdOn('pagebeforehide', 'mediaLibraryPage', function () { var page = this; taskButton({ - mode: "off", - progressElem: page.querySelector(".refreshProgress"), - taskKey: "RefreshLibrary", - button: page.querySelector(".btnRefresh") + mode: 'off', + progressElem: page.querySelector('.refreshProgress'), + taskKey: 'RefreshLibrary', + button: page.querySelector('.btnRefresh') }); }); }); diff --git a/src/controllers/dashboard/metadataimagespage.js b/src/controllers/dashboard/metadataimagespage.js new file mode 100644 index 0000000000..277eecb42a --- /dev/null +++ b/src/controllers/dashboard/metadataimagespage.js @@ -0,0 +1,64 @@ +define(['jQuery', 'dom', 'loading', 'libraryMenu', 'globalize', 'listViewStyle'], function($, dom, loading, libraryMenu, globalize) { + 'use strict'; + + function populateLanguages(select) { + return ApiClient.getCultures().then(function(languages) { + var html = ''; + html += ""; + for (var i = 0, length = languages.length; i < length; i++) { + var culture = languages[i]; + html += "'; + } + select.innerHTML = html; + }); + } + + function populateCountries(select) { + return ApiClient.getCountries().then(function(allCountries) { + var html = ''; + html += ""; + for (var i = 0, length = allCountries.length; i < length; i++) { + var culture = allCountries[i]; + html += "'; + } + select.innerHTML = html; + }); + } + + function loadPage(page) { + var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector('#selectLanguage')), populateCountries(page.querySelector('#selectCountry'))]; + Promise.all(promises).then(function(responses) { + var config = responses[0]; + page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage || '', page.querySelector('#selectCountry').value = config.MetadataCountryCode || '', loading.hide(); + }); + } + + function onSubmit() { + var form = this; + return loading.show(), ApiClient.getServerConfiguration().then(function(config) { + config.PreferredMetadataLanguage = form.querySelector('#selectLanguage').value, config.MetadataCountryCode = form.querySelector('#selectCountry').value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); + }), !1; + } + + function getTabs() { + return [{ + href: 'library.html', + name: globalize.translate('HeaderLibraries') + }, { + href: 'librarydisplay.html', + name: globalize.translate('TabDisplay') + }, { + href: 'metadataimages.html', + name: globalize.translate('TabMetadata') + }, { + href: 'metadatanfo.html', + name: globalize.translate('TabNfoSettings') + }]; + } + + $(document).on('pageinit', '#metadataImagesConfigurationPage', function() { + $('.metadataImagesConfigurationForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#metadataImagesConfigurationPage', function() { + libraryMenu.setTabs('metadata', 2, getTabs), loading.show(), loadPage(this); + }); +}); diff --git a/src/controllers/dashboard/metadatanfo.js b/src/controllers/dashboard/metadatanfo.js new file mode 100644 index 0000000000..a936192618 --- /dev/null +++ b/src/controllers/dashboard/metadatanfo.js @@ -0,0 +1,74 @@ +define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) { + 'use strict'; + + function loadPage(page, config, users) { + var html = ''; + html += users.map(function (user) { + return ''; + }).join(''); + $('#selectUser', page).html(html).val(config.UserId || ''); + $('#selectReleaseDateFormat', page).val(config.ReleaseDateFormat); + page.querySelector('#chkSaveImagePaths').checked = config.SaveImagePathsInNfo; + page.querySelector('#chkEnablePathSubstitution').checked = config.EnablePathSubstitution; + page.querySelector('#chkEnableExtraThumbs').checked = config.EnableExtraThumbsDuplication; + loading.hide(); + } + + function onSubmit() { + loading.show(); + var form = this; + ApiClient.getNamedConfiguration(metadataKey).then(function (config) { + config.UserId = $('#selectUser', form).val() || null; + config.ReleaseDateFormat = $('#selectReleaseDateFormat', form).val(); + config.SaveImagePathsInNfo = form.querySelector('#chkSaveImagePaths').checked; + config.EnablePathSubstitution = form.querySelector('#chkEnablePathSubstitution').checked; + config.EnableExtraThumbsDuplication = form.querySelector('#chkEnableExtraThumbs').checked; + ApiClient.updateNamedConfiguration(metadataKey, config).then(function () { + Dashboard.processServerConfigurationUpdateResult(); + showConfirmMessage(config); + }); + }); + return false; + } + + function showConfirmMessage(config) { + var msg = []; + msg.push(globalize.translate('MetadataSettingChangeHelp')); + + require(['alert'], function (alert) { + alert({ + text: msg.join('

') + }); + }); + } + + function getTabs() { + return [{ + href: 'library.html', + name: globalize.translate('HeaderLibraries') + }, { + href: 'librarydisplay.html', + name: globalize.translate('TabDisplay') + }, { + href: 'metadataimages.html', + name: globalize.translate('TabMetadata') + }, { + href: 'metadatanfo.html', + name: globalize.translate('TabNfoSettings') + }]; + } + + var metadataKey = 'xbmcmetadata'; + $(document).on('pageinit', '#metadataNfoPage', function () { + $('.metadataNfoForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#metadataNfoPage', function () { + libraryMenu.setTabs('metadata', 3, getTabs); + loading.show(); + var page = this; + var promise1 = ApiClient.getUsers(); + var promise2 = ApiClient.getNamedConfiguration(metadataKey); + Promise.all([promise1, promise2]).then(function (responses) { + loadPage(page, responses[1], responses[0]); + }); + }); +}); diff --git a/src/controllers/dashboard/networking.js b/src/controllers/dashboard/networking.js index a6e42967a4..9cf638ceee 100644 --- a/src/controllers/dashboard/networking.js +++ b/src/controllers/dashboard/networking.js @@ -1,145 +1,206 @@ -define(["loading", "libraryMenu", "globalize", "emby-checkbox", "emby-select"], function(loading, libraryMenu, globalize) { - "use strict"; +define(['loading', 'libraryMenu', 'globalize', 'emby-checkbox', 'emby-select'], function (loading, libraryMenu, globalize) { + 'use strict'; function onSubmit(e) { var form = this; - var localAddress = form.querySelector("#txtLocalAddress").value; - var enableUpnp = form.querySelector("#chkEnableUpnp").checked; - confirmSelections(localAddress, enableUpnp, function() { + var localAddress = form.querySelector('#txtLocalAddress').value; + var enableUpnp = form.querySelector('#chkEnableUpnp').checked; + confirmSelections(localAddress, enableUpnp, function () { var validationResult = getValidationAlert(form); - if (validationResult) return void alertText(validationResult); - validateHttps(form).then(function() { + + if (validationResult) { + alertText(validationResult); + return; + } + + validateHttps(form).then(function () { loading.show(); - ApiClient.getServerConfiguration().then(function(config) { - config.LocalNetworkSubnets = form.querySelector("#txtLanNetworks").value.split(",").map(function(s) { - return s.trim() - }).filter(function(s) { - return s.length > 0 + ApiClient.getServerConfiguration().then(function (config) { + config.LocalNetworkSubnets = form.querySelector('#txtLanNetworks').value.split(',').map(function (s) { + return s.trim(); + }).filter(function (s) { + return s.length > 0; }); - - config.RemoteIPFilter = form.querySelector("#txtExternalAddressFilter").value.split(",").map(function(s) { - return s.trim() - }).filter(function(s) { - return s.length > 0 + config.RemoteIPFilter = form.querySelector('#txtExternalAddressFilter').value.split(',').map(function (s) { + return s.trim(); + }).filter(function (s) { + return s.length > 0; }); + config.IsRemoteIPFilterBlacklist = 'blacklist' === form.querySelector('#selectExternalAddressFilterMode').value; + config.PublicPort = form.querySelector('#txtPublicPort').value; + config.PublicHttpsPort = form.querySelector('#txtPublicHttpsPort').value; + var httpsMode = form.querySelector('#selectHttpsMode').value; - config.IsRemoteIPFilterBlacklist = "blacklist" === form.querySelector("#selectExternalAddressFilterMode").value; - config.PublicPort = form.querySelector("#txtPublicPort").value; - config.PublicHttpsPort = form.querySelector("#txtPublicHttpsPort").value; - var httpsMode = form.querySelector("#selectHttpsMode").value; switch (httpsMode) { - case "proxy": + case 'proxy': config.EnableHttps = true; config.RequireHttps = false; config.IsBehindProxy = true; break; - case "required": + + case 'required': config.EnableHttps = true; config.RequireHttps = true; config.IsBehindProxy = false; break; - case "enabled": + + case 'enabled': config.EnableHttps = true; config.RequireHttps = false; config.IsBehindProxy = false; break; + default: config.EnableHttps = false; config.RequireHttps = false; config.IsBehindProxy = false; } - config.HttpsPortNumber = form.querySelector("#txtHttpsPort").value; - config.HttpServerPortNumber = form.querySelector("#txtPortNumber").value; + + config.HttpsPortNumber = form.querySelector('#txtHttpsPort').value; + config.HttpServerPortNumber = form.querySelector('#txtPortNumber').value; config.EnableUPnP = enableUpnp; - config.BaseUrl = form.querySelector("#txtBaseUrl").value; - config.EnableRemoteAccess = form.querySelector("#chkRemoteAccess").checked; - config.CertificatePath = form.querySelector("#txtCertificatePath").value || null; - config.CertificatePassword = form.querySelector("#txtCertPassword").value || null; + config.BaseUrl = form.querySelector('#txtBaseUrl').value; + config.EnableRemoteAccess = form.querySelector('#chkRemoteAccess').checked; + config.CertificatePath = form.querySelector('#txtCertificatePath').value || null; + config.CertificatePassword = form.querySelector('#txtCertPassword').value || null; config.LocalNetworkAddresses = localAddress ? [localAddress] : []; ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult, Dashboard.processErrorResponse); - }) - }) - }), e.preventDefault() + }); + }); + }); + e.preventDefault(); } function triggerChange(select) { - var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", !1, !0), select.dispatchEvent(evt) + var evt = document.createEvent('HTMLEvents'); + evt.initEvent('change', false, true); + select.dispatchEvent(evt); } function getValidationAlert(form) { - return form.querySelector("#txtPublicPort").value === form.querySelector("#txtPublicHttpsPort").value ? "The public http and https ports must be different." : form.querySelector("#txtPortNumber").value === form.querySelector("#txtHttpsPort").value ? "The http and https ports must be different." : null + if (form.querySelector('#txtPublicPort').value === form.querySelector('#txtPublicHttpsPort').value) { + return 'The public http and https ports must be different.'; + } + + if (form.querySelector('#txtPortNumber').value === form.querySelector('#txtHttpsPort').value) { + return 'The http and https ports must be different.'; + } + + return null; } function validateHttps(form) { - var certPath = form.querySelector("#txtCertificatePath").value || null; - var httpsMode = form.querySelector("#selectHttpsMode").value; - return "enabled" !== httpsMode && "required" !== httpsMode || certPath ? Promise.resolve() : new Promise(function(resolve, reject) { + var remoteAccess = form.querySelector('#chkRemoteAccess').checked; + var certPath = form.querySelector('#txtCertificatePath').value || null; + var httpsMode = form.querySelector('#selectHttpsMode').value; + + if (!remoteAccess || ('enabled' !== httpsMode && 'required' !== httpsMode || certPath)) { + return Promise.resolve(); + } + + return new Promise(function (resolve, reject) { return alertText({ - title: globalize.translate("TitleHostingSettings"), - text: globalize.translate("HttpsRequiresCert") - }).then(reject, reject) - }) + title: globalize.translate('TitleHostingSettings'), + text: globalize.translate('HttpsRequiresCert') + }).then(reject, reject); + }); } function alertText(options) { - return new Promise(function(resolve, reject) { - require(["alert"], function(alert) { - alert(options).then(resolve, reject) - }) - }) - } - - function confirmSelections(localAddress, enableUpnp, callback) { - localAddress || !enableUpnp ? alertText({ - title: globalize.translate("TitleHostingSettings"), - text: globalize.translate("SettingsWarning") - }).then(callback) : callback() - } - - return function(view, params) { - function loadPage(page, config) { - page.querySelector("#txtPortNumber").value = config.HttpServerPortNumber; - page.querySelector("#txtPublicPort").value = config.PublicPort; - page.querySelector("#txtPublicHttpsPort").value = config.PublicHttpsPort; - page.querySelector("#txtLocalAddress").value = config.LocalNetworkAddresses[0] || ""; - page.querySelector("#txtLanNetworks").value = (config.LocalNetworkSubnets || []).join(", "); - page.querySelector("#txtExternalAddressFilter").value = (config.RemoteIPFilter || []).join(", "); - page.querySelector("#selectExternalAddressFilterMode").value = config.IsRemoteIPFilterBlacklist ? "blacklist" : "whitelist"; - page.querySelector("#chkRemoteAccess").checked = null == config.EnableRemoteAccess || config.EnableRemoteAccess; - var selectHttpsMode = page.querySelector("#selectHttpsMode"); - config.IsBehindProxy ? selectHttpsMode.value = "proxy" : config.RequireHttps ? selectHttpsMode.value = "required" : config.EnableHttps ? selectHttpsMode.value = "enabled" : selectHttpsMode.value = "disabled"; - page.querySelector("#txtHttpsPort").value = config.HttpsPortNumber; - page.querySelector("#txtBaseUrl").value = config.BaseUrl || ""; - var txtCertificatePath = page.querySelector("#txtCertificatePath"); - txtCertificatePath.value = config.CertificatePath || ""; - page.querySelector("#txtCertPassword").value = config.CertificatePassword || ""; - page.querySelector("#chkEnableUpnp").checked = config.EnableUPnP; - triggerChange(page.querySelector("#chkRemoteAccess")); - loading.hide(); - } - - view.querySelector("#chkRemoteAccess").addEventListener("change", function() { - this.checked ? (view.querySelector(".fldExternalAddressFilter").classList.remove("hide"), view.querySelector(".fldExternalAddressFilterMode").classList.remove("hide"), view.querySelector(".fldPublicPort").classList.remove("hide"), view.querySelector(".fldPublicHttpsPort").classList.remove("hide"), view.querySelector(".fldCertificatePath").classList.remove("hide"), view.querySelector(".fldCertPassword").classList.remove("hide"), view.querySelector(".fldHttpsMode").classList.remove("hide"), view.querySelector(".fldEnableUpnp").classList.remove("hide")) : (view.querySelector(".fldExternalAddressFilter").classList.add("hide"), view.querySelector(".fldExternalAddressFilterMode").classList.add("hide"), view.querySelector(".fldPublicPort").classList.add("hide"), view.querySelector(".fldPublicHttpsPort").classList.add("hide"), view.querySelector(".fldCertificatePath").classList.add("hide"), view.querySelector(".fldCertPassword").classList.add("hide"), view.querySelector(".fldHttpsMode").classList.add("hide"), view.querySelector(".fldEnableUpnp").classList.add("hide")) - }), view.querySelector("#btnSelectCertPath").addEventListener("click", function() { - require(["directorybrowser"], function(directoryBrowser) { - var picker = new directoryBrowser; - picker.show({ - includeFiles: !0, - includeDirectories: !0, - callback: function(path) { - path && (view.querySelector("#txtCertificatePath").value = path), picker.close() - }, - header: globalize.translate("HeaderSelectCertificatePath") - }) - }) - }); - - view.querySelector(".dashboardHostingForm").addEventListener("submit", onSubmit), view.addEventListener("viewshow", function(e) { - loading.show(); - ApiClient.getServerConfiguration().then(function(config) { - loadPage(view, config); + return new Promise(function (resolve, reject) { + require(['alert'], function (alert) { + alert(options).then(resolve, reject); }); }); } + + function confirmSelections(localAddress, enableUpnp, callback) { + if (localAddress || !enableUpnp) { + alertText({ + title: globalize.translate('TitleHostingSettings'), + text: globalize.translate('SettingsWarning') + }).then(callback); + } else { + callback(); + } + } + + return function (view, params) { + function loadPage(page, config) { + page.querySelector('#txtPortNumber').value = config.HttpServerPortNumber; + page.querySelector('#txtPublicPort').value = config.PublicPort; + page.querySelector('#txtPublicHttpsPort').value = config.PublicHttpsPort; + page.querySelector('#txtLocalAddress').value = config.LocalNetworkAddresses[0] || ''; + page.querySelector('#txtLanNetworks').value = (config.LocalNetworkSubnets || []).join(', '); + page.querySelector('#txtExternalAddressFilter').value = (config.RemoteIPFilter || []).join(', '); + page.querySelector('#selectExternalAddressFilterMode').value = config.IsRemoteIPFilterBlacklist ? 'blacklist' : 'whitelist'; + page.querySelector('#chkRemoteAccess').checked = null == config.EnableRemoteAccess || config.EnableRemoteAccess; + var selectHttpsMode = page.querySelector('#selectHttpsMode'); + + if (config.IsBehindProxy) { + selectHttpsMode.value = 'proxy'; + } else if (config.RequireHttps) { + selectHttpsMode.value = 'required'; + } else if (config.EnableHttps) { + selectHttpsMode.value = 'enabled'; + } else { + selectHttpsMode.value = 'disabled'; + } + + page.querySelector('#txtHttpsPort').value = config.HttpsPortNumber; + page.querySelector('#txtBaseUrl').value = config.BaseUrl || ''; + var txtCertificatePath = page.querySelector('#txtCertificatePath'); + txtCertificatePath.value = config.CertificatePath || ''; + page.querySelector('#txtCertPassword').value = config.CertificatePassword || ''; + page.querySelector('#chkEnableUpnp').checked = config.EnableUPnP; + triggerChange(page.querySelector('#chkRemoteAccess')); + loading.hide(); + } + + view.querySelector('#chkRemoteAccess').addEventListener('change', function () { + if (this.checked) { + view.querySelector('.fldExternalAddressFilter').classList.remove('hide'); + view.querySelector('.fldExternalAddressFilterMode').classList.remove('hide'); + view.querySelector('.fldPublicPort').classList.remove('hide'); + view.querySelector('.fldPublicHttpsPort').classList.remove('hide'); + view.querySelector('.fldCertificatePath').classList.remove('hide'); + view.querySelector('.fldCertPassword').classList.remove('hide'); + view.querySelector('.fldHttpsMode').classList.remove('hide'); + view.querySelector('.fldEnableUpnp').classList.remove('hide'); + } else { + view.querySelector('.fldExternalAddressFilter').classList.add('hide'); + view.querySelector('.fldExternalAddressFilterMode').classList.add('hide'); + view.querySelector('.fldPublicPort').classList.add('hide'); + view.querySelector('.fldPublicHttpsPort').classList.add('hide'); + view.querySelector('.fldCertificatePath').classList.add('hide'); + view.querySelector('.fldCertPassword').classList.add('hide'); + view.querySelector('.fldHttpsMode').classList.add('hide'); + view.querySelector('.fldEnableUpnp').classList.add('hide'); + } + }); + view.querySelector('#btnSelectCertPath').addEventListener('click', function () { + require(['directorybrowser'], function (directoryBrowser) { + var picker = new directoryBrowser(); + picker.show({ + includeFiles: true, + includeDirectories: true, + callback: function (path) { + if (path) { + view.querySelector('#txtCertificatePath').value = path; + } + + picker.close(); + }, + header: globalize.translate('HeaderSelectCertificatePath') + }); + }); + }); + view.querySelector('.dashboardHostingForm').addEventListener('submit', onSubmit); + view.addEventListener('viewshow', function (e) { + loading.show(); + ApiClient.getServerConfiguration().then(function (config) { + loadPage(view, config); + }); + }); + }; }); diff --git a/src/controllers/dashboard/notifications/notification.js b/src/controllers/dashboard/notifications/notification.js index 70e6adaf61..90d453cdae 100644 --- a/src/controllers/dashboard/notifications/notification.js +++ b/src/controllers/dashboard/notifications/notification.js @@ -1,23 +1,23 @@ -define(["jQuery", "emby-checkbox", "fnchecked"], function ($) { - "use strict"; +define(['jQuery', 'emby-checkbox', 'fnchecked'], function ($) { + 'use strict'; function fillItems(elem, items, cssClass, idPrefix, currentList, isEnabledList) { var html = '
'; html += items.map(function (u) { var isChecked = isEnabledList ? currentList.indexOf(u.Id) != -1 : currentList.indexOf(u.Id) == -1; - var checkedHtml = isChecked ? ' checked="checked"' : ""; - return '"; - }).join(""); - html += "
"; - elem.html(html).trigger("create"); + var checkedHtml = isChecked ? ' checked="checked"' : ''; + return ''; + }).join(''); + html += ''; + elem.html(html).trigger('create'); } function reload(page) { - var type = getParameterByName("type"); + var type = getParameterByName('type'); var promise1 = ApiClient.getUsers(); var promise2 = ApiClient.getNamedConfiguration(notificationsConfigurationKey); - var promise3 = ApiClient.getJSON(ApiClient.getUrl("Notifications/Types")); - var promise4 = ApiClient.getJSON(ApiClient.getUrl("Notifications/Services")); + var promise3 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types')); + var promise4 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Services')); Promise.all([promise1, promise2, promise3, promise4]).then(function (responses) { var users = responses[0]; var notificationOptions = responses[1]; @@ -31,34 +31,34 @@ define(["jQuery", "emby-checkbox", "fnchecked"], function ($) { })[0] || {}; if (typeInfo.IsBasedOnUserEvent) { - $(".monitorUsers", page).show(); + $('.monitorUsers', page).show(); } else { - $(".monitorUsers", page).hide(); + $('.monitorUsers', page).hide(); } - $(".notificationType", page).html(typeInfo.Name || "Unknown Notification"); + $('.notificationType', page).html(typeInfo.Name || 'Unknown Notification'); if (!notificationConfig) { notificationConfig = { DisabledMonitorUsers: [], SendToUsers: [], DisabledServices: [], - SendToUserMode: "Admins" + SendToUserMode: 'Admins' }; } - fillItems($(".monitorUsersList", page), users, "chkMonitor", "chkMonitor", notificationConfig.DisabledMonitorUsers); - fillItems($(".sendToUsersList", page), users, "chkSendTo", "chkSendTo", notificationConfig.SendToUsers, true); - fillItems($(".servicesList", page), services, "chkService", "chkService", notificationConfig.DisabledServices); - $("#chkEnabled", page).checked(notificationConfig.Enabled || false); - $("#selectUsers", page).val(notificationConfig.SendToUserMode).trigger("change"); + fillItems($('.monitorUsersList', page), users, 'chkMonitor', 'chkMonitor', notificationConfig.DisabledMonitorUsers); + fillItems($('.sendToUsersList', page), users, 'chkSendTo', 'chkSendTo', notificationConfig.SendToUsers, true); + fillItems($('.servicesList', page), services, 'chkService', 'chkService', notificationConfig.DisabledServices); + $('#chkEnabled', page).checked(notificationConfig.Enabled || false); + $('#selectUsers', page).val(notificationConfig.SendToUserMode).trigger('change'); }); } function save(page) { - var type = getParameterByName("type"); + var type = getParameterByName('type'); var promise1 = ApiClient.getNamedConfiguration(notificationsConfigurationKey); - var promise2 = ApiClient.getJSON(ApiClient.getUrl("Notifications/Types")); + var promise2 = ApiClient.getJSON(ApiClient.getUrl('Notifications/Types')); Promise.all([promise1, promise2]).then(function (responses) { var notificationOptions = responses[0]; var types = responses[1]; @@ -76,47 +76,47 @@ define(["jQuery", "emby-checkbox", "fnchecked"], function ($) { types.filter(function (n) { return n.Type == type; })[0]; - notificationConfig.Enabled = $("#chkEnabled", page).checked(); - notificationConfig.SendToUserMode = $("#selectUsers", page).val(); - notificationConfig.DisabledMonitorUsers = $(".chkMonitor", page).get().filter(function (c) { + notificationConfig.Enabled = $('#chkEnabled', page).checked(); + notificationConfig.SendToUserMode = $('#selectUsers', page).val(); + notificationConfig.DisabledMonitorUsers = $('.chkMonitor', page).get().filter(function (c) { return !c.checked; }).map(function (c) { - return c.getAttribute("data-itemid"); + return c.getAttribute('data-itemid'); }); - notificationConfig.SendToUsers = $(".chkSendTo", page).get().filter(function (c) { + notificationConfig.SendToUsers = $('.chkSendTo', page).get().filter(function (c) { return c.checked; }).map(function (c) { - return c.getAttribute("data-itemid"); + return c.getAttribute('data-itemid'); }); - notificationConfig.DisabledServices = $(".chkService", page).get().filter(function (c) { + notificationConfig.DisabledServices = $('.chkService', page).get().filter(function (c) { return !c.checked; }).map(function (c) { - return c.getAttribute("data-itemid"); + return c.getAttribute('data-itemid'); }); ApiClient.updateNamedConfiguration(notificationsConfigurationKey, notificationOptions).then(function (r) { Dashboard.processServerConfigurationUpdateResult(); - Dashboard.navigate("notificationsettings.html"); + Dashboard.navigate('notificationsettings.html'); }); }); } function onSubmit() { - save($(this).parents(".page")); + save($(this).parents('.page')); return false; } - var notificationsConfigurationKey = "notifications"; - $(document).on("pageinit", "#notificationSettingPage", function () { + var notificationsConfigurationKey = 'notifications'; + $(document).on('pageinit', '#notificationSettingPage', function () { var page = this; - $("#selectUsers", page).on("change", function () { - if ("Custom" == this.value) { - $(".selectCustomUsers", page).show(); + $('#selectUsers', page).on('change', function () { + if ('Custom' == this.value) { + $('.selectCustomUsers', page).show(); } else { - $(".selectCustomUsers", page).hide(); + $('.selectCustomUsers', page).hide(); } }); - $(".notificationSettingForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#notificationSettingPage", function () { + $('.notificationSettingForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#notificationSettingPage', function () { reload(this); }); }); diff --git a/src/controllers/dashboard/notifications/notifications.js b/src/controllers/dashboard/notifications/notifications.js index 8b56dc506d..4e049bc106 100644 --- a/src/controllers/dashboard/notifications/notifications.js +++ b/src/controllers/dashboard/notifications/notifications.js @@ -1,60 +1,60 @@ -define(["loading", "libraryMenu", "globalize", "listViewStyle", "emby-button"], function(loading, libraryMenu, globalize) { - "use strict"; +define(['loading', 'libraryMenu', 'globalize', 'listViewStyle', 'emby-button'], function(loading, libraryMenu, globalize) { + 'use strict'; function reload(page) { loading.show(); - ApiClient.getJSON(ApiClient.getUrl("Notifications/Types")).then(function(list) { - var html = ""; - var lastCategory = ""; + ApiClient.getJSON(ApiClient.getUrl('Notifications/Types')).then(function(list) { + var html = ''; + var lastCategory = ''; var showHelp = true; html += list.map(function(notification) { - var itemHtml = ""; + var itemHtml = ''; if (notification.Category !== lastCategory) { lastCategory = notification.Category; if (lastCategory) { - itemHtml += ""; - itemHtml += ""; + itemHtml += ''; + itemHtml += ''; } itemHtml += '
'; itemHtml += '
'; itemHtml += '

'; itemHtml += notification.Category; - itemHtml += "

"; + itemHtml += ''; if (showHelp) { showHelp = false; itemHtml += ''; - itemHtml += globalize.translate("Help"); - itemHtml += ""; + itemHtml += globalize.translate('Help'); + itemHtml += ''; } - itemHtml += "
"; + itemHtml += '
'; itemHtml += ''; + itemHtml += ''; + itemHtml += ''; return itemHtml; - }).join(""); + }).join(''); if (list.length) { - html += ""; - html += ""; + html += ''; + html += ''; } - page.querySelector(".notificationList").innerHTML = html; + page.querySelector('.notificationList').innerHTML = html; loading.hide(); - }) + }); } return function(view, params) { - view.addEventListener("viewshow", function() { + view.addEventListener('viewshow', function() { reload(view); }); - } + }; }); diff --git a/src/controllers/playbackconfiguration.js b/src/controllers/dashboard/playbackconfiguration.js similarity index 50% rename from src/controllers/playbackconfiguration.js rename to src/controllers/dashboard/playbackconfiguration.js index 76c704f7eb..d5b67a2961 100644 --- a/src/controllers/playbackconfiguration.js +++ b/src/controllers/dashboard/playbackconfiguration.js @@ -1,10 +1,10 @@ -define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) { - "use strict"; +define(['jQuery', 'loading', 'libraryMenu', 'globalize'], function ($, loading, libraryMenu, globalize) { + 'use strict'; function loadPage(page, config) { - $("#txtMinResumePct", page).val(config.MinResumePct); - $("#txtMaxResumePct", page).val(config.MaxResumePct); - $("#txtMinResumeDuration", page).val(config.MinResumeDurationSeconds); + $('#txtMinResumePct', page).val(config.MinResumePct); + $('#txtMaxResumePct', page).val(config.MaxResumePct); + $('#txtMinResumeDuration', page).val(config.MinResumeDurationSeconds); loading.hide(); } @@ -24,22 +24,22 @@ define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) function getTabs() { return [{ - href: "encodingsettings.html", - name: Globalize.translate("Transcoding") + href: 'encodingsettings.html', + name: globalize.translate('Transcoding') }, { - href: "playbackconfiguration.html", - name: Globalize.translate("TabResumeSettings") + href: 'playbackconfiguration.html', + name: globalize.translate('TabResumeSettings') }, { - href: "streamingsettings.html", - name: Globalize.translate("TabStreaming") + href: 'streamingsettings.html', + name: globalize.translate('TabStreaming') }]; } - $(document).on("pageinit", "#playbackConfigurationPage", function () { - $(".playbackConfigurationForm").off("submit", onSubmit).on("submit", onSubmit) - }).on("pageshow", "#playbackConfigurationPage", function () { + $(document).on('pageinit', '#playbackConfigurationPage', function () { + $('.playbackConfigurationForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#playbackConfigurationPage', function () { loading.show(); - libraryMenu.setTabs("playback", 1, getTabs); + libraryMenu.setTabs('playback', 1, getTabs); var page = this; ApiClient.getServerConfiguration().then(function (config) { loadPage(page, config); diff --git a/src/controllers/dashboard/plugins/add.js b/src/controllers/dashboard/plugins/add.js index 7930d6927b..1ceee102e3 100644 --- a/src/controllers/dashboard/plugins/add.js +++ b/src/controllers/dashboard/plugins/add.js @@ -1,43 +1,36 @@ -define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "emby-button"], function ($, loading, libraryMenu, globalize, connectionManager) { - "use strict"; +define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'connectionManager', 'emby-button'], function ($, loading, libraryMenu, globalize, connectionManager) { + 'use strict'; function populateHistory(packageInfo, page) { - var html = ""; + var html = ''; var length = Math.min(packageInfo.versions.length, 10); for (var i = 0; i < length; i++) { var version = packageInfo.versions[i]; - html += '

' + version.versionStr + " (" + version.classification + ")

"; - html += '
' + version.description + "
"; + html += '

' + version.version + '

'; + html += '
' + version.changelog + '
'; } - $("#revisionHistory", page).html(html); + $('#revisionHistory', page).html(html); } function populateVersions(packageInfo, page, installedPlugin) { - var html = ""; + var html = ''; for (var i = 0; i < packageInfo.versions.length; i++) { var version = packageInfo.versions[i]; - html += '"; + html += ''; } - var selectmenu = $("#selectVersion", page).html(html); + var selectmenu = $('#selectVersion', page).html(html); if (!installedPlugin) { - $("#pCurrentVersion", page).hide().html(""); + $('#pCurrentVersion', page).hide().html(''); } - var packageVersion = packageInfo.versions.filter(function (current) { - return "Release" == current.classification; - })[0]; - packageVersion = packageVersion || packageInfo.versions.filter(function (current) { - return "Beta" == current.classification; - })[0]; - + var packageVersion = packageInfo.versions[0]; if (packageVersion) { - var val = packageVersion.versionStr + "|" + packageVersion.classification; - selectmenu.val(val); + selectmenu.val(packageVersion.version); } } @@ -45,84 +38,63 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e var installedPlugin = installedPlugins.filter(function (ip) { return ip.Name == pkg.name; })[0]; + populateVersions(pkg, page, installedPlugin); populateHistory(pkg, page); - $(".pluginName", page).html(pkg.name); - if ("Server" == pkg.targetSystem) { - $("#btnInstallDiv", page).removeClass("hide"); - $("#nonServerMsg", page).hide(); - $("#pSelectVersion", page).removeClass("hide"); + $('.pluginName', page).html(pkg.name); + $('#btnInstallDiv', page).removeClass('hide'); + $('#pSelectVersion', page).removeClass('hide'); + + if (pkg.overview) { + $('#overview', page).show().html(pkg.overview); } else { - $("#btnInstallDiv", page).addClass("hide"); - $("#pSelectVersion", page).addClass("hide"); - var msg = globalize.translate("MessageInstallPluginFromApp"); - $("#nonServerMsg", page).html(msg).show(); + $('#overview', page).hide(); } - if (pkg.shortDescription) { - $("#tagline", page).show().html(pkg.shortDescription); - } else { - $("#tagline", page).hide(); - } - - $("#overview", page).html(pkg.overview || ""); - $("#developer", page).html(pkg.owner); - - if (pkg.richDescUrl) { - $("#pViewWebsite", page).show(); - $("#pViewWebsite a", page).attr("href", pkg.richDescUrl); - } else { - $("#pViewWebsite", page).hide(); - } - - if (pkg.previewImage || pkg.thumbImage) { - var img = pkg.previewImage ? pkg.previewImage : pkg.thumbImage; - $("#pPreviewImage", page).show().html(""); - } else { - $("#pPreviewImage", page).hide().html(""); - } + $('#description', page).html(pkg.description); + $('#developer', page).html(pkg.owner); if (installedPlugin) { - var currentVersionText = globalize.translate("MessageYouHaveVersionInstalled").replace("{0}", "" + installedPlugin.Version + ""); - $("#pCurrentVersion", page).show().html(currentVersionText); + var currentVersionText = globalize.translate('MessageYouHaveVersionInstalled', '' + installedPlugin.Version + ''); + $('#pCurrentVersion', page).show().html(currentVersionText); } else { - $("#pCurrentVersion", page).hide().html(""); + $('#pCurrentVersion', page).hide().html(''); } loading.hide(); } function alertText(options) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert(options); }); } function performInstallation(page, packageName, guid, updateClass, version) { - var developer = $("#developer", page).html().toLowerCase(); + var developer = $('#developer', page).html().toLowerCase(); var alertCallback = function () { loading.show(); - page.querySelector("#btnInstall").disabled = true; + page.querySelector('#btnInstall').disabled = true; ApiClient.installPlugin(packageName, guid, updateClass, version).then(function () { loading.hide(); - alertText(globalize.translate("PluginInstalledMessage")); + alertText(globalize.translate('PluginInstalledMessage')); }); }; if (developer !== 'jellyfin') { loading.hide(); - var msg = globalize.translate("MessagePluginInstallDisclaimer"); - msg += "
"; - msg += "
"; - msg += globalize.translate("PleaseConfirmPluginInstallation"); + var msg = globalize.translate('MessagePluginInstallDisclaimer'); + msg += '
'; + msg += '
'; + msg += globalize.translate('PleaseConfirmPluginInstallation'); - require(["confirm"], function (confirm) { - confirm(msg, globalize.translate("HeaderConfirmPluginInstallation")).then(function () { + require(['confirm'], function (confirm) { + confirm(msg, globalize.translate('HeaderConfirmPluginInstallation')).then(function () { alertCallback(); }, function () { - console.log('plugin not installed'); + console.debug('plugin not installed'); }); }); } else { @@ -131,24 +103,24 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e } return function (view, params) { - $(".addPluginForm", view).on("submit", function () { + $('.addPluginForm', view).on('submit', function () { loading.show(); - var page = $(this).parents("#addPluginPage")[0]; + var page = $(this).parents('#addPluginPage')[0]; var name = params.name; var guid = params.guid; ApiClient.getInstalledPlugins().then(function (plugins) { var installedPlugin = plugins.filter(function (plugin) { return plugin.Name == name; })[0]; - var vals = $("#selectVersion", page).val().split("|"); + var vals = $('#selectVersion', page).val().split('|'); var version = vals[0]; if (installedPlugin) { if (installedPlugin.Version === version) { loading.hide(); Dashboard.alert({ - message: globalize.translate("MessageAlreadyInstalled"), - title: globalize.translate("HeaderPluginInstallation") + message: globalize.translate('MessageAlreadyInstalled'), + title: globalize.translate('HeaderPluginInstallation') }); } } else { @@ -157,7 +129,7 @@ define(["jQuery", "loading", "libraryMenu", "globalize", "connectionManager", "e }); return false; }); - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { var page = this; loading.show(); var name = params.name; diff --git a/src/controllers/dashboard/plugins/available.js b/src/controllers/dashboard/plugins/available.js index 1679fec5e7..82fea00b58 100644 --- a/src/controllers/dashboard/plugins/available.js +++ b/src/controllers/dashboard/plugins/available.js @@ -1,5 +1,5 @@ -define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby-checkbox", "emby-select"], function (loading, libraryMenu, globalize) { - "use strict"; +define(['loading', 'libraryMenu', 'globalize', 'cardStyle', 'emby-button', 'emby-checkbox', 'emby-select'], function (loading, libraryMenu, globalize) { + 'use strict'; function reloadList(page) { loading.show(); @@ -7,8 +7,8 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby var promise2 = ApiClient.getInstalledPlugins(); Promise.all([promise1, promise2]).then(function (responses) { populateList({ - catalogElement: page.querySelector("#pluginTiles"), - noItemsElement: page.querySelector("#noPlugins"), + catalogElement: page.querySelector('#pluginTiles'), + noItemsElement: page.querySelector('#noPlugins'), availablePlugins: responses[0], installedPlugins: responses[1] }); @@ -16,15 +16,15 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby } function getHeaderText(category) { - category = category.replace(" ", ""); - if ("Channel" === category) { - category = "Channels"; - } else if ("Theme" === category) { - category = "Themes"; - } else if ("LiveTV" === category) { - category = "HeaderLiveTV"; - } else if ("ScreenSaver" === category) { - category = "HeaderScreenSavers"; + category = category.replace(' ', ''); + if ('Channel' === category) { + category = 'Channels'; + } else if ('Theme' === category) { + category = 'Themes'; + } else if ('LiveTV' === category) { + category = 'HeaderLiveTV'; + } else if ('ScreenSaver' === category) { + category = 'HeaderScreenSavers'; } return globalize.translate(category); @@ -56,28 +56,28 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby }); var currentCategory = null; - var html = ""; + var html = ''; for (var i = 0; i < availablePlugins.length; i++) { var plugin = availablePlugins[i]; var category = plugin.categoryDisplayName; if (category != currentCategory) { if (currentCategory) { - html += ""; - html += ""; + html += ''; + html += ''; } html += '
'; - html += '

' + category + "

"; + html += '

' + category + '

'; html += '
'; currentCategory = category; } html += getPluginHtml(plugin, options, installedPlugins); } - html += "
"; - html += "
"; + html += ''; + html += ''; if (!availablePlugins.length && options.noItemsElement) { - options.noItemsElement.classList.remove("hide"); + options.noItemsElement.classList.remove('hide'); } options.catalogElement.innerHTML = html; @@ -85,51 +85,44 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby } function getPluginHtml(plugin, options, installedPlugins) { - var html = ""; - var href = plugin.externalUrl ? plugin.externalUrl : "addplugin.html?name=" + encodeURIComponent(plugin.name) + "&guid=" + plugin.guid; + var html = ''; + var href = plugin.externalUrl ? plugin.externalUrl : 'addplugin.html?name=' + encodeURIComponent(plugin.name) + '&guid=' + plugin.guid; if (options.context) { - href += "&context=" + options.context; + href += '&context=' + options.context; } - var target = plugin.externalUrl ? ' target="_blank"' : ""; + var target = plugin.externalUrl ? ' target="_blank"' : ''; html += "
"; html += ''; html += '
'; html += "
"; html += plugin.name; - html += "
"; - var installedPlugin = plugin.isApp ? null : installedPlugins.filter(function (ip) { + html += '
'; + var installedPlugin = installedPlugins.filter(function (ip) { return ip.Id == plugin.guid; })[0]; html += "
"; - html += installedPlugin ? globalize.translate("LabelVersionInstalled").replace("{0}", installedPlugin.Version) : " "; - html += "
"; - html += "
"; - html += ""; - return html += ""; + html += installedPlugin ? globalize.translate('LabelVersionInstalled', installedPlugin.Version) : ' '; + html += ''; + html += ''; + html += ''; + return html += ''; } function getTabs() { return [{ - href: "installedplugins.html", - name: globalize.translate("TabMyPlugins") + href: 'installedplugins.html', + name: globalize.translate('TabMyPlugins') }, { - href: "availableplugins.html", - name: globalize.translate("TabCatalog") + href: 'availableplugins.html', + name: globalize.translate('TabCatalog') }]; } @@ -138,8 +131,8 @@ define(["loading", "libraryMenu", "globalize", "cardStyle", "emby-button", "emby }; return function (view, params) { - view.addEventListener("viewshow", function () { - libraryMenu.setTabs("plugins", 1, getTabs); + view.addEventListener('viewshow', function () { + libraryMenu.setTabs('plugins', 1, getTabs); reloadList(this); }); }; diff --git a/src/controllers/dashboard/plugins/installed.js b/src/controllers/dashboard/plugins/installed.js index c18673738e..427ce7d94b 100644 --- a/src/controllers/dashboard/plugins/installed.js +++ b/src/controllers/dashboard/plugins/installed.js @@ -1,15 +1,15 @@ -define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button"], function (loading, libraryMenu, dom, globalize) { - "use strict"; +define(['loading', 'libraryMenu', 'dom', 'globalize', 'cardStyle', 'emby-button'], function (loading, libraryMenu, dom, globalize) { + 'use strict'; function deletePlugin(page, uniqueid, name) { - var msg = globalize.translate("UninstallPluginConfirmation").replace("{0}", name); + var msg = globalize.translate('UninstallPluginConfirmation', name); - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ - title: globalize.translate("UninstallPluginHeader"), + title: globalize.translate('UninstallPluginHeader'), text: msg, - primary: "delete", - confirmText: globalize.translate("UninstallPluginHeader") + primary: 'delete', + confirmText: globalize.translate('UninstallPluginHeader') }).then(function () { loading.show(); ApiClient.uninstallPlugin(uniqueid).then(function () { @@ -21,13 +21,13 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" function showNoConfigurationMessage() { Dashboard.alert({ - message: globalize.translate("NoPluginConfigurationMessage") + message: globalize.translate('NoPluginConfigurationMessage') }); } function showConnectMessage() { Dashboard.alert({ - message: globalize.translate("MessagePluginConfigurationRequiresLocalAccess") + message: globalize.translate('MessagePluginConfigurationRequiresLocalAccess') }); } @@ -36,40 +36,33 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" return pluginConfigurationPage.PluginId == plugin.Id; })[0]; var configPageUrl = configPage ? Dashboard.getConfigurationPageUrl(configPage.Name) : null; - var html = ""; + var html = ''; html += "
"; html += '
'; html += '"; + html += ''; + html += configPageUrl ? '' : '
'; + html += '
'; html += '
'; html += '
'; - html += ''; - html += "
"; + html += ''; + html += '
'; html += "
"; - html += configPage ? configPage.DisplayName || plugin.Name : plugin.Name; - html += "
"; + html += configPage.DisplayName || plugin.Name; + html += ''; html += "
"; html += plugin.Version; - html += "
"; - html += ""; - html += ""; - html += ""; + html += ''; + html += ''; + html += ''; + html += ''; return html; } function renderPlugins(page, plugins) { - ApiClient.getJSON(ApiClient.getUrl("web/configurationpages") + "?pageType=PluginConfiguration").then(function (configPages) { + ApiClient.getJSON(ApiClient.getUrl('web/configurationpages') + '?pageType=PluginConfiguration').then(function (configPages) { populateList(page, plugins, configPages); }); } @@ -82,23 +75,25 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" return -1; }); + var html = plugins.map(function (p) { return getPluginCardHtml(p, pluginConfigurationPages); - }).join(""); - var installedPluginsElement = page.querySelector(".installedPlugins"); - installedPluginsElement.removeEventListener("click", onInstalledPluginsClick); - installedPluginsElement.addEventListener("click", onInstalledPluginsClick); + }).join(''); + + var installedPluginsElement = page.querySelector('.installedPlugins'); + installedPluginsElement.removeEventListener('click', onInstalledPluginsClick); + installedPluginsElement.addEventListener('click', onInstalledPluginsClick); if (plugins.length) { - installedPluginsElement.classList.add("itemsContainer"); - installedPluginsElement.classList.add("vertical-wrap"); + installedPluginsElement.classList.add('itemsContainer'); + installedPluginsElement.classList.add('vertical-wrap'); } else { - html += '
'; - html += "

" + globalize.translate("MessageNoPluginsInstalled") + "

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

' + globalize.translate('MessageNoPluginsInstalled') + '

'; html += '

'; - html += globalize.translate("BrowsePluginCatalogMessage"); - html += "

"; - html += "
"; + html += globalize.translate('BrowsePluginCatalogMessage'); + html += '

'; + html += '
'; } installedPluginsElement.innerHTML = html; @@ -106,38 +101,38 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" } function showPluginMenu(page, elem) { - var card = dom.parentWithClass(elem, "card"); - var id = card.getAttribute("data-id"); - var name = card.getAttribute("data-name"); - var configHref = card.querySelector(".cardContent").getAttribute("href"); + var card = dom.parentWithClass(elem, 'card'); + var id = card.getAttribute('data-id'); + var name = card.getAttribute('data-name'); + var configHref = card.querySelector('.cardContent').getAttribute('href'); var menuItems = []; if (configHref) { menuItems.push({ - name: globalize.translate("ButtonSettings"), - id: "open", - icon: "mode_edit" + name: globalize.translate('ButtonSettings'), + id: 'open', + icon: 'mode_edit' }); } menuItems.push({ - name: globalize.translate("ButtonUninstall"), - id: "delete", - icon: "delete" + name: globalize.translate('ButtonUninstall'), + id: 'delete', + icon: 'delete' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: elem, callback: function (resultId) { switch (resultId) { - case "open": + case 'open': Dashboard.navigate(configHref); break; - - case "delete": + case 'delete': deletePlugin(page, id, name); + break; } } }); @@ -153,32 +148,32 @@ define(["loading", "libraryMenu", "dom", "globalize", "cardStyle", "emby-button" function getTabs() { return [{ - href: "installedplugins.html", - name: globalize.translate("TabMyPlugins") + href: 'installedplugins.html', + name: globalize.translate('TabMyPlugins') }, { - href: "availableplugins.html", - name: globalize.translate("TabCatalog") + href: 'availableplugins.html', + name: globalize.translate('TabCatalog') }]; } function onInstalledPluginsClick(e) { - if (dom.parentWithClass(e.target, "noConfigPluginCard")) { + if (dom.parentWithClass(e.target, 'noConfigPluginCard')) { showNoConfigurationMessage(); - } else if (dom.parentWithClass(e.target, "connectModePluginCard")) { + } else if (dom.parentWithClass(e.target, 'connectModePluginCard')) { showConnectMessage(); } else { - var btnCardMenu = dom.parentWithClass(e.target, "btnCardMenu"); - + var btnCardMenu = dom.parentWithClass(e.target, 'btnCardMenu'); if (btnCardMenu) { - showPluginMenu(dom.parentWithClass(btnCardMenu, "page"), btnCardMenu); + showPluginMenu(dom.parentWithClass(btnCardMenu, 'page'), btnCardMenu); } } } - pageIdOn("pageshow", "pluginsPage", function () { - libraryMenu.setTabs("plugins", 0, getTabs); + pageIdOn('pageshow', 'pluginsPage', function () { + libraryMenu.setTabs('plugins', 0, getTabs); reloadList(this); }); + window.PluginsPage = { renderPlugins: renderPlugins }; diff --git a/src/controllers/dashboard/scheduledtasks/scheduledtask.js b/src/controllers/dashboard/scheduledtasks/scheduledtask.js index 7a3e1dbcd6..52050d1f80 100644 --- a/src/controllers/dashboard/scheduledtasks/scheduledtask.js +++ b/src/controllers/dashboard/scheduledtasks/scheduledtask.js @@ -1,5 +1,5 @@ -define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby-button", "emby-select"], function ($, loading, datetime, dom, globalize) { - "use strict"; +define(['jQuery', 'loading', 'datetime', 'dom', 'globalize', 'emby-input', 'emby-button', 'emby-select'], function ($, loading, datetime, dom, globalize) { + 'use strict'; function fillTimeOfDay(select) { @@ -14,7 +14,7 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby select.innerHTML = options.map(function (o) { return ''; - }).join(""); + }).join(''); } Array.prototype.remove = function (from, to) { @@ -26,90 +26,92 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby var ScheduledTaskPage = { refreshScheduledTask: function (view) { loading.show(); - var id = getParameterByName("id"); + var id = getParameterByName('id'); ApiClient.getScheduledTask(id).then(function (task) { ScheduledTaskPage.loadScheduledTask(view, task); }); }, loadScheduledTask: function (view, task) { - $(".taskName", view).html(task.Name); - $("#pTaskDescription", view).html(task.Description); + $('.taskName', view).html(task.Name); + $('#pTaskDescription', view).html(task.Description); - require(["listViewStyle"], function () { + require(['listViewStyle'], function () { ScheduledTaskPage.loadTaskTriggers(view, task); }); loading.hide(); }, loadTaskTriggers: function (context, task) { - var html = ""; + var html = ''; html += '
'; for (var i = 0, length = task.Triggers.length; i < length; i++) { var trigger = task.Triggers[i]; html += '
'; - html += 'schedule'; + html += ''; if (trigger.MaxRuntimeMs) { html += '
'; } else { html += '
'; } - html += "
" + ScheduledTaskPage.getTriggerFriendlyName(trigger) + "
"; + html += "
" + ScheduledTaskPage.getTriggerFriendlyName(trigger) + '
'; if (trigger.MaxRuntimeMs) { html += '
'; var hours = trigger.MaxRuntimeTicks / 36e9; if (hours == 1) { - html += globalize.translate("ValueTimeLimitSingleHour"); + html += globalize.translate('ValueTimeLimitSingleHour'); } else { - html += globalize.translate("ValueTimeLimitMultiHour", hours); + html += globalize.translate('ValueTimeLimitMultiHour', hours); } - html += "
"; + html += '
'; } - html += "
"; - html += ''; - html += "
"; + html += '
'; + html += ''; + html += ''; } - html += ""; - context.querySelector(".taskTriggers").innerHTML = html; + html += ''; + context.querySelector('.taskTriggers').innerHTML = html; }, + // TODO: Replace this mess with date-fns and remove datetime completely getTriggerFriendlyName: function (trigger) { - if ("DailyTrigger" == trigger.Type) { - return "Daily at " + ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks); + if ('DailyTrigger' == trigger.Type) { + return globalize.translate('DailyAt', ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks)); } - if ("WeeklyTrigger" == trigger.Type) { - return trigger.DayOfWeek + "s at " + ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks); + if ('WeeklyTrigger' == trigger.Type) { + // TODO: The day of week isn't localised as well + return globalize.translate('WeeklyAt', trigger.DayOfWeek, ScheduledTaskPage.getDisplayTime(trigger.TimeOfDayTicks)); } - if ("SystemEventTrigger" == trigger.Type && "WakeFromSleep" == trigger.SystemEvent) { - return "On wake from sleep"; + if ('SystemEventTrigger' == trigger.Type && 'WakeFromSleep' == trigger.SystemEvent) { + return globalize.translate('OnWakeFromSleep'); } - if (trigger.Type == "IntervalTrigger") { + if (trigger.Type == 'IntervalTrigger') { var hours = trigger.IntervalTicks / 36e9; if (hours == 0.25) { - return "Every 15 minutes"; + return globalize.translate('EveryXMinutes', '15'); } if (hours == 0.5) { - return "Every 30 minutes"; + return globalize.translate('EveryXMinutes', '30'); } if (hours == 0.75) { - return "Every 45 minutes"; + return globalize.translate('EveryXMinutes', '45'); } if (hours == 1) { - return "Every hour"; + return globalize.translate('EveryHour'); } - return "Every " + hours + " hours"; + return globalize.translate('EveryXHours', hours); } - if (trigger.Type == "StartupTrigger") { - return "On application startup"; + if (trigger.Type == 'StartupTrigger') { + return globalize.translate('OnApplicationStartup'); } return trigger.Type; @@ -122,20 +124,20 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby return datetime.getDisplayTime(now); }, showAddTriggerPopup: function (view) { - $("#selectTriggerType", view).val("DailyTrigger"); - view.querySelector("#selectTriggerType").dispatchEvent(new CustomEvent("change", {})); - $("#popupAddTrigger", view).removeClass("hide"); + $('#selectTriggerType', view).val('DailyTrigger'); + view.querySelector('#selectTriggerType').dispatchEvent(new CustomEvent('change', {})); + $('#popupAddTrigger', view).removeClass('hide'); }, confirmDeleteTrigger: function (view, index) { - require(["confirm"], function (confirm) { - confirm(globalize.translate("MessageDeleteTaskTrigger"), globalize.translate("HeaderDeleteTaskTrigger")).then(function () { + require(['confirm'], function (confirm) { + confirm(globalize.translate('MessageDeleteTaskTrigger'), globalize.translate('HeaderDeleteTaskTrigger')).then(function () { ScheduledTaskPage.deleteTrigger(view, index); }); }); }, deleteTrigger: function (view, index) { loading.show(); - var id = getParameterByName("id"); + var id = getParameterByName('id'); ApiClient.getScheduledTask(id).then(function (task) { task.Triggers.remove(index); ApiClient.updateScheduledTaskTriggers(task.Id, task.Triggers).then(function () { @@ -144,55 +146,55 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby }); }, refreshTriggerFields: function (page, triggerType) { - if (triggerType == "DailyTrigger") { - $("#fldTimeOfDay", page).show(); - $("#fldDayOfWeek", page).hide(); - $("#fldSelectSystemEvent", page).hide(); - $("#fldSelectInterval", page).hide(); - $("#selectTimeOfDay", page).attr("required", "required"); - } else if (triggerType == "WeeklyTrigger") { - $("#fldTimeOfDay", page).show(); - $("#fldDayOfWeek", page).show(); - $("#fldSelectSystemEvent", page).hide(); - $("#fldSelectInterval", page).hide(); - $("#selectTimeOfDay", page).attr("required", "required"); - } else if (triggerType == "SystemEventTrigger") { - $("#fldTimeOfDay", page).hide(); - $("#fldDayOfWeek", page).hide(); - $("#fldSelectSystemEvent", page).show(); - $("#fldSelectInterval", page).hide(); - $("#selectTimeOfDay", page).removeAttr("required"); - } else if (triggerType == "IntervalTrigger") { - $("#fldTimeOfDay", page).hide(); - $("#fldDayOfWeek", page).hide(); - $("#fldSelectSystemEvent", page).hide(); - $("#fldSelectInterval", page).show(); - $("#selectTimeOfDay", page).removeAttr("required"); - } else if (triggerType == "StartupTrigger") { - $("#fldTimeOfDay", page).hide(); - $("#fldDayOfWeek", page).hide(); - $("#fldSelectSystemEvent", page).hide(); - $("#fldSelectInterval", page).hide(); - $("#selectTimeOfDay", page).removeAttr("required"); + if (triggerType == 'DailyTrigger') { + $('#fldTimeOfDay', page).show(); + $('#fldDayOfWeek', page).hide(); + $('#fldSelectSystemEvent', page).hide(); + $('#fldSelectInterval', page).hide(); + $('#selectTimeOfDay', page).attr('required', 'required'); + } else if (triggerType == 'WeeklyTrigger') { + $('#fldTimeOfDay', page).show(); + $('#fldDayOfWeek', page).show(); + $('#fldSelectSystemEvent', page).hide(); + $('#fldSelectInterval', page).hide(); + $('#selectTimeOfDay', page).attr('required', 'required'); + } else if (triggerType == 'SystemEventTrigger') { + $('#fldTimeOfDay', page).hide(); + $('#fldDayOfWeek', page).hide(); + $('#fldSelectSystemEvent', page).show(); + $('#fldSelectInterval', page).hide(); + $('#selectTimeOfDay', page).removeAttr('required'); + } else if (triggerType == 'IntervalTrigger') { + $('#fldTimeOfDay', page).hide(); + $('#fldDayOfWeek', page).hide(); + $('#fldSelectSystemEvent', page).hide(); + $('#fldSelectInterval', page).show(); + $('#selectTimeOfDay', page).removeAttr('required'); + } else if (triggerType == 'StartupTrigger') { + $('#fldTimeOfDay', page).hide(); + $('#fldDayOfWeek', page).hide(); + $('#fldSelectSystemEvent', page).hide(); + $('#fldSelectInterval', page).hide(); + $('#selectTimeOfDay', page).removeAttr('required'); } }, getTriggerToAdd: function (page) { var trigger = { - Type: $("#selectTriggerType", page).val() + Type: $('#selectTriggerType', page).val() }; - if (trigger.Type == "DailyTrigger") { - trigger.TimeOfDayTicks = $("#selectTimeOfDay", page).val(); - } else if (trigger.Type == "WeeklyTrigger") { - trigger.DayOfWeek = $("#selectDayOfWeek", page).val(); - trigger.TimeOfDayTicks = $("#selectTimeOfDay", page).val(); - } else if (trigger.Type == "SystemEventTrigger") { - trigger.SystemEvent = $("#selectSystemEvent", page).val(); - } else if (trigger.Type == "IntervalTrigger") { - trigger.IntervalTicks = $("#selectInterval", page).val(); + if (trigger.Type == 'DailyTrigger') { + trigger.TimeOfDayTicks = $('#selectTimeOfDay', page).val(); + } else if (trigger.Type == 'WeeklyTrigger') { + trigger.DayOfWeek = $('#selectDayOfWeek', page).val(); + trigger.TimeOfDayTicks = $('#selectTimeOfDay', page).val(); + } else if (trigger.Type == 'SystemEventTrigger') { + trigger.SystemEvent = $('#selectSystemEvent', page).val(); + } else if (trigger.Type == 'IntervalTrigger') { + trigger.IntervalTicks = $('#selectInterval', page).val(); } - var timeLimit = $("#txtTimeLimit", page).val() || "0"; + var timeLimit = $('#txtTimeLimit', page).val() || '0'; timeLimit = parseFloat(timeLimit) * 3600000; trigger.MaxRuntimeMs = timeLimit || null; @@ -203,34 +205,34 @@ define(["jQuery", "loading", "datetime", "dom", "globalize", "emby-input", "emby return function (view, params) { function onSubmit(e) { loading.show(); - var id = getParameterByName("id"); + var id = getParameterByName('id'); ApiClient.getScheduledTask(id).then(function (task) { task.Triggers.push(ScheduledTaskPage.getTriggerToAdd(view)); ApiClient.updateScheduledTaskTriggers(task.Id, task.Triggers).then(function () { - $("#popupAddTrigger").addClass("hide"); + $('#popupAddTrigger').addClass('hide'); ScheduledTaskPage.refreshScheduledTask(view); }); }); e.preventDefault(); } - view.querySelector(".addTriggerForm").addEventListener("submit", onSubmit); - fillTimeOfDay(view.querySelector("#selectTimeOfDay")); - $(view.querySelector("#popupAddTrigger").parentNode).trigger("create"); - view.querySelector(".selectTriggerType").addEventListener("change", function () { + view.querySelector('.addTriggerForm').addEventListener('submit', onSubmit); + fillTimeOfDay(view.querySelector('#selectTimeOfDay')); + $(view.querySelector('#popupAddTrigger').parentNode).trigger('create'); + view.querySelector('.selectTriggerType').addEventListener('change', function () { ScheduledTaskPage.refreshTriggerFields(view, this.value); }); - view.querySelector(".btnAddTrigger").addEventListener("click", function () { + view.querySelector('.btnAddTrigger').addEventListener('click', function () { ScheduledTaskPage.showAddTriggerPopup(view); }); - view.addEventListener("click", function (e) { - var btnDeleteTrigger = dom.parentWithClass(e.target, "btnDeleteTrigger"); + view.addEventListener('click', function (e) { + var btnDeleteTrigger = dom.parentWithClass(e.target, 'btnDeleteTrigger'); if (btnDeleteTrigger) { - ScheduledTaskPage.confirmDeleteTrigger(view, parseInt(btnDeleteTrigger.getAttribute("data-index"))); + ScheduledTaskPage.confirmDeleteTrigger(view, parseInt(btnDeleteTrigger.getAttribute('data-index'))); } }); - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { ScheduledTaskPage.refreshScheduledTask(view); }); }; diff --git a/src/controllers/dashboard/scheduledtasks/scheduledtasks.js b/src/controllers/dashboard/scheduledtasks/scheduledtasks.js index 87297dbcf3..5ce53cf6fe 100644 --- a/src/controllers/dashboard/scheduledtasks/scheduledtasks.js +++ b/src/controllers/dashboard/scheduledtasks/scheduledtasks.js @@ -1,5 +1,5 @@ -define(["jQuery", "loading", "events", "globalize", "serverNotifications", "humanedate", "listViewStyle", "emby-button"], function($, loading, events, globalize, serverNotifications) { - "use strict"; +define(['jQuery', 'loading', 'events', 'globalize', 'serverNotifications', 'date-fns', 'dfnshelper', 'listViewStyle', 'emby-button'], function ($, loading, events, globalize, serverNotifications, datefns, dfnshelper) { + 'use strict'; function reloadList(page) { ApiClient.getScheduledTasks({ @@ -7,110 +7,119 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma }).then(function(tasks) { populateList(page, tasks); loading.hide(); - }) + }); } function populateList(page, tasks) { tasks = tasks.sort(function(a, b) { - a = a.Category + " " + a.Name; - b = b.Category + " " + b.Name; + a = a.Category + ' ' + a.Name; + b = b.Category + ' ' + b.Name; return a == b ? 0 : a < b ? -1 : 1; }); var currentCategory; - var html = ""; + var html = ''; for (var i = 0; i < tasks.length; i++) { var task = tasks[i]; if (task.Category != currentCategory) { currentCategory = task.Category; if (currentCategory) { - html += ""; - html += ""; + html += ''; + html += ''; } html += '
'; html += '
'; html += '

'; html += currentCategory; - html += "

"; + html += ''; if (i === 0) { - html += '' + globalize.translate("Help") + ""; + html += '' + globalize.translate('Help') + ''; } - html += "
"; + html += '
'; html += '
'; } html += '
'; html += ""; - html += 'schedule'; - html += ""; + html += ''; + html += ''; html += '"; - if (task.State === "Running") { - html += ''; - } else if (task.State === "Idle") { - html += ''; + html += "

" + task.Name + '

'; + html += "
" + getTaskProgressHtml(task) + '
'; + html += ''; + html += '
'; + if (task.State === 'Running') { + html += ''; + } else if (task.State === 'Idle') { + html += ''; } - html += "
"; + html += ''; } if (tasks.length) { - html += ""; - html += ""; + html += ''; + html += ''; } - page.querySelector(".divScheduledTasks").innerHTML = html; + page.querySelector('.divScheduledTasks').innerHTML = html; } function getTaskProgressHtml(task) { - var html = ""; - if (task.State === "Idle") { + var html = ''; + if (task.State === 'Idle') { if (task.LastExecutionResult) { - html += globalize.translate("LabelScheduledTaskLastRan").replace("{0}", humaneDate(task.LastExecutionResult.EndTimeUtc)).replace("{1}", humaneElapsed(task.LastExecutionResult.StartTimeUtc, task.LastExecutionResult.EndTimeUtc)); - if (task.LastExecutionResult.Status === "Failed") { - html += " (" + globalize.translate("LabelFailed") + ")"; - } else if (task.LastExecutionResult.Status === "Cancelled") { - html += " (" + globalize.translate("LabelCancelled") + ")"; - } else if (task.LastExecutionResult.Status === "Aborted") { - html += " " + globalize.translate("LabelAbortedByServerShutdown") + ""; + var endtime = Date.parse(task.LastExecutionResult.EndTimeUtc); + var starttime = Date.parse(task.LastExecutionResult.StartTimeUtc); + html += globalize.translate('LabelScheduledTaskLastRan', datefns.formatDistanceToNow(endtime, dfnshelper.localeWithSuffix), + datefns.formatDistance(starttime, endtime, { locale: dfnshelper.getLocale() })); + if (task.LastExecutionResult.Status === 'Failed') { + html += " (" + globalize.translate('LabelFailed') + ')'; + } else if (task.LastExecutionResult.Status === 'Cancelled') { + html += " (" + globalize.translate('LabelCancelled') + ')'; + } else if (task.LastExecutionResult.Status === 'Aborted') { + html += " " + globalize.translate('LabelAbortedByServerShutdown') + ''; } } - } else if (task.State === "Running") { + } else if (task.State === 'Running') { var progress = (task.CurrentProgressPercentage || 0).toFixed(1); html += '
'; html += '
'; html += '
'; - html += "
"; - html += "
"; - html += "" + progress + "%"; - html += "
"; + html += ''; + html += ''; + html += "" + progress + '%'; + html += ''; } else { - html += "" + globalize.translate("LabelStopping") + ""; + html += "" + globalize.translate('LabelStopping') + ''; } return html; } + function setTaskButtonIcon(button, icon) { + var inner = button.querySelector('.material-icons'); + inner.classList.remove('stop', 'play_arrow'); + inner.classList.add(icon); + } + function updateTaskButton(elem, state) { - if (state === "Running") { - elem.classList.remove("btnStartTask"); - elem.classList.add("btnStopTask"); - elem.querySelector("i").innerHTML = "stop"; - elem.title = globalize.translate("ButtonStop"); - } else if (state === "Idle") { - elem.classList.add("btnStartTask"); - elem.classList.remove("btnStopTask"); - elem.querySelector("i").innerHTML = "play_arrow"; - elem.title = globalize.translate("ButtonStart"); + if (state === 'Running') { + elem.classList.remove('btnStartTask'); + elem.classList.add('btnStopTask'); + setTaskButtonIcon(elem, 'stop'); + elem.title = globalize.translate('ButtonStop'); + } else if (state === 'Idle') { + elem.classList.add('btnStartTask'); + elem.classList.remove('btnStopTask'); + setTaskButtonIcon(elem, 'play_arrow'); + elem.title = globalize.translate('ButtonStart'); } - $(elem).parents(".listItem")[0].setAttribute("data-status", state); + $(elem).parents('.listItem')[0].setAttribute('data-status', state); } return function(view, params) { function updateTasks(tasks) { for (var i = 0; i < tasks.length; i++) { var task = tasks[i]; - view.querySelector("#taskProgress" + task.Id).innerHTML = getTaskProgressHtml(task); - updateTaskButton(view.querySelector("#btnTask" + task.Id), task.State); + view.querySelector('#taskProgress' + task.Id).innerHTML = getTaskProgressHtml(task); + updateTaskButton(view.querySelector('#btnTask' + task.Id), task.State); } } @@ -127,47 +136,47 @@ define(["jQuery", "loading", "events", "globalize", "serverNotifications", "huma } function startInterval() { - ApiClient.sendMessage("ScheduledTasksInfoStart", "1000,1000"); + ApiClient.sendMessage('ScheduledTasksInfoStart', '1000,1000'); pollInterval && clearInterval(pollInterval); pollInterval = setInterval(onPollIntervalFired, 1e4); } function stopInterval() { - ApiClient.sendMessage("ScheduledTasksInfoStop"); + ApiClient.sendMessage('ScheduledTasksInfoStop'); pollInterval && clearInterval(pollInterval); } var pollInterval; var serverId = ApiClient.serverId(); - $(".divScheduledTasks", view).on("click", ".btnStartTask", function() { + $('.divScheduledTasks', view).on('click', '.btnStartTask', function() { var button = this; - var id = button.getAttribute("data-taskid"); + var id = button.getAttribute('data-taskid'); ApiClient.startScheduledTask(id).then(function() { - updateTaskButton(button, "Running"); + updateTaskButton(button, 'Running'); reloadList(view); - }) + }); }); - $(".divScheduledTasks", view).on("click", ".btnStopTask", function() { + $('.divScheduledTasks', view).on('click', '.btnStopTask', function() { var button = this; - var id = button.getAttribute("data-taskid"); + var id = button.getAttribute('data-taskid'); ApiClient.stopScheduledTask(id).then(function() { - updateTaskButton(button, ""); + updateTaskButton(button, ''); reloadList(view); - }) + }); }); - view.addEventListener("viewbeforehide", function() { - events.off(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + view.addEventListener('viewbeforehide', function() { + events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); stopInterval(); }); - view.addEventListener("viewshow", function() { + view.addEventListener('viewshow', function() { loading.show(); startInterval(); reloadList(view); - events.on(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); }); - } + }; }); diff --git a/src/controllers/dashboard/serveractivity.js b/src/controllers/dashboard/serveractivity.js new file mode 100644 index 0000000000..c48a2903ae --- /dev/null +++ b/src/controllers/dashboard/serveractivity.js @@ -0,0 +1,31 @@ +define(['components/activitylog', 'globalize'], function (ActivityLog, globalize) { + 'use strict'; + + return function (view, params) { + var activityLog; + + if (params.useractivity !== 'false') { + view.querySelector('.activityItems').setAttribute('data-useractivity', 'true'); + view.querySelector('.sectionTitle').innerHTML = globalize.translate('HeaderActivity'); + } else { + view.querySelector('.activityItems').setAttribute('data-useractivity', 'false'); + view.querySelector('.sectionTitle').innerHTML = globalize.translate('Alerts'); + } + + view.addEventListener('viewshow', function () { + if (!activityLog) { + activityLog = new ActivityLog({ + serverId: ApiClient.serverId(), + element: view.querySelector('.activityItems') + }); + } + }); + view.addEventListener('viewdestroy', function () { + if (activityLog) { + activityLog.destroy(); + } + + activityLog = null; + }); + }; +}); diff --git a/src/controllers/dashboard/streamingsettings.js b/src/controllers/dashboard/streamingsettings.js new file mode 100644 index 0000000000..37afe5a054 --- /dev/null +++ b/src/controllers/dashboard/streamingsettings.js @@ -0,0 +1,43 @@ +define(['jQuery', 'libraryMenu', 'loading', 'globalize'], function ($, libraryMenu, loading, globalize) { + 'use strict'; + + function loadPage(page, config) { + $('#txtRemoteClientBitrateLimit', page).val(config.RemoteClientBitrateLimit / 1e6 || ''); + loading.hide(); + } + + function onSubmit() { + loading.show(); + var form = this; + ApiClient.getServerConfiguration().then(function (config) { + config.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', form).val() || '0')); + ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); + }); + + return false; + } + + function getTabs() { + return [{ + href: 'encodingsettings.html', + name: globalize.translate('Transcoding') + }, { + href: 'playbackconfiguration.html', + name: globalize.translate('TabResumeSettings') + }, { + href: 'streamingsettings.html', + name: globalize.translate('TabStreaming') + }]; + } + + $(document).on('pageinit', '#streamingSettingsPage', function () { + $('.streamingSettingsForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#streamingSettingsPage', function () { + loading.show(); + libraryMenu.setTabs('playback', 2, getTabs); + var page = this; + ApiClient.getServerConfiguration().then(function (config) { + loadPage(page, config); + }); + }); +}); diff --git a/src/controllers/device.js b/src/controllers/device.js deleted file mode 100644 index cfe7efbe73..0000000000 --- a/src/controllers/device.js +++ /dev/null @@ -1,50 +0,0 @@ -define(["loading", "libraryMenu", "dom", "emby-input", "emby-button"], function (loading, libraryMenu, dom) { - "use strict"; - - function load(page, device, deviceOptions) { - page.querySelector("#txtCustomName", page).value = deviceOptions.CustomName || ""; - page.querySelector(".reportedName", page).innerHTML = device.Name || ""; - } - - function loadData() { - var page = this; - loading.show(); - var id = getParameterByName("id"); - var promise1 = ApiClient.getJSON(ApiClient.getUrl("Devices/Info", { - Id: id - })); - var promise2 = ApiClient.getJSON(ApiClient.getUrl("Devices/Options", { - Id: id - })); - Promise.all([promise1, promise2]).then(function (responses) { - load(page, responses[0], responses[1]); - loading.hide(); - }); - } - - function save(page) { - var id = getParameterByName("id"); - ApiClient.ajax({ - url: ApiClient.getUrl("Devices/Options", { - Id: id - }), - type: "POST", - data: JSON.stringify({ - CustomName: page.querySelector("#txtCustomName").value - }), - contentType: "application/json" - }).then(Dashboard.processServerConfigurationUpdateResult); - } - - function onSubmit(e) { - var form = this; - save(dom.parentWithClass(form, "page")); - e.preventDefault(); - return false; - } - - return function (view, params) { - view.querySelector("form").addEventListener("submit", onSubmit); - view.addEventListener("viewshow", loadData); - }; -}); diff --git a/src/controllers/dlnaprofile.js b/src/controllers/dlnaprofile.js deleted file mode 100644 index e9239693d8..0000000000 --- a/src/controllers/dlnaprofile.js +++ /dev/null @@ -1,829 +0,0 @@ -define(["jQuery", "loading", "fnchecked", "emby-select", "emby-button", "emby-input", "emby-checkbox", "listViewStyle", "emby-button"], function ($, loading) { - "use strict"; - - function loadProfile(page) { - loading.show(); - var promise1 = getProfile(); - var promise2 = ApiClient.getUsers(); - Promise.all([promise1, promise2]).then(function (responses) { - currentProfile = responses[0]; - renderProfile(page, currentProfile, responses[1]); - loading.hide(); - }); - } - - function getProfile() { - var id = getParameterByName("id"); - var url = id ? "Dlna/Profiles/" + id : "Dlna/Profiles/Default"; - return ApiClient.getJSON(ApiClient.getUrl(url)); - } - - function renderProfile(page, profile, users) { - $("#txtName", page).val(profile.Name); - $(".chkMediaType", page).each(function () { - this.checked = -1 != (profile.SupportedMediaTypes || "").split(",").indexOf(this.getAttribute("data-value")); - }); - $("#chkEnableAlbumArtInDidl", page).checked(profile.EnableAlbumArtInDidl); - $("#chkEnableSingleImageLimit", page).checked(profile.EnableSingleAlbumArtLimit); - renderXmlDocumentAttributes(page, profile.XmlRootAttributes || []); - var idInfo = profile.Identification || {}; - renderIdentificationHeaders(page, idInfo.Headers || []); - renderSubtitleProfiles(page, profile.SubtitleProfiles || []); - $("#txtInfoFriendlyName", page).val(profile.FriendlyName || ""); - $("#txtInfoModelName", page).val(profile.ModelName || ""); - $("#txtInfoModelNumber", page).val(profile.ModelNumber || ""); - $("#txtInfoModelDescription", page).val(profile.ModelDescription || ""); - $("#txtInfoModelUrl", page).val(profile.ModelUrl || ""); - $("#txtInfoManufacturer", page).val(profile.Manufacturer || ""); - $("#txtInfoManufacturerUrl", page).val(profile.ManufacturerUrl || ""); - $("#txtInfoSerialNumber", page).val(profile.SerialNumber || ""); - $("#txtIdFriendlyName", page).val(idInfo.FriendlyName || ""); - $("#txtIdModelName", page).val(idInfo.ModelName || ""); - $("#txtIdModelNumber", page).val(idInfo.ModelNumber || ""); - $("#txtIdModelDescription", page).val(idInfo.ModelDescription || ""); - $("#txtIdModelUrl", page).val(idInfo.ModelUrl || ""); - $("#txtIdManufacturer", page).val(idInfo.Manufacturer || ""); - $("#txtIdManufacturerUrl", page).val(idInfo.ManufacturerUrl || ""); - $("#txtIdSerialNumber", page).val(idInfo.SerialNumber || ""); - $("#txtIdDeviceDescription", page).val(idInfo.DeviceDescription || ""); - $("#txtAlbumArtPn", page).val(profile.AlbumArtPn || ""); - $("#txtAlbumArtMaxWidth", page).val(profile.MaxAlbumArtWidth || ""); - $("#txtAlbumArtMaxHeight", page).val(profile.MaxAlbumArtHeight || ""); - $("#txtIconMaxWidth", page).val(profile.MaxIconWidth || ""); - $("#txtIconMaxHeight", page).val(profile.MaxIconHeight || ""); - $("#chkIgnoreTranscodeByteRangeRequests", page).checked(profile.IgnoreTranscodeByteRangeRequests); - $("#txtMaxAllowedBitrate", page).val(profile.MaxStreamingBitrate || ""); - $("#txtMusicStreamingTranscodingBitrate", page).val(profile.MusicStreamingTranscodingBitrate || ""); - $("#chkRequiresPlainFolders", page).checked(profile.RequiresPlainFolders); - $("#chkRequiresPlainVideoItems", page).checked(profile.RequiresPlainVideoItems); - $("#txtProtocolInfo", page).val(profile.ProtocolInfo || ""); - $("#txtXDlnaCap", page).val(profile.XDlnaCap || ""); - $("#txtXDlnaDoc", page).val(profile.XDlnaDoc || ""); - $("#txtSonyAggregationFlags", page).val(profile.SonyAggregationFlags || ""); - profile.DirectPlayProfiles = profile.DirectPlayProfiles || []; - profile.TranscodingProfiles = profile.TranscodingProfiles || []; - profile.ContainerProfiles = profile.ContainerProfiles || []; - profile.CodecProfiles = profile.CodecProfiles || []; - profile.ResponseProfiles = profile.ResponseProfiles || []; - var usersHtml = "" + users.map(function (u) { - return '"; - }).join(""); - $("#selectUser", page).html(usersHtml).val(profile.UserId || ""); - renderSubProfiles(page, profile); - } - - function renderIdentificationHeaders(page, headers) { - var index = 0; - var html = '
' + headers.map(function (h) { - var li = '
'; - li += 'info'; - li += '
'; - li += '

' + h.Name + ": " + (h.Value || "") + "

"; - li += '
' + (h.Match || "") + "
"; - li += "
"; - li += ''; - li += "
"; - index++; - return li; - }).join("") + "
"; - var elem = $(".httpHeaderIdentificationList", page).html(html).trigger("create"); - $(".btnDeleteIdentificationHeader", elem).on("click", function () { - var itemIndex = parseInt(this.getAttribute("data-index")); - currentProfile.Identification.Headers.splice(itemIndex, 1); - renderIdentificationHeaders(page, currentProfile.Identification.Headers); - }); - } - - function openPopup(elem) { - elem.classList.remove("hide"); - } - - function closePopup(elem) { - elem.classList.add("hide"); - } - - function editIdentificationHeader(page, header) { - isSubProfileNew = null == header; - header = header || {}; - currentSubProfile = header; - var popup = $("#identificationHeaderPopup", page); - $("#txtIdentificationHeaderName", popup).val(header.Name || ""); - $("#txtIdentificationHeaderValue", popup).val(header.Value || ""); - $("#selectMatchType", popup).val(header.Match || "Equals"); - openPopup(popup[0]); - } - - function saveIdentificationHeader(page) { - currentSubProfile.Name = $("#txtIdentificationHeaderName", page).val(); - currentSubProfile.Value = $("#txtIdentificationHeaderValue", page).val(); - currentSubProfile.Match = $("#selectMatchType", page).val(); - - if (isSubProfileNew) { - currentProfile.Identification = currentProfile.Identification || {}; - currentProfile.Identification.Headers = currentProfile.Identification.Headers || []; - currentProfile.Identification.Headers.push(currentSubProfile); - } - - renderIdentificationHeaders(page, currentProfile.Identification.Headers); - currentSubProfile = null; - closePopup($("#identificationHeaderPopup", page)[0]); - } - - function renderXmlDocumentAttributes(page, attribute) { - var html = '
' + attribute.map(function (h) { - var li = '
'; - li += 'info'; - li += '
'; - li += '

' + h.Name + " = " + (h.Value || "") + "

"; - li += "
"; - li += ''; - return li += "
"; - }).join("") + "
"; - var elem = $(".xmlDocumentAttributeList", page).html(html).trigger("create"); - $(".btnDeleteXmlAttribute", elem).on("click", function () { - var itemIndex = parseInt(this.getAttribute("data-index")); - currentProfile.XmlRootAttributes.splice(itemIndex, 1); - renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes); - }); - } - - function editXmlDocumentAttribute(page, attribute) { - isSubProfileNew = null == attribute; - attribute = attribute || {}; - currentSubProfile = attribute; - var popup = $("#xmlAttributePopup", page); - $("#txtXmlAttributeName", popup).val(attribute.Name || ""); - $("#txtXmlAttributeValue", popup).val(attribute.Value || ""); - openPopup(popup[0]); - } - - function saveXmlDocumentAttribute(page) { - currentSubProfile.Name = $("#txtXmlAttributeName", page).val(); - currentSubProfile.Value = $("#txtXmlAttributeValue", page).val(); - - if (isSubProfileNew) { - currentProfile.XmlRootAttributes.push(currentSubProfile); - } - - renderXmlDocumentAttributes(page, currentProfile.XmlRootAttributes); - currentSubProfile = null; - closePopup($("#xmlAttributePopup", page)[0]); - } - - function renderSubtitleProfiles(page, profiles) { - var index = 0; - var html = '
' + profiles.map(function (h) { - var li = '
'; - li += 'info'; - li += '
'; - li += '

' + (h.Format || "") + "

"; - li += "
"; - li += ''; - li += "
"; - index++; - return li; - }).join("") + "
"; - var elem = $(".subtitleProfileList", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var itemIndex = parseInt(this.getAttribute("data-index")); - currentProfile.SubtitleProfiles.splice(itemIndex, 1); - renderSubtitleProfiles(page, currentProfile.SubtitleProfiles); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var itemIndex = parseInt(this.getAttribute("data-index")); - editSubtitleProfile(page, currentProfile.SubtitleProfiles[itemIndex]); - }); - } - - function editSubtitleProfile(page, profile) { - isSubProfileNew = null == profile; - profile = profile || {}; - currentSubProfile = profile; - var popup = $("#subtitleProfilePopup", page); - $("#txtSubtitleProfileFormat", popup).val(profile.Format || ""); - $("#selectSubtitleProfileMethod", popup).val(profile.Method || ""); - $("#selectSubtitleProfileDidlMode", popup).val(profile.DidlMode || ""); - openPopup(popup[0]); - } - - function saveSubtitleProfile(page) { - currentSubProfile.Format = $("#txtSubtitleProfileFormat", page).val(); - currentSubProfile.Method = $("#selectSubtitleProfileMethod", page).val(); - currentSubProfile.DidlMode = $("#selectSubtitleProfileDidlMode", page).val(); - - if (isSubProfileNew) { - currentProfile.SubtitleProfiles.push(currentSubProfile); - } - - renderSubtitleProfiles(page, currentProfile.SubtitleProfiles); - currentSubProfile = null; - closePopup($("#subtitleProfilePopup", page)[0]); - } - - function renderSubProfiles(page, profile) { - renderDirectPlayProfiles(page, profile.DirectPlayProfiles); - renderTranscodingProfiles(page, profile.TranscodingProfiles); - renderContainerProfiles(page, profile.ContainerProfiles); - renderCodecProfiles(page, profile.CodecProfiles); - renderResponseProfiles(page, profile.ResponseProfiles); - } - - function saveDirectPlayProfile(page) { - currentSubProfile.Type = $("#selectDirectPlayProfileType", page).val(); - currentSubProfile.Container = $("#txtDirectPlayContainer", page).val(); - currentSubProfile.AudioCodec = $("#txtDirectPlayAudioCodec", page).val(); - currentSubProfile.VideoCodec = $("#txtDirectPlayVideoCodec", page).val(); - - if (isSubProfileNew) { - currentProfile.DirectPlayProfiles.push(currentSubProfile); - } - - renderSubProfiles(page, currentProfile); - currentSubProfile = null; - closePopup($("#popupEditDirectPlayProfile", page)[0]); - } - - function renderDirectPlayProfiles(page, profiles) { - var html = ""; - html += '"; - var elem = $(".directPlayProfiles", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var index = this.getAttribute("data-profileindex"); - deleteDirectPlayProfile(page, index); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var index = parseInt(this.getAttribute("data-profileindex")); - editDirectPlayProfile(page, currentProfile.DirectPlayProfiles[index]); - }); - } - - function deleteDirectPlayProfile(page, index) { - currentProfile.DirectPlayProfiles.splice(index, 1); - renderDirectPlayProfiles(page, currentProfile.DirectPlayProfiles); - } - - function editDirectPlayProfile(page, directPlayProfile) { - isSubProfileNew = null == directPlayProfile; - directPlayProfile = directPlayProfile || {}; - currentSubProfile = directPlayProfile; - var popup = $("#popupEditDirectPlayProfile", page); - $("#selectDirectPlayProfileType", popup).val(directPlayProfile.Type || "Video").trigger("change"); - $("#txtDirectPlayContainer", popup).val(directPlayProfile.Container || ""); - $("#txtDirectPlayAudioCodec", popup).val(directPlayProfile.AudioCodec || ""); - $("#txtDirectPlayVideoCodec", popup).val(directPlayProfile.VideoCodec || ""); - openPopup(popup[0]); - } - - function renderTranscodingProfiles(page, profiles) { - var html = ""; - html += '"; - var elem = $(".transcodingProfiles", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var index = this.getAttribute("data-profileindex"); - deleteTranscodingProfile(page, index); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var index = parseInt(this.getAttribute("data-profileindex")); - editTranscodingProfile(page, currentProfile.TranscodingProfiles[index]); - }); - } - - function editTranscodingProfile(page, transcodingProfile) { - isSubProfileNew = null == transcodingProfile; - transcodingProfile = transcodingProfile || {}; - currentSubProfile = transcodingProfile; - var popup = $("#transcodingProfilePopup", page); - $("#selectTranscodingProfileType", popup).val(transcodingProfile.Type || "Video").trigger("change"); - $("#txtTranscodingContainer", popup).val(transcodingProfile.Container || ""); - $("#txtTranscodingAudioCodec", popup).val(transcodingProfile.AudioCodec || ""); - $("#txtTranscodingVideoCodec", popup).val(transcodingProfile.VideoCodec || ""); - $("#selectTranscodingProtocol", popup).val(transcodingProfile.Protocol || "Http"); - $("#chkEnableMpegtsM2TsMode", popup).checked(transcodingProfile.EnableMpegtsM2TsMode || false); - $("#chkEstimateContentLength", popup).checked(transcodingProfile.EstimateContentLength || false); - $("#chkReportByteRangeRequests", popup).checked("Bytes" == transcodingProfile.TranscodeSeekInfo); - $(".radioTabButton:first", popup).trigger("click"); - openPopup(popup[0]); - } - - function deleteTranscodingProfile(page, index) { - currentProfile.TranscodingProfiles.splice(index, 1); - renderTranscodingProfiles(page, currentProfile.TranscodingProfiles); - } - - function saveTranscodingProfile(page) { - currentSubProfile.Type = $("#selectTranscodingProfileType", page).val(); - currentSubProfile.Container = $("#txtTranscodingContainer", page).val(); - currentSubProfile.AudioCodec = $("#txtTranscodingAudioCodec", page).val(); - currentSubProfile.VideoCodec = $("#txtTranscodingVideoCodec", page).val(); - currentSubProfile.Protocol = $("#selectTranscodingProtocol", page).val(); - currentSubProfile.Context = "Streaming"; - currentSubProfile.EnableMpegtsM2TsMode = $("#chkEnableMpegtsM2TsMode", page).checked(); - currentSubProfile.EstimateContentLength = $("#chkEstimateContentLength", page).checked(); - currentSubProfile.TranscodeSeekInfo = $("#chkReportByteRangeRequests", page).checked() ? "Bytes" : "Auto"; - - if (isSubProfileNew) { - currentProfile.TranscodingProfiles.push(currentSubProfile); - } - - renderSubProfiles(page, currentProfile); - currentSubProfile = null; - closePopup($("#transcodingProfilePopup", page)[0]); - } - - function renderContainerProfiles(page, profiles) { - var html = ""; - html += '"; - var elem = $(".containerProfiles", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var index = this.getAttribute("data-profileindex"); - deleteContainerProfile(page, index); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var index = parseInt(this.getAttribute("data-profileindex")); - editContainerProfile(page, currentProfile.ContainerProfiles[index]); - }); - } - - function deleteContainerProfile(page, index) { - currentProfile.ContainerProfiles.splice(index, 1); - renderContainerProfiles(page, currentProfile.ContainerProfiles); - } - - function editContainerProfile(page, containerProfile) { - isSubProfileNew = null == containerProfile; - containerProfile = containerProfile || {}; - currentSubProfile = containerProfile; - var popup = $("#containerProfilePopup", page); - $("#selectContainerProfileType", popup).val(containerProfile.Type || "Video").trigger("change"); - $("#txtContainerProfileContainer", popup).val(containerProfile.Container || ""); - $(".radioTabButton:first", popup).trigger("click"); - openPopup(popup[0]); - } - - function saveContainerProfile(page) { - currentSubProfile.Type = $("#selectContainerProfileType", page).val(); - currentSubProfile.Container = $("#txtContainerProfileContainer", page).val(); - - if (isSubProfileNew) { - currentProfile.ContainerProfiles.push(currentSubProfile); - } - - renderSubProfiles(page, currentProfile); - currentSubProfile = null; - closePopup($("#containerProfilePopup", page)[0]); - } - - function renderCodecProfiles(page, profiles) { - var html = ""; - html += '"; - var elem = $(".codecProfiles", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var index = this.getAttribute("data-profileindex"); - deleteCodecProfile(page, index); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var index = parseInt(this.getAttribute("data-profileindex")); - editCodecProfile(page, currentProfile.CodecProfiles[index]); - }); - } - - function deleteCodecProfile(page, index) { - currentProfile.CodecProfiles.splice(index, 1); - renderCodecProfiles(page, currentProfile.CodecProfiles); - } - - function editCodecProfile(page, codecProfile) { - isSubProfileNew = null == codecProfile; - codecProfile = codecProfile || {}; - currentSubProfile = codecProfile; - var popup = $("#codecProfilePopup", page); - $("#selectCodecProfileType", popup).val(codecProfile.Type || "Video").trigger("change"); - $("#txtCodecProfileCodec", popup).val(codecProfile.Codec || ""); - $(".radioTabButton:first", popup).trigger("click"); - openPopup(popup[0]); - } - - function saveCodecProfile(page) { - currentSubProfile.Type = $("#selectCodecProfileType", page).val(); - currentSubProfile.Codec = $("#txtCodecProfileCodec", page).val(); - - if (isSubProfileNew) { - currentProfile.CodecProfiles.push(currentSubProfile); - } - - renderSubProfiles(page, currentProfile); - currentSubProfile = null; - closePopup($("#codecProfilePopup", page)[0]); - } - - function renderResponseProfiles(page, profiles) { - var html = ""; - html += '"; - var elem = $(".mediaProfiles", page).html(html).trigger("create"); - $(".btnDeleteProfile", elem).on("click", function () { - var index = this.getAttribute("data-profileindex"); - deleteResponseProfile(page, index); - }); - $(".lnkEditSubProfile", elem).on("click", function () { - var index = parseInt(this.getAttribute("data-profileindex")); - editResponseProfile(page, currentProfile.ResponseProfiles[index]); - }); - } - - function deleteResponseProfile(page, index) { - currentProfile.ResponseProfiles.splice(index, 1); - renderResponseProfiles(page, currentProfile.ResponseProfiles); - } - - function editResponseProfile(page, responseProfile) { - isSubProfileNew = null == responseProfile; - responseProfile = responseProfile || {}; - currentSubProfile = responseProfile; - var popup = $("#responseProfilePopup", page); - $("#selectResponseProfileType", popup).val(responseProfile.Type || "Video").trigger("change"); - $("#txtResponseProfileContainer", popup).val(responseProfile.Container || ""); - $("#txtResponseProfileAudioCodec", popup).val(responseProfile.AudioCodec || ""); - $("#txtResponseProfileVideoCodec", popup).val(responseProfile.VideoCodec || ""); - $(".radioTabButton:first", popup).trigger("click"); - openPopup(popup[0]); - } - - function saveResponseProfile(page) { - currentSubProfile.Type = $("#selectResponseProfileType", page).val(); - currentSubProfile.Container = $("#txtResponseProfileContainer", page).val(); - currentSubProfile.AudioCodec = $("#txtResponseProfileAudioCodec", page).val(); - currentSubProfile.VideoCodec = $("#txtResponseProfileVideoCodec", page).val(); - - if (isSubProfileNew) { - currentProfile.ResponseProfiles.push(currentSubProfile); - } - - renderSubProfiles(page, currentProfile); - currentSubProfile = null; - closePopup($("#responseProfilePopup", page)[0]); - } - - function saveProfile(page, profile) { - updateProfile(page, profile); - var id = getParameterByName("id"); - - if (id) { - ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("Dlna/Profiles/" + id), - data: JSON.stringify(profile), - contentType: "application/json" - }).then(function () { - require(["toast"], function (toast) { - toast("Settings saved."); - }); - }, Dashboard.processErrorResponse); - } else { - ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("Dlna/Profiles"), - data: JSON.stringify(profile), - contentType: "application/json" - }).then(function () { - Dashboard.navigate("dlnaprofiles.html"); - }, Dashboard.processErrorResponse); - } - - loading.hide(); - } - - function updateProfile(page, profile) { - profile.Name = $("#txtName", page).val(); - profile.EnableAlbumArtInDidl = $("#chkEnableAlbumArtInDidl", page).checked(); - profile.EnableSingleAlbumArtLimit = $("#chkEnableSingleImageLimit", page).checked(); - profile.SupportedMediaTypes = $(".chkMediaType:checked", page).get().map(function (c) { - return c.getAttribute("data-value"); - }).join(","); - profile.Identification = profile.Identification || {}; - profile.FriendlyName = $("#txtInfoFriendlyName", page).val(); - profile.ModelName = $("#txtInfoModelName", page).val(); - profile.ModelNumber = $("#txtInfoModelNumber", page).val(); - profile.ModelDescription = $("#txtInfoModelDescription", page).val(); - profile.ModelUrl = $("#txtInfoModelUrl", page).val(); - profile.Manufacturer = $("#txtInfoManufacturer", page).val(); - profile.ManufacturerUrl = $("#txtInfoManufacturerUrl", page).val(); - profile.SerialNumber = $("#txtInfoSerialNumber", page).val(); - profile.Identification.FriendlyName = $("#txtIdFriendlyName", page).val(); - profile.Identification.ModelName = $("#txtIdModelName", page).val(); - profile.Identification.ModelNumber = $("#txtIdModelNumber", page).val(); - profile.Identification.ModelDescription = $("#txtIdModelDescription", page).val(); - profile.Identification.ModelUrl = $("#txtIdModelUrl", page).val(); - profile.Identification.Manufacturer = $("#txtIdManufacturer", page).val(); - profile.Identification.ManufacturerUrl = $("#txtIdManufacturerUrl", page).val(); - profile.Identification.SerialNumber = $("#txtIdSerialNumber", page).val(); - profile.Identification.DeviceDescription = $("#txtIdDeviceDescription", page).val(); - profile.AlbumArtPn = $("#txtAlbumArtPn", page).val(); - profile.MaxAlbumArtWidth = $("#txtAlbumArtMaxWidth", page).val(); - profile.MaxAlbumArtHeight = $("#txtAlbumArtMaxHeight", page).val(); - profile.MaxIconWidth = $("#txtIconMaxWidth", page).val(); - profile.MaxIconHeight = $("#txtIconMaxHeight", page).val(); - profile.RequiresPlainFolders = $("#chkRequiresPlainFolders", page).checked(); - profile.RequiresPlainVideoItems = $("#chkRequiresPlainVideoItems", page).checked(); - profile.IgnoreTranscodeByteRangeRequests = $("#chkIgnoreTranscodeByteRangeRequests", page).checked(); - profile.MaxStreamingBitrate = $("#txtMaxAllowedBitrate", page).val(); - profile.MusicStreamingTranscodingBitrate = $("#txtMusicStreamingTranscodingBitrate", page).val(); - profile.ProtocolInfo = $("#txtProtocolInfo", page).val(); - profile.XDlnaCap = $("#txtXDlnaCap", page).val(); - profile.XDlnaDoc = $("#txtXDlnaDoc", page).val(); - profile.SonyAggregationFlags = $("#txtSonyAggregationFlags", page).val(); - profile.UserId = $("#selectUser", page).val(); - } - - var currentProfile; - var currentSubProfile; - var isSubProfileNew; - var allText = Globalize.translate("LabelAll"); - - $(document).on("pageinit", "#dlnaProfilePage", function () { - var page = this; - $(".radioTabButton", page).on("click", function () { - $(this).siblings().removeClass("ui-btn-active"); - $(this).addClass("ui-btn-active"); - var value = "A" == this.tagName ? this.getAttribute("data-value") : this.value; - var elem = $("." + value, page); - elem.siblings(".tabContent").hide(); - elem.show(); - }); - $("#selectDirectPlayProfileType", page).on("change", function () { - if ("Video" == this.value) { - $("#fldDirectPlayVideoCodec", page).show(); - } else { - $("#fldDirectPlayVideoCodec", page).hide(); - } - - if ("Photo" == this.value) { - $("#fldDirectPlayAudioCodec", page).hide(); - } else { - $("#fldDirectPlayAudioCodec", page).show(); - } - }); - $("#selectTranscodingProfileType", page).on("change", function () { - if ("Video" == this.value) { - $("#fldTranscodingVideoCodec", page).show(); - $("#fldTranscodingProtocol", page).show(); - $("#fldEnableMpegtsM2TsMode", page).show(); - } else { - $("#fldTranscodingVideoCodec", page).hide(); - $("#fldTranscodingProtocol", page).hide(); - $("#fldEnableMpegtsM2TsMode", page).hide(); - } - - if ("Photo" == this.value) { - $("#fldTranscodingAudioCodec", page).hide(); - $("#fldEstimateContentLength", page).hide(); - $("#fldReportByteRangeRequests", page).hide(); - } else { - $("#fldTranscodingAudioCodec", page).show(); - $("#fldEstimateContentLength", page).show(); - $("#fldReportByteRangeRequests", page).show(); - } - }); - $("#selectResponseProfileType", page).on("change", function () { - if ("Video" == this.value) { - $("#fldResponseProfileVideoCodec", page).show(); - } else { - $("#fldResponseProfileVideoCodec", page).hide(); - } - - if ("Photo" == this.value) { - $("#fldResponseProfileAudioCodec", page).hide(); - } else { - $("#fldResponseProfileAudioCodec", page).show(); - } - }); - $(".btnAddDirectPlayProfile", page).on("click", function () { - editDirectPlayProfile(page); - }); - $(".btnAddTranscodingProfile", page).on("click", function () { - editTranscodingProfile(page); - }); - $(".btnAddContainerProfile", page).on("click", function () { - editContainerProfile(page); - }); - $(".btnAddCodecProfile", page).on("click", function () { - editCodecProfile(page); - }); - $(".btnAddResponseProfile", page).on("click", function () { - editResponseProfile(page); - }); - $(".btnAddIdentificationHttpHeader", page).on("click", function () { - editIdentificationHeader(page); - }); - $(".btnAddXmlDocumentAttribute", page).on("click", function () { - editXmlDocumentAttribute(page); - }); - $(".btnAddSubtitleProfile", page).on("click", function () { - editSubtitleProfile(page); - }); - $(".dlnaProfileForm").off("submit", DlnaProfilePage.onSubmit).on("submit", DlnaProfilePage.onSubmit); - $(".editDirectPlayProfileForm").off("submit", DlnaProfilePage.onDirectPlayFormSubmit).on("submit", DlnaProfilePage.onDirectPlayFormSubmit); - $(".transcodingProfileForm").off("submit", DlnaProfilePage.onTranscodingProfileFormSubmit).on("submit", DlnaProfilePage.onTranscodingProfileFormSubmit); - $(".containerProfileForm").off("submit", DlnaProfilePage.onContainerProfileFormSubmit).on("submit", DlnaProfilePage.onContainerProfileFormSubmit); - $(".codecProfileForm").off("submit", DlnaProfilePage.onCodecProfileFormSubmit).on("submit", DlnaProfilePage.onCodecProfileFormSubmit); - $(".editResponseProfileForm").off("submit", DlnaProfilePage.onResponseProfileFormSubmit).on("submit", DlnaProfilePage.onResponseProfileFormSubmit); - $(".identificationHeaderForm").off("submit", DlnaProfilePage.onIdentificationHeaderFormSubmit).on("submit", DlnaProfilePage.onIdentificationHeaderFormSubmit); - $(".xmlAttributeForm").off("submit", DlnaProfilePage.onXmlAttributeFormSubmit).on("submit", DlnaProfilePage.onXmlAttributeFormSubmit); - $(".subtitleProfileForm").off("submit", DlnaProfilePage.onSubtitleProfileFormSubmit).on("submit", DlnaProfilePage.onSubtitleProfileFormSubmit); - }).on("pageshow", "#dlnaProfilePage", function () { - var page = this; - $("#radioInfo", page).trigger("click"); - loadProfile(page); - }); - window.DlnaProfilePage = { - onSubmit: function () { - loading.show(); - saveProfile($(this).parents(".page"), currentProfile); - return false; - }, - onDirectPlayFormSubmit: function () { - saveDirectPlayProfile($(this).parents(".page")); - return false; - }, - onTranscodingProfileFormSubmit: function () { - saveTranscodingProfile($(this).parents(".page")); - return false; - }, - onContainerProfileFormSubmit: function () { - saveContainerProfile($(this).parents(".page")); - return false; - }, - onCodecProfileFormSubmit: function () { - saveCodecProfile($(this).parents(".page")); - return false; - }, - onResponseProfileFormSubmit: function () { - saveResponseProfile($(this).parents(".page")); - return false; - }, - onIdentificationHeaderFormSubmit: function () { - saveIdentificationHeader($(this).parents(".page")); - return false; - }, - onXmlAttributeFormSubmit: function () { - saveXmlDocumentAttribute($(this).parents(".page")); - return false; - }, - onSubtitleProfileFormSubmit: function () { - saveSubtitleProfile($(this).parents(".page")); - return false; - } - }; -}); diff --git a/src/controllers/dlnaprofiles.js b/src/controllers/dlnaprofiles.js deleted file mode 100644 index ae708bcd4e..0000000000 --- a/src/controllers/dlnaprofiles.js +++ /dev/null @@ -1,89 +0,0 @@ -define(["jQuery", "globalize", "loading", "libraryMenu", "listViewStyle", "emby-button"], function ($, globalize, loading, libraryMenu) { - "use strict"; - - function loadProfiles(page) { - loading.show(); - ApiClient.getJSON(ApiClient.getUrl("Dlna/ProfileInfos")).then(function (result) { - renderUserProfiles(page, result); - renderSystemProfiles(page, result); - loading.hide(); - }); - } - - function renderUserProfiles(page, profiles) { - renderProfiles(page, page.querySelector(".customProfiles"), profiles.filter(function (p) { - return "User" == p.Type; - })); - } - - function renderSystemProfiles(page, profiles) { - renderProfiles(page, page.querySelector(".systemProfiles"), profiles.filter(function (p) { - return "System" == p.Type; - })); - } - - function renderProfiles(page, element, profiles) { - var html = ""; - - if (profiles.length) { - html += '
'; - } - - for (var i = 0, length = profiles.length; i < length; i++) { - var profile = profiles[i]; - html += '
'; - html += 'live_tv'; - html += '"; - - if ("User" == profile.Type) { - html += ''; - } - - html += "
"; - } - - if (profiles.length) { - html += "
"; - } - - element.innerHTML = html; - $(".btnDeleteProfile", element).on("click", function () { - var id = this.getAttribute("data-profileid"); - deleteProfile(page, id); - }); - } - - function deleteProfile(page, id) { - require(["confirm"], function (confirm) { - confirm(globalize.translate("MessageConfirmProfileDeletion"), globalize.translate("HeaderConfirmProfileDeletion")).then(function () { - loading.show(); - ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("Dlna/Profiles/" + id) - }).then(function () { - loading.hide(); - loadProfiles(page); - }); - }); - }); - } - - function getTabs() { - return [{ - href: "dlnasettings.html", - name: globalize.translate("TabSettings") - }, { - href: "dlnaprofiles.html", - name: globalize.translate("TabProfiles") - }]; - } - - $(document).on("pageshow", "#dlnaProfilesPage", function () { - libraryMenu.setTabs("dlna", 1, getTabs); - loadProfiles(this); - }); -}); diff --git a/src/controllers/dlnasettings.js b/src/controllers/dlnasettings.js deleted file mode 100644 index fbb3af1205..0000000000 --- a/src/controllers/dlnasettings.js +++ /dev/null @@ -1,56 +0,0 @@ -define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, libraryMenu) { - "use strict"; - - function loadPage(page, config, users) { - page.querySelector("#chkEnablePlayTo").checked = config.EnablePlayTo; - page.querySelector("#chkEnableDlnaDebugLogging").checked = config.EnableDebugLog; - $("#txtClientDiscoveryInterval", page).val(config.ClientDiscoveryIntervalSeconds); - $("#chkEnableServer", page).checked(config.EnableServer); - $("#chkBlastAliveMessages", page).checked(config.BlastAliveMessages); - $("#txtBlastInterval", page).val(config.BlastAliveMessageIntervalSeconds); - var usersHtml = users.map(function (u) { - return '"; - }).join(""); - $("#selectUser", page).html(usersHtml).val(config.DefaultUserId || ""); - loading.hide(); - } - - function onSubmit() { - loading.show(); - var form = this; - ApiClient.getNamedConfiguration("dlna").then(function (config) { - config.EnablePlayTo = form.querySelector("#chkEnablePlayTo").checked; - config.EnableDebugLog = form.querySelector("#chkEnableDlnaDebugLogging").checked; - config.ClientDiscoveryIntervalSeconds = $("#txtClientDiscoveryInterval", form).val(); - config.EnableServer = $("#chkEnableServer", form).checked(); - config.BlastAliveMessages = $("#chkBlastAliveMessages", form).checked(); - config.BlastAliveMessageIntervalSeconds = $("#txtBlastInterval", form).val(); - config.DefaultUserId = $("#selectUser", form).val(); - ApiClient.updateNamedConfiguration("dlna", config).then(Dashboard.processServerConfigurationUpdateResult); - }); - return false; - } - - function getTabs() { - return [{ - href: "dlnasettings.html", - name: Globalize.translate("TabSettings") - }, { - href: "dlnaprofiles.html", - name: Globalize.translate("TabProfiles") - }]; - } - - $(document).on("pageinit", "#dlnaSettingsPage", function () { - $(".dlnaSettingsForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#dlnaSettingsPage", function () { - libraryMenu.setTabs("dlna", 0, getTabs); - loading.show(); - var page = this; - var promise1 = ApiClient.getNamedConfiguration("dlna"); - var promise2 = ApiClient.getUsers(); - Promise.all([promise1, promise2]).then(function (responses) { - loadPage(page, responses[0], responses[1]); - }); - }); -}); diff --git a/src/controllers/edititemmetadata.js b/src/controllers/edititemmetadata.js index aba741d64c..2bfc5e560d 100644 --- a/src/controllers/edititemmetadata.js +++ b/src/controllers/edititemmetadata.js @@ -1,25 +1,25 @@ -define(["loading", "scripts/editorsidebar"], function (loading) { - "use strict"; +define(['loading', 'scripts/editorsidebar'], function (loading) { + 'use strict'; function reload(context, itemId) { loading.show(); if (itemId) { - require(["metadataEditor"], function (metadataEditor) { - metadataEditor.embed(context.querySelector(".editPageInnerContent"), itemId, ApiClient.serverInfo().Id); + require(['metadataEditor'], function (metadataEditor) { + metadataEditor.embed(context.querySelector('.editPageInnerContent'), itemId, ApiClient.serverInfo().Id); }); } else { - context.querySelector(".editPageInnerContent").innerHTML = ""; + context.querySelector('.editPageInnerContent').innerHTML = ''; loading.hide(); } } return function (view, params) { - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { reload(this, MetadataEditor.getCurrentItemId()); }); MetadataEditor.setCurrentItemId(null); - view.querySelector(".libraryTree").addEventListener("itemclicked", function (event) { + view.querySelector('.libraryTree').addEventListener('itemclicked', function (event) { var data = event.detail; if (data.id != MetadataEditor.getCurrentItemId()) { diff --git a/src/controllers/encodingsettings.js b/src/controllers/encodingsettings.js deleted file mode 100644 index f3dfd2706e..0000000000 --- a/src/controllers/encodingsettings.js +++ /dev/null @@ -1,181 +0,0 @@ -define(["jQuery", "loading", "globalize", "dom", "libraryMenu"], function ($, loading, globalize, dom, libraryMenu) { - "use strict"; - - function loadPage(page, config, systemInfo) { - Array.prototype.forEach.call(page.querySelectorAll(".chkDecodeCodec"), function (c) { - c.checked = -1 !== (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute("data-codec")); - }); - page.querySelector("#chkHardwareEncoding").checked = config.EnableHardwareEncoding; - $("#selectVideoDecoder", page).val(config.HardwareAccelerationType); - $("#selectThreadCount", page).val(config.EncodingThreadCount); - $("#txtDownMixAudioBoost", page).val(config.DownMixAudioBoost); - page.querySelector(".txtEncoderPath").value = config.EncoderAppPathDisplay || ""; - $("#txtTranscodingTempPath", page).val(systemInfo.TranscodingTempPath || ""); - $("#txtVaapiDevice", page).val(config.VaapiDevice || ""); - page.querySelector("#selectH264Preset").value = config.H264Preset || ""; - page.querySelector("#txtH264Crf").value = config.H264Crf || ""; - page.querySelector("#chkEnableSubtitleExtraction").checked = config.EnableSubtitleExtraction || false; - page.querySelector("#selectVideoDecoder").dispatchEvent(new CustomEvent("change", { - bubbles: true - })); - loading.hide(); - } - - function onSaveEncodingPathFailure(response) { - loading.hide(); - var msg = ""; - msg = globalize.translate("FFmpegSavePathNotFound"); - - require(["alert"], function (alert) { - alert(msg); - }); - } - - function updateEncoder(form) { - return ApiClient.getSystemInfo().then(function (systemInfo) { - return ApiClient.ajax({ - url: ApiClient.getUrl("System/MediaEncoder/Path"), - type: "POST", - data: { - Path: form.querySelector(".txtEncoderPath").value, - PathType: "Custom" - } - }).then(Dashboard.processServerConfigurationUpdateResult, onSaveEncodingPathFailure); - }); - } - - function onSubmit() { - var form = this; - - var onDecoderConfirmed = function () { - loading.show(); - ApiClient.getNamedConfiguration("encoding").then(function (config) { - config.DownMixAudioBoost = $("#txtDownMixAudioBoost", form).val(); - config.TranscodingTempPath = $("#txtTranscodingTempPath", form).val(); - config.EncodingThreadCount = $("#selectThreadCount", form).val(); - config.HardwareAccelerationType = $("#selectVideoDecoder", form).val(); - config.VaapiDevice = $("#txtVaapiDevice", form).val(); - config.H264Preset = form.querySelector("#selectH264Preset").value; - config.H264Crf = parseInt(form.querySelector("#txtH264Crf").value || "0"); - config.EnableSubtitleExtraction = form.querySelector("#chkEnableSubtitleExtraction").checked; - config.HardwareDecodingCodecs = Array.prototype.map.call(Array.prototype.filter.call(form.querySelectorAll(".chkDecodeCodec"), function (c) { - return c.checked; - }), function (c) { - return c.getAttribute("data-codec"); - }); - config.EnableHardwareEncoding = form.querySelector("#chkHardwareEncoding").checked; - ApiClient.updateNamedConfiguration("encoding", config).then(function () { - updateEncoder(form); - }); - }); - }; - - if ($("#selectVideoDecoder", form).val()) { - require(["alert"], function (alert) { - alert({ - title: globalize.translate("TitleHardwareAcceleration"), - text: globalize.translate("HardwareAccelerationWarning") - }).then(onDecoderConfirmed); - }); - } else { - onDecoderConfirmed(); - } - - return false; - } - - function setDecodingCodecsVisible(context, value) { - value = value || ""; - var any; - Array.prototype.forEach.call(context.querySelectorAll(".chkDecodeCodec"), function (c) { - if (-1 === c.getAttribute("data-types").split(",").indexOf(value)) { - dom.parentWithTag(c, "LABEL").classList.add("hide"); - } else { - dom.parentWithTag(c, "LABEL").classList.remove("hide"); - any = true; - } - }); - - if (any) { - context.querySelector(".decodingCodecsList").classList.remove("hide"); - } else { - context.querySelector(".decodingCodecsList").classList.add("hide"); - } - } - - function getTabs() { - return [{ - href: "encodingsettings.html", - name: Globalize.translate("Transcoding") - }, { - href: "playbackconfiguration.html", - name: Globalize.translate("TabResumeSettings") - }, { - href: "streamingsettings.html", - name: Globalize.translate("TabStreaming") - }]; - } - - $(document).on("pageinit", "#encodingSettingsPage", function () { - var page = this; - page.querySelector("#selectVideoDecoder").addEventListener("change", function () { - if ("vaapi" == this.value) { - page.querySelector(".fldVaapiDevice").classList.remove("hide"); - page.querySelector("#txtVaapiDevice").setAttribute("required", "required"); - } else { - page.querySelector(".fldVaapiDevice").classList.add("hide"); - page.querySelector("#txtVaapiDevice").removeAttribute("required"); - } - - if (this.value) { - page.querySelector(".hardwareAccelerationOptions").classList.remove("hide"); - } else { - page.querySelector(".hardwareAccelerationOptions").classList.add("hide"); - } - - setDecodingCodecsVisible(page, this.value); - }); - $("#btnSelectEncoderPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { - var picker = new directoryBrowser(); - picker.show({ - includeFiles: true, - callback: function (path) { - if (path) { - $(".txtEncoderPath", page).val(path); - } - - picker.close(); - } - }); - }); - }); - $("#btnSelectTranscodingTempPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { - var picker = new directoryBrowser(); - picker.show({ - callback: function (path) { - if (path) { - $("#txtTranscodingTempPath", page).val(path); - } - - picker.close(); - }, - validateWriteable: true, - header: globalize.translate("HeaderSelectTranscodingPath"), - instruction: globalize.translate("HeaderSelectTranscodingPathHelp") - }); - }); - }); - $(".encodingSettingsForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#encodingSettingsPage", function () { - loading.show(); - libraryMenu.setTabs("playback", 0, getTabs); - var page = this; - ApiClient.getNamedConfiguration("encoding").then(function (config) { - ApiClient.getSystemInfo().then(function (systemInfo) { - loadPage(page, config, systemInfo); - }); - }); - }); -}); diff --git a/src/controllers/favorites.js b/src/controllers/favorites.js index 0bfe3c4550..b4c7936239 100644 --- a/src/controllers/favorites.js +++ b/src/controllers/favorites.js @@ -1,26 +1,26 @@ -define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "apphost", "layoutManager", "focusManager", "emby-itemscontainer", "emby-scroller"], function (appRouter, cardBuilder, dom, globalize, connectionManager, appHost, layoutManager, focusManager) { - "use strict"; +define(['appRouter', 'cardBuilder', 'dom', 'globalize', 'connectionManager', 'apphost', 'layoutManager', 'focusManager', 'emby-itemscontainer', 'emby-scroller'], function (appRouter, cardBuilder, dom, globalize, connectionManager, appHost, layoutManager, focusManager) { + 'use strict'; function enableScrollX() { return true; } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function getPosterShape() { - return enableScrollX() ? "overflowPortrait" : "portrait"; + return enableScrollX() ? 'overflowPortrait' : 'portrait'; } function getSquareShape() { - return enableScrollX() ? "overflowSquare" : "square"; + return enableScrollX() ? 'overflowSquare' : 'square'; } function getSections() { return [{ - name: "HeaderFavoriteMovies", - types: "Movie", + name: 'HeaderFavoriteMovies', + types: 'Movie', shape: getPosterShape(), showTitle: true, showYear: true, @@ -28,8 +28,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayText: false, centerText: true }, { - name: "HeaderFavoriteShows", - types: "Series", + name: 'HeaderFavoriteShows', + types: 'Series', shape: getPosterShape(), showTitle: true, showYear: true, @@ -37,8 +37,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayText: false, centerText: true }, { - name: "HeaderFavoriteEpisodes", - types: "Episode", + name: 'HeaderFavoriteEpisodes', + types: 'Episode', shape: getThumbShape(), preferThumb: false, showTitle: true, @@ -47,8 +47,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayText: false, centerText: true }, { - name: "HeaderFavoriteVideos", - types: "Video", + name: 'HeaderFavoriteVideos', + types: 'Video', shape: getThumbShape(), preferThumb: true, showTitle: true, @@ -56,16 +56,16 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayText: false, centerText: true }, { - name: "HeaderFavoriteCollections", - types: "BoxSet", + name: 'HeaderFavoriteCollections', + types: 'BoxSet', shape: getPosterShape(), showTitle: true, overlayPlayButton: true, overlayText: false, centerText: true }, { - name: "HeaderFavoritePlaylists", - types: "Playlist", + name: 'HeaderFavoritePlaylists', + types: 'Playlist', shape: getSquareShape(), preferThumb: false, showTitle: true, @@ -75,8 +75,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayPlayButton: true, coverImage: true }, { - name: "HeaderFavoritePeople", - types: "Person", + name: 'HeaderFavoritePeople', + types: 'Person', shape: getPosterShape(), preferThumb: false, showTitle: true, @@ -86,8 +86,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayPlayButton: true, coverImage: true }, { - name: "HeaderFavoriteArtists", - types: "MusicArtist", + name: 'HeaderFavoriteArtists', + types: 'MusicArtist', shape: getSquareShape(), preferThumb: false, showTitle: true, @@ -97,8 +97,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayPlayButton: true, coverImage: true }, { - name: "HeaderFavoriteAlbums", - types: "MusicAlbum", + name: 'HeaderFavoriteAlbums', + types: 'MusicAlbum', shape: getSquareShape(), preferThumb: false, showTitle: true, @@ -108,8 +108,8 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap overlayPlayButton: true, coverImage: true }, { - name: "HeaderFavoriteSongs", - types: "Audio", + name: 'HeaderFavoriteSongs', + types: 'Audio', shape: getSquareShape(), preferThumb: false, showTitle: true, @@ -117,11 +117,11 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap showParentTitle: true, centerText: true, overlayMoreButton: true, - action: "instantmix", + action: 'instantmix', coverImage: true }, { - name: "HeaderFavoriteBooks", - types: "Book", + name: 'HeaderFavoriteBooks', + types: 'Book', shape: getPosterShape(), showTitle: true, showYear: true, @@ -135,23 +135,23 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap return function () { var apiClient = this.apiClient; var options = { - SortBy: (section.types, "SeriesName,SortName"), - SortOrder: "Ascending", - Filters: "IsFavorite", + SortBy: (section.types, 'SeriesName,SortName'), + SortOrder: 'Ascending', + Filters: 'IsFavorite', Recursive: true, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', CollapseBoxSetItems: false, - ExcludeLocationTypes: "Virtual", + ExcludeLocationTypes: 'Virtual', EnableTotalRecordCount: false }; options.Limit = 20; var userId = apiClient.getCurrentUserId(); - if ("MusicArtist" === section.types) { + if ('MusicArtist' === section.types) { return apiClient.getArtists(userId, options); } - if ("Person" === section.types) { + if ('Person' === section.types) { return apiClient.getPeople(userId, options); } @@ -161,7 +161,7 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap } function getRouteUrl(section, serverId) { - return appRouter.getRouteUrl("list", { + return appRouter.getRouteUrl('list', { serverId: serverId, itemTypes: section.types, isFavorite: true @@ -170,14 +170,14 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap function getItemsHtmlFn(section) { return function (items) { - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); var cardLayout = (appHost.preferVisualCards || supportsImageAnalysis) && section.autoCardLayout && section.showTitle; cardLayout = false; var serverId = this.apiClient.serverId(); var leadingButtons = layoutManager.tv ? [{ - name: globalize.translate("All"), - id: "more", - icon: "favorite", + name: globalize.translate('All'), + id: 'more', + icon: 'favorite', routeUrl: getRouteUrl(section, serverId) }] : null; var lines = 0; @@ -220,7 +220,7 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap this.view = view; this.params = params; this.apiClient = connectionManager.currentApiClient(); - this.sectionsContainer = view.querySelector(".sections"); + this.sectionsContainer = view.querySelector('.sections'); createSections(this, this.sectionsContainer, this.apiClient); } @@ -228,50 +228,50 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap var i; var length; var sections = getSections(); - var html = ""; + var html = ''; for (i = 0, length = sections.length; i < length; i++) { var section = sections[i]; - var sectionClass = "verticalSection"; + var sectionClass = 'verticalSection'; if (!section.showTitle) { - sectionClass += " verticalSection-extrabottompadding"; + sectionClass += ' verticalSection-extrabottompadding'; } html += '
'; html += '
'; if (layoutManager.tv) { - html += '

' + globalize.translate(section.name) + "

"; + html += '

' + globalize.translate(section.name) + '

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

'; html += globalize.translate(section.name); - html += "

"; - html += 'chevron_right'; - html += "
"; + html += ''; + html += ''; + html += ''; } - html += "
"; - html += '
'; - html += "
"; + html += ''; + html += '
'; + html += ''; } elem.innerHTML = html; - var elems = elem.querySelectorAll(".itemsContainer"); + var elems = elem.querySelectorAll('.itemsContainer'); for (i = 0, length = elems.length; i < length; i++) { var itemsContainer = elems[i]; itemsContainer.fetchData = getFetchDataFn(sections[i]).bind(instance); itemsContainer.getItemsHtml = getItemsHtmlFn(sections[i]).bind(instance); - itemsContainer.parentContainer = dom.parentWithClass(itemsContainer, "verticalSection"); + itemsContainer.parentContainer = dom.parentWithClass(itemsContainer, 'verticalSection'); } } FavoritesTab.prototype.onResume = function (options) { var promises = (this.apiClient, []); var view = this.view; - var elems = this.sectionsContainer.querySelectorAll(".itemsContainer"); + var elems = this.sectionsContainer.querySelectorAll('.itemsContainer'); for (var i = 0, length = elems.length; i < length; i++) { promises.push(elems[i].resume(options)); @@ -285,7 +285,7 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap }; FavoritesTab.prototype.onPause = function () { - var elems = this.sectionsContainer.querySelectorAll(".itemsContainer"); + var elems = this.sectionsContainer.querySelectorAll('.itemsContainer'); for (var i = 0, length = elems.length; i < length; i++) { elems[i].pause(); @@ -296,7 +296,7 @@ define(["appRouter", "cardBuilder", "dom", "globalize", "connectionManager", "ap this.view = null; this.params = null; this.apiClient = null; - var elems = this.sectionsContainer.querySelectorAll(".itemsContainer"); + var elems = this.sectionsContainer.querySelectorAll('.itemsContainer'); for (var i = 0, length = elems.length; i < length; i++) { elems[i].fetchData = null; diff --git a/src/controllers/home.js b/src/controllers/home.js index b1dd70ebd6..9a4cea2227 100644 --- a/src/controllers/home.js +++ b/src/controllers/home.js @@ -1,11 +1,11 @@ -define(["tabbedView", "globalize", "require", "emby-tabs", "emby-button", "emby-scroller"], function (TabbedView, globalize, require) { - "use strict"; +define(['tabbedView', 'globalize', 'require', 'emby-tabs', 'emby-button', 'emby-scroller'], function (TabbedView, globalize, require) { + 'use strict'; function getTabs() { return [{ - name: globalize.translate("Home") + name: globalize.translate('Home') }, { - name: globalize.translate("Favorites") + name: globalize.translate('Favorites') }]; } @@ -21,18 +21,18 @@ define(["tabbedView", "globalize", "require", "emby-tabs", "emby-button", "emby- function getTabController(index) { if (null == index) { - throw new Error("index cannot be null"); + throw new Error('index cannot be null'); } var depends = []; switch (index) { case 0: - depends.push("controllers/hometab"); + depends.push('controllers/hometab'); break; case 1: - depends.push("controllers/favorites"); + depends.push('controllers/favorites'); } var instance = this; @@ -63,12 +63,12 @@ define(["tabbedView", "globalize", "require", "emby-tabs", "emby-button", "emby- HomeView.prototype.onPause = function () { TabbedView.prototype.onPause.call(this); - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); + document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader'); }; HomeView.prototype.onResume = function (options) { TabbedView.prototype.onResume.call(this, options); - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); + document.querySelector('.skinHeader').classList.add('noHomeButtonHeader'); }; return HomeView; diff --git a/src/controllers/hometab.js b/src/controllers/hometab.js index d2adcb2da2..8e2a1f92e7 100644 --- a/src/controllers/hometab.js +++ b/src/controllers/hometab.js @@ -1,12 +1,12 @@ -define(["userSettings", "loading", "connectionManager", "apphost", "layoutManager", "focusManager", "homeSections", "emby-itemscontainer"], function (userSettings, loading, connectionManager, appHost, layoutManager, focusManager, homeSections) { - "use strict"; +define(['userSettings', 'loading', 'connectionManager', 'apphost', 'layoutManager', 'focusManager', 'homeSections', 'emby-itemscontainer'], function (userSettings, loading, connectionManager, appHost, layoutManager, focusManager, homeSections) { + 'use strict'; function HomeTab(view, params) { this.view = view; this.params = params; this.apiClient = connectionManager.currentApiClient(); - this.sectionsContainer = view.querySelector(".sections"); - view.querySelector(".sections").addEventListener("settingschange", onHomeScreenSettingsChanged.bind(this)); + this.sectionsContainer = view.querySelector('.sections'); + view.querySelector('.sections').addEventListener('settingschange', onHomeScreenSettingsChanged.bind(this)); } function onHomeScreenSettingsChanged() { @@ -36,7 +36,7 @@ define(["userSettings", "loading", "connectionManager", "apphost", "layoutManage this.destroyHomeSections(); this.sectionsRendered = true; return apiClient.getCurrentUser().then(function (user) { - return homeSections.loadSections(view.querySelector(".sections"), apiClient, user, userSettings).then(function () { + return homeSections.loadSections(view.querySelector('.sections'), apiClient, user, userSettings).then(function () { if (options.autoFocus) { focusManager.autoFocus(view); } diff --git a/src/controllers/itemdetailpage.js b/src/controllers/itemdetailpage.js index 1a0b66c75a..45342208ea 100644 --- a/src/controllers/itemdetailpage.js +++ b/src/controllers/itemdetailpage.js @@ -1,5 +1,5 @@ -define(["loading", "appRouter", "layoutManager", "userSettings", "connectionManager", "cardBuilder", "datetime", "mediaInfo", "backdrop", "listView", "itemContextMenu", "itemHelper", "dom", "indicators", "apphost", "imageLoader", "libraryMenu", "globalize", "browser", "events", "scrollHelper", "playbackManager", "libraryBrowser", "scrollStyles", "emby-itemscontainer", "emby-checkbox", "emby-button", "emby-playstatebutton", "emby-ratingbutton", "emby-scroller", "emby-select"], function (loading, appRouter, layoutManager, userSettings, connectionManager, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, appHost, imageLoader, libraryMenu, globalize, browser, events, scrollHelper, playbackManager, libraryBrowser) { - "use strict"; +define(['loading', 'appRouter', 'layoutManager', 'connectionManager', 'userSettings', 'cardBuilder', 'datetime', 'mediaInfo', 'backdrop', 'listView', 'itemContextMenu', 'itemHelper', 'dom', 'indicators', 'imageLoader', 'libraryMenu', 'globalize', 'browser', 'events', 'playbackManager', 'scrollStyles', 'emby-itemscontainer', 'emby-checkbox', 'emby-button', 'emby-playstatebutton', 'emby-ratingbutton', 'emby-scroller', 'emby-select'], function (loading, appRouter, layoutManager, connectionManager, userSettings, cardBuilder, datetime, mediaInfo, backdrop, listView, itemContextMenu, itemHelper, dom, indicators, imageLoader, libraryMenu, globalize, browser, events, playbackManager) { + 'use strict'; function getPromise(apiClient, params) { var id = params.id; @@ -24,19 +24,19 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana return apiClient.getArtist(params.musicartist, apiClient.getCurrentUserId()); } - throw new Error("Invalid request"); + throw new Error('Invalid request'); } function hideAll(page, className, show) { var i; var length; - var elems = page.querySelectorAll("." + className); + var elems = page.querySelectorAll('.' + className); for (i = 0, length = elems.length; i < length; i++) { if (show) { - elems[i].classList.remove("hide"); + elems[i].classList.remove('hide'); } else { - elems[i].classList.add("hide"); + elems[i].classList.add('hide'); } } } @@ -60,103 +60,102 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana return options; } - function getProgramScheduleHtml(items, options) { - options = options || {}; - var html = ""; + function getProgramScheduleHtml(items) { + var html = ''; html += '
'; html += listView.getListViewHtml({ items: items, enableUserDataButtons: false, image: true, - imageSource: "channel", + imageSource: 'channel', showProgramDateTime: true, showChannel: false, mediaInfo: false, - action: "none", + action: 'none', moreButton: false, recordButton: false }); - return html += "
"; + return html += ''; } function renderSeriesTimerSchedule(page, apiClient, seriesTimerId) { apiClient.getLiveTvTimers({ UserId: apiClient.getCurrentUserId(), ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", - SortBy: "StartDate", + EnableImageTypes: 'Primary,Backdrop,Thumb', + SortBy: 'StartDate', EnableTotalRecordCount: false, EnableUserData: false, SeriesTimerId: seriesTimerId, - Fields: "ChannelInfo,ChannelImage" + Fields: 'ChannelInfo,ChannelImage' }).then(function (result) { if (result.Items.length && result.Items[0].SeriesTimerId != seriesTimerId) { result.Items = []; } var html = getProgramScheduleHtml(result.Items); - var scheduleTab = page.querySelector(".seriesTimerSchedule"); + var scheduleTab = page.querySelector('.seriesTimerSchedule'); scheduleTab.innerHTML = html; imageLoader.lazyChildren(scheduleTab); }); } function renderTimerEditor(page, item, apiClient, user) { - if ("Recording" !== item.Type || !user.Policy.EnableLiveTvManagement || !item.TimerId || "InProgress" !== item.Status) { - return void hideAll(page, "btnCancelTimer"); + if ('Recording' !== item.Type || !user.Policy.EnableLiveTvManagement || !item.TimerId || 'InProgress' !== item.Status) { + return void hideAll(page, 'btnCancelTimer'); } - hideAll(page, "btnCancelTimer", true); + hideAll(page, 'btnCancelTimer', true); } function renderSeriesTimerEditor(page, item, apiClient, user) { - if ("SeriesTimer" !== item.Type) { - return void hideAll(page, "btnCancelSeriesTimer"); + if ('SeriesTimer' !== item.Type) { + return void hideAll(page, 'btnCancelSeriesTimer'); } if (user.Policy.EnableLiveTvManagement) { - require(["seriesRecordingEditor"], function (seriesRecordingEditor) { + require(['seriesRecordingEditor'], function (seriesRecordingEditor) { seriesRecordingEditor.embed(item, apiClient.serverId(), { - context: page.querySelector(".seriesRecordingEditor") + context: page.querySelector('.seriesRecordingEditor') }); }); - page.querySelector(".seriesTimerScheduleSection").classList.remove("hide"); - hideAll(page, "btnCancelSeriesTimer", true); + page.querySelector('.seriesTimerScheduleSection').classList.remove('hide'); + hideAll(page, 'btnCancelSeriesTimer', true); return void renderSeriesTimerSchedule(page, apiClient, item.Id); } - page.querySelector(".seriesTimerScheduleSection").classList.add("hide"); - return void hideAll(page, "btnCancelSeriesTimer"); + page.querySelector('.seriesTimerScheduleSection').classList.add('hide'); + return void hideAll(page, 'btnCancelSeriesTimer'); } function renderTrackSelections(page, instance, item, forceReload) { - var select = page.querySelector(".selectSource"); + var select = page.querySelector('.selectSource'); - if (!item.MediaSources || !itemHelper.supportsMediaSourceSelection(item) || -1 === playbackManager.getSupportedCommands().indexOf("PlayMediaSource") || !playbackManager.canPlay(item)) { - page.querySelector(".trackSelections").classList.add("hide"); - select.innerHTML = ""; - page.querySelector(".selectVideo").innerHTML = ""; - page.querySelector(".selectAudio").innerHTML = ""; - page.querySelector(".selectSubtitles").innerHTML = ""; + if (!item.MediaSources || !itemHelper.supportsMediaSourceSelection(item) || -1 === playbackManager.getSupportedCommands().indexOf('PlayMediaSource') || !playbackManager.canPlay(item)) { + page.querySelector('.trackSelections').classList.add('hide'); + select.innerHTML = ''; + page.querySelector('.selectVideo').innerHTML = ''; + page.querySelector('.selectAudio').innerHTML = ''; + page.querySelector('.selectSubtitles').innerHTML = ''; return; } playbackManager.getPlaybackMediaSources(item).then(function (mediaSources) { instance._currentPlaybackMediaSources = mediaSources; - page.querySelector(".trackSelections").classList.remove("hide"); - select.setLabel(globalize.translate("LabelVersion")); + page.querySelector('.trackSelections').classList.remove('hide'); + select.setLabel(globalize.translate('LabelVersion')); var currentValue = select.value; var selectedId = mediaSources[0].Id; select.innerHTML = mediaSources.map(function (v) { - var selected = v.Id === selectedId ? " selected" : ""; - return '"; - }).join(""); + var selected = v.Id === selectedId ? ' selected' : ''; + return ''; + }).join(''); if (mediaSources.length > 1) { - page.querySelector(".selectSourceContainer").classList.remove("hide"); + page.querySelector('.selectSourceContainer').classList.remove('hide'); } else { - page.querySelector(".selectSourceContainer").classList.add("hide"); + page.querySelector('.selectSourceContainer').classList.add('hide'); } if (select.value !== currentValue || forceReload) { @@ -168,18 +167,18 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function renderVideoSelections(page, mediaSources) { - var mediaSourceId = page.querySelector(".selectSource").value; + var mediaSourceId = page.querySelector('.selectSource').value; var mediaSource = mediaSources.filter(function (m) { return m.Id === mediaSourceId; })[0]; var tracks = mediaSource.MediaStreams.filter(function (m) { - return "Video" === m.Type; + return 'Video' === m.Type; }); - var select = page.querySelector(".selectVideo"); - select.setLabel(globalize.translate("LabelVideo")); + var select = page.querySelector('.selectVideo'); + select.setLabel(globalize.translate('LabelVideo')); var selectedId = tracks.length ? tracks[0].Index : -1; select.innerHTML = tracks.map(function (v) { - var selected = v.Index === selectedId ? " selected" : ""; + var selected = v.Index === selectedId ? ' selected' : ''; var titleParts = []; var resolutionText = mediaInfo.getResolutionText(v); @@ -191,100 +190,100 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana titleParts.push(v.Codec.toUpperCase()); } - return '"; - }).join(""); - select.setAttribute("disabled", "disabled"); + return ''; + }).join(''); + select.setAttribute('disabled', 'disabled'); if (tracks.length) { - page.querySelector(".selectVideoContainer").classList.remove("hide"); + page.querySelector('.selectVideoContainer').classList.remove('hide'); } else { - page.querySelector(".selectVideoContainer").classList.add("hide"); + page.querySelector('.selectVideoContainer').classList.add('hide'); } } function renderAudioSelections(page, mediaSources) { - var mediaSourceId = page.querySelector(".selectSource").value; + var mediaSourceId = page.querySelector('.selectSource').value; var mediaSource = mediaSources.filter(function (m) { return m.Id === mediaSourceId; })[0]; var tracks = mediaSource.MediaStreams.filter(function (m) { - return "Audio" === m.Type; + return 'Audio' === m.Type; }); - var select = page.querySelector(".selectAudio"); - select.setLabel(globalize.translate("LabelAudio")); + var select = page.querySelector('.selectAudio'); + select.setLabel(globalize.translate('LabelAudio')); var selectedId = mediaSource.DefaultAudioStreamIndex; select.innerHTML = tracks.map(function (v) { - var selected = v.Index === selectedId ? " selected" : ""; - return '"; - }).join(""); + var selected = v.Index === selectedId ? ' selected' : ''; + return ''; + }).join(''); if (tracks.length > 1) { - select.removeAttribute("disabled"); + select.removeAttribute('disabled'); } else { - select.setAttribute("disabled", "disabled"); + select.setAttribute('disabled', 'disabled'); } if (tracks.length) { - page.querySelector(".selectAudioContainer").classList.remove("hide"); + page.querySelector('.selectAudioContainer').classList.remove('hide'); } else { - page.querySelector(".selectAudioContainer").classList.add("hide"); + page.querySelector('.selectAudioContainer').classList.add('hide'); } } function renderSubtitleSelections(page, mediaSources) { - var mediaSourceId = page.querySelector(".selectSource").value; + var mediaSourceId = page.querySelector('.selectSource').value; var mediaSource = mediaSources.filter(function (m) { return m.Id === mediaSourceId; })[0]; var tracks = mediaSource.MediaStreams.filter(function (m) { - return "Subtitle" === m.Type; + return 'Subtitle' === m.Type; }); - var select = page.querySelector(".selectSubtitles"); - select.setLabel(globalize.translate("LabelSubtitles")); + var select = page.querySelector('.selectSubtitles'); + select.setLabel(globalize.translate('LabelSubtitles')); var selectedId = null == mediaSource.DefaultSubtitleStreamIndex ? -1 : mediaSource.DefaultSubtitleStreamIndex; if (tracks.length) { - var selected = -1 === selectedId ? " selected" : ""; - select.innerHTML = '" + tracks.map(function (v) { - selected = v.Index === selectedId ? " selected" : ""; - return '"; - }).join(""); - page.querySelector(".selectSubtitlesContainer").classList.remove("hide"); + var selected = -1 === selectedId ? ' selected' : ''; + select.innerHTML = '' + tracks.map(function (v) { + selected = v.Index === selectedId ? ' selected' : ''; + return ''; + }).join(''); + page.querySelector('.selectSubtitlesContainer').classList.remove('hide'); } else { - select.innerHTML = ""; - page.querySelector(".selectSubtitlesContainer").classList.add("hide"); + select.innerHTML = ''; + page.querySelector('.selectSubtitlesContainer').classList.add('hide'); } } function reloadPlayButtons(page, item) { var canPlay = false; - if ("Program" == item.Type) { + if ('Program' == item.Type) { var now = new Date(); if (now >= datetime.parseISO8601Date(item.StartDate, true) && now < datetime.parseISO8601Date(item.EndDate, true)) { - hideAll(page, "btnPlay", true); + hideAll(page, 'btnPlay', true); canPlay = true; } else { - hideAll(page, "btnPlay"); + hideAll(page, 'btnPlay'); } - hideAll(page, "btnResume"); - hideAll(page, "btnInstantMix"); - hideAll(page, "btnShuffle"); + hideAll(page, 'btnResume'); + hideAll(page, 'btnInstantMix'); + hideAll(page, 'btnShuffle'); } else if (playbackManager.canPlay(item)) { - hideAll(page, "btnPlay", true); - var enableInstantMix = -1 !== ["Audio", "MusicAlbum", "MusicGenre", "MusicArtist"].indexOf(item.Type); - hideAll(page, "btnInstantMix", enableInstantMix); - var enableShuffle = item.IsFolder || -1 !== ["MusicAlbum", "MusicGenre", "MusicArtist"].indexOf(item.Type); - hideAll(page, "btnShuffle", enableShuffle); + hideAll(page, 'btnPlay', true); + var enableInstantMix = -1 !== ['Audio', 'MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type); + hideAll(page, 'btnInstantMix', enableInstantMix); + var enableShuffle = item.IsFolder || -1 !== ['MusicAlbum', 'MusicGenre', 'MusicArtist'].indexOf(item.Type); + hideAll(page, 'btnShuffle', enableShuffle); canPlay = true; - hideAll(page, "btnResume", item.UserData && item.UserData.PlaybackPositionTicks > 0); + hideAll(page, 'btnResume', item.UserData && item.UserData.PlaybackPositionTicks > 0); } else { - hideAll(page, "btnPlay"); - hideAll(page, "btnResume"); - hideAll(page, "btnInstantMix"); - hideAll(page, "btnShuffle"); + hideAll(page, 'btnPlay'); + hideAll(page, 'btnResume'); + hideAll(page, 'btnInstantMix'); + hideAll(page, 'btnShuffle'); } return canPlay; @@ -293,30 +292,30 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function reloadUserDataButtons(page, item) { var i; var length; - var btnPlaystates = page.querySelectorAll(".btnPlaystate"); + var btnPlaystates = page.querySelectorAll('.btnPlaystate'); for (i = 0, length = btnPlaystates.length; i < length; i++) { var btnPlaystate = btnPlaystates[i]; if (itemHelper.canMarkPlayed(item)) { - btnPlaystate.classList.remove("hide"); + btnPlaystate.classList.remove('hide'); btnPlaystate.setItem(item); } else { - btnPlaystate.classList.add("hide"); + btnPlaystate.classList.add('hide'); btnPlaystate.setItem(null); } } - var btnUserRatings = page.querySelectorAll(".btnUserRating"); + var btnUserRatings = page.querySelectorAll('.btnUserRating'); for (i = 0, length = btnUserRatings.length; i < length; i++) { var btnUserRating = btnUserRatings[i]; if (itemHelper.canRate(item)) { - btnUserRating.classList.remove("hide"); + btnUserRating.classList.remove('hide'); btnUserRating.setItem(item); } else { - btnUserRating.classList.add("hide"); + btnUserRating.classList.add('hide'); btnUserRating.setItem(null); } } @@ -329,15 +328,14 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana var artist = artists[i]; var href = appRouter.getRouteUrl(artist, { context: context, - itemType: "MusicArtist", + itemType: 'MusicArtist', serverId: serverId }); - html.push('' + artist.Name + ""); + html.push('' + artist.Name + ''); } - return html = html.join(" / "); + return html = html.join(' / '); } - function renderName(item, container, isStatic, context) { var parentRoute; var parentNameHtml = []; @@ -346,177 +344,201 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (item.AlbumArtists) { parentNameHtml.push(getArtistLinksHtml(item.AlbumArtists, item.ServerId, context)); parentNameLast = true; - } else if (item.ArtistItems && item.ArtistItems.length && "MusicVideo" === item.Type) { + } else if (item.ArtistItems && item.ArtistItems.length && 'MusicVideo' === item.Type) { parentNameHtml.push(getArtistLinksHtml(item.ArtistItems, item.ServerId, context)); parentNameLast = true; - } else if (item.SeriesName && "Episode" === item.Type) { + } else if (item.SeriesName && 'Episode' === item.Type) { parentRoute = appRouter.getRouteUrl({ Id: item.SeriesId, Name: item.SeriesName, - Type: "Series", + Type: 'Series', IsFolder: true, ServerId: item.ServerId }, { context: context }); - parentNameHtml.push('' + item.SeriesName + ""); + parentNameHtml.push('' + item.SeriesName + ''); } else if (item.IsSeries || item.EpisodeTitle) { parentNameHtml.push(item.Name); } - if (item.SeriesName && "Season" === item.Type) { + if (item.SeriesName && 'Season' === item.Type) { parentRoute = appRouter.getRouteUrl({ Id: item.SeriesId, Name: item.SeriesName, - Type: "Series", + Type: 'Series', IsFolder: true, ServerId: item.ServerId }, { context: context }); - parentNameHtml.push('' + item.SeriesName + ""); - } else if (null != item.ParentIndexNumber && "Episode" === item.Type) { + parentNameHtml.push('' + item.SeriesName + ''); + } else if (null != item.ParentIndexNumber && 'Episode' === item.Type) { parentRoute = appRouter.getRouteUrl({ Id: item.SeasonId, Name: item.SeasonName, - Type: "Season", + Type: 'Season', IsFolder: true, ServerId: item.ServerId }, { context: context }); - parentNameHtml.push('' + item.SeasonName + ""); + parentNameHtml.push('' + item.SeasonName + ''); } else if (null != item.ParentIndexNumber && item.IsSeries) { - parentNameHtml.push(item.SeasonName || "S" + item.ParentIndexNumber); - } else if (item.Album && item.AlbumId && ("MusicVideo" === item.Type || "Audio" === item.Type)) { + parentNameHtml.push(item.SeasonName || 'S' + item.ParentIndexNumber); + } else if (item.Album && item.AlbumId && ('MusicVideo' === item.Type || 'Audio' === item.Type)) { parentRoute = appRouter.getRouteUrl({ Id: item.AlbumId, Name: item.Album, - Type: "MusicAlbum", + Type: 'MusicAlbum', IsFolder: true, ServerId: item.ServerId }, { context: context }); - parentNameHtml.push('' + item.Album + ""); + parentNameHtml.push('' + item.Album + ''); } else if (item.Album) { parentNameHtml.push(item.Album); } - - var html = ""; + // FIXME: This whole section needs some refactoring, so it becames easier to scale across all form factors. See GH #1022 + var html = ''; + var tvShowHtml = parentNameHtml[0]; + var tvSeasonHtml = parentNameHtml[1]; if (parentNameHtml.length) { if (parentNameLast) { - html = '

' + parentNameHtml.join(" - ") + "

"; + // Music + if (layoutManager.mobile) { + html = '

' + parentNameHtml.join('
') + '

'; + } else { + html = '

' + parentNameHtml.join(' - ') + '

'; + } } else { - html = '

' + parentNameHtml.join(" - ") + "

"; + if (layoutManager.mobile) { + html = '

' + parentNameHtml.join('
') + '

'; + } else { + html = '

' + tvShowHtml + '

'; + } } } var name = itemHelper.getDisplayName(item, { includeParentInfo: false }); - var offset = parentNameLast ? ".25em" : ".5em"; + var offset = parentNameLast ? '.25em' : '.5em'; if (html && !parentNameLast) { - html += '

' + name + '

'; + if (!layoutManager.mobile && tvSeasonHtml) { + html += '

' + tvSeasonHtml + ' - ' + name + '

'; + } else { + html += '

' + name + '

'; + } } else { - html = '

' + name + "

" + html; + html = '

' + name + '

' + html; } if (item.OriginalTitle && item.OriginalTitle != item.Name) { - html += '

' + item.OriginalTitle + '

'; + html += '

' + item.OriginalTitle + '

'; } container.innerHTML = html; if (html.length) { - container.classList.remove("hide"); + container.classList.remove('hide'); } else { - container.classList.add("hide"); + container.classList.add('hide'); } } function setTrailerButtonVisibility(page, item) { - if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers")) { - hideAll(page, "btnPlayTrailer", true); + if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) { + hideAll(page, 'btnPlayTrailer', true); } else { - hideAll(page, "btnPlayTrailer"); + hideAll(page, 'btnPlayTrailer'); } } - function enabled() { - return userSettings.enableBackdrops(); - } - - function renderBackdrop(page, item, apiClient) { - if (enabled()) { - if (dom.getWindowSize().innerWidth >= 1000) { - backdrop.setBackdrops([item]); - } else { - backdrop.clear(); - } + function renderBackdrop(item) { + if (dom.getWindowSize().innerWidth >= 1000) { + backdrop.setBackdrops([item]); + } else { + backdrop.clear(); } } function renderDetailPageBackdrop(page, item, apiClient) { var imgUrl; - var screenWidth = screen.availWidth; var hasbackdrop = false; - var itemBackdropElement = page.querySelector("#itemBackdrop"); - var usePrimaryImage = item.MediaType === "Video" && item.Type !== "Movie" && item.Type !== "Trailer" || - item.MediaType && item.MediaType !== "Video" || - item.Type === "MusicAlbum" || - item.Type === "MusicArtist"; + var itemBackdropElement = page.querySelector('#itemBackdrop'); + var usePrimaryImage = item.MediaType === 'Video' && item.Type !== 'Movie' && item.Type !== 'Trailer' || + item.MediaType && item.MediaType !== 'Video' || + item.Type === 'MusicAlbum' || + item.Type === 'Person'; - if ("Program" === item.Type && item.ImageTags && item.ImageTags.Thumb) { + if (!layoutManager.mobile && !userSettings.enableBackdrops()) { + return false; + } + + if ('Program' === item.Type && item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', + maxWidth: dom.getScreenWidth(), index: 0, tag: item.ImageTags.Thumb }); - itemBackdropElement.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + page.classList.remove('noBackdrop'); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (usePrimaryImage && item.ImageTags && item.ImageTags.Primary) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Primary", + type: 'Primary', + maxWidth: dom.getScreenWidth(), index: 0, tag: item.ImageTags.Primary }); - itemBackdropElement.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + page.classList.remove('noBackdrop'); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.BackdropImageTags && item.BackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: dom.getScreenWidth(), index: 0, tag: item.BackdropImageTags[0] }); - itemBackdropElement.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + page.classList.remove('noBackdrop'); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.ParentBackdropItemId && item.ParentBackdropImageTags && item.ParentBackdropImageTags.length) { imgUrl = apiClient.getScaledImageUrl(item.ParentBackdropItemId, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: dom.getScreenWidth(), index: 0, tag: item.ParentBackdropImageTags[0] }); - itemBackdropElement.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + page.classList.remove('noBackdrop'); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else if (item.ImageTags && item.ImageTags.Thumb) { imgUrl = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', + maxWidth: dom.getScreenWidth(), index: 0, tag: item.ImageTags.Thumb }); - itemBackdropElement.classList.remove("noBackdrop"); - imageLoader.lazyImage(itemBackdropElement, imgUrl, false); + page.classList.remove('noBackdrop'); + imageLoader.lazyImage(itemBackdropElement, imgUrl); hasbackdrop = true; } else { - itemBackdropElement.classList.add("noBackdrop"); - itemBackdropElement.style.backgroundImage = ""; + itemBackdropElement.style.backgroundImage = ''; + } + + if ('Person' === item.Type) { + // FIXME: This hides the backdrop on all persons to fix a margin issue. Ideally, a proper fix should be made. + page.classList.add('noBackdrop'); + itemBackdropElement.classList.add('personBackdrop'); + } else { + itemBackdropElement.classList.remove('personBackdrop'); } return hasbackdrop; @@ -524,110 +546,112 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function reloadFromItem(instance, page, params, item, user) { var context = params.context; - renderName(item, page.querySelector(".nameContainer"), false, context); + page.querySelector('.detailPagePrimaryContainer').classList.add('detailSticky'); + + renderName(item, page.querySelector('.nameContainer'), false, context); var apiClient = connectionManager.getApiClient(item.ServerId); renderSeriesTimerEditor(page, item, apiClient, user); renderTimerEditor(page, item, apiClient, user); renderImage(page, item, apiClient, user); renderLogo(page, item, apiClient); - setTitle(item, apiClient); + Emby.Page.setTitle(''); setInitialCollapsibleState(page, item, apiClient, context, user); renderDetails(page, item, apiClient, context); renderTrackSelections(page, instance, item); - renderBackdrop(page, item, apiClient); + renderBackdrop(item); renderDetailPageBackdrop(page, item, apiClient); var canPlay = reloadPlayButtons(page, item); - if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf("PlayTrailers")) { - hideAll(page, "btnPlayTrailer", true); + if ((item.LocalTrailerCount || item.RemoteTrailers && item.RemoteTrailers.length) && -1 !== playbackManager.getSupportedCommands().indexOf('PlayTrailers')) { + hideAll(page, 'btnPlayTrailer', true); } else { - hideAll(page, "btnPlayTrailer"); + hideAll(page, 'btnPlayTrailer'); } setTrailerButtonVisibility(page, item); if (item.CanDelete && !item.IsFolder) { - hideAll(page, "btnDeleteItem", true); + hideAll(page, 'btnDeleteItem', true); } else { - hideAll(page, "btnDeleteItem"); + hideAll(page, 'btnDeleteItem'); } - if ("Program" !== item.Type || canPlay) { - hideAll(page, "mainDetailButtons", true); + if ('Program' !== item.Type || canPlay) { + hideAll(page, 'mainDetailButtons', true); } else { - hideAll(page, "mainDetailButtons"); + hideAll(page, 'mainDetailButtons'); } showRecordingFields(instance, page, item, user); var groupedVersions = (item.MediaSources || []).filter(function (g) { - return "Grouping" == g.Type; + return 'Grouping' == g.Type; }); if (user.Policy.IsAdministrator && groupedVersions.length) { - page.querySelector(".btnSplitVersions").classList.remove("hide"); + page.querySelector('.btnSplitVersions').classList.remove('hide'); } else { - page.querySelector(".btnSplitVersions").classList.add("hide"); + page.querySelector('.btnSplitVersions').classList.add('hide'); } if (itemContextMenu.getCommands(getContextMenuOptions(item, user)).length) { - hideAll(page, "btnMoreCommands", true); + hideAll(page, 'btnMoreCommands', true); } else { - hideAll(page, "btnMoreCommands"); + hideAll(page, 'btnMoreCommands'); } - var itemBirthday = page.querySelector("#itemBirthday"); + var itemBirthday = page.querySelector('#itemBirthday'); - if ("Person" == item.Type && item.PremiereDate) { + if ('Person' == item.Type && item.PremiereDate) { try { var birthday = datetime.parseISO8601Date(item.PremiereDate, true).toDateString(); - itemBirthday.classList.remove("hide"); - itemBirthday.innerHTML = globalize.translate("BirthDateValue").replace("{0}", birthday); + itemBirthday.classList.remove('hide'); + itemBirthday.innerHTML = globalize.translate('BirthDateValue', birthday); } catch (err) { - itemBirthday.classList.add("hide"); + itemBirthday.classList.add('hide'); } } else { - itemBirthday.classList.add("hide"); + itemBirthday.classList.add('hide'); } - var itemDeathDate = page.querySelector("#itemDeathDate"); + var itemDeathDate = page.querySelector('#itemDeathDate'); - if ("Person" == item.Type && item.EndDate) { + if ('Person' == item.Type && item.EndDate) { try { var deathday = datetime.parseISO8601Date(item.EndDate, true).toDateString(); - itemDeathDate.classList.remove("hide"); - itemDeathDate.innerHTML = globalize.translate("DeathDateValue").replace("{0}", deathday); + itemDeathDate.classList.remove('hide'); + itemDeathDate.innerHTML = globalize.translate('DeathDateValue', deathday); } catch (err) { - itemDeathDate.classList.add("hide"); + itemDeathDate.classList.add('hide'); } } else { - itemDeathDate.classList.add("hide"); + itemDeathDate.classList.add('hide'); } - var itemBirthLocation = page.querySelector("#itemBirthLocation"); + var itemBirthLocation = page.querySelector('#itemBirthLocation'); - if ("Person" == item.Type && item.ProductionLocations && item.ProductionLocations.length) { - var gmap = '' + item.ProductionLocations[0] + ""; - itemBirthLocation.classList.remove("hide"); - itemBirthLocation.innerHTML = globalize.translate("BirthPlaceValue").replace("{0}", gmap); + if ('Person' == item.Type && item.ProductionLocations && item.ProductionLocations.length) { + var gmap = '' + item.ProductionLocations[0] + ''; + itemBirthLocation.classList.remove('hide'); + itemBirthLocation.innerHTML = globalize.translate('BirthPlaceValue', gmap); } else { - itemBirthLocation.classList.add("hide"); + itemBirthLocation.classList.add('hide'); } setPeopleHeader(page, item); loading.hide(); - if (item.Type === "Book") { - hideAll(page, "btnDownload", true); + if (item.Type === 'Book') { + hideAll(page, 'btnDownload', true); } - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); } function logoImageUrl(item, apiClient, options) { options = options || {}; - options.type = "Logo"; + options.type = 'Logo'; if (item.ImageTags && item.ImageTags.Logo) { options.tag = item.ImageTags.Logo; @@ -642,111 +666,78 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana return null; } - function setTitle(item, apiClient) { - var url = logoImageUrl(item, apiClient, {}); - - if (url = null) { - var pageTitle = document.querySelector(".pageTitle"); - pageTitle.style.backgroundImage = "url('" + url + "')"; - pageTitle.classList.add("pageTitleWithLogo"); - pageTitle.innerHTML = ""; - } else { - Emby.Page.setTitle(""); - } - } - function renderLogo(page, item, apiClient) { var url = logoImageUrl(item, apiClient, { maxWidth: 400 }); - var detailLogo = page.querySelector(".detailLogo"); + var detailLogo = page.querySelector('.detailLogo'); - if (url) { - detailLogo.classList.remove("hide"); - detailLogo.classList.add("lazy"); - detailLogo.setAttribute("data-src", url); + if (!layoutManager.mobile && !userSettings.enableBackdrops()) { + detailLogo.classList.add('hide'); + } else if (url) { + detailLogo.classList.remove('hide'); + detailLogo.classList.add('lazy'); + detailLogo.setAttribute('data-src', url); imageLoader.lazyImage(detailLogo); } else { - detailLogo.classList.add("hide"); + detailLogo.classList.add('hide'); } } function showRecordingFields(instance, page, item, user) { if (!instance.currentRecordingFields) { - var recordingFieldsElement = page.querySelector(".recordingFields"); + var recordingFieldsElement = page.querySelector('.recordingFields'); - if ("Program" == item.Type && user.Policy.EnableLiveTvManagement) { - require(["recordingFields"], function (recordingFields) { + if ('Program' == item.Type && user.Policy.EnableLiveTvManagement) { + require(['recordingFields'], function (recordingFields) { instance.currentRecordingFields = new recordingFields({ parent: recordingFieldsElement, programId: item.Id, serverId: item.ServerId }); - recordingFieldsElement.classList.remove("hide"); + recordingFieldsElement.classList.remove('hide'); }); } else { - recordingFieldsElement.classList.add("hide"); - recordingFieldsElement.innerHTML = ""; + recordingFieldsElement.classList.add('hide'); + recordingFieldsElement.innerHTML = ''; } } } - function renderUserInfo(page, item) { - var lastPlayedElement = page.querySelector(".itemLastPlayed"); - - if (item.UserData && item.UserData.LastPlayedDate) { - lastPlayedElement.classList.remove("hide"); - var datePlayed = datetime.parseISO8601Date(item.UserData.LastPlayedDate); - lastPlayedElement.innerHTML = globalize.translate("DatePlayed") + ": " + datetime.toLocaleDateString(datePlayed) + " " + datetime.getDisplayTime(datePlayed); - } else { - lastPlayedElement.classList.add("hide"); - } - } - function renderLinks(linksElem, item) { var html = []; - if (item.DateCreated && itemHelper.enableDateAddedDisplay(item)) { - var dateCreated = datetime.parseISO8601Date(item.DateCreated); - html.push(globalize.translate("AddedOnValue", datetime.toLocaleDateString(dateCreated) + " " + datetime.getDisplayTime(dateCreated))); - } - var links = []; if (!layoutManager.tv && item.HomePageUrl) { - links.push('' + globalize.translate("ButtonWebsite") + ""); + links.push('' + globalize.translate('ButtonWebsite') + ''); } if (item.ExternalUrls) { for (var i = 0, length = item.ExternalUrls.length; i < length; i++) { var url = item.ExternalUrls[i]; - links.push('' + url.Name + ""); + links.push('' + url.Name + ''); } } if (links.length) { - html.push(globalize.translate("LinksValue", links.join(", "))); + html.push(links.join(', ')); } - linksElem.innerHTML = html.join(", "); + linksElem.innerHTML = html.join(', '); if (html.length) { - linksElem.classList.remove("hide"); + linksElem.classList.remove('hide'); } else { - linksElem.classList.add("hide"); + linksElem.classList.add('hide'); } } function renderDetailImage(page, elem, item, apiClient, editable, imageLoader, indicators) { - if ("SeriesTimer" === item.Type || "Program" === item.Type) { + if ('SeriesTimer' === item.Type || 'Program' === item.Type) { editable = false; } - if ("Person" !== item.Type) { - elem.classList.add("detailimg-hidemobile"); - page.querySelector(".detailPageContent").classList.add("detailPageContent-nodetailimg"); - } else { - page.querySelector(".detailPageContent").classList.remove("detailPageContent-nodetailimg"); - } + elem.classList.add('detailimg-hidemobile'); var imageTags = item.ImageTags || {}; @@ -755,132 +746,154 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } var url; - var html = ""; - var shape = "portrait"; + var html = ''; + var shape = 'portrait'; var detectRatio = false; + /* In the following section, getScreenWidth() is multiplied by 0.5 as the posters + are 25vw and we need double the resolution to counter Skia's scaling. */ + // TODO: Find a reliable way to get the poster width if (imageTags.Primary) { url = apiClient.getScaledImageUrl(item.Id, { - type: "Primary", + type: 'Primary', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.ImageTags.Primary }); detectRatio = true; } else if (item.BackdropImageTags && item.BackdropImageTags.length) { url = apiClient.getScaledImageUrl(item.Id, { - type: "Backdrop", + type: 'Backdrop', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.BackdropImageTags[0] }); - shape = "thumb"; + shape = 'thumb'; } else if (imageTags.Thumb) { url = apiClient.getScaledImageUrl(item.Id, { - type: "Thumb", + type: 'Thumb', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.ImageTags.Thumb }); - shape = "thumb"; + shape = 'thumb'; } else if (imageTags.Disc) { url = apiClient.getScaledImageUrl(item.Id, { - type: "Disc", + type: 'Disc', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.ImageTags.Disc }); - shape = "square"; + shape = 'square'; } else if (item.AlbumId && item.AlbumPrimaryImageTag) { url = apiClient.getScaledImageUrl(item.AlbumId, { - type: "Primary", + type: 'Primary', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.AlbumPrimaryImageTag }); - shape = "square"; + shape = 'square'; } else if (item.SeriesId && item.SeriesPrimaryImageTag) { url = apiClient.getScaledImageUrl(item.SeriesId, { - type: "Primary", + type: 'Primary', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.SeriesPrimaryImageTag }); } else if (item.ParentPrimaryImageItemId && item.ParentPrimaryImageTag) { url = apiClient.getScaledImageUrl(item.ParentPrimaryImageItemId, { - type: "Primary", + type: 'Primary', + maxWidth: Math.round(dom.getScreenWidth() * 0.5), tag: item.ParentPrimaryImageTag }); } - if (editable) { + if (editable && url === undefined) { + html += ""; + } else if (!editable && url === undefined) { + html += "'; } - var progressHtml = item.IsFolder || !item.UserData ? "" : indicators.getProgressBarHtml(item); + var progressHtml = item.IsFolder || !item.UserData ? '' : indicators.getProgressBarHtml(item); html += '
'; if (progressHtml) { html += progressHtml; } - html += "
"; + html += ''; elem.innerHTML = html; - if ("thumb" == shape) { - elem.classList.add("thumbDetailImageContainer"); - elem.classList.remove("portraitDetailImageContainer"); - elem.classList.remove("squareDetailImageContainer"); - } else if ("square" == shape) { - elem.classList.remove("thumbDetailImageContainer"); - elem.classList.remove("portraitDetailImageContainer"); - elem.classList.add("squareDetailImageContainer"); + if (detectRatio && item.PrimaryImageAspectRatio) { + if (item.PrimaryImageAspectRatio >= 1.48) { + shape = 'thumb'; + } else if (item.PrimaryImageAspectRatio >= 0.85 && item.PrimaryImageAspectRatio <= 1.34) { + shape = 'square'; + } + } + + if ('thumb' == shape) { + elem.classList.add('thumbDetailImageContainer'); + elem.classList.remove('portraitDetailImageContainer'); + elem.classList.remove('squareDetailImageContainer'); + } else if ('square' == shape) { + elem.classList.remove('thumbDetailImageContainer'); + elem.classList.remove('portraitDetailImageContainer'); + elem.classList.add('squareDetailImageContainer'); } else { - elem.classList.remove("thumbDetailImageContainer"); - elem.classList.add("portraitDetailImageContainer"); - elem.classList.remove("squareDetailImageContainer"); + elem.classList.remove('thumbDetailImageContainer'); + elem.classList.add('portraitDetailImageContainer'); + elem.classList.remove('squareDetailImageContainer'); } if (url) { - imageLoader.lazyImage(elem.querySelector("img"), url); + imageLoader.lazyImage(elem.querySelector('img'), url); } } function renderImage(page, item, apiClient, user) { renderDetailImage( page, - page.querySelector(".detailImageContainer"), + page.querySelector('.detailImageContainer'), item, apiClient, - user.Policy.IsAdministrator && "Photo" != item.MediaType, + user.Policy.IsAdministrator && 'Photo' != item.MediaType, imageLoader, indicators ); } function refreshDetailImageUserData(elem, item) { - elem.querySelector(".detailImageProgressContainer").innerHTML = indicators.getProgressBarHtml(item); + elem.querySelector('.detailImageProgressContainer').innerHTML = indicators.getProgressBarHtml(item); } - function refreshImage(page, item, user) { - refreshDetailImageUserData(page.querySelector(".detailImageContainer"), item); + function refreshImage(page, item) { + refreshDetailImageUserData(page.querySelector('.detailImageContainer'), item); } function setPeopleHeader(page, item) { - if ("Audio" == item.MediaType || "MusicAlbum" == item.Type || "Book" == item.MediaType || "Photo" == item.MediaType) { - page.querySelector("#peopleHeader").innerHTML = globalize.translate("HeaderPeople"); + if ('Audio' == item.MediaType || 'MusicAlbum' == item.Type || 'Book' == item.MediaType || 'Photo' == item.MediaType) { + page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderPeople'); } else { - page.querySelector("#peopleHeader").innerHTML = globalize.translate("HeaderCastAndCrew"); + page.querySelector('#peopleHeader').innerHTML = globalize.translate('HeaderCastAndCrew'); } } function renderNextUp(page, item, user) { - var section = page.querySelector(".nextUpSection"); + var section = page.querySelector('.nextUpSection'); - if ("Series" != item.Type) { - return void section.classList.add("hide"); + if ('Series' != item.Type) { + return void section.classList.add('hide'); } connectionManager.getApiClient(item.ServerId).getNextUpEpisodes({ @@ -888,109 +901,109 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana UserId: user.Id }).then(function (result) { if (result.Items.length) { - section.classList.remove("hide"); + section.classList.remove('hide'); } else { - section.classList.add("hide"); + section.classList.add('hide'); } var html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "overflowBackdrop", + shape: 'overflowBackdrop', showTitle: true, - displayAsSpecial: "Season" == item.Type && item.IndexNumber, + displayAsSpecial: 'Season' == item.Type && item.IndexNumber, overlayText: false, centerText: true, overlayPlayButton: true }); - var itemsContainer = section.querySelector(".nextUpItems"); + var itemsContainer = section.querySelector('.nextUpItems'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); }); } function setInitialCollapsibleState(page, item, apiClient, context, user) { - page.querySelector(".collectionItems").innerHTML = ""; + page.querySelector('.collectionItems').innerHTML = ''; - if ("Playlist" == item.Type) { - page.querySelector("#childrenCollapsible").classList.remove("hide"); - renderPlaylistItems(page, item, user); - } else if ("Studio" == item.Type || "Person" == item.Type || "Genre" == item.Type || "MusicGenre" == item.Type || "MusicArtist" == item.Type) { - page.querySelector("#childrenCollapsible").classList.remove("hide"); - renderItemsByName(page, item, user); + if ('Playlist' == item.Type) { + page.querySelector('#childrenCollapsible').classList.remove('hide'); + renderPlaylistItems(page, item); + } else if ('Studio' == item.Type || 'Person' == item.Type || 'Genre' == item.Type || 'MusicGenre' == item.Type || 'MusicArtist' == item.Type) { + page.querySelector('#childrenCollapsible').classList.remove('hide'); + renderItemsByName(page, item); } else if (item.IsFolder) { - if ("BoxSet" == item.Type) { - page.querySelector("#childrenCollapsible").classList.add("hide"); + if ('BoxSet' == item.Type) { + page.querySelector('#childrenCollapsible').classList.add('hide'); } renderChildren(page, item); } else { - page.querySelector("#childrenCollapsible").classList.add("hide"); + page.querySelector('#childrenCollapsible').classList.add('hide'); } - if ("Series" == item.Type) { - renderSeriesSchedule(page, item, user); + if ('Series' == item.Type) { + renderSeriesSchedule(page, item); renderNextUp(page, item, user); } else { - page.querySelector(".nextUpSection").classList.add("hide"); + page.querySelector('.nextUpSection').classList.add('hide'); } renderScenes(page, item); - if (item.SpecialFeatureCount && 0 != item.SpecialFeatureCount && "Series" != item.Type) { - page.querySelector("#specialsCollapsible").classList.remove("hide"); + if (item.SpecialFeatureCount && 0 != item.SpecialFeatureCount && 'Series' != item.Type) { + page.querySelector('#specialsCollapsible').classList.remove('hide'); renderSpecials(page, item, user, 6); } else { - page.querySelector("#specialsCollapsible").classList.add("hide"); + page.querySelector('#specialsCollapsible').classList.add('hide'); } - renderCast(page, item, context, enableScrollX() ? null : 12); + renderCast(page, item); if (item.PartCount && item.PartCount > 1) { - page.querySelector("#additionalPartsCollapsible").classList.remove("hide"); + page.querySelector('#additionalPartsCollapsible').classList.remove('hide'); renderAdditionalParts(page, item, user); } else { - page.querySelector("#additionalPartsCollapsible").classList.add("hide"); + page.querySelector('#additionalPartsCollapsible').classList.add('hide'); } - if ("MusicAlbum" == item.Type) { + if ('MusicAlbum' == item.Type) { renderMusicVideos(page, item, user); } else { - page.querySelector("#musicVideosCollapsible").classList.add("hide"); + page.querySelector('#musicVideosCollapsible').classList.add('hide'); } } function renderOverview(elems, item) { for (var i = 0, length = elems.length; i < length; i++) { var elem = elems[i]; - var overview = item.Overview || ""; + var overview = item.Overview || ''; if (overview) { elem.innerHTML = overview; - elem.classList.remove("hide"); - var anchors = elem.querySelectorAll("a"); + elem.classList.remove('hide'); + var anchors = elem.querySelectorAll('a'); for (var j = 0, length2 = anchors.length; j < length2; j++) { - anchors[j].setAttribute("target", "_blank"); + anchors[j].setAttribute('target', '_blank'); } } else { - elem.innerHTML = ""; - elem.classList.add("hide"); + elem.innerHTML = ''; + elem.classList.add('hide'); } } } - function renderGenres(page, item, apiClient, context, isStatic) { + function renderGenres(page, item, context) { context = context || inferContext(item); var type; var genres = item.GenreItems || []; switch (context) { - case "music": - type = "MusicGenre"; + case 'music': + type = 'MusicGenre'; break; default: - type = "Genre"; + type = 'Genre'; } var html = genres.map(function (p) { @@ -1001,39 +1014,47 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana Id: p.Id }, { context: context - }) + '">' + p.Name + ""; - }).join(", "); - var elem = page.querySelector(".genres"); - elem.innerHTML = globalize.translate(genres.length > 1 ? "GenresValue" : "GenreValue", html); + }) + '">' + p.Name + ''; + }).join(', '); + var genresLabel = page.querySelector('.genresLabel'); + genresLabel.innerHTML = globalize.translate(genres.length > 1 ? 'Genres' : 'Genre'); + var genresValue = page.querySelector('.genres'); + genresValue.innerHTML = html; + + var genresGroup = page.querySelector('.genresGroup'); if (genres.length) { - elem.classList.remove("hide"); + genresGroup.classList.remove('hide'); } else { - elem.classList.add("hide"); + genresGroup.classList.add('hide'); } } - function renderDirector(page, item, apiClient, context, isStatic) { + function renderDirector(page, item, context) { var directors = (item.People || []).filter(function (p) { - return "Director" === p.Type; + return 'Director' === p.Type; }); var html = directors.map(function (p) { return '' + p.Name + ""; - }).join(", "); - var elem = page.querySelector(".directors"); - elem.innerHTML = globalize.translate(directors.length > 1 ? "DirectorsValue" : "DirectorValue", html); + }) + '">' + p.Name + ''; + }).join(', '); + var directorsLabel = page.querySelector('.directorsLabel'); + directorsLabel.innerHTML = globalize.translate(directors.length > 1 ? 'Directors' : 'Director'); + var directorsValue = page.querySelector('.directors'); + directorsValue.innerHTML = html; + + var directorsGroup = page.querySelector('.directorsGroup'); if (directors.length) { - elem.classList.remove("hide"); + directorsGroup.classList.remove('hide'); } else { - elem.classList.add("hide"); + directorsGroup.classList.add('hide'); } } @@ -1041,30 +1062,25 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana renderSimilarItems(page, item, context); renderMoreFromSeason(page, item, apiClient); renderMoreFromArtist(page, item, apiClient); - renderDirector(page, item, apiClient, context, isStatic); - renderGenres(page, item, apiClient, context, isStatic); + renderDirector(page, item, context); + renderGenres(page, item, context); renderChannelGuide(page, apiClient, item); - var taglineElement = page.querySelector(".tagline"); + var taglineElement = page.querySelector('.tagline'); if (item.Taglines && item.Taglines.length) { - taglineElement.classList.remove("hide"); + taglineElement.classList.remove('hide'); taglineElement.innerHTML = item.Taglines[0]; } else { - taglineElement.classList.add("hide"); + taglineElement.classList.add('hide'); } - var overview = page.querySelector(".overview"); - var externalLinksElem = page.querySelector(".itemExternalLinks"); - - if ("Season" !== item.Type && "MusicAlbum" !== item.Type && "MusicArtist" !== item.Type) { - overview.classList.add("detailsHiddenOnMobile"); - externalLinksElem.classList.add("detailsHiddenOnMobile"); - } + var overview = page.querySelector('.overview'); + var externalLinksElem = page.querySelector('.itemExternalLinks'); renderOverview([overview], item); var i; var itemMiscInfo; - itemMiscInfo = page.querySelectorAll(".itemMiscInfo-primary"); + itemMiscInfo = page.querySelectorAll('.itemMiscInfo-primary'); for (i = 0; i < itemMiscInfo.length; i++) { mediaInfo.fillPrimaryMediaInfo(itemMiscInfo[i], item, { @@ -1073,30 +1089,29 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana subtitles: false }); - if (itemMiscInfo[i].innerHTML && "SeriesTimer" !== item.Type) { - itemMiscInfo[i].classList.remove("hide"); + if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) { + itemMiscInfo[i].classList.remove('hide'); } else { - itemMiscInfo[i].classList.add("hide"); + itemMiscInfo[i].classList.add('hide'); } } - itemMiscInfo = page.querySelectorAll(".itemMiscInfo-secondary"); + itemMiscInfo = page.querySelectorAll('.itemMiscInfo-secondary'); for (i = 0; i < itemMiscInfo.length; i++) { mediaInfo.fillSecondaryMediaInfo(itemMiscInfo[i], item, { interactive: true }); - if (itemMiscInfo[i].innerHTML && "SeriesTimer" !== item.Type) { - itemMiscInfo[i].classList.remove("hide"); + if (itemMiscInfo[i].innerHTML && 'SeriesTimer' !== item.Type) { + itemMiscInfo[i].classList.remove('hide'); } else { - itemMiscInfo[i].classList.add("hide"); + itemMiscInfo[i].classList.add('hide'); } } reloadUserDataButtons(page, item); renderLinks(externalLinksElem, item); - renderUserInfo(page, item); renderTags(page, item); renderSeriesAirTime(page, item, isStatic); } @@ -1110,7 +1125,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana scrollX = enableScrollX(); } - return scrollX ? "overflowPortrait" : "portrait"; + return scrollX ? 'overflowPortrait' : 'portrait'; } function getSquareShape(scrollX) { @@ -1118,43 +1133,35 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana scrollX = enableScrollX(); } - return scrollX ? "overflowSquare" : "square"; - } - - function getThumbShape(scrollX) { - if (null == scrollX) { - scrollX = enableScrollX(); - } - - return scrollX ? "overflowBackdrop" : "backdrop"; + return scrollX ? 'overflowSquare' : 'square'; } function renderMoreFromSeason(view, item, apiClient) { - var section = view.querySelector(".moreFromSeasonSection"); + var section = view.querySelector('.moreFromSeasonSection'); if (section) { - if ("Episode" !== item.Type || !item.SeasonId || !item.SeriesId) { - return void section.classList.add("hide"); + if ('Episode' !== item.Type || !item.SeasonId || !item.SeriesId) { + return void section.classList.add('hide'); } var userId = apiClient.getCurrentUserId(); apiClient.getEpisodes(item.SeriesId, { SeasonId: item.SeasonId, UserId: userId, - Fields: "ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount" + Fields: 'ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount' }).then(function (result) { if (result.Items.length < 2) { - return void section.classList.add("hide"); + return void section.classList.add('hide'); } - section.classList.remove("hide"); - section.querySelector("h2").innerHTML = globalize.translate("MoreFromValue", item.SeasonName); - var itemsContainer = section.querySelector(".itemsContainer"); + section.classList.remove('hide'); + section.querySelector('h2').innerHTML = globalize.translate('MoreFromValue', item.SeasonName); + var itemsContainer = section.querySelector('.itemsContainer'); cardBuilder.buildCards(result.Items, { parentContainer: section, itemsContainer: itemsContainer, - shape: "autooverflow", - sectionTitleTagName: "h2", + shape: 'autooverflow', + sectionTitleTagName: 'h2', scalable: true, showTitle: true, overlayText: false, @@ -1166,7 +1173,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (card) { setTimeout(function () { - section.querySelector(".emby-scroller").toStart(card.previousSibling || card, true); + section.querySelector('.emby-scroller').toStart(card.previousSibling || card, true); }, 100); } }); @@ -1174,28 +1181,28 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function renderMoreFromArtist(view, item, apiClient) { - var section = view.querySelector(".moreFromArtistSection"); + var section = view.querySelector('.moreFromArtistSection'); if (section) { - if ("MusicArtist" === item.Type) { - if (!apiClient.isMinServerVersion("3.4.1.19")) { - return void section.classList.add("hide"); + if ('MusicArtist' === item.Type) { + if (!apiClient.isMinServerVersion('3.4.1.19')) { + return void section.classList.add('hide'); } - } else if ("MusicAlbum" !== item.Type || !item.AlbumArtists || !item.AlbumArtists.length) { - return void section.classList.add("hide"); + } else if ('MusicAlbum' !== item.Type || !item.AlbumArtists || !item.AlbumArtists.length) { + return void section.classList.add('hide'); } var query = { - IncludeItemTypes: "MusicAlbum", + IncludeItemTypes: 'MusicAlbum', Recursive: true, ExcludeItemIds: item.Id, - SortBy: "ProductionYear,SortName", - SortOrder: "Descending" + SortBy: 'ProductionYear,SortName', + SortOrder: 'Descending' }; - if ("MusicArtist" === item.Type) { + if ('MusicArtist' === item.Type) { query.ContributingArtistIds = item.Id; - } else if (apiClient.isMinServerVersion("3.4.1.18")) { + } else if (apiClient.isMinServerVersion('3.4.1.18')) { query.AlbumArtistIds = item.AlbumArtists[0].Id; } else { query.ArtistIds = item.AlbumArtists[0].Id; @@ -1203,24 +1210,24 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana apiClient.getItems(apiClient.getCurrentUserId(), query).then(function (result) { if (!result.Items.length) { - return void section.classList.add("hide"); + return void section.classList.add('hide'); } - section.classList.remove("hide"); + section.classList.remove('hide'); - if ("MusicArtist" === item.Type) { - section.querySelector("h2").innerHTML = globalize.translate("HeaderAppearsOn"); + if ('MusicArtist' === item.Type) { + section.querySelector('h2').innerHTML = globalize.translate('HeaderAppearsOn'); } else { - section.querySelector("h2").innerHTML = globalize.translate("MoreFromValue", item.AlbumArtists[0].Name); + section.querySelector('h2').innerHTML = globalize.translate('MoreFromValue', item.AlbumArtists[0].Name); } cardBuilder.buildCards(result.Items, { parentContainer: section, - itemsContainer: section.querySelector(".itemsContainer"), - shape: "autooverflow", - sectionTitleTagName: "h2", + itemsContainer: section.querySelector('.itemsContainer'), + shape: 'autooverflow', + sectionTitleTagName: 'h2', scalable: true, - coverImage: "MusicArtist" === item.Type || "MusicAlbum" === item.Type, + coverImage: 'MusicArtist' === item.Type || 'MusicAlbum' === item.Type, showTitle: true, showParentTitle: false, centerText: true, @@ -1233,47 +1240,47 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function renderSimilarItems(page, item, context) { - var similarCollapsible = page.querySelector("#similarCollapsible"); + var similarCollapsible = page.querySelector('#similarCollapsible'); if (similarCollapsible) { - if ("Movie" != item.Type && "Trailer" != item.Type && "Series" != item.Type && "Program" != item.Type && "Recording" != item.Type && "MusicAlbum" != item.Type && "MusicArtist" != item.Type && "Playlist" != item.Type) { - return void similarCollapsible.classList.add("hide"); + if ('Movie' != item.Type && 'Trailer' != item.Type && 'Series' != item.Type && 'Program' != item.Type && 'Recording' != item.Type && 'MusicAlbum' != item.Type && 'MusicArtist' != item.Type && 'Playlist' != item.Type) { + return void similarCollapsible.classList.add('hide'); } - similarCollapsible.classList.remove("hide"); + similarCollapsible.classList.remove('hide'); var apiClient = connectionManager.getApiClient(item.ServerId); var options = { userId: apiClient.getCurrentUserId(), limit: 12, - fields: "PrimaryImageAspectRatio,UserData,CanDelete" + fields: 'PrimaryImageAspectRatio,UserData,CanDelete' }; - if ("MusicAlbum" == item.Type && item.AlbumArtists && item.AlbumArtists.length) { + if ('MusicAlbum' == item.Type && item.AlbumArtists && item.AlbumArtists.length) { options.ExcludeArtistIds = item.AlbumArtists[0].Id; } apiClient.getSimilarItems(item.Id, options).then(function (result) { if (!result.Items.length) { - return void similarCollapsible.classList.add("hide"); + return void similarCollapsible.classList.add('hide'); } - similarCollapsible.classList.remove("hide"); - var html = ""; + similarCollapsible.classList.remove('hide'); + var html = ''; html += cardBuilder.getCardsHtml({ items: result.Items, - shape: "autooverflow", - showParentTitle: "MusicAlbum" == item.Type, + shape: 'autooverflow', + showParentTitle: 'MusicAlbum' == item.Type, centerText: true, showTitle: true, context: context, lazy: true, showDetailsMenu: true, - coverImage: "MusicAlbum" == item.Type || "MusicArtist" == item.Type, + coverImage: 'MusicAlbum' == item.Type || 'MusicArtist' == item.Type, overlayPlayButton: true, overlayText: false, - showYear: "Movie" === item.Type || "Trailer" === item.Type || "Series" === item.Type + showYear: 'Movie' === item.Type || 'Trailer' === item.Type || 'Series' === item.Type }); - var similarContent = similarCollapsible.querySelector(".similarContent"); + var similarContent = similarCollapsible.querySelector('.similarContent'); similarContent.innerHTML = html; imageLoader.lazyChildren(similarContent); }); @@ -1281,52 +1288,52 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function renderSeriesAirTime(page, item, isStatic) { - var seriesAirTime = page.querySelector("#seriesAirTime"); - if ("Series" != item.Type) { - seriesAirTime.classList.add("hide"); + var seriesAirTime = page.querySelector('#seriesAirTime'); + if ('Series' != item.Type) { + seriesAirTime.classList.add('hide'); return; } - var html = ""; + var html = ''; if (item.AirDays && item.AirDays.length) { if (7 == item.AirDays.length) { - html += "daily"; + html += 'daily'; } else { html += item.AirDays.map(function (a) { - return a + "s"; - }).join(","); + return a + 's'; + }).join(','); } } if (item.AirTime) { - html += " at " + item.AirTime; + html += ' at ' + item.AirTime; } if (item.Studios.length) { if (isStatic) { - html += " on " + item.Studios[0].Name; + html += ' on ' + item.Studios[0].Name; } else { var context = inferContext(item); var href = appRouter.getRouteUrl(item.Studios[0], { context: context, - itemType: "Studio", + itemType: 'Studio', serverId: item.ServerId }); - html += ' on ' + item.Studios[0].Name + ""; + html += ' on ' + item.Studios[0].Name + ''; } } if (html) { - html = ("Ended" == item.Status ? "Aired " : "Airs ") + html; + html = ('Ended' == item.Status ? 'Aired ' : 'Airs ') + html; seriesAirTime.innerHTML = html; - seriesAirTime.classList.remove("hide"); + seriesAirTime.classList.remove('hide'); } else { - seriesAirTime.classList.add("hide"); + seriesAirTime.classList.add('hide'); } } function renderTags(page, item) { - var itemTags = page.querySelector(".itemTags"); + var itemTags = page.querySelector('.itemTags'); var tagElements = []; var tags = item.Tags || []; - if ("Program" === item.Type) { + if ('Program' === item.Type) { tags = []; } @@ -1335,93 +1342,93 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } if (tagElements.length) { - itemTags.innerHTML = globalize.translate("TagsValue", tagElements.join(", ")); - itemTags.classList.remove("hide"); + itemTags.innerHTML = globalize.translate('TagsValue', tagElements.join(', ')); + itemTags.classList.remove('hide'); } else { - itemTags.innerHTML = ""; - itemTags.classList.add("hide"); + itemTags.innerHTML = ''; + itemTags.classList.add('hide'); } } function renderChildren(page, item) { - var fields = "ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount"; + var fields = 'ItemCounts,PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount'; var query = { ParentId: item.Id, Fields: fields }; - if ("BoxSet" !== item.Type) { - query.SortBy = "SortName"; + if ('BoxSet' !== item.Type) { + query.SortBy = 'SortName'; } var promise; var apiClient = connectionManager.getApiClient(item.ServerId); var userId = apiClient.getCurrentUserId(); - if ("Series" == item.Type) { + if ('Series' == item.Type) { promise = apiClient.getSeasons(item.Id, { userId: userId, Fields: fields }); - } else if ("Season" == item.Type) { - fields += ",Overview"; + } else if ('Season' == item.Type) { + fields += ',Overview'; promise = apiClient.getEpisodes(item.SeriesId, { seasonId: item.Id, userId: userId, Fields: fields }); - } else if ("MusicArtist" == item.Type) { - query.SortBy = "ProductionYear,SortName"; + } else if ('MusicArtist' == item.Type) { + query.SortBy = 'ProductionYear,SortName'; } promise = promise || apiClient.getItems(apiClient.getCurrentUserId(), query); promise.then(function (result) { - var html = ""; + var html = ''; var scrollX = false; var isList = false; - var childrenItemsContainer = page.querySelector(".childrenItemsContainer"); + var childrenItemsContainer = page.querySelector('.childrenItemsContainer'); - if ("MusicAlbum" == item.Type) { + if ('MusicAlbum' == item.Type) { html = listView.getListViewHtml({ items: result.Items, smallIcon: true, showIndex: true, - index: "disc", + index: 'disc', showIndexNumberLeft: true, playFromHere: true, - action: "playallfromhere", + action: 'playallfromhere', image: false, - artist: "auto", + artist: 'auto', containerAlbumArtists: item.AlbumArtists, addToListButton: true }); isList = true; - } else if ("Series" == item.Type) { + } else if ('Series' == item.Type) { scrollX = enableScrollX(); html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "overflowPortrait", + shape: 'overflowPortrait', showTitle: true, centerText: true, lazy: true, overlayPlayButton: true, allowBottomPadding: !scrollX }); - } else if ("Season" == item.Type || "Episode" == item.Type) { - if ("Episode" !== item.Type) { + } else if ('Season' == item.Type || 'Episode' == item.Type) { + if ('Episode' !== item.Type) { isList = true; } - scrollX = "Episode" == item.Type; - if (result.Items.length < 2 && "Episode" === item.Type) { + scrollX = 'Episode' == item.Type; + if (result.Items.length < 2 && 'Episode' === item.Type) { return; } - if ("Episode" === item.Type) { + if ('Episode' === item.Type) { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "overflowBackdrop", + shape: 'overflowBackdrop', showTitle: true, - displayAsSpecial: "Season" == item.Type && item.IndexNumber, + displayAsSpecial: 'Season' == item.Type && item.IndexNumber, playFromHere: true, overlayText: true, lazy: true, @@ -1430,15 +1437,15 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana allowBottomPadding: !scrollX, includeParentInfoInTitle: false }); - } else if ("Season" === item.Type) { + } else if ('Season' === item.Type) { html = listView.getListViewHtml({ items: result.Items, showIndexNumber: false, enableOverview: true, - imageSize: "large", + imageSize: 'large', enableSideMediaInfo: false, highlight: false, - action: layoutManager.tv ? "resume" : "none", + action: layoutManager.tv ? 'resume' : 'none', infoButton: true, imagePlayButton: true, includeParentInfoInTitle: false @@ -1446,78 +1453,78 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } } - if ("BoxSet" !== item.Type) { - page.querySelector("#childrenCollapsible").classList.remove("hide"); + if ('BoxSet' !== item.Type) { + page.querySelector('#childrenCollapsible').classList.remove('hide'); } if (scrollX) { - childrenItemsContainer.classList.add("scrollX"); - childrenItemsContainer.classList.add("hiddenScrollX"); - childrenItemsContainer.classList.remove("vertical-wrap"); - childrenItemsContainer.classList.remove("vertical-list"); + childrenItemsContainer.classList.add('scrollX'); + childrenItemsContainer.classList.add('hiddenScrollX'); + childrenItemsContainer.classList.remove('vertical-wrap'); + childrenItemsContainer.classList.remove('vertical-list'); } else { - childrenItemsContainer.classList.remove("scrollX"); - childrenItemsContainer.classList.remove("hiddenScrollX"); - childrenItemsContainer.classList.remove("smoothScrollX"); + childrenItemsContainer.classList.remove('scrollX'); + childrenItemsContainer.classList.remove('hiddenScrollX'); + childrenItemsContainer.classList.remove('smoothScrollX'); if (isList) { - childrenItemsContainer.classList.add("vertical-list"); - childrenItemsContainer.classList.remove("vertical-wrap"); + childrenItemsContainer.classList.add('vertical-list'); + childrenItemsContainer.classList.remove('vertical-wrap'); } else { - childrenItemsContainer.classList.add("vertical-wrap"); - childrenItemsContainer.classList.remove("vertical-list"); + childrenItemsContainer.classList.add('vertical-wrap'); + childrenItemsContainer.classList.remove('vertical-list'); } } childrenItemsContainer.innerHTML = html; imageLoader.lazyChildren(childrenItemsContainer); - if ("BoxSet" == item.Type) { + if ('BoxSet' == item.Type) { var collectionItemTypes = [{ - name: globalize.translate("HeaderVideos"), - mediaType: "Video" + name: globalize.translate('HeaderVideos'), + mediaType: 'Video' }, { - name: globalize.translate("HeaderSeries"), - type: "Series" + name: globalize.translate('HeaderSeries'), + type: 'Series' }, { - name: globalize.translate("HeaderAlbums"), - type: "MusicAlbum" + name: globalize.translate('HeaderAlbums'), + type: 'MusicAlbum' }, { - name: globalize.translate("HeaderBooks"), - type: "Book" + name: globalize.translate('HeaderBooks'), + type: 'Book' }]; renderCollectionItems(page, item, collectionItemTypes, result.Items); } }); - if ("Season" == item.Type) { - page.querySelector("#childrenTitle").innerHTML = globalize.translate("HeaderEpisodes"); - } else if ("Series" == item.Type) { - page.querySelector("#childrenTitle").innerHTML = globalize.translate("HeaderSeasons"); - } else if ("MusicAlbum" == item.Type) { - page.querySelector("#childrenTitle").innerHTML = globalize.translate("HeaderTracks"); + if ('Season' == item.Type) { + page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderEpisodes'); + } else if ('Series' == item.Type) { + page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderSeasons'); + } else if ('MusicAlbum' == item.Type) { + page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderTracks'); } else { - page.querySelector("#childrenTitle").innerHTML = globalize.translate("HeaderItems"); + page.querySelector('#childrenTitle').innerHTML = globalize.translate('HeaderItems'); } - if ("MusicAlbum" == item.Type || "Season" == item.Type) { - page.querySelector(".childrenSectionHeader").classList.add("hide"); - page.querySelector("#childrenCollapsible").classList.add("verticalSection-extrabottompadding"); + if ('MusicAlbum' == item.Type || 'Season' == item.Type) { + page.querySelector('.childrenSectionHeader').classList.add('hide'); + page.querySelector('#childrenCollapsible').classList.add('verticalSection-extrabottompadding'); } else { - page.querySelector(".childrenSectionHeader").classList.remove("hide"); + page.querySelector('.childrenSectionHeader').classList.remove('hide'); } } - function renderItemsByName(page, item, user) { - require("scripts/itembynamedetailpage".split(","), function () { + function renderItemsByName(page, item) { + require('scripts/itembynamedetailpage'.split(','), function () { window.ItemsByName.renderItems(page, item); }); } - function renderPlaylistItems(page, item, user) { - require("scripts/playlistedit".split(","), function () { + function renderPlaylistItems(page, item) { + require('scripts/playlistedit'.split(','), function () { PlaylistViewer.render(page, item); }); } function renderProgramsForChannel(page, result) { - var html = ""; + var html = ''; var currentItems = []; var currentStartDate = null; @@ -1529,10 +1536,10 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (currentItems.length) { html += '
'; html += '

' + datetime.toLocaleDateString(currentStartDate, { - weekday: "long", - month: "long", - day: "numeric" - }) + "

"; + weekday: 'long', + month: 'long', + day: 'numeric' + }) + ''; html += '
' + listView.getListViewHtml({ items: currentItems, enableUserDataButtons: false, @@ -1541,7 +1548,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana showProgramTime: true, mediaInfo: false, parentTitleWithTitle: true - }) + "
"; + }) + ''; } currentStartDate = itemStartDate; @@ -1554,10 +1561,10 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (currentItems.length) { html += '
'; html += '

' + datetime.toLocaleDateString(currentStartDate, { - weekday: "long", - month: "long", - day: "numeric" - }) + "

"; + weekday: 'long', + month: 'long', + day: 'numeric' + }) + ''; html += '
' + listView.getListViewHtml({ items: currentItems, enableUserDataButtons: false, @@ -1566,20 +1573,20 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana showProgramTime: true, mediaInfo: false, parentTitleWithTitle: true - }) + "
"; + }) + ''; } - page.querySelector(".programGuide").innerHTML = html; + page.querySelector('.programGuide').innerHTML = html; } function renderChannelGuide(page, apiClient, item) { - if ("TvChannel" === item.Type) { - page.querySelector(".programGuideSection").classList.remove("hide"); + if ('TvChannel' === item.Type) { + page.querySelector('.programGuideSection').classList.remove('hide'); apiClient.getLiveTvPrograms({ ChannelIds: item.Id, UserId: apiClient.getCurrentUserId(), HasAired: false, - SortBy: "StartDate", + SortBy: 'StartDate', EnableTotalRecordCount: false, EnableImages: false, ImageTypeLimit: 0, @@ -1590,12 +1597,12 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } } - function renderSeriesSchedule(page, item, user) { + function renderSeriesSchedule(page, item) { var apiClient = connectionManager.getApiClient(item.ServerId); apiClient.getLiveTvPrograms({ UserId: apiClient.getCurrentUserId(), HasAired: false, - SortBy: "StartDate", + SortBy: 'StartDate', EnableTotalRecordCount: false, EnableImages: false, ImageTypeLimit: 0, @@ -1604,12 +1611,12 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana LibrarySeriesId: item.Id }).then(function (result) { if (result.Items.length) { - page.querySelector("#seriesScheduleSection").classList.remove("hide"); + page.querySelector('#seriesScheduleSection').classList.remove('hide'); } else { - page.querySelector("#seriesScheduleSection").classList.add("hide"); + page.querySelector('#seriesScheduleSection').classList.add('hide'); } - page.querySelector("#seriesScheduleList").innerHTML = listView.getListViewHtml({ + page.querySelector('#seriesScheduleList').innerHTML = listView.getListViewHtml({ items: result.Items, enableUserDataButtons: false, showParentTitle: false, @@ -1618,27 +1625,27 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana mediaInfo: false, showTitle: true, moreButton: false, - action: "programdialog" + action: 'programdialog' }); loading.hide(); }); } function inferContext(item) { - if ("Movie" === item.Type || "BoxSet" === item.Type) { - return "movies"; + if ('Movie' === item.Type || 'BoxSet' === item.Type) { + return 'movies'; } - if ("Series" === item.Type || "Season" === item.Type || "Episode" === item.Type) { - return "tvshows"; + if ('Series' === item.Type || 'Season' === item.Type || 'Episode' === item.Type) { + return 'tvshows'; } - if ("MusicArtist" === item.Type || "MusicAlbum" === item.Type || "Audio" === item.Type || "AudioBook" === item.Type) { - return "music"; + if ('MusicArtist' === item.Type || 'MusicAlbum' === item.Type || 'Audio' === item.Type || 'AudioBook' === item.Type) { + return 'music'; } - if ("Program" === item.Type) { - return "livetv"; + if ('Program' === item.Type) { + return 'livetv'; } return null; @@ -1657,7 +1664,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function canPlaySomeItemInCollection(items) { var i = 0; - for (length = items.length; i < length; i++) { + for (var length = items.length; i < length; i++) { if (playbackManager.canPlay(items[i])) { return true; } @@ -1667,7 +1674,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function renderCollectionItems(page, parentItem, types, items) { - page.querySelector(".collectionItems").innerHTML = ""; + page.querySelector('.collectionItems').innerHTML = ''; var i; var length; @@ -1681,7 +1688,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } var otherType = { - name: globalize.translate("HeaderOtherItems") + name: globalize.translate('HeaderOtherItems') }; var otherTypeItems = items.filter(function (curr) { return !types.filter(function (t) { @@ -1695,11 +1702,11 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (!items.length) { renderCollectionItemType(page, parentItem, { - name: globalize.translate("HeaderItems") + name: globalize.translate('HeaderItems') }, items); } - var containers = page.querySelectorAll(".collectionItemsContainer"); + var containers = page.querySelectorAll('.collectionItemsContainer'); var notifyRefreshNeeded = function () { renderChildren(page, parentItem); @@ -1711,33 +1718,33 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana // if nothing in the collection can be played hide play and shuffle buttons if (!canPlaySomeItemInCollection(items)) { - hideAll(page, "btnPlay", false); - hideAll(page, "btnShuffle", false); + hideAll(page, 'btnPlay', false); + hideAll(page, 'btnShuffle', false); } // HACK: Call autoFocuser again because btnPlay may be hidden, but focused by reloadFromItem // FIXME: Sometimes focus does not move until all (?) sections are loaded - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); } function renderCollectionItemType(page, parentItem, type, items) { - var html = ""; + var html = ''; html += '
'; html += '
'; html += '

'; - html += "" + type.name + ""; - html += "

"; - html += ''; - html += "
"; + html += '' + type.name + ''; + html += ''; + html += ''; + html += '
'; html += '
'; - var shape = "MusicAlbum" == type.type ? getSquareShape(false) : getPortraitShape(false); + var shape = 'MusicAlbum' == type.type ? getSquareShape(false) : getPortraitShape(false); html += cardBuilder.getCardsHtml({ items: items, shape: shape, showTitle: true, - showYear: "Video" === type.mediaType || "Series" === type.type, + showYear: 'Video' === type.mediaType || 'Series' === type.type, centerText: true, lazy: true, showDetailsMenu: true, @@ -1746,16 +1753,16 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana showRemoveFromCollection: true, collectionId: parentItem.Id }); - html += "
"; - html += ""; - var collectionItems = page.querySelector(".collectionItems"); - collectionItems.insertAdjacentHTML("beforeend", html); + html += ''; + html += ''; + var collectionItems = page.querySelector('.collectionItems'); + collectionItems.insertAdjacentHTML('beforeend', html); imageLoader.lazyChildren(collectionItems); - collectionItems.querySelector(".btnAddToCollection").addEventListener("click", function () { - require(["alert"], function (alert) { + collectionItems.querySelector('.btnAddToCollection').addEventListener('click', function () { + require(['alert'], function (alert) { alert({ - text: globalize.translate("AddItemToCollectionHelp"), - html: globalize.translate("AddItemToCollectionHelp") + '

' + globalize.translate("ButtonLearnMore") + "" + text: globalize.translate('AddItemToCollectionHelp'), + html: globalize.translate('AddItemToCollectionHelp') + '

' + globalize.translate('ButtonLearnMore') + '' }); }); }); @@ -1763,20 +1770,20 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function renderMusicVideos(page, item, user) { connectionManager.getApiClient(item.ServerId).getItems(user.Id, { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "MusicVideo", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'MusicVideo', Recursive: true, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo,CanDelete,MediaSourceCount', AlbumIds: item.Id }).then(function (result) { if (result.Items.length) { - page.querySelector("#musicVideosCollapsible").classList.remove("hide"); - var musicVideosContent = page.querySelector(".musicVideosContent"); + page.querySelector('#musicVideosCollapsible').classList.remove('hide'); + var musicVideosContent = page.querySelector('.musicVideosContent'); musicVideosContent.innerHTML = getVideosHtml(result.Items, user); imageLoader.lazyChildren(musicVideosContent); } else { - page.querySelector("#musicVideosCollapsible").classList.add("hide"); + page.querySelector('#musicVideosCollapsible').classList.add('hide'); } }); } @@ -1784,12 +1791,12 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function renderAdditionalParts(page, item, user) { connectionManager.getApiClient(item.ServerId).getAdditionalVideoParts(user.Id, item.Id).then(function (result) { if (result.Items.length) { - page.querySelector("#additionalPartsCollapsible").classList.remove("hide"); - var additionalPartsContent = page.querySelector("#additionalPartsContent"); + page.querySelector('#additionalPartsCollapsible').classList.remove('hide'); + var additionalPartsContent = page.querySelector('#additionalPartsContent'); additionalPartsContent.innerHTML = getVideosHtml(result.Items, user); imageLoader.lazyChildren(additionalPartsContent); } else { - page.querySelector("#additionalPartsCollapsible").classList.add("hide"); + page.querySelector('#additionalPartsCollapsible').classList.add('hide'); } }); } @@ -1798,35 +1805,34 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana var chapters = item.Chapters || []; if (chapters.length && !chapters[0].ImageTag && (chapters = []), chapters.length) { - page.querySelector("#scenesCollapsible").classList.remove("hide"); - var scenesContent = page.querySelector("#scenesContent"); + page.querySelector('#scenesCollapsible').classList.remove('hide'); + var scenesContent = page.querySelector('#scenesContent'); - require(["chaptercardbuilder"], function (chaptercardbuilder) { + require(['chaptercardbuilder'], function (chaptercardbuilder) { chaptercardbuilder.buildChapterCards(item, chapters, { itemsContainer: scenesContent, - width: 400, - backdropShape: "overflowBackdrop", - squareShape: "overflowSquare" + backdropShape: 'overflowBackdrop', + squareShape: 'overflowSquare' }); }); } else { - page.querySelector("#scenesCollapsible").classList.add("hide"); + page.querySelector('#scenesCollapsible').classList.add('hide'); } } function getVideosHtml(items, user, limit, moreButtonClass) { var html = cardBuilder.getCardsHtml({ items: items, - shape: "auto", + shape: 'auto', showTitle: true, - action: "play", + action: 'play', overlayText: false, centerText: true, showRuntime: true }); if (limit && items.length > limit) { - html += '

"; + html += '

'; } return html; @@ -1834,31 +1840,30 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function renderSpecials(page, item, user, limit) { connectionManager.getApiClient(item.ServerId).getSpecialFeatures(user.Id, item.Id).then(function (specials) { - var specialsContent = page.querySelector("#specialsContent"); - specialsContent.innerHTML = getVideosHtml(specials, user, limit, "moreSpecials"); + var specialsContent = page.querySelector('#specialsContent'); + specialsContent.innerHTML = getVideosHtml(specials, user, limit, 'moreSpecials'); imageLoader.lazyChildren(specialsContent); }); } - function renderCast(page, item, context, limit, isStatic) { + function renderCast(page, item) { var people = (item.People || []).filter(function (p) { - return "Director" !== p.Type; + return 'Director' !== p.Type; }); if (!people.length) { - return void page.querySelector("#castCollapsible").classList.add("hide"); + return void page.querySelector('#castCollapsible').classList.add('hide'); } - page.querySelector("#castCollapsible").classList.remove("hide"); - var castContent = page.querySelector("#castContent"); + page.querySelector('#castCollapsible').classList.remove('hide'); + var castContent = page.querySelector('#castContent'); - require(["peoplecardbuilder"], function (peoplecardbuilder) { + require(['peoplecardbuilder'], function (peoplecardbuilder) { peoplecardbuilder.buildPeopleCards(people, { itemsContainer: castContent, coverImage: true, serverId: item.ServerId, - width: 160, - shape: "overflowPortrait" + shape: 'overflowPortrait' }); }); } @@ -1900,12 +1905,12 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function splitVersions(instance, page, apiClient, params) { - require(["confirm"], function (confirm) { - confirm("Are you sure you wish to split the media sources into separate items?", "Split Media Apart").then(function () { + require(['confirm'], function (confirm) { + confirm('Are you sure you wish to split the media sources into separate items?', 'Split Media Apart').then(function () { loading.show(); apiClient.ajax({ - type: "DELETE", - url: apiClient.getUrl("Videos/" + params.id + "/AlternateSources") + type: 'DELETE', + url: apiClient.getUrl('Videos/' + params.id + '/AlternateSources') }).then(function () { loading.hide(); reload(instance, page, params); @@ -1915,12 +1920,12 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function getPlayOptions(startPosition) { - var audioStreamIndex = view.querySelector(".selectAudio").value || null; + var audioStreamIndex = view.querySelector('.selectAudio').value || null; return { startPositionTicks: startPosition, - mediaSourceId: view.querySelector(".selectSource").value, + mediaSourceId: view.querySelector('.selectSource').value, audioStreamIndex: audioStreamIndex, - subtitleStreamIndex: view.querySelector(".selectSubtitles").value + subtitleStreamIndex: view.querySelector('.selectSubtitles').value }; } @@ -1930,14 +1935,14 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana playbackManager.play(playOptions); } - function playTrailer(page) { + function playTrailer() { playbackManager.playTrailers(currentItem); } function playCurrentItem(button, mode) { var item = currentItem; - if ("Program" === item.Type) { + if ('Program' === item.Type) { var apiClient = connectionManager.getApiClient(item.ServerId); return void apiClient.getLiveTvChannel(item.ChannelId, apiClient.getCurrentUserId()).then(function (channel) { playbackManager.play({ @@ -1946,11 +1951,11 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana }); } - playItem(item, item.UserData && "resume" === mode ? item.UserData.PlaybackPositionTicks : 0); + playItem(item, item.UserData && 'resume' === mode ? item.UserData.PlaybackPositionTicks : 0); } function onPlayClick() { - playCurrentItem(this, this.getAttribute("data-mode")); + playCurrentItem(this, this.getAttribute('data-mode')); } function onInstantMixClick() { @@ -1962,7 +1967,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function onDeleteClick() { - require(["deleteHelper"], function (deleteHelper) { + require(['deleteHelper'], function (deleteHelper) { deleteHelper.deleteItem({ item: currentItem, navigate: true @@ -1971,15 +1976,15 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function onCancelSeriesTimerClick() { - require(["recordingHelper"], function (recordingHelper) { + require(['recordingHelper'], function (recordingHelper) { recordingHelper.cancelSeriesTimerWithConfirmation(currentItem.Id, currentItem.ServerId).then(function () { - Dashboard.navigate("livetv.html"); + Dashboard.navigate('livetv.html'); }); }); } function onCancelTimerClick() { - require(["recordingHelper"], function (recordingHelper) { + require(['recordingHelper'], function (recordingHelper) { recordingHelper.cancelTimer(connectionManager.getApiClient(currentItem.ServerId), currentItem.TimerId).then(function () { reload(self, view, params); }); @@ -1987,11 +1992,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana } function onPlayTrailerClick() { - playTrailer(view); - } - - function onDownloadChange() { - reload(self, view, params); + playTrailer(); } function onDownloadClick() { @@ -2025,7 +2026,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function editImages() { return new Promise(function (resolve, reject) { - require(["imageEditor"], function (imageEditor) { + require(['imageEditor'], function (imageEditor) { imageEditor.show({ itemId: currentItem.Id, serverId: currentItem.ServerId @@ -2037,7 +2038,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana function onWebSocketMessage(e, data) { var msg = data; - if ("UserDataChanged" === msg.MessageType && currentItem && msg.Data.UserId == apiClient.getCurrentUserId()) { + if ('UserDataChanged' === msg.MessageType && currentItem && msg.Data.UserId == apiClient.getCurrentUserId()) { var key = currentItem.UserData.Key; var userData = msg.Data.UserDataList.filter(function (u) { return u.Key == key; @@ -2046,9 +2047,7 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana if (userData) { currentItem.UserData = userData; reloadPlayButtons(view, currentItem); - apiClient.getCurrentUser().then(function (user) { - refreshImage(view, currentItem, user); - }); + refreshImage(view, currentItem); } } } @@ -2056,69 +2055,69 @@ define(["loading", "appRouter", "layoutManager", "userSettings", "connectionMana var currentItem; var self = this; var apiClient = params.serverId ? connectionManager.getApiClient(params.serverId) : ApiClient; - view.querySelectorAll(".btnPlay"); - bindAll(view, ".btnPlay", "click", onPlayClick); - bindAll(view, ".btnResume", "click", onPlayClick); - bindAll(view, ".btnInstantMix", "click", onInstantMixClick); - bindAll(view, ".btnShuffle", "click", onShuffleClick); - bindAll(view, ".btnPlayTrailer", "click", onPlayTrailerClick); - bindAll(view, ".btnCancelSeriesTimer", "click", onCancelSeriesTimerClick); - bindAll(view, ".btnCancelTimer", "click", onCancelTimerClick); - bindAll(view, ".btnDeleteItem", "click", onDeleteClick); - bindAll(view, ".btnDownload", "click", onDownloadClick); - view.querySelector(".btnMoreCommands i").innerHTML = "more_horiz"; - view.querySelector(".trackSelections").addEventListener("submit", onTrackSelectionsSubmit); - view.querySelector(".btnSplitVersions").addEventListener("click", function () { + view.querySelectorAll('.btnPlay'); + bindAll(view, '.btnPlay', 'click', onPlayClick); + bindAll(view, '.btnResume', 'click', onPlayClick); + bindAll(view, '.btnInstantMix', 'click', onInstantMixClick); + bindAll(view, '.btnShuffle', 'click', onShuffleClick); + bindAll(view, '.btnPlayTrailer', 'click', onPlayTrailerClick); + bindAll(view, '.btnCancelSeriesTimer', 'click', onCancelSeriesTimerClick); + bindAll(view, '.btnCancelTimer', 'click', onCancelTimerClick); + bindAll(view, '.btnDeleteItem', 'click', onDeleteClick); + bindAll(view, '.btnDownload', 'click', onDownloadClick); + view.querySelector('.trackSelections').addEventListener('submit', onTrackSelectionsSubmit); + view.querySelector('.btnSplitVersions').addEventListener('click', function () { splitVersions(self, view, apiClient, params); }); - bindAll(view, ".btnMoreCommands", "click", onMoreCommandsClick); - view.querySelector(".selectSource").addEventListener("change", function () { + bindAll(view, '.btnMoreCommands', 'click', onMoreCommandsClick); + view.querySelector('.selectSource').addEventListener('change', function () { renderVideoSelections(view, self._currentPlaybackMediaSources); renderAudioSelections(view, self._currentPlaybackMediaSources); renderSubtitleSelections(view, self._currentPlaybackMediaSources); }); - view.addEventListener("click", function (e) { - if (dom.parentWithClass(e.target, "moreScenes")) { - apiClient.getCurrentUser().then(function (user) { - renderScenes(view, currentItem); - }); - } else if (dom.parentWithClass(e.target, "morePeople")) { - renderCast(view, currentItem, params.context); - } else if (dom.parentWithClass(e.target, "moreSpecials")) { + view.addEventListener('click', function (e) { + if (dom.parentWithClass(e.target, 'moreScenes')) { + renderScenes(view, currentItem); + } else if (dom.parentWithClass(e.target, 'morePeople')) { + renderCast(view, currentItem); + } else if (dom.parentWithClass(e.target, 'moreSpecials')) { apiClient.getCurrentUser().then(function (user) { renderSpecials(view, currentItem, user); }); } }); - view.querySelector(".detailImageContainer").addEventListener("click", function (e) { - if (dom.parentWithClass(e.target, "itemDetailGalleryLink")) { + view.querySelector('.detailImageContainer').addEventListener('click', function (e) { + if (dom.parentWithClass(e.target, 'itemDetailGalleryLink')) { editImages().then(function () { reload(self, view, params); }); } }); - view.addEventListener("viewshow", function (e) { + view.addEventListener('viewshow', function (e) { var page = this; - libraryMenu.setTransparentMenu(true); + + if (layoutManager.mobile) { + libraryMenu.setTransparentMenu(true); + } if (e.detail.isRestored) { if (currentItem) { - setTitle(currentItem, connectionManager.getApiClient(currentItem.ServerId)); + Emby.Page.setTitle(''); renderTrackSelections(page, self, currentItem, true); } } else { reload(self, page, params); } - events.on(apiClient, "message", onWebSocketMessage); - events.on(playbackManager, "playerchange", onPlayerChange); + events.on(apiClient, 'message', onWebSocketMessage); + events.on(playbackManager, 'playerchange', onPlayerChange); }); - view.addEventListener("viewbeforehide", function () { - events.off(apiClient, "message", onWebSocketMessage); - events.off(playbackManager, "playerchange", onPlayerChange); + view.addEventListener('viewbeforehide', function () { + events.off(apiClient, 'message', onWebSocketMessage); + events.off(playbackManager, 'playerchange', onPlayerChange); libraryMenu.setTransparentMenu(false); }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { currentItem = null; self._currentPlaybackMediaSources = null; self.currentRecordingFields = null; diff --git a/src/controllers/librarydisplay.js b/src/controllers/librarydisplay.js deleted file mode 100644 index 10a0eb945b..0000000000 --- a/src/controllers/librarydisplay.js +++ /dev/null @@ -1,71 +0,0 @@ -define(["globalize", "loading", "libraryMenu", "emby-checkbox", "emby-button", "emby-button"], function(globalize, loading, libraryMenu) { - "use strict"; - - function getTabs() { - return [{ - href: "library.html", - name: Globalize.translate("HeaderLibraries") - }, { - href: "librarydisplay.html", - name: Globalize.translate("TabDisplay") - }, { - href: "metadataimages.html", - name: Globalize.translate("TabMetadata") - }, { - href: "metadatanfo.html", - name: Globalize.translate("TabNfoSettings") - }] - } - - return function(view, params) { - function loadData() { - ApiClient.getServerConfiguration().then(function(config) { - view.querySelector(".chkFolderView").checked = config.EnableFolderView; - view.querySelector(".chkGroupMoviesIntoCollections").checked = config.EnableGroupingIntoCollections; - view.querySelector(".chkDisplaySpecialsWithinSeasons").checked = config.DisplaySpecialsWithinSeasons; - view.querySelector(".chkExternalContentInSuggestions").checked = config.EnableExternalContentInSuggestions; - view.querySelector("#chkSaveMetadataHidden").checked = config.SaveMetadataHidden; - }); - ApiClient.getNamedConfiguration("metadata").then(function(metadata) { - loadMetadataConfig(this, metadata) - }); - } - - function loadMetadataConfig(page, config) { - $("#selectDateAdded", page).val(config.UseFileCreationTimeForDateAdded ? "1" : "0"); - } - - view.querySelector("form").addEventListener("submit", function(e) { - loading.show(); - var form = this; - ApiClient.getServerConfiguration().then(function(config) { - config.EnableFolderView = form.querySelector(".chkFolderView").checked; - config.EnableGroupingIntoCollections = form.querySelector(".chkGroupMoviesIntoCollections").checked; - config.DisplaySpecialsWithinSeasons = form.querySelector(".chkDisplaySpecialsWithinSeasons").checked; - config.EnableExternalContentInSuggestions = form.querySelector(".chkExternalContentInSuggestions").checked; - config.SaveMetadataHidden = form.querySelector("#chkSaveMetadataHidden").checked; - ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); - }); - ApiClient.getNamedConfiguration("metadata").then(function(config) { - config.UseFileCreationTimeForDateAdded = "1" === $("#selectDateAdded", form).val(); - ApiClient.updateNamedConfiguration("metadata", config); - }); - - e.preventDefault(); - loading.hide(); - return false; - }); - - view.addEventListener("viewshow", function() { - libraryMenu.setTabs("librarysetup", 1, getTabs); - loadData(); - ApiClient.getSystemInfo().then(function(info) { - if ("Windows" === info.OperatingSystem) { - view.querySelector(".fldSaveMetadataHidden").classList.remove("hide"); - } else { - view.querySelector(".fldSaveMetadataHidden").classList.add("hide"); - } - }); - }); - } -}); \ No newline at end of file diff --git a/src/controllers/list.js b/src/controllers/list.js index a554bec611..edd4469007 100644 --- a/src/controllers/list.js +++ b/src/controllers/list.js @@ -1,15 +1,15 @@ -define(["globalize", "listView", "layoutManager", "userSettings", "focusManager", "cardBuilder", "loading", "connectionManager", "alphaNumericShortcuts", "scroller", "playbackManager", "alphaPicker", "emby-itemscontainer", "emby-scroller"], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, scroller, playbackManager, alphaPicker) { - "use strict"; +define(['globalize', 'listView', 'layoutManager', 'userSettings', 'focusManager', 'cardBuilder', 'loading', 'connectionManager', 'alphaNumericShortcuts', 'scroller', 'playbackManager', 'alphaPicker', 'emby-itemscontainer', 'emby-scroller'], function (globalize, listView, layoutManager, userSettings, focusManager, cardBuilder, loading, connectionManager, AlphaNumericShortcuts, scroller, playbackManager, alphaPicker) { + 'use strict'; function getInitialLiveTvQuery(instance, params) { var query = { UserId: connectionManager.getApiClient(params.serverId).getCurrentUserId(), StartIndex: 0, - Fields: "ChannelInfo,PrimaryImageAspectRatio", + Fields: 'ChannelInfo,PrimaryImageAspectRatio', Limit: 300 }; - if ("Recordings" === params.type) { + if ('Recordings' === params.type) { query.IsInProgress = false; } else { query.HasAired = false; @@ -19,39 +19,39 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" query.GenreIds = params.genreId; } - if ("true" === params.IsMovie) { + if ('true' === params.IsMovie) { query.IsMovie = true; - } else if ("false" === params.IsMovie) { + } else if ('false' === params.IsMovie) { query.IsMovie = false; } - if ("true" === params.IsSeries) { + if ('true' === params.IsSeries) { query.IsSeries = true; - } else if ("false" === params.IsSeries) { + } else if ('false' === params.IsSeries) { query.IsSeries = false; } - if ("true" === params.IsNews) { + if ('true' === params.IsNews) { query.IsNews = true; - } else if ("false" === params.IsNews) { + } else if ('false' === params.IsNews) { query.IsNews = false; } - if ("true" === params.IsSports) { + if ('true' === params.IsSports) { query.IsSports = true; - } else if ("false" === params.IsSports) { + } else if ('false' === params.IsSports) { query.IsSports = false; } - if ("true" === params.IsKids) { + if ('true' === params.IsKids) { query.IsKids = true; - } else if ("false" === params.IsKids) { + } else if ('false' === params.IsKids) { query.IsKids = false; } - if ("true" === params.IsAiring) { + if ('true' === params.IsAiring) { query.IsAiring = true; - } else if ("false" === params.IsAiring) { + } else if ('false' === params.IsAiring) { query.IsAiring = false; } @@ -66,29 +66,29 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" query.SortOrder = sortValues.sortOrder; } - query.Fields = query.Fields ? query.Fields + ",PrimaryImageAspectRatio" : "PrimaryImageAspectRatio"; + query.Fields = query.Fields ? query.Fields + ',PrimaryImageAspectRatio' : 'PrimaryImageAspectRatio'; query.ImageTypeLimit = 1; var hasFilters; var queryFilters = []; var filters = instance.getFilters(); if (filters.IsPlayed) { - queryFilters.push("IsPlayed"); + queryFilters.push('IsPlayed'); hasFilters = true; } if (filters.IsUnplayed) { - queryFilters.push("IsUnplayed"); + queryFilters.push('IsUnplayed'); hasFilters = true; } if (filters.IsFavorite) { - queryFilters.push("IsFavorite"); + queryFilters.push('IsFavorite'); hasFilters = true; } if (filters.IsResumable) { - queryFilters.push("IsResumable"); + queryFilters.push('IsResumable'); hasFilters = true; } @@ -147,7 +147,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" hasFilters = true; } - query.Filters = queryFilters.length ? queryFilters.join(",") : null; + query.Filters = queryFilters.length ? queryFilters.join(',') : null; instance.setFilterStatus(hasFilters); if (instance.alphaPicker) { @@ -157,6 +157,12 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" return query; } + function setSortButtonIcon(btnSortIcon, icon) { + btnSortIcon.classList.remove('arrow_downward'); + btnSortIcon.classList.remove('arrow_upward'); + btnSortIcon.classList.add(icon); + } + function updateSortText(instance) { var btnSortText = instance.btnSortText; @@ -167,7 +173,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" for (var i = 0, length = options.length; i < length; i++) { if (sortBy === options[i].value) { - btnSortText.innerHTML = globalize.translate("SortByValue", options[i].name); + btnSortText.innerHTML = globalize.translate('SortByValue', options[i].name); break; } } @@ -175,18 +181,18 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var btnSortIcon = instance.btnSortIcon; if (btnSortIcon) { - btnSortIcon.innerHTML = "Descending" === values.sortOrder ? "arrow_downward" : "arrow_upward"; + setSortButtonIcon(btnSortIcon, 'Descending' === values.sortOrder ? 'arrow_downward' : 'arrow_upward'); } } } function updateItemsContainerForViewType(instance) { - if ("list" === instance.getViewSettings().imageType) { - instance.itemsContainer.classList.remove("vertical-wrap"); - instance.itemsContainer.classList.add("vertical-list"); + if ('list' === instance.getViewSettings().imageType) { + instance.itemsContainer.classList.remove('vertical-wrap'); + instance.itemsContainer.classList.add('vertical-list'); } else { - instance.itemsContainer.classList.add("vertical-wrap"); - instance.itemsContainer.classList.remove("vertical-list"); + instance.itemsContainer.classList.add('vertical-wrap'); + instance.itemsContainer.classList.remove('vertical-list'); } } @@ -201,18 +207,12 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" numItems = 100; } - if ("SortName" === values.sortBy && "Ascending" === values.sortOrder && numItems > 40) { - alphaPicker.classList.remove("hide"); - - if (layoutManager.tv) { - instance.itemsContainer.parentNode.classList.add("padded-left-withalphapicker"); - } else { - instance.itemsContainer.parentNode.classList.add("padded-right-withalphapicker"); - } + if ('SortName' === values.sortBy && 'Ascending' === values.sortOrder && numItems > 40) { + alphaPicker.classList.remove('hide'); + instance.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); } else { - alphaPicker.classList.add("hide"); - instance.itemsContainer.parentNode.classList.remove("padded-left-withalphapicker"); - instance.itemsContainer.parentNode.classList.remove("padded-right-withalphapicker"); + alphaPicker.classList.add('hide'); + instance.itemsContainer.parentNode.classList.remove('padded-right-withalphapicker'); } } } @@ -222,25 +222,25 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var apiClient = connectionManager.getApiClient(params.serverId); instance.queryRecursive = false; - if ("Recordings" === params.type) { + if ('Recordings' === params.type) { return apiClient.getLiveTvRecordings(getInitialLiveTvQuery(instance, params)); } - if ("Programs" === params.type) { - if ("true" === params.IsAiring) { + if ('Programs' === params.type) { + if ('true' === params.IsAiring) { return apiClient.getLiveTvRecommendedPrograms(getInitialLiveTvQuery(instance, params)); } return apiClient.getLiveTvPrograms(getInitialLiveTvQuery(instance, params)); } - if ("nextup" === params.type) { + if ('nextup' === params.type) { return apiClient.getNextUpEpisodes(modifyQueryWithFilters(instance, { Limit: limit, - Fields: "PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo', UserId: apiClient.getCurrentUserId(), ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', EnableTotalRecordCount: false, SortBy: sortBy })); @@ -248,57 +248,57 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" if (!item) { instance.queryRecursive = true; - var method = "getItems"; + var method = 'getItems'; - if ("MusicArtist" === params.type) { - method = "getArtists"; - } else if ("Person" === params.type) { - method = "getPeople"; + if ('MusicArtist' === params.type) { + method = 'getArtists'; + } else if ('Person' === params.type) { + method = 'getPeople'; } return apiClient[method](apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { StartIndex: startIndex, Limit: limit, - Fields: "PrimaryImageAspectRatio,SortName", + Fields: 'PrimaryImageAspectRatio,SortName', ImageTypeLimit: 1, - IncludeItemTypes: "MusicArtist" === params.type || "Person" === params.type ? null : params.type, + IncludeItemTypes: 'MusicArtist' === params.type || 'Person' === params.type ? null : params.type, Recursive: true, - IsFavorite: "true" === params.IsFavorite || null, + IsFavorite: 'true' === params.IsFavorite || null, ArtistIds: params.artistId || null, SortBy: sortBy })); } - if ("Genre" === item.Type || "MusicGenre" === item.Type || "Studio" === item.Type || "Person" === item.Type) { + if ('Genre' === item.Type || 'MusicGenre' === item.Type || 'Studio' === item.Type || 'Person' === item.Type) { instance.queryRecursive = true; var query = { StartIndex: startIndex, Limit: limit, - Fields: "PrimaryImageAspectRatio,SortName", + Fields: 'PrimaryImageAspectRatio,SortName', Recursive: true, parentId: params.parentId, SortBy: sortBy }; - if ("Studio" === item.Type) { + if ('Studio' === item.Type) { query.StudioIds = item.Id; - } else if ("Genre" === item.Type || "MusicGenre" === item.Type) { + } else if ('Genre' === item.Type || 'MusicGenre' === item.Type) { query.GenreIds = item.Id; - } else if ("Person" === item.Type) { + } else if ('Person' === item.Type) { query.PersonIds = item.Id; } - if ("MusicGenre" === item.Type) { - query.IncludeItemTypes = "MusicAlbum"; - } else if ("GameGenre" === item.Type) { - query.IncludeItemTypes = "Game"; - } else if ("movies" === item.CollectionType) { - query.IncludeItemTypes = "Movie"; - } else if ("tvshows" === item.CollectionType) { - query.IncludeItemTypes = "Series"; - } else if ("Genre" === item.Type) { - query.IncludeItemTypes = "Movie,Series,Video"; - } else if ("Person" === item.Type) { + if ('MusicGenre' === item.Type) { + query.IncludeItemTypes = 'MusicAlbum'; + } else if ('GameGenre' === item.Type) { + query.IncludeItemTypes = 'Game'; + } else if ('movies' === item.CollectionType) { + query.IncludeItemTypes = 'Movie'; + } else if ('tvshows' === item.CollectionType) { + query.IncludeItemTypes = 'Series'; + } else if ('Genre' === item.Type) { + query.IncludeItemTypes = 'Movie,Series,Video'; + } else if ('Person' === item.Type) { query.IncludeItemTypes = params.type; } @@ -308,7 +308,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { StartIndex: startIndex, Limit: limit, - Fields: "PrimaryImageAspectRatio,SortName", + Fields: 'PrimaryImageAspectRatio,SortName', ImageTypeLimit: 1, ParentId: item.Id, SortBy: sortBy @@ -316,7 +316,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" } function getItem(params) { - if ("Recordings" === params.type || "Programs" === params.type || "nextup" === params.type) { + if ('Recordings' === params.type || 'Programs' === params.type || 'nextup' === params.type) { return Promise.resolve(null); } @@ -333,7 +333,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function showViewSettingsMenu() { var instance = this; - require(["viewSettings"], function (ViewSettings) { + require(['viewSettings'], function (ViewSettings) { new ViewSettings().show({ settingsKey: instance.getSettingsKey(), settings: instance.getViewSettings(), @@ -348,7 +348,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function showFilterMenu() { var instance = this; - require(["filterMenu"], function (FilterMenu) { + require(['filterMenu'], function (FilterMenu) { new FilterMenu().show({ settingsKey: instance.getSettingsKey(), settings: instance.getFilters(), @@ -367,7 +367,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function showSortMenu() { var instance = this; - require(["sortMenu"], function (SortMenu) { + require(['sortMenu'], function (SortMenu) { new SortMenu().show({ settingsKey: instance.getSettingsKey(), settings: instance.getSortValues(), @@ -385,7 +385,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function onNewItemClick() { var instance = this; - require(["playlistEditor"], function (playlistEditor) { + require(['playlistEditor'], function (playlistEditor) { new playlistEditor().show({ items: [], serverId: instance.params.serverId @@ -396,9 +396,9 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function hideOrShowAll(elems, hide) { for (var i = 0, length = elems.length; i < length; i++) { if (hide) { - elems[i].classList.add("hide"); + elems[i].classList.add('hide'); } else { - elems[i].classList.remove("hide"); + elems[i].classList.remove('hide'); } } } @@ -424,7 +424,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" function getItemsHtml(items) { var settings = self.getViewSettings(); - if ("list" === settings.imageType) { + if ('list' === settings.imageType) { return listView.getListViewHtml({ items: items }); @@ -438,26 +438,26 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var item = self.currentItem; var lines = settings.showTitle ? 2 : 0; - if ("banner" === settings.imageType) { - shape = "banner"; - } else if ("disc" === settings.imageType) { - shape = "square"; + if ('banner' === settings.imageType) { + shape = 'banner'; + } else if ('disc' === settings.imageType) { + shape = 'square'; preferDisc = true; - } else if ("logo" === settings.imageType) { - shape = "backdrop"; + } else if ('logo' === settings.imageType) { + shape = 'backdrop'; preferLogo = true; - } else if ("thumb" === settings.imageType) { - shape = "backdrop"; + } else if ('thumb' === settings.imageType) { + shape = 'backdrop'; preferThumb = true; - } else if ("nextup" === params.type) { - shape = "backdrop"; - preferThumb = "thumb" === settings.imageType; - } else if ("Programs" === params.type || "Recordings" === params.type) { - shape = "true" === params.IsMovie ? "portrait" : "autoVertical"; - preferThumb = "true" !== params.IsMovie ? "auto" : false; - defaultShape = "true" === params.IsMovie ? "portrait" : "backdrop"; + } else if ('nextup' === params.type) { + shape = 'backdrop'; + preferThumb = 'thumb' === settings.imageType; + } else if ('Programs' === params.type || 'Recordings' === params.type) { + shape = 'true' === params.IsMovie ? 'portrait' : 'autoVertical'; + preferThumb = 'true' !== params.IsMovie ? 'auto' : false; + defaultShape = 'true' === params.IsMovie ? 'portrait' : 'backdrop'; } else { - shape = "autoVertical"; + shape = 'autoVertical'; } var posterOptions = { @@ -473,47 +473,47 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" overlayMoreButton: true, overlayText: !settings.showTitle, defaultShape: defaultShape, - action: "Audio" === params.type ? "playallfromhere" : null + action: 'Audio' === params.type ? 'playallfromhere' : null }; - if ("nextup" === params.type) { + if ('nextup' === params.type) { posterOptions.showParentTitle = settings.showTitle; - } else if ("Person" === params.type) { + } else if ('Person' === params.type) { posterOptions.showYear = false; posterOptions.showParentTitle = false; lines = 1; - } else if ("Audio" === params.type) { + } else if ('Audio' === params.type) { posterOptions.showParentTitle = settings.showTitle; - } else if ("MusicAlbum" === params.type) { + } else if ('MusicAlbum' === params.type) { posterOptions.showParentTitle = settings.showTitle; - } else if ("Episode" === params.type) { + } else if ('Episode' === params.type) { posterOptions.showParentTitle = settings.showTitle; - } else if ("MusicArtist" === params.type) { + } else if ('MusicArtist' === params.type) { posterOptions.showYear = false; lines = 1; - } else if ("Programs" === params.type) { + } else if ('Programs' === params.type) { lines = settings.showTitle ? 1 : 0; - var showParentTitle = settings.showTitle && "true" !== params.IsMovie; + var showParentTitle = settings.showTitle && 'true' !== params.IsMovie; if (showParentTitle) { lines++; } - var showAirTime = settings.showTitle && "Recordings" !== params.type; + var showAirTime = settings.showTitle && 'Recordings' !== params.type; if (showAirTime) { lines++; } - var showYear = settings.showTitle && "true" === params.IsMovie && "Recordings" === params.type; + var showYear = settings.showTitle && 'true' === params.IsMovie && 'Recordings' === params.type; if (showYear) { lines++; } posterOptions = Object.assign(posterOptions, { - inheritThumb: "Recordings" === params.type, - context: "livetv", + inheritThumb: 'Recordings' === params.type, + context: 'livetv', showParentTitle: showParentTitle, showAirTime: showAirTime, showAirDateTime: showAirTime, @@ -529,34 +529,28 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" posterOptions.lines = lines; posterOptions.items = items; - if (item && "folders" === item.CollectionType) { - posterOptions.context = "folders"; + if (item && 'folders' === item.CollectionType) { + posterOptions.context = 'folders'; } return cardBuilder.getCardsHtml(posterOptions); } function initAlphaPicker() { - self.scroller = view.querySelector(".scrollFrameY"); + self.scroller = view.querySelector('.scrollFrameY'); var alphaPickerElement = self.alphaPickerElement; - if (layoutManager.tv) { - alphaPickerElement.classList.add("alphaPicker-fixed-left"); - alphaPickerElement.classList.add("focuscontainer-left"); - self.itemsContainer.parentNode.classList.add("padded-left-withalphapicker"); - } else { - alphaPickerElement.classList.add("alphaPicker-fixed-right"); - alphaPickerElement.classList.add("focuscontainer-right"); - self.itemsContainer.parentNode.classList.add("padded-right-withalphapicker"); - } + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + alphaPickerElement.classList.add('focuscontainer-right'); + self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, itemsContainer: layoutManager.tv ? self.itemsContainer : null, - itemClass: "card", - valueChangeEvent: layoutManager.tv ? null : "click" + itemClass: 'card', + valueChangeEvent: layoutManager.tv ? null : 'click' }); - self.alphaPicker.on("alphavaluechanged", onAlphaPickerValueChanged); + self.alphaPicker.on('alphavaluechanged', onAlphaPickerValueChanged); } function onAlphaPickerValueChanged() { @@ -565,90 +559,90 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" } function setTitle(item) { - Emby.Page.setTitle(getTitle(item) || ""); + Emby.Page.setTitle(getTitle(item) || ''); - if (item && "playlists" === item.CollectionType) { - hideOrShowAll(view.querySelectorAll(".btnNewItem"), false); + if (item && 'playlists' === item.CollectionType) { + hideOrShowAll(view.querySelectorAll('.btnNewItem'), false); } else { - hideOrShowAll(view.querySelectorAll(".btnNewItem"), true); + hideOrShowAll(view.querySelectorAll('.btnNewItem'), true); } } function getTitle(item) { - if ("Recordings" === params.type) { - return globalize.translate("Recordings"); + if ('Recordings' === params.type) { + return globalize.translate('Recordings'); } - if ("Programs" === params.type) { - if ("true" === params.IsMovie) { - return globalize.translate("Movies"); + if ('Programs' === params.type) { + if ('true' === params.IsMovie) { + return globalize.translate('Movies'); } - if ("true" === params.IsSports) { - return globalize.translate("Sports"); + if ('true' === params.IsSports) { + return globalize.translate('Sports'); } - if ("true" === params.IsKids) { - return globalize.translate("HeaderForKids"); + if ('true' === params.IsKids) { + return globalize.translate('HeaderForKids'); } - if ("true" === params.IsAiring) { - return globalize.translate("HeaderOnNow"); + if ('true' === params.IsAiring) { + return globalize.translate('HeaderOnNow'); } - if ("true" === params.IsSeries) { - return globalize.translate("Shows"); + if ('true' === params.IsSeries) { + return globalize.translate('Shows'); } - if ("true" === params.IsNews) { - return globalize.translate("News"); + if ('true' === params.IsNews) { + return globalize.translate('News'); } - return globalize.translate("Programs"); + return globalize.translate('Programs'); } - if ("nextup" === params.type) { - return globalize.translate("NextUp"); + if ('nextup' === params.type) { + return globalize.translate('NextUp'); } - if ("favoritemovies" === params.type) { - return globalize.translate("FavoriteMovies"); + if ('favoritemovies' === params.type) { + return globalize.translate('FavoriteMovies'); } if (item) { return item.Name; } - if ("Movie" === params.type) { - return globalize.translate("Movies"); + if ('Movie' === params.type) { + return globalize.translate('Movies'); } - if ("Series" === params.type) { - return globalize.translate("Shows"); + if ('Series' === params.type) { + return globalize.translate('Shows'); } - if ("Season" === params.type) { - return globalize.translate("Seasons"); + if ('Season' === params.type) { + return globalize.translate('Seasons'); } - if ("Episode" === params.type) { - return globalize.translate("Episodes"); + if ('Episode' === params.type) { + return globalize.translate('Episodes'); } - if ("MusicArtist" === params.type) { - return globalize.translate("Artists"); + if ('MusicArtist' === params.type) { + return globalize.translate('Artists'); } - if ("MusicAlbum" === params.type) { - return globalize.translate("Albums"); + if ('MusicAlbum' === params.type) { + return globalize.translate('Albums'); } - if ("Audio" === params.type) { - return globalize.translate("Songs"); + if ('Audio' === params.type) { + return globalize.translate('Songs'); } - if ("Video" === params.type) { - return globalize.translate("Videos"); + if ('Video' === params.type) { + return globalize.translate('Videos'); } return void 0; @@ -692,7 +686,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" if (currentItem && !self.hasFilters) { playbackManager.shuffle(currentItem); } else { - getItems(self, self.params, currentItem, "Random", null, 300).then(function (result) { + getItems(self, self.params, currentItem, 'Random', null, 300).then(function (result) { playbackManager.play({ items: result.Items }); @@ -702,59 +696,59 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var self = this; self.params = params; - this.itemsContainer = view.querySelector(".itemsContainer"); + this.itemsContainer = view.querySelector('.itemsContainer'); if (params.parentId) { - this.itemsContainer.setAttribute("data-parentid", params.parentId); - } else if ("nextup" === params.type) { - this.itemsContainer.setAttribute("data-monitor", "videoplayback"); - } else if ("favoritemovies" === params.type) { - this.itemsContainer.setAttribute("data-monitor", "markfavorite"); - } else if ("Programs" === params.type) { - this.itemsContainer.setAttribute("data-refreshinterval", "300000"); + this.itemsContainer.setAttribute('data-parentid', params.parentId); + } else if ('nextup' === params.type) { + this.itemsContainer.setAttribute('data-monitor', 'videoplayback'); + } else if ('favoritemovies' === params.type) { + this.itemsContainer.setAttribute('data-monitor', 'markfavorite'); + } else if ('Programs' === params.type) { + this.itemsContainer.setAttribute('data-refreshinterval', '300000'); } var i; var length; - var btnViewSettings = view.querySelectorAll(".btnViewSettings"); + var btnViewSettings = view.querySelectorAll('.btnViewSettings'); for (i = 0, length = btnViewSettings.length; i < length; i++) { - btnViewSettings[i].addEventListener("click", showViewSettingsMenu.bind(this)); + btnViewSettings[i].addEventListener('click', showViewSettingsMenu.bind(this)); } - var filterButtons = view.querySelectorAll(".btnFilter"); + var filterButtons = view.querySelectorAll('.btnFilter'); this.filterButtons = filterButtons; var hasVisibleFilters = this.getVisibleFilters().length; for (i = 0, length = filterButtons.length; i < length; i++) { var btnFilter = filterButtons[i]; - btnFilter.addEventListener("click", showFilterMenu.bind(this)); + btnFilter.addEventListener('click', showFilterMenu.bind(this)); if (hasVisibleFilters) { - btnFilter.classList.remove("hide"); + btnFilter.classList.remove('hide'); } else { - btnFilter.classList.add("hide"); + btnFilter.classList.add('hide'); } } - var sortButtons = view.querySelectorAll(".btnSort"); + var sortButtons = view.querySelectorAll('.btnSort'); for (this.sortButtons = sortButtons, i = 0, length = sortButtons.length; i < length; i++) { var sortButton = sortButtons[i]; - sortButton.addEventListener("click", showSortMenu.bind(this)); + sortButton.addEventListener('click', showSortMenu.bind(this)); - if ("nextup" !== params.type) { - sortButton.classList.remove("hide"); + if ('nextup' !== params.type) { + sortButton.classList.remove('hide'); } } - this.btnSortText = view.querySelector(".btnSortText"); - this.btnSortIcon = view.querySelector(".btnSortIcon"); - bindAll(view.querySelectorAll(".btnNewItem"), "click", onNewItemClick.bind(this)); - this.alphaPickerElement = view.querySelector(".alphaPicker"); + this.btnSortText = view.querySelector('.btnSortText'); + this.btnSortIcon = view.querySelector('.btnSortIcon'); + bindAll(view.querySelectorAll('.btnNewItem'), 'click', onNewItemClick.bind(this)); + this.alphaPickerElement = view.querySelector('.alphaPicker'); self.itemsContainer.fetchData = fetchData; self.itemsContainer.getItemsHtml = getItemsHtml; - view.addEventListener("viewshow", function (e) { + view.addEventListener('viewshow', function (e) { var isRestored = e.detail.isRestored; if (!isRestored) { @@ -778,42 +772,42 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" } }); - if (!isRestored && item && "PhotoAlbum" !== item.Type) { + if (!isRestored && item && 'PhotoAlbum' !== item.Type) { initAlphaPicker(); } var itemType = item ? item.Type : null; - if ("MusicGenre" === itemType || "Programs" !== params.type && "Channel" !== itemType) { - hideOrShowAll(view.querySelectorAll(".btnPlay"), false); + if ('MusicGenre' === itemType || 'Programs' !== params.type && 'Channel' !== itemType) { + hideOrShowAll(view.querySelectorAll('.btnPlay'), false); } else { - hideOrShowAll(view.querySelectorAll(".btnPlay"), true); + hideOrShowAll(view.querySelectorAll('.btnPlay'), true); } - if ("MusicGenre" === itemType || "Programs" !== params.type && "nextup" !== params.type && "Channel" !== itemType) { - hideOrShowAll(view.querySelectorAll(".btnShuffle"), false); + if ('MusicGenre' === itemType || 'Programs' !== params.type && 'nextup' !== params.type && 'Channel' !== itemType) { + hideOrShowAll(view.querySelectorAll('.btnShuffle'), false); } else { - hideOrShowAll(view.querySelectorAll(".btnShuffle"), true); + hideOrShowAll(view.querySelectorAll('.btnShuffle'), true); } if (item && playbackManager.canQueue(item)) { - hideOrShowAll(view.querySelectorAll(".btnQueue"), false); + hideOrShowAll(view.querySelectorAll('.btnQueue'), false); } else { - hideOrShowAll(view.querySelectorAll(".btnQueue"), true); + hideOrShowAll(view.querySelectorAll('.btnQueue'), true); } }); if (!isRestored) { - bindAll(view.querySelectorAll(".btnPlay"), "click", play); - bindAll(view.querySelectorAll(".btnQueue"), "click", queue); - bindAll(view.querySelectorAll(".btnShuffle"), "click", shuffle); + bindAll(view.querySelectorAll('.btnPlay'), 'click', play); + bindAll(view.querySelectorAll('.btnQueue'), 'click', queue); + bindAll(view.querySelectorAll('.btnShuffle'), 'click', shuffle); } this.alphaNumericShortcuts = new AlphaNumericShortcuts({ itemsContainer: self.itemsContainer }); }); - view.addEventListener("viewhide", function (e) { + view.addEventListener('viewhide', function (e) { var itemsContainer = self.itemsContainer; if (itemsContainer) { @@ -827,13 +821,13 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" self.alphaNumericShortcuts = null; } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (self.listController) { self.listController.destroy(); } if (self.alphaPicker) { - self.alphaPicker.off("alphavaluechanged", onAlphaPickerValueChanged); + self.alphaPicker.off('alphavaluechanged', onAlphaPickerValueChanged); self.alphaPicker.destroy(); } @@ -851,30 +845,30 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" ItemsView.prototype.getFilters = function () { var basekey = this.getSettingsKey(); return { - IsPlayed: "true" === userSettings.getFilter(basekey + "-filter-IsPlayed"), - IsUnplayed: "true" === userSettings.getFilter(basekey + "-filter-IsUnplayed"), - IsFavorite: "true" === userSettings.getFilter(basekey + "-filter-IsFavorite"), - IsResumable: "true" === userSettings.getFilter(basekey + "-filter-IsResumable"), - Is4K: "true" === userSettings.getFilter(basekey + "-filter-Is4K"), - IsHD: "true" === userSettings.getFilter(basekey + "-filter-IsHD"), - IsSD: "true" === userSettings.getFilter(basekey + "-filter-IsSD"), - Is3D: "true" === userSettings.getFilter(basekey + "-filter-Is3D"), - VideoTypes: userSettings.getFilter(basekey + "-filter-VideoTypes"), - SeriesStatus: userSettings.getFilter(basekey + "-filter-SeriesStatus"), - HasSubtitles: userSettings.getFilter(basekey + "-filter-HasSubtitles"), - HasTrailer: userSettings.getFilter(basekey + "-filter-HasTrailer"), - HasSpecialFeature: userSettings.getFilter(basekey + "-filter-HasSpecialFeature"), - HasThemeSong: userSettings.getFilter(basekey + "-filter-HasThemeSong"), - HasThemeVideo: userSettings.getFilter(basekey + "-filter-HasThemeVideo"), - GenreIds: userSettings.getFilter(basekey + "-filter-GenreIds") + IsPlayed: 'true' === userSettings.getFilter(basekey + '-filter-IsPlayed'), + IsUnplayed: 'true' === userSettings.getFilter(basekey + '-filter-IsUnplayed'), + IsFavorite: 'true' === userSettings.getFilter(basekey + '-filter-IsFavorite'), + IsResumable: 'true' === userSettings.getFilter(basekey + '-filter-IsResumable'), + Is4K: 'true' === userSettings.getFilter(basekey + '-filter-Is4K'), + IsHD: 'true' === userSettings.getFilter(basekey + '-filter-IsHD'), + IsSD: 'true' === userSettings.getFilter(basekey + '-filter-IsSD'), + Is3D: 'true' === userSettings.getFilter(basekey + '-filter-Is3D'), + VideoTypes: userSettings.getFilter(basekey + '-filter-VideoTypes'), + SeriesStatus: userSettings.getFilter(basekey + '-filter-SeriesStatus'), + HasSubtitles: userSettings.getFilter(basekey + '-filter-HasSubtitles'), + HasTrailer: userSettings.getFilter(basekey + '-filter-HasTrailer'), + HasSpecialFeature: userSettings.getFilter(basekey + '-filter-HasSpecialFeature'), + HasThemeSong: userSettings.getFilter(basekey + '-filter-HasThemeSong'), + HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'), + GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds') }; }; ItemsView.prototype.getSortValues = function () { var basekey = this.getSettingsKey(); return { - sortBy: userSettings.getFilter(basekey + "-sortby") || this.getDefaultSortBy(), - sortOrder: "Descending" === userSettings.getFilter(basekey + "-sortorder") ? "Descending" : "Ascending" + sortBy: userSettings.getFilter(basekey + '-sortby') || this.getDefaultSortBy(), + sortOrder: 'Descending' === userSettings.getFilter(basekey + '-sortorder') ? 'Descending' : 'Ascending' }; }; @@ -886,17 +880,17 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" return sortNameOption.value; } - return "IsFolder," + sortNameOption.value; + return 'IsFolder,' + sortNameOption.value; }; ItemsView.prototype.getSortMenuOptions = function () { var sortBy = []; var params = this.params; - if ("Programs" === params.type) { + if ('Programs' === params.type) { sortBy.push({ - name: globalize.translate("AirDate"), - value: "StartDate,SortName" + name: globalize.translate('AirDate'), + value: 'StartDate,SortName' }); } @@ -918,10 +912,10 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" sortBy.push(option); } - if ("Programs" !== params.type) { + if ('Programs' !== params.type) { sortBy.push({ - name: globalize.translate("DateAdded"), - value: "DateCreated,SortName" + name: globalize.translate('DateAdded'), + value: 'DateCreated,SortName' }); } @@ -934,14 +928,14 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" if (!params.type) { option = this.getNameSortOption(params); sortBy.push({ - name: globalize.translate("Folders"), - value: "IsFolder," + option.value + name: globalize.translate('Folders'), + value: 'IsFolder,' + option.value }); } sortBy.push({ - name: globalize.translate("ParentalRating"), - value: "OfficialRating,SortName" + name: globalize.translate('ParentalRating'), + value: 'OfficialRating,SortName' }); option = this.getPlayCountSortOption(); @@ -950,67 +944,67 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" } sortBy.push({ - name: globalize.translate("ReleaseDate"), - value: "ProductionYear,PremiereDate,SortName" + name: globalize.translate('ReleaseDate'), + value: 'ProductionYear,PremiereDate,SortName' }); sortBy.push({ - name: globalize.translate("Runtime"), - value: "Runtime,SortName" + name: globalize.translate('Runtime'), + value: 'Runtime,SortName' }); return sortBy; }; ItemsView.prototype.getNameSortOption = function (params) { - if ("Episode" === params.type) { + if ('Episode' === params.type) { return { - name: globalize.translate("Name"), - value: "SeriesName,SortName" + name: globalize.translate('Name'), + value: 'SeriesName,SortName' }; } return { - name: globalize.translate("Name"), - value: "SortName" + name: globalize.translate('Name'), + value: 'SortName' }; }; ItemsView.prototype.getPlayCountSortOption = function () { - if ("Programs" === this.params.type) { + if ('Programs' === this.params.type) { return null; } return { - name: globalize.translate("PlayCount"), - value: "PlayCount,SortName" + name: globalize.translate('PlayCount'), + value: 'PlayCount,SortName' }; }; ItemsView.prototype.getDatePlayedSortOption = function () { - if ("Programs" === this.params.type) { + if ('Programs' === this.params.type) { return null; } return { - name: globalize.translate("DatePlayed"), - value: "DatePlayed,SortName" + name: globalize.translate('DatePlayed'), + value: 'DatePlayed,SortName' }; }; ItemsView.prototype.getCriticRatingSortOption = function () { - if ("Programs" === this.params.type) { + if ('Programs' === this.params.type) { return null; } return { - name: globalize.translate("CriticRating"), - value: "CriticRating,SortName" + name: globalize.translate('CriticRating'), + value: 'CriticRating,SortName' }; }; ItemsView.prototype.getCommunityRatingSortOption = function () { return { - name: globalize.translate("CommunityRating"), - value: "CommunityRating,SortName" + name: globalize.translate('CommunityRating'), + value: 'CommunityRating,SortName' }; }; @@ -1018,25 +1012,24 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var filters = []; var params = this.params; - if (!("nextup" === params.type)) { - if ("Programs" === params.type) { - filters.push("Genres"); + if (!('nextup' === params.type)) { + if ('Programs' === params.type) { + filters.push('Genres'); } else { - params.type; - filters.push("IsUnplayed"); - filters.push("IsPlayed"); + filters.push('IsUnplayed'); + filters.push('IsPlayed'); if (!params.IsFavorite) { - filters.push("IsFavorite"); + filters.push('IsFavorite'); } - filters.push("IsResumable"); - filters.push("VideoType"); - filters.push("HasSubtitles"); - filters.push("HasTrailer"); - filters.push("HasSpecialFeature"); - filters.push("HasThemeSong"); - filters.push("HasThemeVideo"); + filters.push('IsResumable'); + filters.push('VideoType'); + filters.push('HasSubtitles'); + filters.push('HasTrailer'); + filters.push('HasSpecialFeature'); + filters.push('HasThemeSong'); + filters.push('HasThemeVideo'); } } @@ -1050,22 +1043,22 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" if (filterButtons.length) { for (var i = 0, length = filterButtons.length; i < length; i++) { var btnFilter = filterButtons[i]; - var bubble = btnFilter.querySelector(".filterButtonBubble"); + var bubble = btnFilter.querySelector('.filterButtonBubble'); if (!bubble) { if (!hasFilters) { continue; } - btnFilter.insertAdjacentHTML("afterbegin", '
!
'); - btnFilter.classList.add("btnFilterWithBubble"); - bubble = btnFilter.querySelector(".filterButtonBubble"); + btnFilter.insertAdjacentHTML('afterbegin', '
!
'); + btnFilter.classList.add('btnFilterWithBubble'); + bubble = btnFilter.querySelector('.filterButtonBubble'); } if (hasFilters) { - bubble.classList.remove("hide"); + bubble.classList.remove('hide'); } else { - bubble.classList.add("hide"); + bubble.classList.add('hide'); } } } @@ -1086,13 +1079,13 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" ItemsView.prototype.getVisibleViewSettings = function () { var item = (this.params, this.currentItem); - var fields = ["showTitle"]; + var fields = ['showTitle']; - if (!item || "PhotoAlbum" !== item.Type && "ChannelFolderItem" !== item.Type) { - fields.push("imageType"); + if (!item || 'PhotoAlbum' !== item.Type && 'ChannelFolderItem' !== item.Type) { + fields.push('imageType'); } - fields.push("viewType"); + fields.push('viewType'); return fields; }; @@ -1100,41 +1093,41 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" var basekey = this.getSettingsKey(); var params = this.params; var item = this.currentItem; - var showTitle = userSettings.get(basekey + "-showTitle"); + var showTitle = userSettings.get(basekey + '-showTitle'); - if ("true" === showTitle) { + if ('true' === showTitle) { showTitle = true; - } else if ("false" === showTitle) { + } else if ('false' === showTitle) { showTitle = false; - } else if ("Programs" === params.type || "Recordings" === params.type || "Person" === params.type || "nextup" === params.type || "Audio" === params.type || "MusicAlbum" === params.type || "MusicArtist" === params.type) { + } else if ('Programs' === params.type || 'Recordings' === params.type || 'Person' === params.type || 'nextup' === params.type || 'Audio' === params.type || 'MusicAlbum' === params.type || 'MusicArtist' === params.type) { showTitle = true; - } else if (item && "PhotoAlbum" !== item.Type) { + } else if (item && 'PhotoAlbum' !== item.Type) { showTitle = true; } - var imageType = userSettings.get(basekey + "-imageType"); + var imageType = userSettings.get(basekey + '-imageType'); - if (!imageType && "nextup" === params.type) { - imageType = "thumb"; + if (!imageType && 'nextup' === params.type) { + imageType = 'thumb'; } return { showTitle: showTitle, - showYear: "false" !== userSettings.get(basekey + "-showYear"), - imageType: imageType || "primary", - viewType: userSettings.get(basekey + "-viewType") || "images" + showYear: 'false' !== userSettings.get(basekey + '-showYear'), + imageType: imageType || 'primary', + viewType: userSettings.get(basekey + '-viewType') || 'images' }; }; ItemsView.prototype.getItemTypes = function () { var params = this.params; - if ("nextup" === params.type) { - return ["Episode"]; + if ('nextup' === params.type) { + return ['Episode']; } - if ("Programs" === params.type) { - return ["Program"]; + if ('Programs' === params.type) { + return ['Program']; } return []; @@ -1142,7 +1135,7 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" ItemsView.prototype.getSettingsKey = function () { var values = []; - values.push("items"); + values.push('items'); var params = this.params; if (params.type) { @@ -1152,54 +1145,54 @@ define(["globalize", "listView", "layoutManager", "userSettings", "focusManager" } if (params.IsAiring) { - values.push("IsAiring"); + values.push('IsAiring'); } if (params.IsMovie) { - values.push("IsMovie"); + values.push('IsMovie'); } if (params.IsKids) { - values.push("IsKids"); + values.push('IsKids'); } if (params.IsSports) { - values.push("IsSports"); + values.push('IsSports'); } if (params.IsNews) { - values.push("IsNews"); + values.push('IsNews'); } if (params.IsSeries) { - values.push("IsSeries"); + values.push('IsSeries'); } if (params.IsFavorite) { - values.push("IsFavorite"); + values.push('IsFavorite'); } if (params.genreId) { - values.push("Genre"); + values.push('Genre'); } if (params.musicGenreId) { - values.push("MusicGenre"); + values.push('MusicGenre'); } if (params.studioId) { - values.push("Studio"); + values.push('Studio'); } if (params.personId) { - values.push("Person"); + values.push('Person'); } if (params.parentId) { - values.push("Folder"); + values.push('Folder'); } - return values.join("-"); + return values.join('-'); }; return ItemsView; diff --git a/src/controllers/livetv/livetvchannels.js b/src/controllers/livetv/livetvchannels.js index 2de7e81843..7f22d3dd13 100644 --- a/src/controllers/livetv/livetvchannels.js +++ b/src/controllers/livetv/livetvchannels.js @@ -1,5 +1,5 @@ -define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "emby-itemscontainer"], function (cardBuilder, imageLoader, libraryBrowser, loading, events) { - "use strict"; +define(['cardBuilder', 'imageLoader', 'libraryBrowser', 'loading', 'events', 'userSettings', 'emby-itemscontainer'], function (cardBuilder, imageLoader, libraryBrowser, loading, events, userSettings) { + 'use strict'; return function (view, params, tabContent) { function getPageData() { @@ -7,12 +7,15 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em pageData = { query: { StartIndex: 0, - Limit: 100, - Fields: "PrimaryImageAspectRatio" + Fields: 'PrimaryImageAspectRatio' } }; } + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + return pageData; } @@ -23,7 +26,7 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em function getChannelsHtml(channels) { return cardBuilder.getCardsHtml({ items: channels, - shape: "square", + shape: 'square', showTitle: true, lazy: true, cardLayout: true, @@ -39,7 +42,9 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(context); } @@ -48,12 +53,14 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(context); } var query = getQuery(); - context.querySelector(".paging").innerHTML = libraryBrowser.getQueryPagingHtml({ + context.querySelector('.paging').innerHTML = libraryBrowser.getQueryPagingHtml({ startIndex: query.StartIndex, limit: query.Limit, totalRecordCount: result.TotalRecordCount, @@ -62,30 +69,30 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em filterButton: false }); var html = getChannelsHtml(result.Items); - var elem = context.querySelector("#items"); + var elem = context.querySelector('#items'); elem.innerHTML = html; imageLoader.lazyChildren(elem); var i; var length; var elems; - for (elems = context.querySelectorAll(".btnNextPage"), i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + for (elems = context.querySelectorAll('.btnNextPage'), i = 0, length = elems.length; i < length; i++) { + elems[i].addEventListener('click', onNextPageClick); } - for (elems = context.querySelectorAll(".btnPreviousPage"), i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + for (elems = context.querySelectorAll('.btnPreviousPage'), i = 0, length = elems.length; i < length; i++) { + elems[i].addEventListener('click', onPreviousPageClick); } } function showFilterMenu(context) { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(), - mode: "livetvchannels", + mode: 'livetvchannels', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { reloadItems(context); }); filterDialog.show(); @@ -103,7 +110,7 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(view); }); }); @@ -112,7 +119,7 @@ define(["cardBuilder", "imageLoader", "libraryBrowser", "loading", "events", "em var pageData; var self = this; var isLoading = false; - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.btnFilter').addEventListener('click', function () { showFilterMenu(tabContent); }); diff --git a/src/controllers/livetv/livetvguide.js b/src/controllers/livetv/livetvguide.js index f7c2f1baaa..ec7a7a3f81 100644 --- a/src/controllers/livetv/livetvguide.js +++ b/src/controllers/livetv/livetvguide.js @@ -1,5 +1,5 @@ -define(["tvguide"], function (tvguide) { - "use strict"; +define(['tvguide'], function (tvguide) { + 'use strict'; return function (view, params, tabContent) { var guideInstance; diff --git a/src/controllers/livetv/livetvrecordings.js b/src/controllers/livetv/livetvrecordings.js index ed3ae24087..d5cfe66672 100644 --- a/src/controllers/livetv/livetvrecordings.js +++ b/src/controllers/livetv/livetvrecordings.js @@ -1,37 +1,41 @@ -define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "scripts/livetvcomponents", "listViewStyle", "emby-itemscontainer"], function (layoutManager, loading, cardBuilder, appHost, imageLoader) { - "use strict"; +define(['layoutManager', 'loading', 'cardBuilder', 'apphost', 'imageLoader', 'scripts/livetvcomponents', 'listViewStyle', 'emby-itemscontainer'], function (layoutManager, loading, cardBuilder, appHost, imageLoader) { + 'use strict'; function renderRecordings(elem, recordings, cardOptions, scrollX) { - if (recordings.length) { - elem.classList.remove("hide"); - } else { - elem.classList.add("hide"); + if (!elem) { + return; } - var recordingItems = elem.querySelector(".recordingItems"); + if (recordings.length) { + elem.classList.remove('hide'); + } else { + elem.classList.add('hide'); + } + + var recordingItems = elem.querySelector('.recordingItems'); if (scrollX) { - recordingItems.classList.add("scrollX"); - recordingItems.classList.add("hiddenScrollX"); - recordingItems.classList.remove("vertical-wrap"); + recordingItems.classList.add('scrollX'); + recordingItems.classList.add('hiddenScrollX'); + recordingItems.classList.remove('vertical-wrap'); } else { - recordingItems.classList.remove("scrollX"); - recordingItems.classList.remove("hiddenScrollX"); - recordingItems.classList.add("vertical-wrap"); + recordingItems.classList.remove('scrollX'); + recordingItems.classList.remove('hiddenScrollX'); + recordingItems.classList.add('vertical-wrap'); } - appHost.supports("imageanalysis"); + appHost.supports('imageanalysis'); recordingItems.innerHTML = cardBuilder.getCardsHtml(Object.assign({ items: recordings, - shape: scrollX ? "autooverflow" : "auto", - defaultShape: scrollX ? "overflowBackdrop" : "backdrop", + shape: scrollX ? 'autooverflow' : 'auto', + defaultShape: scrollX ? 'overflowBackdrop' : 'backdrop', showTitle: true, showParentTitle: true, coverImage: true, cardLayout: false, centerText: true, allowBottomPadding: !scrollX, - preferThumb: "auto", + preferThumb: 'auto', overlayText: false }, cardOptions || {})); imageLoader.lazyChildren(recordingItems); @@ -39,7 +43,7 @@ define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "sc function renderLatestRecordings(context, promise) { promise.then(function (result) { - renderRecordings(context.querySelector("#latestRecordings"), result.Items, { + renderRecordings(context.querySelector('#latestRecordings'), result.Items, { showYear: true, lines: 2 }, false); @@ -49,7 +53,7 @@ define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "sc function renderRecordingFolders(context, promise) { promise.then(function (result) { - renderRecordings(context.querySelector("#recordingFolders"), result.Items, { + renderRecordings(context.querySelector('#recordingFolders'), result.Items, { showYear: false, showParentTitle: false }, false); @@ -57,12 +61,12 @@ define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "sc } function onMoreClick(e) { - var type = this.getAttribute("data-type"); + var type = this.getAttribute('data-type'); var serverId = ApiClient.serverId(); switch (type) { - case "latest": - Dashboard.navigate("list.html?type=Recordings&serverId=" + serverId); + case 'latest': + Dashboard.navigate('list.html?type=Recordings&serverId=' + serverId); } } @@ -75,10 +79,10 @@ define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "sc var latestPromise; var self = this; var lastFullRender = 0; - var moreButtons = tabContent.querySelectorAll(".more"); + var moreButtons = tabContent.querySelectorAll('.more'); for (var i = 0, length = moreButtons.length; i < length; i++) { - moreButtons[i].addEventListener("click", onMoreClick); + moreButtons[i].addEventListener('click', onMoreClick); } self.preRender = function () { @@ -86,9 +90,9 @@ define(["layoutManager", "loading", "cardBuilder", "apphost", "imageLoader", "sc latestPromise = ApiClient.getLiveTvRecordings({ UserId: Dashboard.getCurrentUserId(), Limit: 12, - Fields: "CanDelete,PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'CanDelete,PrimaryImageAspectRatio,BasicSyncInfo', EnableTotalRecordCount: false, - EnableImageTypes: "Primary,Thumb,Backdrop" + EnableImageTypes: 'Primary,Thumb,Backdrop' }); foldersPromise = ApiClient.getRecordingFolders(Dashboard.getCurrentUserId()); } diff --git a/src/controllers/livetv/livetvschedule.js b/src/controllers/livetv/livetvschedule.js index 3ee56a2a95..a6f509c6f1 100644 --- a/src/controllers/livetv/livetvschedule.js +++ b/src/controllers/livetv/livetvschedule.js @@ -1,5 +1,5 @@ -define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "scripts/livetvcomponents", "emby-button", "emby-itemscontainer"], function (layoutManager, cardBuilder, appHost, imageLoader, loading) { - "use strict"; +define(['layoutManager', 'cardBuilder', 'apphost', 'imageLoader', 'loading', 'scripts/livetvcomponents', 'emby-button', 'emby-itemscontainer'], function (layoutManager, cardBuilder, appHost, imageLoader, loading) { + 'use strict'; function enableScrollX() { return !layoutManager.desktop; @@ -7,54 +7,54 @@ define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "sc function renderRecordings(elem, recordings, cardOptions) { if (recordings.length) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } - var recordingItems = elem.querySelector(".recordingItems"); + var recordingItems = elem.querySelector('.recordingItems'); if (enableScrollX()) { - recordingItems.classList.add("scrollX"); + recordingItems.classList.add('scrollX'); if (layoutManager.tv) { - recordingItems.classList.add("smoothScrollX"); + recordingItems.classList.add('smoothScrollX'); } - recordingItems.classList.add("hiddenScrollX"); - recordingItems.classList.remove("vertical-wrap"); + recordingItems.classList.add('hiddenScrollX'); + recordingItems.classList.remove('vertical-wrap'); } else { - recordingItems.classList.remove("scrollX"); - recordingItems.classList.remove("smoothScrollX"); - recordingItems.classList.remove("hiddenScrollX"); - recordingItems.classList.add("vertical-wrap"); + recordingItems.classList.remove('scrollX'); + recordingItems.classList.remove('smoothScrollX'); + recordingItems.classList.remove('hiddenScrollX'); + recordingItems.classList.add('vertical-wrap'); } - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); var cardLayout = appHost.preferVisualCards || supportsImageAnalysis; cardLayout = false; recordingItems.innerHTML = cardBuilder.getCardsHtml(Object.assign({ items: recordings, - shape: enableScrollX() ? "autooverflow" : "auto", + shape: enableScrollX() ? 'autooverflow' : 'auto', showTitle: true, showParentTitle: true, coverImage: true, cardLayout: cardLayout, centerText: !cardLayout, allowBottomPadding: !enableScrollX(), - preferThumb: "auto" + preferThumb: 'auto' }, cardOptions || {})); imageLoader.lazyChildren(recordingItems); } function getBackdropShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop" + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function renderActiveRecordings(context, promise) { promise.then(function (result) { - renderRecordings(context.querySelector("#activeRecordings"), result.Items, { - shape: enableScrollX() ? "autooverflow" : "auto", + renderRecordings(context.querySelector('#activeRecordings'), result.Items, { + shape: enableScrollX() ? 'autooverflow' : 'auto', defaultShape: getBackdropShape(), showParentTitle: false, showParentTitleOrTitle: true, @@ -74,19 +74,19 @@ define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "sc var elem = context; if (html) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } - elem.querySelector(".recordingItems").innerHTML = html; + elem.querySelector('.recordingItems').innerHTML = html; imageLoader.lazyChildren(elem); }); } function renderUpcomingRecordings(context, promise) { promise.then(function (result) { - renderTimers(context.querySelector("#upcomingRecordings"), result.Items); + renderTimers(context.querySelector('#upcomingRecordings'), result.Items); loading.hide(); }); } @@ -95,7 +95,7 @@ define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "sc var activeRecordingsPromise; var upcomingRecordingsPromise; var self = this; - tabContent.querySelector("#upcomingRecordings .recordingItems").addEventListener("timercancelled", function () { + tabContent.querySelector('#upcomingRecordings .recordingItems').addEventListener('timercancelled', function () { self.preRender(); self.renderTab(); }); @@ -104,9 +104,9 @@ define(["layoutManager", "cardBuilder", "apphost", "imageLoader", "loading", "sc activeRecordingsPromise = ApiClient.getLiveTvRecordings({ UserId: Dashboard.getCurrentUserId(), IsInProgress: true, - Fields: "CanDelete,PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'CanDelete,PrimaryImageAspectRatio,BasicSyncInfo', EnableTotalRecordCount: false, - EnableImageTypes: "Primary,Thumb,Backdrop" + EnableImageTypes: 'Primary,Thumb,Backdrop' }); upcomingRecordingsPromise = ApiClient.getLiveTvTimers({ IsActive: false, diff --git a/src/controllers/livetv/livetvseriestimers.js b/src/controllers/livetv/livetvseriestimers.js index 9c95cfa91f..27daca1983 100644 --- a/src/controllers/livetv/livetvseriestimers.js +++ b/src/controllers/livetv/livetvseriestimers.js @@ -1,16 +1,16 @@ -define(["datetime", "cardBuilder", "imageLoader", "apphost", "loading", "paper-icon-button-light", "emby-button"], function (datetime, cardBuilder, imageLoader, appHost, loading) { - "use strict"; +define(['datetime', 'cardBuilder', 'imageLoader', 'apphost', 'loading', 'paper-icon-button-light', 'emby-button'], function (datetime, cardBuilder, imageLoader, appHost, loading) { + 'use strict'; function renderTimers(context, timers) { - var html = ""; - appHost.supports("imageanalysis"); + var html = ''; + appHost.supports('imageanalysis'); html += cardBuilder.getCardsHtml({ items: timers, - shape: "auto", - defaultShape: "portrait", + shape: 'auto', + defaultShape: 'portrait', showTitle: true, cardLayout: false, - preferThumb: "auto", + preferThumb: 'auto', coverImage: true, overlayText: false, showSeriesTimerTime: true, @@ -19,7 +19,7 @@ define(["datetime", "cardBuilder", "imageLoader", "apphost", "loading", "paper-i overlayMoreButton: true, lines: 3 }); - var elem = context.querySelector("#items"); + var elem = context.querySelector('#items'); elem.innerHTML = html; imageLoader.lazyChildren(elem); loading.hide(); @@ -33,8 +33,8 @@ define(["datetime", "cardBuilder", "imageLoader", "apphost", "loading", "paper-i } var query = { - SortBy: "SortName", - SortOrder: "Ascending" + SortBy: 'SortName', + SortOrder: 'Ascending' }; return function (view, params, tabContent) { var timersPromise; diff --git a/src/controllers/livetv/livetvsuggested.js b/src/controllers/livetv/livetvsuggested.js index 8f65df7e6f..036eee9fc6 100644 --- a/src/controllers/livetv/livetvsuggested.js +++ b/src/controllers/livetv/livetvsuggested.js @@ -1,5 +1,5 @@ -define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", "libraryBrowser", "mainTabsManager", "cardBuilder", "apphost", "imageLoader", "scrollStyles", "emby-itemscontainer", "emby-tabs", "emby-button"], function (layoutManager, userSettings, inputManager, loading, globalize, libraryBrowser, mainTabsManager, cardBuilder, appHost, imageLoader) { - "use strict"; +define(['layoutManager', 'userSettings', 'inputManager', 'loading', 'globalize', 'libraryBrowser', 'mainTabsManager', 'cardBuilder', 'apphost', 'imageLoader', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (layoutManager, userSettings, inputManager, loading, globalize, libraryBrowser, mainTabsManager, cardBuilder, appHost, imageLoader) { + 'use strict'; function enableScrollX() { return !layoutManager.desktop; @@ -7,16 +7,16 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", function getBackdropShape() { if (enableScrollX()) { - return "overflowBackdrop"; + return 'overflowBackdrop'; } - return "backdrop"; + return 'backdrop'; } function getPortraitShape() { if (enableScrollX()) { - return "overflowPortrait"; + return 'overflowPortrait'; } - return "portrait"; + return 'portrait'; } function getLimit() { @@ -40,17 +40,17 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", IsAiring: true, limit: limit, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Thumb,Backdrop", + EnableImageTypes: 'Primary,Thumb,Backdrop', EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio" + Fields: 'ChannelInfo,PrimaryImageAspectRatio' }).then(function (result) { - renderItems(page, result.Items, "activeProgramItems", "play", { + renderItems(page, result.Items, 'activeProgramItems', 'play', { showAirDateTime: false, showAirEndTime: true }); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); @@ -69,10 +69,10 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", IsNews: false, IsSeries: true, EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio", - EnableImageTypes: "Primary,Thumb" + Fields: 'ChannelInfo,PrimaryImageAspectRatio', + EnableImageTypes: 'Primary,Thumb' }).then(function (result) { - renderItems(page, result.Items, "upcomingEpisodeItems"); + renderItems(page, result.Items, 'upcomingEpisodeItems'); }); ApiClient.getLiveTvPrograms({ userId: Dashboard.getCurrentUserId(), @@ -80,10 +80,10 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", limit: getLimit(), IsMovie: true, EnableTotalRecordCount: false, - Fields: "ChannelInfo", - EnableImageTypes: "Primary,Thumb" + Fields: 'ChannelInfo', + EnableImageTypes: 'Primary,Thumb' }).then(function (result) { - renderItems(page, result.Items, "upcomingTvMovieItems", null, { + renderItems(page, result.Items, 'upcomingTvMovieItems', null, { shape: getPortraitShape(), preferThumb: null, showParentTitle: false @@ -95,10 +95,10 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", limit: getLimit(), IsSports: true, EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio", - EnableImageTypes: "Primary,Thumb" + Fields: 'ChannelInfo,PrimaryImageAspectRatio', + EnableImageTypes: 'Primary,Thumb' }).then(function (result) { - renderItems(page, result.Items, "upcomingSportsItems"); + renderItems(page, result.Items, 'upcomingSportsItems'); }); ApiClient.getLiveTvPrograms({ userId: Dashboard.getCurrentUserId(), @@ -106,10 +106,10 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", limit: getLimit(), IsKids: true, EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio", - EnableImageTypes: "Primary,Thumb" + Fields: 'ChannelInfo,PrimaryImageAspectRatio', + EnableImageTypes: 'Primary,Thumb' }).then(function (result) { - renderItems(page, result.Items, "upcomingKidsItems"); + renderItems(page, result.Items, 'upcomingKidsItems'); }); ApiClient.getLiveTvPrograms({ userId: Dashboard.getCurrentUserId(), @@ -117,10 +117,10 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", limit: getLimit(), IsNews: true, EnableTotalRecordCount: false, - Fields: "ChannelInfo,PrimaryImageAspectRatio", - EnableImageTypes: "Primary,Thumb" + Fields: 'ChannelInfo,PrimaryImageAspectRatio', + EnableImageTypes: 'Primary,Thumb' }).then(function (result) { - renderItems(page, result.Items, "upcomingNewsItems", null, { + renderItems(page, result.Items, 'upcomingNewsItems', null, { showParentTitleOrTitle: true, showTitle: false, showParentTitle: false @@ -132,9 +132,9 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", function renderItems(page, items, sectionClass, overlayButton, cardOptions) { var html = cardBuilder.getCardsHtml(Object.assign({ items: items, - preferThumb: "auto", + preferThumb: 'auto', inheritThumb: false, - shape: enableScrollX() ? "autooverflow" : "auto", + shape: enableScrollX() ? 'autooverflow' : 'auto', defaultShape: getBackdropShape(), showParentTitle: true, showTitle: true, @@ -142,57 +142,57 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", coverImage: true, overlayText: false, lazy: true, - overlayPlayButton: "play" === overlayButton, - overlayMoreButton: "more" === overlayButton, - overlayInfoButton: "info" === overlayButton, + overlayPlayButton: 'play' === overlayButton, + overlayMoreButton: 'more' === overlayButton, + overlayInfoButton: 'info' === overlayButton, allowBottomPadding: !enableScrollX(), showAirTime: true, showAirDateTime: true }, cardOptions || {})); - var elem = page.querySelector("." + sectionClass); + var elem = page.querySelector('.' + sectionClass); elem.innerHTML = html; imageLoader.lazyChildren(elem); } function getTabs() { return [{ - name: globalize.translate("Programs") + name: globalize.translate('Programs') }, { - name: globalize.translate("TabGuide") + name: globalize.translate('TabGuide') }, { - name: globalize.translate("TabChannels") + name: globalize.translate('TabChannels') }, { - name: globalize.translate("TabRecordings") + name: globalize.translate('TabRecordings') }, { - name: globalize.translate("HeaderSchedule") + name: globalize.translate('HeaderSchedule') }, { - name: globalize.translate("TabSeries") + name: globalize.translate('TabSeries') }, { - name: globalize.translate("ButtonSearch"), - cssClass: "searchTabButton" + name: globalize.translate('ButtonSearch'), + cssClass: 'searchTabButton' }]; } function setScrollClasses(elem, scrollX) { if (scrollX) { - elem.classList.add("hiddenScrollX"); + elem.classList.add('hiddenScrollX'); if (layoutManager.tv) { - elem.classList.add("smoothScrollX"); + elem.classList.add('smoothScrollX'); } - elem.classList.add("scrollX"); - elem.classList.remove("vertical-wrap"); + elem.classList.add('scrollX'); + elem.classList.remove('vertical-wrap'); } else { - elem.classList.remove("hiddenScrollX"); - elem.classList.remove("smoothScrollX"); - elem.classList.remove("scrollX"); - elem.classList.add("vertical-wrap"); + elem.classList.remove('hiddenScrollX'); + elem.classList.remove('smoothScrollX'); + elem.classList.remove('scrollX'); + elem.classList.add('vertical-wrap'); } } function getDefaultTabIndex(folderId) { - if (userSettings.get("landing-" + folderId) === "guide") { + if (userSettings.get('landing-' + folderId) === 'guide') { return 1; } @@ -219,7 +219,7 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", } function getTabContainers() { - return view.querySelectorAll(".pageTabContent"); + return view.querySelectorAll('.pageTabContent'); } function initTabs() { @@ -235,27 +235,27 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", break; case 1: - depends.push("controllers/livetv/livetvguide"); + depends.push('controllers/livetv/livetvguide'); break; case 2: - depends.push("controllers/livetv/livetvchannels"); + depends.push('controllers/livetv/livetvchannels'); break; case 3: - depends.push("controllers/livetv/livetvrecordings"); + depends.push('controllers/livetv/livetvrecordings'); break; case 4: - depends.push("controllers/livetv/livetvschedule"); + depends.push('controllers/livetv/livetvschedule'); break; case 5: - depends.push("controllers/livetv/livetvseriestimers"); + depends.push('controllers/livetv/livetvseriestimers'); break; case 6: - depends.push("scripts/searchtab"); + depends.push('scripts/searchtab'); } require(depends, function (controllerFactory) { @@ -275,7 +275,7 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", controller = self; } else if (6 === index) { controller = new controllerFactory(view, tabContent, { - collectionType: "livetv" + collectionType: 'livetv' }); } else { controller = new controllerFactory(view, params, tabContent); @@ -320,28 +320,28 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", } function onInputCommand(evt) { - if (evt.detail.command === "search") { + if (evt.detail.command === 'search') { evt.preventDefault(); - Dashboard.navigate("search.html?collectionType=livetv"); + Dashboard.navigate('search.html?collectionType=livetv'); } } var isViewRestored; var self = this; - var currentTabIndex = parseInt(params.tab || getDefaultTabIndex("livetv")); + var currentTabIndex = parseInt(params.tab || getDefaultTabIndex('livetv')); var initialTabIndex = currentTabIndex; var lastFullRender = 0; - [].forEach.call(view.querySelectorAll(".sectionTitleTextButton-programs"), function (link) { + [].forEach.call(view.querySelectorAll('.sectionTitleTextButton-programs'), function (link) { var href = link.href; if (href) { - link.href = href + "&serverId=" + ApiClient.serverId(); + link.href = href + '&serverId=' + ApiClient.serverId(); } }); self.initTab = function () { var tabContent = view.querySelector(".pageTabContent[data-index='0']"); - var containers = tabContent.querySelectorAll(".itemsContainer"); + var containers = tabContent.querySelectorAll('.itemsContainer'); for (var i = 0, length = containers.length; i < length; i++) { setScrollClasses(containers[i], enableScrollX()); @@ -362,11 +362,11 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", var currentTabController; var tabControllers = []; var renderedTabs = []; - view.addEventListener("viewbeforeshow", function (evt) { + view.addEventListener('viewbeforeshow', function (evt) { isViewRestored = evt.detail.isRestored; initTabs(); }); - view.addEventListener("viewshow", function (evt) { + view.addEventListener('viewshow', function (evt) { isViewRestored = evt.detail.isRestored; if (!isViewRestored) { @@ -375,14 +375,14 @@ define(["layoutManager", "userSettings", "inputManager", "loading", "globalize", inputManager.on(window, onInputCommand); }); - view.addEventListener("viewbeforehide", function (e) { + view.addEventListener('viewbeforehide', function (e) { if (currentTabController && currentTabController.onHide) { currentTabController.onHide(); } inputManager.off(window, onInputCommand); }); - view.addEventListener("viewdestroy", function (evt) { + view.addEventListener('viewdestroy', function (evt) { tabControllers.forEach(function (tabController) { if (tabController.destroy) { tabController.destroy(); diff --git a/src/controllers/livetvguideprovider.js b/src/controllers/livetvguideprovider.js index a58917f22d..e83036992b 100644 --- a/src/controllers/livetvguideprovider.js +++ b/src/controllers/livetvguideprovider.js @@ -1,30 +1,30 @@ -define(["events", "loading"], function (events, loading) { - "use strict"; +define(['events', 'loading', 'globalize'], function (events, loading, globalize) { + 'use strict'; function onListingsSubmitted() { - Dashboard.navigate("livetvstatus.html"); + Dashboard.navigate('livetvstatus.html'); } function init(page, type, providerId) { - var url = "components/tvproviders/" + type + ".js"; + var url = 'components/tvproviders/' + type + '.js'; require([url], function (factory) { var instance = new factory(page, providerId, {}); - events.on(instance, "submitted", onListingsSubmitted); + events.on(instance, 'submitted', onListingsSubmitted); instance.init(); }); } function loadTemplate(page, type, providerId) { - require(["text!./components/tvproviders/" + type + ".template.html"], function (html) { - page.querySelector(".providerTemplate").innerHTML = Globalize.translateDocument(html); + require(['text!./components/tvproviders/' + type + '.template.html'], function (html) { + page.querySelector('.providerTemplate').innerHTML = globalize.translateDocument(html); init(page, type, providerId); }); } - pageIdOn("pageshow", "liveTvGuideProviderPage", function () { + pageIdOn('pageshow', 'liveTvGuideProviderPage', function () { loading.show(); - var providerId = getParameterByName("id"); - loadTemplate(this, getParameterByName("type"), providerId); + var providerId = getParameterByName('id'); + loadTemplate(this, getParameterByName('type'), providerId); }); }); diff --git a/src/controllers/livetvsettings.js b/src/controllers/livetvsettings.js index 2b11071c75..7a8552b9ac 100644 --- a/src/controllers/livetvsettings.js +++ b/src/controllers/livetvsettings.js @@ -1,38 +1,38 @@ -define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) { - "use strict"; +define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-button'], function ($, loading, globalize) { + 'use strict'; function loadPage(page, config) { - $(".liveTvSettingsForm", page).show(); - $(".noLiveTvServices", page).hide(); - $("#selectGuideDays", page).val(config.GuideDays || ""); - $("#txtPrePaddingMinutes", page).val(config.PrePaddingSeconds / 60); - $("#txtPostPaddingMinutes", page).val(config.PostPaddingSeconds / 60); - page.querySelector("#txtRecordingPath").value = config.RecordingPath || ""; - page.querySelector("#txtMovieRecordingPath").value = config.MovieRecordingPath || ""; - page.querySelector("#txtSeriesRecordingPath").value = config.SeriesRecordingPath || ""; - page.querySelector("#txtPostProcessor").value = config.RecordingPostProcessor || ""; - page.querySelector("#txtPostProcessorArguments").value = config.RecordingPostProcessorArguments || ""; + $('.liveTvSettingsForm', page).show(); + $('.noLiveTvServices', page).hide(); + $('#selectGuideDays', page).val(config.GuideDays || ''); + $('#txtPrePaddingMinutes', page).val(config.PrePaddingSeconds / 60); + $('#txtPostPaddingMinutes', page).val(config.PostPaddingSeconds / 60); + page.querySelector('#txtRecordingPath').value = config.RecordingPath || ''; + page.querySelector('#txtMovieRecordingPath').value = config.MovieRecordingPath || ''; + page.querySelector('#txtSeriesRecordingPath').value = config.SeriesRecordingPath || ''; + page.querySelector('#txtPostProcessor').value = config.RecordingPostProcessor || ''; + page.querySelector('#txtPostProcessorArguments').value = config.RecordingPostProcessorArguments || ''; loading.hide(); } function onSubmit() { loading.show(); var form = this; - ApiClient.getNamedConfiguration("livetv").then(function (config) { - config.GuideDays = $("#selectGuideDays", form).val() || null; - var recordingPath = form.querySelector("#txtRecordingPath").value || null; - var movieRecordingPath = form.querySelector("#txtMovieRecordingPath").value || null; - var seriesRecordingPath = form.querySelector("#txtSeriesRecordingPath").value || null; + ApiClient.getNamedConfiguration('livetv').then(function (config) { + config.GuideDays = $('#selectGuideDays', form).val() || null; + var recordingPath = form.querySelector('#txtRecordingPath').value || null; + var movieRecordingPath = form.querySelector('#txtMovieRecordingPath').value || null; + var seriesRecordingPath = form.querySelector('#txtSeriesRecordingPath').value || null; var recordingPathChanged = recordingPath != config.RecordingPath || movieRecordingPath != config.MovieRecordingPath || seriesRecordingPath != config.SeriesRecordingPath; config.RecordingPath = recordingPath; config.MovieRecordingPath = movieRecordingPath; config.SeriesRecordingPath = seriesRecordingPath; - config.RecordingEncodingFormat = "mkv"; - config.PrePaddingSeconds = 60 * $("#txtPrePaddingMinutes", form).val(); - config.PostPaddingSeconds = 60 * $("#txtPostPaddingMinutes", form).val(); - config.RecordingPostProcessor = $("#txtPostProcessor", form).val(); - config.RecordingPostProcessorArguments = $("#txtPostProcessorArguments", form).val(); - ApiClient.updateNamedConfiguration("livetv", config).then(function () { + config.RecordingEncodingFormat = 'mkv'; + config.PrePaddingSeconds = 60 * $('#txtPrePaddingMinutes', form).val(); + config.PostPaddingSeconds = 60 * $('#txtPostPaddingMinutes', form).val(); + config.RecordingPostProcessor = $('#txtPostProcessor', form).val(); + config.RecordingPostProcessorArguments = $('#txtPostProcessorArguments', form).val(); + ApiClient.updateNamedConfiguration('livetv', config).then(function () { Dashboard.processServerConfigurationUpdateResult(); showSaveMessage(recordingPathChanged); }); @@ -41,29 +41,29 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) } function showSaveMessage(recordingPathChanged) { - var msg = ""; + var msg = ''; if (recordingPathChanged) { - msg += Globalize.translate("RecordingPathChangeMessage"); + msg += globalize.translate('RecordingPathChangeMessage'); } if (msg) { - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert(msg); }); } } - $(document).on("pageinit", "#liveTvSettingsPage", function () { + $(document).on('pageinit', '#liveTvSettingsPage', function () { var page = this; - $(".liveTvSettingsForm").off("submit", onSubmit).on("submit", onSubmit); - $("#btnSelectRecordingPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { + $('.liveTvSettingsForm').off('submit', onSubmit).on('submit', onSubmit); + $('#btnSelectRecordingPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ callback: function (path) { if (path) { - $("#txtRecordingPath", page).val(path); + $('#txtRecordingPath', page).val(path); } picker.close(); @@ -72,13 +72,13 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) }); }); }); - $("#btnSelectMovieRecordingPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { + $('#btnSelectMovieRecordingPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ callback: function (path) { if (path) { - $("#txtMovieRecordingPath", page).val(path); + $('#txtMovieRecordingPath', page).val(path); } picker.close(); @@ -87,13 +87,13 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) }); }); }); - $("#btnSelectSeriesRecordingPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { + $('#btnSelectSeriesRecordingPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ callback: function (path) { if (path) { - $("#txtSeriesRecordingPath", page).val(path); + $('#txtSeriesRecordingPath', page).val(path); } picker.close(); @@ -102,14 +102,14 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) }); }); }); - $("#btnSelectPostProcessorPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { + $('#btnSelectPostProcessorPath', page).on('click.selectDirectory', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ includeFiles: true, callback: function (path) { if (path) { - $("#txtPostProcessor", page).val(path); + $('#txtPostProcessor', page).val(path); } picker.close(); @@ -117,10 +117,10 @@ define(["jQuery", "loading", "fnchecked", "emby-button"], function ($, loading) }); }); }); - }).on("pageshow", "#liveTvSettingsPage", function () { + }).on('pageshow', '#liveTvSettingsPage', function () { loading.show(); var page = this; - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { loadPage(page, config); }); }); diff --git a/src/controllers/livetvstatus.js b/src/controllers/livetvstatus.js index c25487fd32..053e5d3d4c 100644 --- a/src/controllers/livetvstatus.js +++ b/src/controllers/livetvstatus.js @@ -1,23 +1,23 @@ -define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layoutManager", "loading", "browser", "listViewStyle", "flexStyles", "emby-itemscontainer", "cardStyle", "material-icons", "emby-button"], function ($, globalize, taskButton, dom, libraryMenu, layoutManager, loading, browser) { - "use strict"; +define(['jQuery', 'globalize', 'scripts/taskbutton', 'dom', 'libraryMenu', 'layoutManager', 'loading', 'browser', 'listViewStyle', 'flexStyles', 'emby-itemscontainer', 'cardStyle', 'material-icons', 'emby-button'], function ($, globalize, taskButton, dom, libraryMenu, layoutManager, loading, browser) { + 'use strict'; var enableFocusTransform = !browser.slow && !browser.edge; function getDeviceHtml(device) { var padderClass; - var html = ""; - var cssClass = "card scalableCard"; - var cardBoxCssClass = "cardBox visualCardBox"; - cssClass += " backdropCard backdropCard-scalable"; - padderClass = "cardPadder-backdrop"; + var html = ''; + var cssClass = 'card scalableCard'; + var cardBoxCssClass = 'cardBox visualCardBox'; + cssClass += ' backdropCard backdropCard-scalable'; + padderClass = 'cardPadder-backdrop'; // TODO move card creation code to Card component if (layoutManager.tv) { - cssClass += " show-focus"; + cssClass += ' show-focus'; if (enableFocusTransform) { - cssClass += " show-animation"; + cssClass += ' show-animation'; } } @@ -26,34 +26,34 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo html += '
'; html += '
'; html += '
'; - html += '
dvr
'; - html += "
"; - html += "
"; + html += '
'; + html += ''; + html += ''; html += '
'; - html += ''; - html += '
' + (device.FriendlyName || getTunerName(device.Type)) + "
"; + html += ''; + html += '
' + (device.FriendlyName || getTunerName(device.Type)) + '
'; html += '
'; - html += device.Url || " "; - html += "
"; - html += "
"; - html += ""; - return html += ""; + html += device.Url || ' '; + html += ''; + html += ''; + html += ''; + return html += ''; } function renderDevices(page, devices) { - var html = devices.map(getDeviceHtml).join(""); - page.querySelector(".devicesList").innerHTML = html; + var html = devices.map(getDeviceHtml).join(''); + page.querySelector('.devicesList').innerHTML = html; } function deleteDevice(page, id) { - var message = globalize.translate("MessageConfirmDeleteTunerDevice"); + var message = globalize.translate('MessageConfirmDeleteTunerDevice'); - require(["confirm"], function (confirm) { - confirm(message, globalize.translate("HeaderDeleteDevice")).then(function () { + require(['confirm'], function (confirm) { + confirm(message, globalize.translate('HeaderDeleteDevice')).then(function () { loading.show(); ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("LiveTv/TunerHosts", { + type: 'DELETE', + url: ApiClient.getUrl('LiveTv/TunerHosts', { Id: id }) }).then(function () { @@ -65,7 +65,7 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo function reload(page) { loading.show(); - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { renderDevices(page, config.TunerHosts); renderProviders(page, config.ListingProviders); }); @@ -73,27 +73,27 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo } function submitAddDeviceForm(page) { - page.querySelector(".dlgAddDevice").close(); + page.querySelector('.dlgAddDevice').close(); loading.show(); ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/TunerHosts"), + type: 'POST', + url: ApiClient.getUrl('LiveTv/TunerHosts'), data: JSON.stringify({ - Type: $("#selectTunerDeviceType", page).val(), - Url: $("#txtDevicePath", page).val() + Type: $('#selectTunerDeviceType', page).val(), + Url: $('#txtDevicePath', page).val() }), - contentType: "application/json" + contentType: 'application/json' }).then(function () { reload(page); }, function () { Dashboard.alert({ - message: globalize.translate("ErrorAddingTunerDevice") + message: globalize.translate('ErrorAddingTunerDevice') }); }); } function renderProviders(page, providers) { - var html = ""; + var html = ''; if (providers.length) { html += '
'; @@ -101,27 +101,27 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo for (var i = 0, length = providers.length; i < length; i++) { var provider = providers[i]; html += '"; + html += provider.Path || provider.ListingsId || ''; + html += '
'; + html += ''; + html += ''; + html += ''; + html += ''; } - html += ""; + html += ''; } - var elem = $(".providerList", page).html(html); - $(".btnOptions", elem).on("click", function () { - var id = this.getAttribute("data-id"); + var elem = $('.providerList', page).html(html); + $('.btnOptions', elem).on('click', function () { + var id = this.getAttribute('data-id'); showProviderOptions(page, id, this); }); } @@ -129,25 +129,25 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo function showProviderOptions(page, providerId, button) { var items = []; items.push({ - name: globalize.translate("ButtonDelete"), - id: "delete" + name: globalize.translate('ButtonDelete'), + id: 'delete' }); items.push({ - name: globalize.translate("MapChannels"), - id: "map" + name: globalize.translate('MapChannels'), + id: 'map' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: items, positionTo: button }).then(function (id) { switch (id) { - case "delete": + case 'delete': deleteProvider(page, providerId); break; - case "map": + case 'map': mapChannels(page, providerId); } }); @@ -155,7 +155,7 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo } function mapChannels(page, providerId) { - require(["components/channelmapper/channelmapper"], function (channelmapper) { + require(['components/channelmapper/channelmapper'], function (channelmapper) { new channelmapper({ serverId: ApiClient.serverInfo().Id, providerId: providerId @@ -164,14 +164,14 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo } function deleteProvider(page, id) { - var message = globalize.translate("MessageConfirmDeleteGuideProvider"); + var message = globalize.translate('MessageConfirmDeleteGuideProvider'); - require(["confirm"], function (confirm) { - confirm(message, globalize.translate("HeaderDeleteProvider")).then(function () { + require(['confirm'], function (confirm) { + confirm(message, globalize.translate('HeaderDeleteProvider')).then(function () { loading.show(); ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("LiveTv/ListingProviders", { + type: 'DELETE', + url: ApiClient.getUrl('LiveTv/ListingProviders', { Id: id }) }).then(function () { @@ -185,64 +185,51 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo function getTunerName(providerId) { switch (providerId = providerId.toLowerCase()) { - case "m3u": - return "M3U"; - - case "hdhomerun": - return "HDHomerun"; - - case "hauppauge": - return "Hauppauge"; - - case "satip": - return "DVB"; - + case 'm3u': + return 'M3U'; + case 'hdhomerun': + return 'HDHomeRun'; + case 'hauppauge': + return 'Hauppauge'; + case 'satip': + return 'DVB'; default: - return "Unknown"; + return 'Unknown'; } } function getProviderName(providerId) { switch (providerId = providerId.toLowerCase()) { - case "schedulesdirect": - return "Schedules Direct"; - - case "xmltv": - return "Xml TV"; - - case "emby": - return "Emby Guide"; - + case 'schedulesdirect': + return 'Schedules Direct'; + case 'xmltv': + return 'XMLTV'; default: - return "Unknown"; + return 'Unknown'; } } function getProviderConfigurationUrl(providerId) { switch (providerId = providerId.toLowerCase()) { - case "xmltv": - return "livetvguideprovider.html?type=xmltv"; - - case "schedulesdirect": - return "livetvguideprovider.html?type=schedulesdirect"; - - case "emby": - return "livetvguideprovider.html?type=emby"; + case 'xmltv': + return 'livetvguideprovider.html?type=xmltv'; + case 'schedulesdirect': + return 'livetvguideprovider.html?type=schedulesdirect'; } } function addProvider(button) { var menuItems = []; menuItems.push({ - name: "Schedules Direct", - id: "SchedulesDirect" + name: 'Schedules Direct', + id: 'SchedulesDirect' }); menuItems.push({ - name: "Xml TV", - id: "xmltv" + name: 'XMLTV', + id: 'xmltv' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, @@ -254,81 +241,81 @@ define(["jQuery", "globalize", "scripts/taskbutton", "dom", "libraryMenu", "layo } function addDevice(button) { - Dashboard.navigate("livetvtuner.html"); + Dashboard.navigate('livetvtuner.html'); } function showDeviceMenu(button, tunerDeviceId) { var items = []; items.push({ - name: globalize.translate("ButtonDelete"), - id: "delete" + name: globalize.translate('ButtonDelete'), + id: 'delete' }); items.push({ - name: globalize.translate("ButtonEdit"), - id: "edit" + name: globalize.translate('ButtonEdit'), + id: 'edit' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: items, positionTo: button }).then(function (id) { switch (id) { - case "delete": - deleteDevice(dom.parentWithClass(button, "page"), tunerDeviceId); + case 'delete': + deleteDevice(dom.parentWithClass(button, 'page'), tunerDeviceId); break; - case "edit": - Dashboard.navigate("livetvtuner.html?id=" + tunerDeviceId); + case 'edit': + Dashboard.navigate('livetvtuner.html?id=' + tunerDeviceId); } }); }); } function onDevicesListClick(e) { - var card = dom.parentWithClass(e.target, "card"); + var card = dom.parentWithClass(e.target, 'card'); if (card) { - var id = card.getAttribute("data-id"); - var btnCardOptions = dom.parentWithClass(e.target, "btnCardOptions"); + var id = card.getAttribute('data-id'); + var btnCardOptions = dom.parentWithClass(e.target, 'btnCardOptions'); if (btnCardOptions) { showDeviceMenu(btnCardOptions, id); } else { - Dashboard.navigate("livetvtuner.html?id=" + id); + Dashboard.navigate('livetvtuner.html?id=' + id); } } } - $(document).on("pageinit", "#liveTvStatusPage", function () { + $(document).on('pageinit', '#liveTvStatusPage', function () { var page = this; - $(".btnAddDevice", page).on("click", function () { + $('.btnAddDevice', page).on('click', function () { addDevice(this); }); - $(".formAddDevice", page).on("submit", function () { + $('.formAddDevice', page).on('submit', function () { submitAddDeviceForm(page); return false; }); - $(".btnAddProvider", page).on("click", function () { + $('.btnAddProvider', page).on('click', function () { addProvider(this); }); - page.querySelector(".devicesList").addEventListener("click", onDevicesListClick); - }).on("pageshow", "#liveTvStatusPage", function () { + page.querySelector('.devicesList').addEventListener('click', onDevicesListClick); + }).on('pageshow', '#liveTvStatusPage', function () { var page = this; reload(page); taskButton({ - mode: "on", - progressElem: page.querySelector(".refreshGuideProgress"), - taskKey: "RefreshGuide", - button: page.querySelector(".btnRefresh") + mode: 'on', + progressElem: page.querySelector('.refreshGuideProgress'), + taskKey: 'RefreshGuide', + button: page.querySelector('.btnRefresh') }); - }).on("pagehide", "#liveTvStatusPage", function () { + }).on('pagehide', '#liveTvStatusPage', function () { var page = this; taskButton({ - mode: "off", - progressElem: page.querySelector(".refreshGuideProgress"), - taskKey: "RefreshGuide", - button: page.querySelector(".btnRefresh") + mode: 'off', + progressElem: page.querySelector('.refreshGuideProgress'), + taskKey: 'RefreshGuide', + button: page.querySelector('.btnRefresh') }); }); }); diff --git a/src/controllers/livetvtuner.js b/src/controllers/livetvtuner.js index 55a86d4be7..d7a4d92db2 100644 --- a/src/controllers/livetvtuner.js +++ b/src/controllers/livetvtuner.js @@ -1,34 +1,34 @@ -define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button", "emby-checkbox", "emby-select"], function (globalize, loading, libraryMenu, dom) { - "use strict"; +define(['globalize', 'loading', 'libraryMenu', 'dom', 'emby-input', 'emby-button', 'emby-checkbox', 'emby-select'], function (globalize, loading, libraryMenu, dom) { + 'use strict'; function isM3uVariant(type) { - return ["nextpvr"].indexOf(type || "") !== -1; + return ['nextpvr'].indexOf(type || '') !== -1; } function fillTypes(view, currentId) { - return ApiClient.getJSON(ApiClient.getUrl("LiveTv/TunerHosts/Types")).then(function (types) { - var selectType = view.querySelector(".selectType"); - var html = ""; + return ApiClient.getJSON(ApiClient.getUrl('LiveTv/TunerHosts/Types')).then(function (types) { + var selectType = view.querySelector('.selectType'); + var html = ''; html += types.map(function (tuner) { - return '"; - }).join(""); + return ''; + }).join(''); html += '"; + html += globalize.translate('TabOther'); + html += ''; selectType.innerHTML = html; selectType.disabled = null != currentId; - selectType.value = ""; + selectType.value = ''; onTypeChange.call(selectType); }); } function reload(view, providerId) { - view.querySelector(".txtDevicePath").value = ""; - view.querySelector(".chkFavorite").checked = false; - view.querySelector(".txtDevicePath").value = ""; + view.querySelector('.txtDevicePath').value = ''; + view.querySelector('.chkFavorite').checked = false; + view.querySelector('.txtDevicePath').value = ''; if (providerId) { - ApiClient.getNamedConfiguration("livetv").then(function (config) { + ApiClient.getNamedConfiguration('livetv').then(function (config) { var info = config.TunerHosts.filter(function (i) { return i.Id === providerId; })[0]; @@ -38,8 +38,8 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button } function fillTunerHostInfo(view, info) { - var selectType = view.querySelector(".selectType"); - var type = info.Type || ""; + var selectType = view.querySelector('.selectType'); + var type = info.Type || ''; if (info.Source && isM3uVariant(info.Source)) { type = info.Source; @@ -47,54 +47,53 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button selectType.value = type; onTypeChange.call(selectType); - view.querySelector(".txtDevicePath").value = info.Url || ""; - view.querySelector(".txtFriendlyName").value = info.FriendlyName || ""; - view.querySelector(".txtUserAgent").value = info.UserAgent || ""; - view.querySelector(".fldDeviceId").value = info.DeviceId || ""; - view.querySelector(".chkFavorite").checked = info.ImportFavoritesOnly; - view.querySelector(".chkTranscode").checked = info.AllowHWTranscoding; - view.querySelector(".chkStreamLoop").checked = info.EnableStreamLooping; - view.querySelector(".txtTunerCount").value = info.TunerCount || "0"; + view.querySelector('.txtDevicePath').value = info.Url || ''; + view.querySelector('.txtFriendlyName').value = info.FriendlyName || ''; + view.querySelector('.txtUserAgent').value = info.UserAgent || ''; + view.querySelector('.fldDeviceId').value = info.DeviceId || ''; + view.querySelector('.chkFavorite').checked = info.ImportFavoritesOnly; + view.querySelector('.chkTranscode').checked = info.AllowHWTranscoding; + view.querySelector('.chkStreamLoop').checked = info.EnableStreamLooping; + view.querySelector('.txtTunerCount').value = info.TunerCount || '0'; } function submitForm(page) { loading.show(); var info = { - Type: page.querySelector(".selectType").value, - Url: page.querySelector(".txtDevicePath").value || null, - UserAgent: page.querySelector(".txtUserAgent").value || null, - FriendlyName: page.querySelector(".txtFriendlyName").value || null, - DeviceId: page.querySelector(".fldDeviceId").value || null, - TunerCount: page.querySelector(".txtTunerCount").value || 0, - ImportFavoritesOnly: page.querySelector(".chkFavorite").checked, - AllowHWTranscoding: page.querySelector(".chkTranscode").checked, - EnableStreamLooping: page.querySelector(".chkStreamLoop").checked + Type: page.querySelector('.selectType').value, + Url: page.querySelector('.txtDevicePath').value || null, + UserAgent: page.querySelector('.txtUserAgent').value || null, + FriendlyName: page.querySelector('.txtFriendlyName').value || null, + DeviceId: page.querySelector('.fldDeviceId').value || null, + TunerCount: page.querySelector('.txtTunerCount').value || 0, + ImportFavoritesOnly: page.querySelector('.chkFavorite').checked, + AllowHWTranscoding: page.querySelector('.chkTranscode').checked, + EnableStreamLooping: page.querySelector('.chkStreamLoop').checked }; if (isM3uVariant(info.Type)) { info.Source = info.Type; - info.Type = "m3u"; + info.Type = 'm3u'; } - var id = getParameterByName("id"); + var id = getParameterByName('id'); if (id) { info.Id = id; } - info.Id; ApiClient.ajax({ - type: "POST", - url: ApiClient.getUrl("LiveTv/TunerHosts"), + type: 'POST', + url: ApiClient.getUrl('LiveTv/TunerHosts'), data: JSON.stringify(info), - contentType: "application/json" + contentType: 'application/json' }).then(function (result) { Dashboard.processServerConfigurationUpdateResult(); - Dashboard.navigate("livetvstatus.html"); + Dashboard.navigate('livetvstatus.html'); }, function () { loading.hide(); Dashboard.alert({ - message: globalize.translate("ErrorSavingTvProvider") + message: globalize.translate('ErrorSavingTvProvider') }); }); } @@ -106,7 +105,7 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button } function getDetectedDevice() { - return getRequirePromise(["tunerPicker"]).then(function (tunerPicker) { + return getRequirePromise(['tunerPicker']).then(function (tunerPicker) { return new tunerPicker().show({ serverId: ApiClient.serverId() }); @@ -115,113 +114,113 @@ define(["globalize", "loading", "libraryMenu", "dom", "emby-input", "emby-button function onTypeChange() { var value = this.value; - var view = dom.parentWithClass(this, "page"); - var mayIncludeUnsupportedDrmChannels = "hdhomerun" === value; - var supportsTranscoding = "hdhomerun" === value; - var supportsFavorites = "hdhomerun" === value; - var supportsTunerIpAddress = "hdhomerun" === value; - var supportsTunerFileOrUrl = "m3u" === value; - var supportsStreamLooping = "m3u" === value; - var supportsTunerCount = "m3u" === value; - var supportsUserAgent = "m3u" === value; - var suppportsSubmit = "other" !== value; + var view = dom.parentWithClass(this, 'page'); + var mayIncludeUnsupportedDrmChannels = 'hdhomerun' === value; + var supportsTranscoding = 'hdhomerun' === value; + var supportsFavorites = 'hdhomerun' === value; + var supportsTunerIpAddress = 'hdhomerun' === value; + var supportsTunerFileOrUrl = 'm3u' === value; + var supportsStreamLooping = 'm3u' === value; + var supportsTunerCount = 'm3u' === value; + var supportsUserAgent = 'm3u' === value; + var suppportsSubmit = 'other' !== value; var supportsSelectablePath = supportsTunerFileOrUrl; - var txtDevicePath = view.querySelector(".txtDevicePath"); + var txtDevicePath = view.querySelector('.txtDevicePath'); if (supportsTunerIpAddress) { - txtDevicePath.label(globalize.translate("LabelTunerIpAddress")); - view.querySelector(".fldPath").classList.remove("hide"); + txtDevicePath.label(globalize.translate('LabelTunerIpAddress')); + view.querySelector('.fldPath').classList.remove('hide'); } else if (supportsTunerFileOrUrl) { - txtDevicePath.label(globalize.translate("LabelFileOrUrl")); - view.querySelector(".fldPath").classList.remove("hide"); + txtDevicePath.label(globalize.translate('LabelFileOrUrl')); + view.querySelector('.fldPath').classList.remove('hide'); } else { - view.querySelector(".fldPath").classList.add("hide"); + view.querySelector('.fldPath').classList.add('hide'); } if (supportsSelectablePath) { - view.querySelector(".btnSelectPath").classList.remove("hide"); - view.querySelector(".txtDevicePath").setAttribute("required", "required"); + view.querySelector('.btnSelectPath').classList.remove('hide'); + view.querySelector('.txtDevicePath').setAttribute('required', 'required'); } else { - view.querySelector(".btnSelectPath").classList.add("hide"); - view.querySelector(".txtDevicePath").removeAttribute("required"); + view.querySelector('.btnSelectPath').classList.add('hide'); + view.querySelector('.txtDevicePath').removeAttribute('required'); } if (supportsUserAgent) { - view.querySelector(".fldUserAgent").classList.remove("hide"); + view.querySelector('.fldUserAgent').classList.remove('hide'); } else { - view.querySelector(".fldUserAgent").classList.add("hide"); + view.querySelector('.fldUserAgent').classList.add('hide'); } if (supportsFavorites) { - view.querySelector(".fldFavorites").classList.remove("hide"); + view.querySelector('.fldFavorites').classList.remove('hide'); } else { - view.querySelector(".fldFavorites").classList.add("hide"); + view.querySelector('.fldFavorites').classList.add('hide'); } if (supportsTranscoding) { - view.querySelector(".fldTranscode").classList.remove("hide"); + view.querySelector('.fldTranscode').classList.remove('hide'); } else { - view.querySelector(".fldTranscode").classList.add("hide"); + view.querySelector('.fldTranscode').classList.add('hide'); } if (supportsStreamLooping) { - view.querySelector(".fldStreamLoop").classList.remove("hide"); + view.querySelector('.fldStreamLoop').classList.remove('hide'); } else { - view.querySelector(".fldStreamLoop").classList.add("hide"); + view.querySelector('.fldStreamLoop').classList.add('hide'); } if (supportsTunerCount) { - view.querySelector(".fldTunerCount").classList.remove("hide"); - view.querySelector(".txtTunerCount").setAttribute("required", "required"); + view.querySelector('.fldTunerCount').classList.remove('hide'); + view.querySelector('.txtTunerCount').setAttribute('required', 'required'); } else { - view.querySelector(".fldTunerCount").classList.add("hide"); - view.querySelector(".txtTunerCount").removeAttribute("required"); + view.querySelector('.fldTunerCount').classList.add('hide'); + view.querySelector('.txtTunerCount').removeAttribute('required'); } if (mayIncludeUnsupportedDrmChannels) { - view.querySelector(".drmMessage").classList.remove("hide"); + view.querySelector('.drmMessage').classList.remove('hide'); } else { - view.querySelector(".drmMessage").classList.add("hide"); + view.querySelector('.drmMessage').classList.add('hide'); } if (suppportsSubmit) { - view.querySelector(".button-submit").classList.remove("hide"); + view.querySelector('.button-submit').classList.remove('hide'); } else { - view.querySelector(".button-submit").classList.add("hide"); + view.querySelector('.button-submit').classList.add('hide'); } } return function (view, params) { if (!params.id) { - view.querySelector(".btnDetect").classList.remove("hide"); + view.querySelector('.btnDetect').classList.remove('hide'); } - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { var currentId = params.id; fillTypes(view, currentId).then(function () { reload(view, currentId); }); }); - view.querySelector("form").addEventListener("submit", function (e) { + view.querySelector('form').addEventListener('submit', function (e) { submitForm(view); e.preventDefault(); e.stopPropagation(); return false; }); - view.querySelector(".selectType").addEventListener("change", onTypeChange); - view.querySelector(".btnDetect").addEventListener("click", function () { + view.querySelector('.selectType').addEventListener('change', onTypeChange); + view.querySelector('.btnDetect').addEventListener('click', function () { getDetectedDevice().then(function (info) { fillTunerHostInfo(view, info); }); }); - view.querySelector(".btnSelectPath").addEventListener("click", function () { - require(["directorybrowser"], function (directoryBrowser) { + view.querySelector('.btnSelectPath').addEventListener('click', function () { + require(['directorybrowser'], function (directoryBrowser) { var picker = new directoryBrowser(); picker.show({ includeFiles: true, callback: function (path) { if (path) { - view.querySelector(".txtDevicePath").value = path; + view.querySelector('.txtDevicePath').value = path; } picker.close(); diff --git a/src/controllers/metadataimagespage.js b/src/controllers/metadataimagespage.js deleted file mode 100644 index 3a6656e4b6..0000000000 --- a/src/controllers/metadataimagespage.js +++ /dev/null @@ -1,64 +0,0 @@ -define(["jQuery", "dom", "loading", "libraryMenu", "listViewStyle"], function($, dom, loading, libraryMenu) { - "use strict"; - - function populateLanguages(select) { - return ApiClient.getCultures().then(function(languages) { - var html = ""; - html += ""; - for (var i = 0, length = languages.length; i < length; i++) { - var culture = languages[i]; - html += "" - } - select.innerHTML = html - }) - } - - function populateCountries(select) { - return ApiClient.getCountries().then(function(allCountries) { - var html = ""; - html += ""; - for (var i = 0, length = allCountries.length; i < length; i++) { - var culture = allCountries[i]; - html += "" - } - select.innerHTML = html - }) - } - - function loadPage(page) { - var promises = [ApiClient.getServerConfiguration(), populateLanguages(page.querySelector("#selectLanguage")), populateCountries(page.querySelector("#selectCountry"))]; - Promise.all(promises).then(function(responses) { - var config = responses[0]; - page.querySelector("#selectLanguage").value = config.PreferredMetadataLanguage || "", page.querySelector("#selectCountry").value = config.MetadataCountryCode || "", loading.hide() - }) - } - - function onSubmit() { - var form = this; - return loading.show(), ApiClient.getServerConfiguration().then(function(config) { - config.PreferredMetadataLanguage = form.querySelector("#selectLanguage").value, config.MetadataCountryCode = form.querySelector("#selectCountry").value, ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult) - }), !1 - } - - function getTabs() { - return [{ - href: "library.html", - name: Globalize.translate("HeaderLibraries") - }, { - href: "librarydisplay.html", - name: Globalize.translate("TabDisplay") - }, { - href: "metadataimages.html", - name: Globalize.translate("TabMetadata") - }, { - href: "metadatanfo.html", - name: Globalize.translate("TabNfoSettings") - }] - } - - $(document).on("pageinit", "#metadataImagesConfigurationPage", function() { - $(".metadataImagesConfigurationForm").off("submit", onSubmit).on("submit", onSubmit) - }).on("pageshow", "#metadataImagesConfigurationPage", function() { - libraryMenu.setTabs("metadata", 2, getTabs), loading.show(), loadPage(this) - }) -}); \ No newline at end of file diff --git a/src/controllers/metadatanfo.js b/src/controllers/metadatanfo.js deleted file mode 100644 index 20049837dd..0000000000 --- a/src/controllers/metadatanfo.js +++ /dev/null @@ -1,74 +0,0 @@ -define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) { - "use strict"; - - function loadPage(page, config, users) { - var html = '"; - html += users.map(function (user) { - return '"; - }).join(""); - $("#selectUser", page).html(html).val(config.UserId || ""); - $("#selectReleaseDateFormat", page).val(config.ReleaseDateFormat); - page.querySelector("#chkSaveImagePaths").checked = config.SaveImagePathsInNfo; - page.querySelector("#chkEnablePathSubstitution").checked = config.EnablePathSubstitution; - page.querySelector("#chkEnableExtraThumbs").checked = config.EnableExtraThumbsDuplication; - loading.hide(); - } - - function onSubmit() { - loading.show(); - var form = this; - ApiClient.getNamedConfiguration(metadataKey).then(function (config) { - config.UserId = $("#selectUser", form).val() || null; - config.ReleaseDateFormat = $("#selectReleaseDateFormat", form).val(); - config.SaveImagePathsInNfo = form.querySelector("#chkSaveImagePaths").checked; - config.EnablePathSubstitution = form.querySelector("#chkEnablePathSubstitution").checked; - config.EnableExtraThumbsDuplication = form.querySelector("#chkEnableExtraThumbs").checked; - ApiClient.updateNamedConfiguration(metadataKey, config).then(function () { - Dashboard.processServerConfigurationUpdateResult(); - showConfirmMessage(config); - }); - }); - return false; - } - - function showConfirmMessage(config) { - var msg = []; - msg.push(Globalize.translate("MetadataSettingChangeHelp")); - - require(["alert"], function (alert) { - alert({ - text: msg.join("

") - }); - }); - } - - function getTabs() { - return [{ - href: "library.html", - name: Globalize.translate("HeaderLibraries") - }, { - href: "librarydisplay.html", - name: Globalize.translate("TabDisplay") - }, { - href: "metadataimages.html", - name: Globalize.translate("TabMetadata") - }, { - href: "metadatanfo.html", - name: Globalize.translate("TabNfoSettings") - }]; - } - - var metadataKey = "xbmcmetadata"; - $(document).on("pageinit", "#metadataNfoPage", function () { - $(".metadataNfoForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#metadataNfoPage", function () { - libraryMenu.setTabs("metadata", 3, getTabs); - loading.show(); - var page = this; - var promise1 = ApiClient.getUsers(); - var promise2 = ApiClient.getNamedConfiguration(metadataKey); - Promise.all([promise1, promise2]).then(function (responses) { - loadPage(page, responses[1], responses[0]); - }); - }); -}); diff --git a/src/controllers/movies/moviecollections.js b/src/controllers/movies/moviecollections.js index f17f64b7c8..e9ae599b92 100644 --- a/src/controllers/movies/moviecollections.js +++ b/src/controllers/movies/moviecollections.js @@ -1,5 +1,5 @@ -define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "apphost", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, appHost) { - "use strict"; +define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -9,18 +9,22 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "BoxSet", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'BoxSet', Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName", + Fields: 'PrimaryImageAspectRatio,SortName', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - StartIndex: 0, - Limit: pageSize + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -34,7 +38,7 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB function getSavedQueryKey(context) { if (!context.savedQueryKey) { - context.savedQueryKey = libraryBrowser.getSavedQueryKey("moviecollections"); + context.savedQueryKey = libraryBrowser.getSavedQueryKey('moviecollections'); } return context.savedQueryKey; @@ -42,17 +46,17 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB function onViewStyleChange() { var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems(page) { @@ -65,7 +69,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -74,7 +80,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -91,45 +99,45 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB filterButton: false }); var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', overlayPlayButton: true, centerText: true, showTitle: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', lazy: true, cardLayout: true, showTitle: true }); - } else if (viewStyle == "Banner") { + } else if (viewStyle == 'Banner') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "banner", + shape: 'banner', preferBanner: true, - context: "movies", + context: 'movies', lazy: true }); - } else if (viewStyle == "List") { + } else if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, - context: "movies", + context: 'movies', sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "auto", - context: "movies", + shape: 'auto', + context: 'movies', showTitle: true, centerText: false, cardLayout: true @@ -137,8 +145,8 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "auto", - context: "movies", + shape: 'auto', + context: 'movies', centerText: true, overlayPlayButton: true, showTitle: true @@ -146,41 +154,40 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB } var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } if (!result.Items.length) { - html = '

' + Globalize.translate("MessageNoCollectionsAvailable") + "

"; + html = '

' + globalize.translate('MessageNoCollectionsAvailable') + '

'; } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(page), query); loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); } var self = this; - var pageSize = 100; var data = {}; var isLoading = false; @@ -189,23 +196,23 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB }; function initPage(tabContent) { - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SortName" + name: globalize.translate('OptionNameSort'), + id: 'SortName' }, { - name: Globalize.translate("OptionImdbRating"), - id: "CommunityRating,SortName" + name: globalize.translate('OptionImdbRating'), + id: 'CommunityRating,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName' }, { - name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SortName" + name: globalize.translate('OptionParentalRating'), + id: 'OfficialRating,SortName' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,SortName" + name: globalize.translate('OptionReleaseDate'), + id: 'PremiereDate,SortName' }], callback: function () { getQuery(tabContent).StartIndex = 0; @@ -215,11 +222,11 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB button: e.target }); }); - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "List,Poster,PosterCard,Thumb,ThumbCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; getPageData(tabContent).view = viewStyle; libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); @@ -227,8 +234,8 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB onViewStyleChange(); reloadItems(tabContent); }); - tabContent.querySelector(".btnNewCollection").addEventListener("click", function () { - require(["collectionEditor"], function (collectionEditor) { + tabContent.querySelector('.btnNewCollection').addEventListener('click', function () { + require(['collectionEditor'], function (collectionEditor) { var serverId = ApiClient.serverInfo().Id; new collectionEditor().show({ items: [], diff --git a/src/controllers/movies/moviegenres.js b/src/controllers/movies/moviegenres.js index e51274d254..e8e49ff9da 100644 --- a/src/controllers/movies/moviegenres.js +++ b/src/controllers/movies/moviegenres.js @@ -1,5 +1,5 @@ -define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader", "apphost", "globalize", "appRouter", "dom", "emby-button"], function (layoutManager, loading, libraryBrowser, cardBuilder, lazyLoader, appHost, globalize, appRouter, dom) { - "use strict"; +define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader', 'apphost', 'globalize', 'appRouter', 'dom', 'emby-button'], function (layoutManager, loading, libraryBrowser, cardBuilder, lazyLoader, appHost, globalize, appRouter, dom) { + 'use strict'; return function (view, params, tabContent) { function getPageData() { @@ -9,13 +9,13 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Movie", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Movie', Recursive: true, EnableTotalRecordCount: false }, - view: "Poster" + view: 'Poster' }; pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); @@ -29,7 +29,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader } function getSavedQueryKey() { - return libraryBrowser.getSavedQueryKey("moviegenres"); + return libraryBrowser.getSavedQueryKey('moviegenres'); } function getPromise() { @@ -43,29 +43,30 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function getPortraitShape() { - return enableScrollX() ? "overflowPortrait" : "portrait"; + return enableScrollX() ? 'overflowPortrait' : 'portrait'; } - function fillItemsContainer(elem) { - var id = elem.getAttribute("data-id"); + function fillItemsContainer(entry) { + var elem = entry.target; + var id = elem.getAttribute('data-id'); var viewStyle = self.getCurrentViewStyle(); - var limit = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? 5 : 9; + var limit = 'Thumb' == viewStyle || 'ThumbCard' == viewStyle ? 5 : 9; if (enableScrollX()) { limit = 10; } - var enableImageTypes = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? "Primary,Backdrop,Thumb" : "Primary"; + var enableImageTypes = 'Thumb' == viewStyle || 'ThumbCard' == viewStyle ? 'Primary,Backdrop,Thumb' : 'Primary'; var query = { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Movie", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Movie', Recursive: true, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', ImageTypeLimit: 1, EnableImageTypes: enableImageTypes, Limit: limit, @@ -74,9 +75,9 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader ParentId: params.topParentId }; ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) { - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getThumbShape(), @@ -87,7 +88,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader overlayMoreButton: true, allowBottomPadding: false }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getThumbShape(), @@ -98,7 +99,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader cardLayout: true, showYear: true }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getPortraitShape(), @@ -108,17 +109,20 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader cardLayout: true, showYear: true }); - } else if (viewStyle == "Poster") { + } else if (viewStyle == 'Poster') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getPortraitShape(), scalable: true, overlayMoreButton: true, - allowBottomPadding: false + allowBottomPadding: true, + showTitle: true, + centerText: true, + showYear: true }); } if (result.Items.length >= query.Limit) { - tabContent.querySelector(".btnMoreFromGenre" + id + " i").classList.remove("hide"); + tabContent.querySelector('.btnMoreFromGenre' + id + ' .material-icons').classList.remove('hide'); } }); } @@ -126,8 +130,8 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader function reloadItems(context, promise) { var query = getQuery(); promise.then(function (result) { - var elem = context.querySelector("#items"); - var html = ""; + var elem = context.querySelector('#items'); + var html = ''; var items = result.Items; for (var i = 0, length = items.length; i < length; i++) { @@ -136,20 +140,20 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader html += '
'; html += '"; + html += ''; + html += ''; + html += ''; + html += '
'; if (enableScrollX()) { - var scrollXClass = "scrollX hiddenScrollX"; + var scrollXClass = 'scrollX hiddenScrollX'; if (layoutManager.tv) { - scrollXClass += "smoothScrollX"; + scrollXClass += 'smoothScrollX padded-top-focusscale padded-bottom-focusscale'; } html += '
'; @@ -157,8 +161,8 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader html += '
'; } - html += "
"; - html += "
"; + html += ''; + html += ''; } elem.innerHTML = html; @@ -177,16 +181,16 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader var data = {}; self.getViewStyles = function () { - return "Poster,PosterCard,Thumb,ThumbCard".split(","); + return 'Poster,PosterCard,Thumb,ThumbCard'.split(','); }; self.getCurrentViewStyle = function () { - return getPageData(tabContent).view; + return getPageData().view; }; self.setCurrentViewStyle = function (viewStyle) { - getPageData(tabContent).view = viewStyle; - libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); + getPageData().view = viewStyle; + libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle); fullyReload(); }; diff --git a/src/controllers/movies/movies.js b/src/controllers/movies/movies.js index 3a365acc90..89bcc215e6 100644 --- a/src/controllers/movies/movies.js +++ b/src/controllers/movies/movies.js @@ -1,17 +1,17 @@ -define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", "alphaPicker", "listView", "cardBuilder", "emby-itemscontainer"], function (loading, layoutManager, userSettings, events, libraryBrowser, alphaPicker, listView, cardBuilder) { - "use strict"; +define(['loading', 'layoutManager', 'userSettings', 'events', 'libraryBrowser', 'alphaPicker', 'listView', 'cardBuilder', 'globalize', 'emby-itemscontainer'], function (loading, layoutManager, userSettings, events, libraryBrowser, alphaPicker, listView, cardBuilder, globalize) { + 'use strict'; return function (view, params, tabContent, options) { function onViewStyleChange() { - if (self.getCurrentViewStyle() == "List") { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if (self.getCurrentViewStyle() == 'List') { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function updateFilterControls() { @@ -32,7 +32,9 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } itemsContainer.refreshItems(); } @@ -41,7 +43,9 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } itemsContainer.refreshItems(); } @@ -59,26 +63,26 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", }); var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } isLoading = false; loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(tabContent); }); } @@ -87,49 +91,49 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", var html; var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', lazy: true, overlayPlayButton: true, showTitle: true, showYear: true, centerText: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', lazy: true, cardLayout: true, showTitle: true, showYear: true, centerText: true }); - } else if (viewStyle == "Banner") { + } else if (viewStyle == 'Banner') { html = cardBuilder.getCardsHtml({ items: items, - shape: "banner", + shape: 'banner', preferBanner: true, - context: "movies", + context: 'movies', lazy: true }); - } else if (viewStyle == "List") { + } else if (viewStyle == 'List') { html = listView.getListViewHtml({ items: items, - context: "movies", + context: 'movies', sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: items, - shape: "portrait", - context: "movies", + shape: 'portrait', + context: 'movies', showTitle: true, showYear: true, centerText: true, @@ -139,8 +143,8 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", } else { html = cardBuilder.getCardsHtml({ items: items, - shape: "portrait", - context: "movies", + shape: 'portrait', + context: 'movies', overlayPlayButton: true, showTitle: true, showYear: true, @@ -155,10 +159,10 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", itemsContainer.fetchData = fetchData; itemsContainer.getItemsHtml = getItemsHtml; itemsContainer.afterRefresh = afterRefresh; - var alphaPickerElement = tabContent.querySelector(".alphaPicker"); + var alphaPickerElement = tabContent.querySelector('.alphaPicker'); if (alphaPickerElement) { - alphaPickerElement.addEventListener("alphavaluechanged", function (e) { + alphaPickerElement.addEventListener('alphavaluechanged', function (e) { var newValue = e.detail.value; query.NameStartsWithOrGreater = newValue; query.StartIndex = 0; @@ -166,55 +170,53 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", }); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, - valueChangeEvent: "click" + valueChangeEvent: 'click' }); - if (layoutManager.desktop || layoutManager.mobile) { - alphaPickerElement.classList.add("alphabetPicker-right"); - itemsContainer.classList.remove("padded-left-withalphapicker"); - itemsContainer.classList.add("padded-right-withalphapicker"); - } + tabContent.querySelector('.alphaPicker').classList.add('alphabetPicker-right'); + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + itemsContainer.classList.add('padded-right-withalphapicker'); } - var btnFilter = tabContent.querySelector(".btnFilter"); + var btnFilter = tabContent.querySelector('.btnFilter'); if (btnFilter) { - btnFilter.addEventListener("click", function () { + btnFilter.addEventListener('click', function () { self.showFilterMenu(); }); } - var btnSort = tabContent.querySelector(".btnSort"); + var btnSort = tabContent.querySelector('.btnSort'); if (btnSort) { - btnSort.addEventListener("click", function (e) { + btnSort.addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SortName,ProductionYear" + name: globalize.translate('OptionNameSort'), + id: 'SortName,ProductionYear' }, { - name: Globalize.translate("OptionImdbRating"), - id: "CommunityRating,SortName,ProductionYear" + name: globalize.translate('OptionImdbRating'), + id: 'CommunityRating,SortName,ProductionYear' }, { - name: Globalize.translate("OptionCriticRating"), - id: "CriticRating,SortName,ProductionYear" + name: globalize.translate('OptionCriticRating'), + id: 'CriticRating,SortName,ProductionYear' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName,ProductionYear" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName,ProductionYear' }, { - name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SortName,ProductionYear" + name: globalize.translate('OptionDatePlayed'), + id: 'DatePlayed,SortName,ProductionYear' }, { - name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SortName,ProductionYear" + name: globalize.translate('OptionParentalRating'), + id: 'OfficialRating,SortName,ProductionYear' }, { - name: Globalize.translate("OptionPlayCount"), - id: "PlayCount,SortName,ProductionYear" + name: globalize.translate('OptionPlayCount'), + id: 'PlayCount,SortName,ProductionYear' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,SortName,ProductionYear" + name: globalize.translate('OptionReleaseDate'), + id: 'PremiereDate,SortName,ProductionYear' }, { - name: Globalize.translate("OptionRuntime"), - id: "Runtime,SortName,ProductionYear" + name: globalize.translate('OptionRuntime'), + id: 'Runtime,SortName,ProductionYear' }], callback: function () { query.StartIndex = 0; @@ -226,11 +228,11 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", }); }); } - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "Banner,List,Poster,PosterCard,Thumb,ThumbCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; userSettings.set(savedViewKey, viewStyle); query.StartIndex = 0; @@ -240,37 +242,41 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", } var self = this; - var itemsContainer = tabContent.querySelector(".itemsContainer"); - var savedQueryKey = params.topParentId + "-" + options.mode; - var savedViewKey = savedQueryKey + "-view"; + var itemsContainer = tabContent.querySelector('.itemsContainer'); + var savedQueryKey = params.topParentId + '-' + options.mode; + var savedViewKey = savedQueryKey + '-view'; var query = { - SortBy: "SortName,ProductionYear", - SortOrder: "Ascending", - IncludeItemTypes: "Movie", + SortBy: 'SortName,ProductionYear', + SortOrder: 'Ascending', + IncludeItemTypes: 'Movie', Recursive: true, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', StartIndex: 0, - Limit: 100, ParentId: params.topParentId }; + + if (userSettings.libraryPageSize() > 0) { + query['Limit'] = userSettings.libraryPageSize(); + } + var isLoading = false; - if (options.mode === "favorites") { + if (options.mode === 'favorites') { query.IsFavorite = true; } query = userSettings.loadQuerySettings(savedQueryKey, query); self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: query, - mode: "movies", + mode: 'movies', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { query.StartIndex = 0; itemsContainer.refreshItems(); }); @@ -279,7 +285,7 @@ define(["loading", "layoutManager", "userSettings", "events", "libraryBrowser", }; self.getCurrentViewStyle = function () { - return userSettings.get(savedViewKey) || "Poster"; + return userSettings.get(savedViewKey) || 'Poster'; }; self.initTab = function () { diff --git a/src/controllers/movies/moviesrecommended.js b/src/controllers/movies/moviesrecommended.js index 0327217e44..d948c1cef7 100644 --- a/src/controllers/movies/moviesrecommended.js +++ b/src/controllers/movies/moviesrecommended.js @@ -1,31 +1,31 @@ -define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu", "mainTabsManager", "cardBuilder", "dom", "imageLoader", "playbackManager", "emby-itemscontainer", "emby-tabs", "emby-button"], function (events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager) { - "use strict"; +define(['events', 'layoutManager', 'inputManager', 'userSettings', 'libraryMenu', 'mainTabsManager', 'cardBuilder', 'dom', 'imageLoader', 'playbackManager', 'globalize', 'emby-scroller', 'emby-itemscontainer', 'emby-tabs', 'emby-button'], function (events, layoutManager, inputManager, userSettings, libraryMenu, mainTabsManager, cardBuilder, dom, imageLoader, playbackManager, globalize) { + 'use strict'; function enableScrollX() { return !layoutManager.desktop; } function getPortraitShape() { - return enableScrollX() ? "overflowPortrait" : "portrait"; + return enableScrollX() ? 'overflowPortrait' : 'portrait'; } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function loadLatest(page, userId, parentId) { var options = { - IncludeItemTypes: "Movie", + IncludeItemTypes: 'Movie', Limit: 18, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; - ApiClient.getJSON(ApiClient.getUrl("Users/" + userId + "/Items/Latest", options)).then(function (items) { + ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { var allowBottomPadding = !enableScrollX(); - var container = page.querySelector("#recentlyAddedItems"); + var container = page.querySelector('#recentlyAddedItems'); cardBuilder.buildCards(items, { itemsContainer: container, shape: getPortraitShape(), @@ -45,28 +45,28 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" function loadResume(page, userId, parentId) { var screenWidth = dom.getWindowSize().innerWidth; var options = { - SortBy: "DatePlayed", - SortOrder: "Descending", - IncludeItemTypes: "Movie", - Filters: "IsResumable", + SortBy: 'DatePlayed', + SortOrder: 'Descending', + IncludeItemTypes: 'Movie', + Filters: 'IsResumable', Limit: screenWidth >= 1920 ? 5 : screenWidth >= 1600 ? 5 : 3, Recursive: true, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', CollapseBoxSetItems: false, ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; ApiClient.getItems(userId, options).then(function (result) { if (result.Items.length) { - page.querySelector("#resumableSection").classList.remove("hide"); + page.querySelector('#resumableSection').classList.remove('hide'); } else { - page.querySelector("#resumableSection").classList.add("hide"); + page.querySelector('#resumableSection').classList.add('hide'); } var allowBottomPadding = !enableScrollX(); - var container = page.querySelector("#resumableItems"); + var container = page.querySelector('#resumableItems'); cardBuilder.buildCards(result.Items, { itemsContainer: container, preferThumb: true, @@ -86,71 +86,78 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" } function getRecommendationHtml(recommendation) { - var html = ""; - var title = ""; + var html = ''; + var title = ''; switch (recommendation.RecommendationType) { - case "SimilarToRecentlyPlayed": - title = Globalize.translate("RecommendationBecauseYouWatched").replace("{0}", recommendation.BaselineItemName); + case 'SimilarToRecentlyPlayed': + title = globalize.translate('RecommendationBecauseYouWatched', recommendation.BaselineItemName); break; - case "SimilarToLikedItem": - title = Globalize.translate("RecommendationBecauseYouLike").replace("{0}", recommendation.BaselineItemName); + case 'SimilarToLikedItem': + title = globalize.translate('RecommendationBecauseYouLike', recommendation.BaselineItemName); break; - case "HasDirectorFromRecentlyPlayed": - case "HasLikedDirector": - title = Globalize.translate("RecommendationDirectedBy").replace("{0}", recommendation.BaselineItemName); + case 'HasDirectorFromRecentlyPlayed': + case 'HasLikedDirector': + title = globalize.translate('RecommendationDirectedBy', recommendation.BaselineItemName); break; - case "HasActorFromRecentlyPlayed": - case "HasLikedActor": - title = Globalize.translate("RecommendationStarring").replace("{0}", recommendation.BaselineItemName); + case 'HasActorFromRecentlyPlayed': + case 'HasLikedActor': + title = globalize.translate('RecommendationStarring', recommendation.BaselineItemName); break; } html += '
'; - html += '

' + title + "

"; + html += '

' + title + '

'; var allowBottomPadding = true; if (enableScrollX()) { - allowBottomPadding = false; - html += '
'; + html += '
'; + html += '
'; } else { - html += '
'; + html += '
'; } html += cardBuilder.getCardsHtml(recommendation.Items, { shape: getPortraitShape(), scalable: true, overlayPlayButton: true, - allowBottomPadding: allowBottomPadding + allowBottomPadding: allowBottomPadding, + showTitle: true, + showYear: true, + centerText: true }); - html += "
"; - html += "
"; + + if (enableScrollX()) { + html += '
'; + } + html += '
'; + html += '
'; return html; } function loadSuggestions(page, userId, parentId) { var screenWidth = dom.getWindowSize().innerWidth; - var url = ApiClient.getUrl("Movies/Recommendations", { + var url = ApiClient.getUrl('Movies/Recommendations', { userId: userId, categoryLimit: 6, ItemLimit: screenWidth >= 1920 ? 8 : screenWidth >= 1600 ? 8 : screenWidth >= 1200 ? 6 : 5, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb" + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb' }); ApiClient.getJSON(url).then(function (recommendations) { if (!recommendations.length) { - page.querySelector(".noItemsMessage").classList.remove("hide"); - page.querySelector(".recommendations").innerHTML = ""; + page.querySelector('.noItemsMessage').classList.remove('hide'); + page.querySelector('.recommendations').innerHTML = ''; return; } - var html = recommendations.map(getRecommendationHtml).join(""); - page.querySelector(".noItemsMessage").classList.add("hide"); - var recs = page.querySelector(".recommendations"); + var html = recommendations.map(getRecommendationHtml).join(''); + page.querySelector('.noItemsMessage').classList.add('hide'); + var recs = page.querySelector('.recommendations'); recs.innerHTML = html; imageLoader.lazyChildren(recs); @@ -160,31 +167,33 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" } function autoFocus(page) { - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); } function setScrollClasses(elem, scrollX) { if (scrollX) { - elem.classList.add("hiddenScrollX"); + elem.classList.add('hiddenScrollX'); if (layoutManager.tv) { - elem.classList.add("smoothScrollX"); + elem.classList.add('smoothScrollX'); + elem.classList.add('padded-top-focusscale'); + elem.classList.add('padded-bottom-focusscale'); } - elem.classList.add("scrollX"); - elem.classList.remove("vertical-wrap"); + elem.classList.add('scrollX'); + elem.classList.remove('vertical-wrap'); } else { - elem.classList.remove("hiddenScrollX"); - elem.classList.remove("smoothScrollX"); - elem.classList.remove("scrollX"); - elem.classList.add("vertical-wrap"); + elem.classList.remove('hiddenScrollX'); + elem.classList.remove('smoothScrollX'); + elem.classList.remove('scrollX'); + elem.classList.add('vertical-wrap'); } } function initSuggestedTab(page, tabContent) { - var containers = tabContent.querySelectorAll(".itemsContainer"); + var containers = tabContent.querySelectorAll('.itemsContainer'); for (var i = 0, length = containers.length; i < length; i++) { setScrollClasses(containers[i], enableScrollX()); @@ -194,7 +203,7 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" function loadSuggestionsTab(view, params, tabContent) { var parentId = params.topParentId; var userId = ApiClient.getCurrentUserId(); - console.log("loadSuggestionsTab"); + console.debug('loadSuggestionsTab'); loadResume(tabContent, userId, parentId); loadLatest(tabContent, userId, parentId); loadSuggestions(tabContent, userId, parentId); @@ -202,35 +211,35 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" function getTabs() { return [{ - name: Globalize.translate("Movies") + name: globalize.translate('Movies') }, { - name: Globalize.translate("TabSuggestions") + name: globalize.translate('TabSuggestions') }, { - name: Globalize.translate("TabTrailers") + name: globalize.translate('TabTrailers') }, { - name: Globalize.translate("TabFavorites") + name: globalize.translate('TabFavorites') }, { - name: Globalize.translate("TabCollections") + name: globalize.translate('TabCollections') }, { - name: Globalize.translate("TabGenres") + name: globalize.translate('TabGenres') }, { - name: Globalize.translate("ButtonSearch"), - cssClass: "searchTabButton" + name: globalize.translate('ButtonSearch'), + cssClass: 'searchTabButton' }]; } function getDefaultTabIndex(folderId) { - switch (userSettings.get("landing-" + folderId)) { - case "suggestions": + switch (userSettings.get('landing-' + folderId)) { + case 'suggestions': return 1; - case "favorites": + case 'favorites': return 3; - case "collections": + case 'collections': return 4; - case "genres": + case 'genres': return 5; default: @@ -249,7 +258,7 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" } function getTabContainers() { - return view.querySelectorAll(".pageTabContent"); + return view.querySelectorAll('.pageTabContent'); } function initTabs() { @@ -261,30 +270,30 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" switch (index) { case 0: - depends.push("controllers/movies/movies"); + depends.push('controllers/movies/movies'); break; case 1: break; case 2: - depends.push("controllers/movies/movietrailers"); + depends.push('controllers/movies/movietrailers'); break; case 3: - depends.push("controllers/movies/movies"); + depends.push('controllers/movies/movies'); break; case 4: - depends.push("controllers/movies/moviecollections"); + depends.push('controllers/movies/moviecollections'); break; case 5: - depends.push("controllers/movies/moviegenres"); + depends.push('controllers/movies/moviegenres'); break; case 6: - depends.push("scripts/searchtab"); + depends.push('scripts/searchtab'); } require(depends, function (controllerFactory) { @@ -304,12 +313,12 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" controller = self; } else if (index === 6) { controller = new controllerFactory(view, tabContent, { - collectionType: "movies", + collectionType: 'movies', parentId: params.topParentId }); } else if (index == 0 || index == 3) { controller = new controllerFactory(view, params, tabContent, { - mode: index ? "favorites" : "movies" + mode: index ? 'favorites' : 'movies' }); } else { controller = new controllerFactory(view, params, tabContent); @@ -347,7 +356,7 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" } function onPlaybackStop(e, state) { - if (state.NowPlayingItem && state.NowPlayingItem.MediaType == "Video") { + if (state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') { renderedTabs = []; mainTabsManager.getTabsElement().triggerTabChange(); } @@ -355,9 +364,9 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" function onInputCommand(e) { switch (e.detail.command) { - case "search": + case 'search': e.preventDefault(); - Dashboard.navigate("search.html?collectionType=movies&parentId=" + params.topParentId); + Dashboard.navigate('search.html?collectionType=movies&parentId=' + params.topParentId); } } @@ -379,28 +388,28 @@ define(["events", "layoutManager", "inputManager", "userSettings", "libraryMenu" var tabControllers = []; var renderedTabs = []; - view.addEventListener("viewshow", function (e) { - if (isViewRestored = e.detail.isRestored, initTabs(), !view.getAttribute("data-title")) { + view.addEventListener('viewshow', function (e) { + if (isViewRestored = e.detail.isRestored, initTabs(), !view.getAttribute('data-title')) { var parentId = params.topParentId; if (parentId) { ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) { - view.setAttribute("data-title", item.Name); + view.setAttribute('data-title', item.Name); libraryMenu.setTitle(item.Name); }); } else { - view.setAttribute("data-title", Globalize.translate("TabMovies")); - libraryMenu.setTitle(Globalize.translate("TabMovies")); + view.setAttribute('data-title', globalize.translate('TabMovies')); + libraryMenu.setTitle(globalize.translate('TabMovies')); } } - events.on(playbackManager, "playbackstop", onPlaybackStop); + events.on(playbackManager, 'playbackstop', onPlaybackStop); inputManager.on(window, onInputCommand); }); - view.addEventListener("viewbeforehide", function (e) { + view.addEventListener('viewbeforehide', function (e) { inputManager.off(window, onInputCommand); }); - view.addEventListener("viewdestroy", function (e) { + view.addEventListener('viewdestroy', function (e) { tabControllers.forEach(function (t) { if (t.destroy) { t.destroy(); diff --git a/src/controllers/movies/movietrailers.js b/src/controllers/movies/movietrailers.js index 3e62298613..25d41d4fba 100644 --- a/src/controllers/movies/movietrailers.js +++ b/src/controllers/movies/movietrailers.js @@ -1,5 +1,5 @@ -define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost) { - "use strict"; +define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -9,18 +9,22 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Trailer", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Trailer', Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,SortName,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - StartIndex: 0, - Limit: pageSize + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -33,7 +37,7 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " function getSavedQueryKey(context) { if (!context.savedQueryKey) { - context.savedQueryKey = libraryBrowser.getSavedQueryKey("trailers"); + context.savedQueryKey = libraryBrowser.getSavedQueryKey('trailers'); } return context.savedQueryKey; @@ -49,7 +53,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(); } @@ -58,7 +64,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(); } @@ -77,43 +85,43 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " var html; var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', overlayPlayButton: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "movies", + context: 'movies', cardLayout: true, showTitle: true, showYear: true, centerText: true }); - } else if (viewStyle == "Banner") { + } else if (viewStyle == 'Banner') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "banner", + shape: 'banner', preferBanner: true, - context: "movies" + context: 'movies' }); - } else if (viewStyle == "List") { + } else if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, - context: "movies", + context: 'movies', sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "portrait", - context: "movies", + shape: 'portrait', + context: 'movies', showTitle: true, showYear: true, cardLayout: true, @@ -122,8 +130,8 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "portrait", - context: "movies", + shape: 'portrait', + context: 'movies', centerText: true, overlayPlayButton: true, showTitle: true, @@ -133,27 +141,27 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } if (!result.Items.length) { - html = '

' + Globalize.translate("MessageNoTrailersFound") + "

"; + html = '

' + globalize.translate('MessageNoTrailersFound') + '

'; } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(tabContent), query); @@ -168,18 +176,17 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } var self = this; - var pageSize = 100; var data = {}; var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), - mode: "movies", + mode: 'movies', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { getQuery(tabContent).StartIndex = 0; reloadItems(); }); @@ -192,8 +199,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }; function initPage(tabContent) { - var alphaPickerElement = tabContent.querySelector(".alphaPicker"); - alphaPickerElement.addEventListener("alphavaluechanged", function (e) { + var alphaPickerElement = tabContent.querySelector('.alphaPicker'); + var itemsContainer = tabContent.querySelector('.itemsContainer'); + alphaPickerElement.addEventListener('alphavaluechanged', function (e) { var newValue = e.detail.value; var query = getQuery(tabContent); query.NameStartsWithOrGreater = newValue; @@ -202,42 +210,39 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, - valueChangeEvent: "click" + valueChangeEvent: 'click' }); - if (layoutManager.desktop || layoutManager.mobile) { - tabContent.querySelector(".alphaPicker").classList.add("alphabetPicker-right"); - var itemsContainer = tabContent.querySelector(".itemsContainer"); - itemsContainer.classList.remove("padded-left-withalphapicker"); - itemsContainer.classList.add("padded-right-withalphapicker"); - } + tabContent.querySelector('.alphaPicker').classList.add('alphabetPicker-right'); + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + itemsContainer.classList.add('padded-right-withalphapicker'); - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SortName" + name: globalize.translate('OptionNameSort'), + id: 'SortName' }, { - name: Globalize.translate("OptionImdbRating"), - id: "CommunityRating,SortName" + name: globalize.translate('OptionImdbRating'), + id: 'CommunityRating,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName' }, { - name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SortName" + name: globalize.translate('OptionDatePlayed'), + id: 'DatePlayed,SortName' }, { - name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SortName" + name: globalize.translate('OptionParentalRating'), + id: 'OfficialRating,SortName' }, { - name: Globalize.translate("OptionPlayCount"), - id: "PlayCount,SortName" + name: globalize.translate('OptionPlayCount'), + id: 'PlayCount,SortName' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,SortName" + name: globalize.translate('OptionReleaseDate'), + id: 'PremiereDate,SortName' }], callback: function () { getQuery(tabContent).StartIndex = 0; diff --git a/src/controllers/music/musicalbums.js b/src/controllers/music/musicalbums.js index 480f0af77f..ecb51f9dc3 100644 --- a/src/controllers/music/musicalbums.js +++ b/src/controllers/music/musicalbums.js @@ -1,5 +1,5 @@ -define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "emby-itemscontainer"], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost) { - "use strict"; +define(['layoutManager', 'playbackManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, playbackManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function playAll() { @@ -23,18 +23,22 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser if (!pageData) { pageData = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "MusicAlbum", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'MusicAlbum', Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,SortName,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - StartIndex: 0, - Limit: pageSize + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -48,7 +52,7 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser function getSavedQueryKey() { if (!savedQueryKey) { - savedQueryKey = libraryBrowser.getSavedQueryKey("musicalbums"); + savedQueryKey = libraryBrowser.getSavedQueryKey('musicalbums'); } return savedQueryKey; @@ -56,17 +60,17 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser function onViewStyleChange() { var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems(page) { @@ -79,7 +83,9 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -88,7 +94,9 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -106,18 +114,18 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser filterButton: false }); var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "List") { + if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, - context: "music", + context: 'music', sortBy: query.SortBy, addToListButton: true }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", - context: "music", + shape: 'square', + context: 'music', showTitle: true, coverImage: true, showParentTitle: true, @@ -127,8 +135,8 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", - context: "music", + shape: 'square', + context: 'music', showTitle: true, showParentTitle: true, lazy: true, @@ -138,30 +146,30 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser } var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(), query); loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(tabContent); }); }); @@ -175,17 +183,16 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser var savedQueryKey; var pageData; var self = this; - var pageSize = 100; var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(), - mode: "albums", + mode: 'albums', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { getQuery().StartIndex = 0; reloadItems(tabContent); }); @@ -198,9 +205,10 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser }; function initPage(tabContent) { - var alphaPickerElement = tabContent.querySelector(".alphaPicker"); + var alphaPickerElement = tabContent.querySelector('.alphaPicker'); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - alphaPickerElement.addEventListener("alphavaluechanged", function (e) { + alphaPickerElement.addEventListener('alphavaluechanged', function (e) { var newValue = e.detail.value; var query = getQuery(); query.NameStartsWithOrGreater = newValue; @@ -209,41 +217,39 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser }); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, - valueChangeEvent: "click" + valueChangeEvent: 'click' }); - if (layoutManager.desktop || layoutManager.mobile) { - tabContent.querySelector(".alphaPicker").classList.add("alphabetPicker-right"); - var itemsContainer = tabContent.querySelector(".itemsContainer"); - itemsContainer.classList.remove("padded-left-withalphapicker"); - itemsContainer.classList.add("padded-right-withalphapicker"); - } - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.alphaPicker').classList.add('alphabetPicker-right'); + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + itemsContainer.classList.add('padded-right-withalphapicker'); + + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SortName" + name: globalize.translate('OptionNameSort'), + id: 'SortName' }, { - name: Globalize.translate("OptionAlbumArtist"), - id: "AlbumArtist,SortName" + name: globalize.translate('OptionAlbumArtist'), + id: 'AlbumArtist,SortName' }, { - name: Globalize.translate("OptionCommunityRating"), - id: "CommunityRating,SortName" + name: globalize.translate('OptionCommunityRating'), + id: 'CommunityRating,SortName' }, { - name: Globalize.translate("OptionCriticRating"), - id: "CriticRating,SortName" + name: globalize.translate('OptionCriticRating'), + id: 'CriticRating,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "ProductionYear,PremiereDate,SortName" + name: globalize.translate('OptionReleaseDate'), + id: 'ProductionYear,PremiereDate,SortName' }, { - name: Globalize.translate("OptionRandom"), - id: "Random,SortName" + name: globalize.translate('OptionRandom'), + id: 'Random,SortName' }], callback: function () { getQuery().StartIndex = 0; @@ -253,11 +259,11 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser button: e.target }); }); - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "List,Poster,PosterCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; getPageData().view = viewStyle; libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle); @@ -265,8 +271,8 @@ define(["layoutManager", "playbackManager", "loading", "events", "libraryBrowser onViewStyleChange(); reloadItems(tabContent); }); - tabContent.querySelector(".btnPlayAll").addEventListener("click", playAll); - tabContent.querySelector(".btnShuffle").addEventListener("click", shuffle); + tabContent.querySelector('.btnPlayAll').addEventListener('click', playAll); + tabContent.querySelector('.btnShuffle').addEventListener('click', shuffle); } initPage(tabContent); diff --git a/src/controllers/music/musicartists.js b/src/controllers/music/musicartists.js index aaeea8c885..bd9341be6d 100644 --- a/src/controllers/music/musicartists.js +++ b/src/controllers/music/musicartists.js @@ -1,5 +1,5 @@ -define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "alphaPicker", "listView", "cardBuilder", "apphost", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost) { - "use strict"; +define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'alphaPicker', 'listView', 'cardBuilder', 'apphost', 'userSettings', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, alphaPicker, listView, cardBuilder, appHost, userSettings) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -7,18 +7,23 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " var pageData = data[key]; if (!pageData) { + var queryValues = { + SortBy: 'SortName', + SortOrder: 'Ascending', + Recursive: true, + Fields: 'PrimaryImageAspectRatio,SortName,BasicSyncInfo', + StartIndex: 0, + ImageTypeLimit: 1, + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb' + }; + + if (userSettings.libraryPageSize() > 0) { + queryValues['Limit'] = userSettings.libraryPageSize(); + } + pageData = data[key] = { - query: { - SortBy: "SortName", - SortOrder: "Ascending", - Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,BasicSyncInfo", - StartIndex: 0, - ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - Limit: 100 - }, - view: libraryBrowser.getSavedView(key) || "Poster" + query: queryValues, + view: libraryBrowser.getSavedView(key) || 'Poster' }; pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); @@ -41,17 +46,17 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " function onViewStyleChange() { var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems(page) { @@ -67,7 +72,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -76,7 +83,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -94,16 +103,16 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " filterButton: false }); var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "List") { + if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", - context: "music", + shape: 'square', + context: 'music', showTitle: true, coverImage: true, cardLayout: true @@ -111,8 +120,8 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", - context: "music", + shape: 'square', + context: 'music', showTitle: true, coverImage: true, lazy: true, @@ -122,30 +131,30 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(page), query); loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(tabContent); }); }); @@ -161,13 +170,13 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), mode: self.mode, serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { getQuery(tabContent).StartIndex = 0; reloadItems(tabContent); }); @@ -180,9 +189,10 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }; function initPage(tabContent) { - var alphaPickerElement = tabContent.querySelector(".alphaPicker"); + var alphaPickerElement = tabContent.querySelector('.alphaPicker'); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - alphaPickerElement.addEventListener("alphavaluechanged", function (e) { + alphaPickerElement.addEventListener('alphavaluechanged', function (e) { var newValue = e.detail.value; var query = getQuery(tabContent); query.NameStartsWithOrGreater = newValue; @@ -191,23 +201,21 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, - valueChangeEvent: "click" + valueChangeEvent: 'click' }); - if (layoutManager.desktop || layoutManager.mobile) { - tabContent.querySelector(".alphaPicker").classList.add("alphabetPicker-right"); - var itemsContainer = tabContent.querySelector(".itemsContainer"); - itemsContainer.classList.remove("padded-left-withalphapicker"); - itemsContainer.classList.add("padded-right-withalphapicker"); - } - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.alphaPicker').classList.add('alphabetPicker-right'); + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + itemsContainer.classList.add('padded-right-withalphapicker'); + + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "List,Poster,PosterCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; getPageData(tabContent).view = viewStyle; libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); diff --git a/src/controllers/music/musicgenres.js b/src/controllers/music/musicgenres.js index b465a4d350..82f2eba574 100644 --- a/src/controllers/music/musicgenres.js +++ b/src/controllers/music/musicgenres.js @@ -1,5 +1,5 @@ -define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], function (libraryBrowser, cardBuilder, appHost, imageLoader, loading) { - "use strict"; +define(['libraryBrowser', 'cardBuilder', 'apphost', 'imageLoader', 'loading'], function (libraryBrowser, cardBuilder, appHost, imageLoader, loading) { + 'use strict'; return function (view, params, tabContent) { function getPageData() { @@ -9,13 +9,13 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", + SortBy: 'SortName', + SortOrder: 'Ascending', Recursive: true, - Fields: "PrimaryImageAspectRatio,ItemCounts", + Fields: 'PrimaryImageAspectRatio,ItemCounts', StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); @@ -29,7 +29,7 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f } function getSavedQueryKey() { - return libraryBrowser.getSavedQueryKey("genres"); + return libraryBrowser.getSavedQueryKey('genres'); } function getPromise() { @@ -41,40 +41,40 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f function reloadItems(context, promise) { var query = getQuery(); promise.then(function (result) { - var html = ""; + var html = ''; var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, context: 'music', centerText: true, overlayMoreButton: true, showTitle: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, context: 'music', cardLayout: true, showTitle: true }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "auto", + shape: 'auto', context: 'music', cardLayout: true, showTitle: true }); - } else if (viewStyle == "Poster") { + } else if (viewStyle == 'Poster') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "auto", + shape: 'auto', context: 'music', centerText: true, overlayMoreButton: true, @@ -82,13 +82,13 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f }); } - var elem = context.querySelector("#items"); + var elem = context.querySelector('#items'); elem.innerHTML = html; imageLoader.lazyChildren(elem); libraryBrowser.saveQueryValues(getSavedQueryKey(), query); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(context); }); }); @@ -103,16 +103,16 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f var data = {}; self.getViewStyles = function () { - return "Poster,PosterCard,Thumb,ThumbCard".split(","); + return 'Poster,PosterCard,Thumb,ThumbCard'.split(','); }; self.getCurrentViewStyle = function () { - return getPageData(tabContent).view; + return getPageData().view; }; self.setCurrentViewStyle = function (viewStyle) { - getPageData(tabContent).view = viewStyle; - libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); + getPageData().view = viewStyle; + libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle); fullyReload(); }; diff --git a/src/controllers/music/musicplaylists.js b/src/controllers/music/musicplaylists.js index fd458c88ac..f508489216 100644 --- a/src/controllers/music/musicplaylists.js +++ b/src/controllers/music/musicplaylists.js @@ -1,5 +1,5 @@ -define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], function (libraryBrowser, cardBuilder, appHost, imageLoader, loading) { - "use strict"; +define(['libraryBrowser', 'cardBuilder', 'apphost', 'imageLoader', 'loading'], function (libraryBrowser, cardBuilder, appHost, imageLoader, loading) { + 'use strict'; return function (view, params, tabContent) { function getPageData() { @@ -9,14 +9,14 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Playlist", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Playlist', Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,CanDelete", + Fields: 'PrimaryImageAspectRatio,SortName,CanDelete', StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); @@ -30,7 +30,7 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f } function getSavedQueryKey() { - return libraryBrowser.getSavedQueryKey("genres"); + return libraryBrowser.getSavedQueryKey('genres'); } function getPromise() { @@ -42,10 +42,10 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f function reloadItems(context, promise) { var query = getQuery(); promise.then(function (result) { - var html = ""; + var html = ''; html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", + shape: 'square', showTitle: true, coverImage: true, centerText: true, @@ -53,13 +53,13 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f allowBottomPadding: true, cardLayout: false }); - var elem = context.querySelector("#items"); + var elem = context.querySelector('#items'); elem.innerHTML = html; imageLoader.lazyChildren(elem); libraryBrowser.saveQueryValues(getSavedQueryKey(), query); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(context); }); }); @@ -69,7 +69,7 @@ define(["libraryBrowser", "cardBuilder", "apphost", "imageLoader", "loading"], f var data = {}; self.getCurrentViewStyle = function () { - return getPageData(tabContent).view; + return getPageData().view; }; var promise; diff --git a/src/controllers/music/musicrecommended.js b/src/controllers/music/musicrecommended.js index 556877aa1b..3f025799f6 100644 --- a/src/controllers/music/musicrecommended.js +++ b/src/controllers/music/musicrecommended.js @@ -1,5 +1,5 @@ -define(["browser", "layoutManager", "userSettings", "inputManager", "loading", "cardBuilder", "dom", "apphost", "imageLoader", "libraryMenu", "playbackManager", "mainTabsManager", "scrollStyles", "emby-itemscontainer", "emby-tabs", "emby-button", "flexStyles"], function (browser, layoutManager, userSettings, inputManager, loading, cardBuilder, dom, appHost, imageLoader, libraryMenu, playbackManager, mainTabsManager) { - "use strict"; +define(['browser', 'layoutManager', 'userSettings', 'inputManager', 'loading', 'cardBuilder', 'dom', 'apphost', 'imageLoader', 'libraryMenu', 'playbackManager', 'mainTabsManager', 'globalize', 'scrollStyles', 'emby-itemscontainer', 'emby-tabs', 'emby-button', 'flexStyles'], function (browser, layoutManager, userSettings, inputManager, loading, cardBuilder, dom, appHost, imageLoader, libraryMenu, playbackManager, mainTabsManager, globalize) { + 'use strict'; function itemsPerRow() { var screenWidth = dom.getWindowSize().innerWidth; @@ -24,24 +24,24 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " } function getSquareShape() { - return enableScrollX() ? "overflowSquare" : "square"; + return enableScrollX() ? 'overflowSquare' : 'square'; } function loadLatest(page, parentId) { loading.show(); var userId = ApiClient.getCurrentUserId(); var options = { - IncludeItemTypes: "Audio", + IncludeItemTypes: 'Audio', Limit: enableScrollX() ? 3 * itemsPerRow() : 2 * itemsPerRow(), - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; - ApiClient.getJSON(ApiClient.getUrl("Users/" + userId + "/Items/Latest", options)).then(function (items) { - var elem = page.querySelector("#recentlyAddedSongs"); - var supportsImageAnalysis = appHost.supports("imageanalysis"); + ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)).then(function (items) { + var elem = page.querySelector('#recentlyAddedSongs'); + var supportsImageAnalysis = appHost.supports('imageanalysis'); supportsImageAnalysis = false; elem.innerHTML = cardBuilder.getCardsHtml({ items: items, @@ -60,7 +60,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " imageLoader.lazyChildren(elem); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); @@ -68,29 +68,29 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " function loadRecentlyPlayed(page, parentId) { var options = { - SortBy: "DatePlayed", - SortOrder: "Descending", - IncludeItemTypes: "Audio", + SortBy: 'DatePlayed', + SortOrder: 'Descending', + IncludeItemTypes: 'Audio', Limit: itemsPerRow(), Recursive: true, - Fields: "PrimaryImageAspectRatio,AudioInfo", - Filters: "IsPlayed", + Fields: 'PrimaryImageAspectRatio,AudioInfo', + Filters: 'IsPlayed', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) { - var elem = page.querySelector("#recentlyPlayed"); + var elem = page.querySelector('#recentlyPlayed'); if (result.Items.length) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } - var itemsContainer = elem.querySelector(".itemsContainer"); - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var itemsContainer = elem.querySelector('.itemsContainer'); + var supportsImageAnalysis = appHost.supports('imageanalysis'); supportsImageAnalysis = false; itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, @@ -98,7 +98,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " shape: getSquareShape(), showTitle: true, showParentTitle: true, - action: "instantmix", + action: 'instantmix', lazy: true, centerText: !supportsImageAnalysis, overlayMoreButton: !supportsImageAnalysis, @@ -112,29 +112,29 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " function loadFrequentlyPlayed(page, parentId) { var options = { - SortBy: "PlayCount", - SortOrder: "Descending", - IncludeItemTypes: "Audio", + SortBy: 'PlayCount', + SortOrder: 'Descending', + IncludeItemTypes: 'Audio', Limit: itemsPerRow(), Recursive: true, - Fields: "PrimaryImageAspectRatio,AudioInfo", - Filters: "IsPlayed", + Fields: 'PrimaryImageAspectRatio,AudioInfo', + Filters: 'IsPlayed', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) { - var elem = page.querySelector("#topPlayed"); + var elem = page.querySelector('#topPlayed'); if (result.Items.length) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } - var itemsContainer = elem.querySelector(".itemsContainer"); - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var itemsContainer = elem.querySelector('.itemsContainer'); + var supportsImageAnalysis = appHost.supports('imageanalysis'); supportsImageAnalysis = false; itemsContainer.innerHTML = cardBuilder.getCardsHtml({ items: result.Items, @@ -142,7 +142,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " shape: getSquareShape(), showTitle: true, showParentTitle: true, - action: "instantmix", + action: 'instantmix', lazy: true, centerText: !supportsImageAnalysis, overlayMoreButton: !supportsImageAnalysis, @@ -155,55 +155,55 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " } function loadSuggestionsTab(page, tabContent, parentId) { - console.log("loadSuggestionsTab"); + console.debug('loadSuggestionsTab'); loadLatest(tabContent, parentId); loadRecentlyPlayed(tabContent, parentId); loadFrequentlyPlayed(tabContent, parentId); - require(["components/favoriteitems"], function (favoriteItems) { - favoriteItems.render(tabContent, ApiClient.getCurrentUserId(), parentId, ["favoriteArtists", "favoriteAlbums", "favoriteSongs"]); + require(['components/favoriteitems'], function (favoriteItems) { + favoriteItems.render(tabContent, ApiClient.getCurrentUserId(), parentId, ['favoriteArtists', 'favoriteAlbums', 'favoriteSongs']); }); } function getTabs() { return [{ - name: Globalize.translate("TabSuggestions") + name: globalize.translate('TabSuggestions') }, { - name: Globalize.translate("TabAlbums") + name: globalize.translate('TabAlbums') }, { - name: Globalize.translate("TabAlbumArtists") + name: globalize.translate('TabAlbumArtists') }, { - name: Globalize.translate("TabArtists") + name: globalize.translate('TabArtists') }, { - name: Globalize.translate("TabPlaylists") + name: globalize.translate('TabPlaylists') }, { - name: Globalize.translate("TabSongs") + name: globalize.translate('TabSongs') }, { - name: Globalize.translate("TabGenres") + name: globalize.translate('TabGenres') }, { - name: Globalize.translate("ButtonSearch"), - cssClass: "searchTabButton" + name: globalize.translate('ButtonSearch'), + cssClass: 'searchTabButton' }]; } function getDefaultTabIndex(folderId) { - switch (userSettings.get("landing-" + folderId)) { - case "albums": + switch (userSettings.get('landing-' + folderId)) { + case 'albums': return 1; - case "albumartists": + case 'albumartists': return 2; - case "artists": + case 'artists': return 3; - case "playlists": + case 'playlists': return 4; - case "songs": + case 'songs': return 5; - case "genres": + case 'genres': return 6; default: @@ -224,19 +224,19 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " function setScrollClasses(elem, scrollX) { if (scrollX) { - elem.classList.add("hiddenScrollX"); + elem.classList.add('hiddenScrollX'); if (layoutManager.tv) { - elem.classList.add("smoothScrollX"); + elem.classList.add('smoothScrollX'); } - elem.classList.add("scrollX"); - elem.classList.remove("vertical-wrap"); + elem.classList.add('scrollX'); + elem.classList.remove('vertical-wrap'); } else { - elem.classList.remove("hiddenScrollX"); - elem.classList.remove("smoothScrollX"); - elem.classList.remove("scrollX"); - elem.classList.add("vertical-wrap"); + elem.classList.remove('hiddenScrollX'); + elem.classList.remove('smoothScrollX'); + elem.classList.remove('scrollX'); + elem.classList.add('vertical-wrap'); } } @@ -249,7 +249,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " } function getTabContainers() { - return view.querySelectorAll(".pageTabContent"); + return view.querySelectorAll('.pageTabContent'); } function initTabs() { @@ -264,28 +264,28 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " break; case 1: - depends.push("controllers/music/musicalbums"); + depends.push('controllers/music/musicalbums'); break; case 2: case 3: - depends.push("controllers/music/musicartists"); + depends.push('controllers/music/musicartists'); break; case 4: - depends.push("controllers/music/musicplaylists"); + depends.push('controllers/music/musicplaylists'); break; case 5: - depends.push("controllers/music/songs"); + depends.push('controllers/music/songs'); break; case 6: - depends.push("controllers/music/musicgenres"); + depends.push('controllers/music/musicgenres'); break; case 7: - depends.push("scripts/searchtab"); + depends.push('scripts/searchtab'); } require(depends, function (controllerFactory) { @@ -305,7 +305,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " controller = self; } else if (index === 7) { controller = new controllerFactory(view, tabContent, { - collectionType: "music", + collectionType: 'music', parentId: params.topParentId }); } else { @@ -313,9 +313,9 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " } if (index == 2) { - controller.mode = "albumartists"; + controller.mode = 'albumartists'; } else if (index == 3) { - controller.mode = "artists"; + controller.mode = 'artists'; } tabControllers[index] = controller; @@ -350,9 +350,9 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " function onInputCommand(e) { switch (e.detail.command) { - case "search": + case 'search': e.preventDefault(); - Dashboard.navigate("search.html?collectionType=music&parentId=" + params.topParentId); + Dashboard.navigate('search.html?collectionType=music&parentId=' + params.topParentId); } } @@ -363,7 +363,7 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " self.initTab = function () { var tabContent = view.querySelector(".pageTabContent[data-index='0']"); - var containers = tabContent.querySelectorAll(".itemsContainer"); + var containers = tabContent.querySelectorAll('.itemsContainer'); for (var i = 0, length = containers.length; i < length; i++) { setScrollClasses(containers[i], enableScrollX()); @@ -376,29 +376,29 @@ define(["browser", "layoutManager", "userSettings", "inputManager", "loading", " var tabControllers = []; var renderedTabs = []; - view.addEventListener("viewshow", function (e) { + view.addEventListener('viewshow', function (e) { isViewRestored = e.detail.isRestored; initTabs(); - if (!view.getAttribute("data-title")) { + if (!view.getAttribute('data-title')) { var parentId = params.topParentId; if (parentId) { ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) { - view.setAttribute("data-title", item.Name); + view.setAttribute('data-title', item.Name); libraryMenu.setTitle(item.Name); }); } else { - view.setAttribute("data-title", Globalize.translate("TabMusic")); - libraryMenu.setTitle(Globalize.translate("TabMusic")); + view.setAttribute('data-title', globalize.translate('TabMusic')); + libraryMenu.setTitle(globalize.translate('TabMusic')); } } inputManager.on(window, onInputCommand); }); - view.addEventListener("viewbeforehide", function (e) { + view.addEventListener('viewbeforehide', function (e) { inputManager.off(window, onInputCommand); }); - view.addEventListener("viewdestroy", function (e) { + view.addEventListener('viewdestroy', function (e) { tabControllers.forEach(function (t) { if (t.destroy) { t.destroy(); diff --git a/src/controllers/music/songs.js b/src/controllers/music/songs.js index 47263be0d2..8e50cd720c 100644 --- a/src/controllers/music/songs.js +++ b/src/controllers/music/songs.js @@ -1,5 +1,5 @@ -define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby-itemscontainer"], function (events, libraryBrowser, imageLoader, listView, loading) { - "use strict"; +define(['events', 'libraryBrowser', 'imageLoader', 'listView', 'loading', 'userSettings', 'globalize', 'emby-itemscontainer'], function (events, libraryBrowser, imageLoader, listView, loading, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -9,17 +9,21 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- if (!pageData) { pageData = data[key] = { query: { - SortBy: "Album,SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Audio", + SortBy: 'Album,SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Audio', Recursive: true, - Fields: "AudioInfo,ParentId", - Limit: 100, + Fields: 'AudioInfo,ParentId', StartIndex: 0, ImageTypeLimit: 1, - EnableImageTypes: "Primary" + EnableImageTypes: 'Primary' } }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -33,7 +37,7 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- function getSavedQueryKey(context) { if (!context.savedQueryKey) { - context.savedQueryKey = libraryBrowser.getSavedQueryKey("songs"); + context.savedQueryKey = libraryBrowser.getSavedQueryKey('songs'); } return context.savedQueryKey; @@ -49,7 +53,9 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -58,7 +64,9 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -77,35 +85,35 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- }); var html = listView.getListViewHtml({ items: result.Items, - action: "playallfromhere", + action: 'playallfromhere', smallIcon: true, artist: true, addToListButton: true }); - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(page), query); loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); @@ -116,13 +124,13 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), - mode: "songs", + mode: 'songs', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { getQuery(tabContent).StartIndex = 0; reloadItems(tabContent); }); @@ -135,38 +143,38 @@ define(["events", "libraryBrowser", "imageLoader", "listView", "loading", "emby- }; function initPage(tabContent) { - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionTrackName"), - id: "Name" + name: globalize.translate('OptionTrackName'), + id: 'Name' }, { - name: Globalize.translate("OptionAlbum"), - id: "Album,SortName" + name: globalize.translate('OptionAlbum'), + id: 'Album,SortName' }, { - name: Globalize.translate("OptionAlbumArtist"), - id: "AlbumArtist,Album,SortName" + name: globalize.translate('OptionAlbumArtist'), + id: 'AlbumArtist,Album,SortName' }, { - name: Globalize.translate("OptionArtist"), - id: "Artist,Album,SortName" + name: globalize.translate('OptionArtist'), + id: 'Artist,Album,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName' }, { - name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SortName" + name: globalize.translate('OptionDatePlayed'), + id: 'DatePlayed,SortName' }, { - name: Globalize.translate("OptionPlayCount"), - id: "PlayCount,SortName" + name: globalize.translate('OptionPlayCount'), + id: 'PlayCount,SortName' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,AlbumArtist,Album,SortName" + name: globalize.translate('OptionReleaseDate'), + id: 'PremiereDate,AlbumArtist,Album,SortName' }, { - name: Globalize.translate("OptionRuntime"), - id: "Runtime,AlbumArtist,Album,SortName" + name: globalize.translate('OptionRuntime'), + id: 'Runtime,AlbumArtist,Album,SortName' }], callback: function () { getQuery(tabContent).StartIndex = 0; diff --git a/src/controllers/playback/nowplayingpage.js b/src/controllers/playback/nowplaying.js similarity index 54% rename from src/controllers/playback/nowplayingpage.js rename to src/controllers/playback/nowplaying.js index 6fcdb2a79c..98c9945e84 100644 --- a/src/controllers/playback/nowplayingpage.js +++ b/src/controllers/playback/nowplaying.js @@ -1,17 +1,17 @@ -define(["components/remotecontrol/remotecontrol", "libraryMenu", "emby-button"], function (remotecontrolFactory, libraryMenu) { - "use strict"; +define(['components/remotecontrol/remotecontrol', 'libraryMenu', 'emby-button'], function (remotecontrolFactory, libraryMenu) { + 'use strict'; return function (view, params) { var remoteControl = new remotecontrolFactory(); - remoteControl.init(view, view.querySelector(".remoteControlContent")); - view.addEventListener("viewshow", function (e) { + remoteControl.init(view, view.querySelector('.remoteControlContent')); + view.addEventListener('viewshow', function (e) { libraryMenu.setTransparentMenu(true); if (remoteControl) { remoteControl.onShow(); } }); - view.addEventListener("viewbeforehide", function (e) { + view.addEventListener('viewbeforehide', function (e) { libraryMenu.setTransparentMenu(false); if (remoteControl) { diff --git a/src/controllers/playback/videoosd.js b/src/controllers/playback/videoosd.js index bd12ba5075..e9923d779c 100644 --- a/src/controllers/playback/videoosd.js +++ b/src/controllers/playback/videoosd.js @@ -1,19 +1,19 @@ -define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "mediaInfo", "focusManager", "imageLoader", "scrollHelper", "events", "connectionManager", "browser", "globalize", "apphost", "layoutManager", "userSettings", "scrollStyles", "emby-slider", "paper-icon-button-light", "css!assets/css/videoosd"], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings) { - "use strict"; +define(['playbackManager', 'dom', 'inputManager', 'datetime', 'itemHelper', 'mediaInfo', 'focusManager', 'imageLoader', 'scrollHelper', 'events', 'connectionManager', 'browser', 'globalize', 'apphost', 'layoutManager', 'userSettings', 'keyboardnavigation', 'scrollStyles', 'emby-slider', 'paper-icon-button-light', 'css!assets/css/videoosd'], function (playbackManager, dom, inputManager, datetime, itemHelper, mediaInfo, focusManager, imageLoader, scrollHelper, events, connectionManager, browser, globalize, appHost, layoutManager, userSettings, keyboardnavigation) { + 'use strict'; function seriesImageUrl(item, options) { - if ("Episode" !== item.Type) { + if ('Episode' !== item.Type) { return null; } options = options || {}; - options.type = options.type || "Primary"; - if ("Primary" === options.type && item.SeriesPrimaryImageTag) { + options.type = options.type || 'Primary'; + if ('Primary' === options.type && item.SeriesPrimaryImageTag) { options.tag = item.SeriesPrimaryImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); } - if ("Thumb" === options.type) { + if ('Thumb' === options.type) { if (item.SeriesThumbImageTag) { options.tag = item.SeriesThumbImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.SeriesId, options); @@ -30,14 +30,14 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function imageUrl(item, options) { options = options || {}; - options.type = options.type || "Primary"; + 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 ("Primary" === options.type && item.AlbumId && item.AlbumPrimaryImageTag) { + if ('Primary' === options.type && item.AlbumId && item.AlbumPrimaryImageTag) { options.tag = item.AlbumPrimaryImageTag; return connectionManager.getApiClient(item.ServerId).getScaledImageUrl(item.AlbumId, options); } @@ -45,23 +45,6 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med return null; } - function logoImageUrl(item, apiClient, options) { - options = options || {}; - options.type = "Logo"; - - if (item.ImageTags && item.ImageTags.Logo) { - options.tag = item.ImageTags.Logo; - return apiClient.getScaledImageUrl(item.Id, options); - } - - if (item.ParentLogoImageTag) { - options.tag = item.ParentLogoImageTag; - return apiClient.getScaledImageUrl(item.ParentLogoItemId, options); - } - - return null; - } - return function (view, params) { function onVerticalSwipe(e, elem, data) { var player = currentPlayer; @@ -110,7 +93,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function getDisplayItem(item) { - if ("TvChannel" === item.Type) { + if ('TvChannel' === item.Type) { var apiClient = connectionManager.getApiClient(item.ServerId); return apiClient.getItem(apiClient.getCurrentUserId(), item.Id).then(function (refreshedItem) { return { @@ -126,27 +109,27 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function updateRecordingButton(item) { - if (!item || "Program" !== item.Type) { + if (!item || 'Program' !== item.Type) { if (recordingButtonManager) { recordingButtonManager.destroy(); recordingButtonManager = null; } - return void view.querySelector(".btnRecord").classList.add("hide"); + return void view.querySelector('.btnRecord').classList.add('hide'); } connectionManager.getApiClient(item.ServerId).getCurrentUser().then(function (user) { if (user.Policy.EnableLiveTvManagement) { - require(["recordingButton"], function (RecordingButton) { + require(['recordingButton'], function (RecordingButton) { if (recordingButtonManager) { return void recordingButtonManager.refreshItem(item); } recordingButtonManager = new RecordingButton({ item: item, - button: view.querySelector(".btnRecord") + button: view.querySelector('.btnRecord') }); - view.querySelector(".btnRecord").classList.remove("hide"); + view.querySelector('.btnRecord').classList.remove('hide'); }); } }); @@ -166,11 +149,11 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med setTitle(displayItem, parentName); var titleElement; - var osdTitle = view.querySelector(".osdTitle"); + var osdTitle = view.querySelector('.osdTitle'); titleElement = osdTitle; var displayName = itemHelper.getDisplayName(displayItem, { - includeParentInfo: "Program" !== displayItem.Type, - includeIndexNumber: "Program" !== displayItem.Type + includeParentInfo: 'Program' !== displayItem.Type, + includeIndexNumber: 'Program' !== displayItem.Type }); if (!displayName) { @@ -180,9 +163,9 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med titleElement.innerHTML = displayName; if (displayName) { - titleElement.classList.remove("hide"); + titleElement.classList.remove('hide'); } else { - titleElement.classList.add("hide"); + titleElement.classList.add('hide'); } var mediaInfoHtml = mediaInfo.getPrimaryMediaInfoHtml(displayItem, { @@ -191,20 +174,20 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med tomatoes: false, endsAt: false, episodeTitle: false, - originalAirDate: "Program" !== displayItem.Type, - episodeTitleIndexNumber: "Program" !== displayItem.Type, + originalAirDate: 'Program' !== displayItem.Type, + episodeTitleIndexNumber: 'Program' !== displayItem.Type, programIndicator: false }); - var osdMediaInfo = view.querySelector(".osdMediaInfo"); + var osdMediaInfo = view.querySelector('.osdMediaInfo'); osdMediaInfo.innerHTML = mediaInfoHtml; if (mediaInfoHtml) { - osdMediaInfo.classList.remove("hide"); + osdMediaInfo.classList.remove('hide'); } else { - osdMediaInfo.classList.add("hide"); + osdMediaInfo.classList.add('hide'); } - var secondaryMediaInfo = view.querySelector(".osdSecondaryMediaInfo"); + var secondaryMediaInfo = view.querySelector('.osdSecondaryMediaInfo'); var secondaryMediaInfoHtml = mediaInfo.getSecondaryMediaInfoHtml(displayItem, { startDate: false, programTime: false @@ -212,29 +195,29 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med secondaryMediaInfo.innerHTML = secondaryMediaInfoHtml; if (secondaryMediaInfoHtml) { - secondaryMediaInfo.classList.remove("hide"); + secondaryMediaInfo.classList.remove('hide'); } else { - secondaryMediaInfo.classList.add("hide"); + secondaryMediaInfo.classList.add('hide'); } if (displayName) { - view.querySelector(".osdMainTextContainer").classList.remove("hide"); + view.querySelector('.osdMainTextContainer').classList.remove('hide'); } else { - view.querySelector(".osdMainTextContainer").classList.add("hide"); + view.querySelector('.osdMainTextContainer').classList.add('hide'); } if (enableProgressByTimeOfDay) { setDisplayTime(startTimeText, displayItem.StartDate); setDisplayTime(endTimeText, displayItem.EndDate); - startTimeText.classList.remove("hide"); - endTimeText.classList.remove("hide"); + startTimeText.classList.remove('hide'); + endTimeText.classList.remove('hide'); programStartDateMs = displayItem.StartDate ? datetime.parseISO8601Date(displayItem.StartDate).getTime() : 0; programEndDateMs = displayItem.EndDate ? datetime.parseISO8601Date(displayItem.EndDate).getTime() : 0; } else { - startTimeText.classList.add("hide"); - endTimeText.classList.add("hide"); - startTimeText.innerHTML = ""; - endTimeText.innerHTML = ""; + startTimeText.classList.add('hide'); + endTimeText.classList.add('hide'); + startTimeText.innerHTML = ''; + endTimeText.innerHTML = ''; programStartDateMs = 0; programEndDateMs = 0; } @@ -243,13 +226,13 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function getDisplayTimeWithoutAmPm(date, showSeconds) { if (showSeconds) { return datetime.toLocaleTimeString(date, { - hour: "numeric", - minute: "2-digit", - second: "2-digit" - }).toLowerCase().replace("am", "").replace("pm", "").trim(); + hour: 'numeric', + minute: '2-digit', + second: '2-digit' + }).toLowerCase().replace('am', '').replace('pm', '').trim(); } - return datetime.getDisplayTime(date).toLowerCase().replace("am", "").replace("pm", "").trim(); + return datetime.getDisplayTime(date).toLowerCase().replace('am', '').replace('pm', '').trim(); } function setDisplayTime(elem, date) { @@ -260,11 +243,11 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med html = getDisplayTimeWithoutAmPm(date); } - elem.innerHTML = html || ""; + elem.innerHTML = html || ''; } function shouldEnableProgressByTimeOfDay(item) { - return !("TvChannel" !== item.Type || !item.CurrentProgram); + return !('TvChannel' !== item.Type || !item.CurrentProgram); } function updateNowPlayingInfo(player, state) { @@ -274,15 +257,15 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med if (!item) { setPoster(null); updateRecordingButton(null); - Emby.Page.setTitle(""); + Emby.Page.setTitle(''); nowPlayingVolumeSlider.disabled = true; nowPlayingPositionSlider.disabled = true; btnFastForward.disabled = true; btnRewind.disabled = true; - view.querySelector(".btnSubtitles").classList.add("hide"); - view.querySelector(".btnAudio").classList.add("hide"); - view.querySelector(".osdTitle").innerHTML = ""; - view.querySelector(".osdMediaInfo").innerHTML = ""; + view.querySelector('.btnSubtitles').classList.add('hide'); + view.querySelector('.btnAudio').classList.add('hide'); + view.querySelector('.osdTitle').innerHTML = ''; + view.querySelector('.osdMediaInfo').innerHTML = ''; return; } @@ -294,33 +277,22 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med btnRewind.disabled = false; if (playbackManager.subtitleTracks(player).length) { - view.querySelector(".btnSubtitles").classList.remove("hide"); + view.querySelector('.btnSubtitles').classList.remove('hide'); toggleSubtitleSync(); } else { - view.querySelector(".btnSubtitles").classList.add("hide"); - toggleSubtitleSync("forceToHide"); + view.querySelector('.btnSubtitles').classList.add('hide'); + toggleSubtitleSync('forceToHide'); } if (playbackManager.audioTracks(player).length > 1) { - view.querySelector(".btnAudio").classList.remove("hide"); + view.querySelector('.btnAudio').classList.remove('hide'); } else { - view.querySelector(".btnAudio").classList.add("hide"); + view.querySelector('.btnAudio').classList.add('hide'); } } function setTitle(item, parentName) { - var url = logoImageUrl(item, connectionManager.getApiClient(item.ServerId), {}); - - if (url) { - Emby.Page.setTitle(""); - var pageTitle = document.querySelector(".pageTitle"); - pageTitle.style.backgroundImage = "url('" + url + "')"; - pageTitle.classList.add("pageTitleWithLogo"); - pageTitle.classList.remove("pageTitleWithDefaultLogo"); - pageTitle.innerHTML = ""; - } else { - Emby.Page.setTitle(parentName || ""); - } + Emby.Page.setTitle(parentName || ''); var documentTitle = parentName || (item ? item.Name : null); @@ -330,29 +302,35 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function setPoster(item, secondaryItem) { - var osdPoster = view.querySelector(".osdPoster"); + var osdPoster = view.querySelector('.osdPoster'); if (item) { var imgUrl = seriesImageUrl(item, { - type: "Primary" + maxWidth: osdPoster.clientWidth * 2, + type: 'Primary' }) || seriesImageUrl(item, { - type: "Thumb" + maxWidth: osdPoster.clientWidth * 2, + type: 'Thumb' }) || imageUrl(item, { - type: "Primary" + maxWidth: osdPoster.clientWidth * 2, + type: 'Primary' }); if (!imgUrl && secondaryItem && (imgUrl = seriesImageUrl(secondaryItem, { - type: "Primary" + maxWidth: osdPoster.clientWidth * 2, + type: 'Primary' }) || seriesImageUrl(secondaryItem, { - type: "Thumb" + maxWidth: osdPoster.clientWidth * 2, + type: 'Thumb' }) || imageUrl(secondaryItem, { - type: "Primary" + maxWidth: osdPoster.clientWidth * 2, + type: 'Primary' })), imgUrl) { return void (osdPoster.innerHTML = ''); } } - osdPoster.innerHTML = ""; + osdPoster.innerHTML = ''; } function showOsd() { @@ -367,7 +345,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function toggleOsd() { - if ("osd" === currentVisibleMenu) { + if ('osd' === currentVisibleMenu) { hideOsd(); } else if (!currentVisibleMenu) { showOsd(); @@ -376,7 +354,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function startOsdHideTimer() { stopOsdHideTimer(); - osdHideTimeout = setTimeout(hideOsd, 5e3); + osdHideTimeout = setTimeout(hideOsd, 3e3); } function stopOsdHideTimer() { @@ -387,11 +365,11 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function slideDownToShow(elem) { - elem.classList.remove("osdHeader-hidden"); + elem.classList.remove('osdHeader-hidden'); } function slideUpToHide(elem) { - elem.classList.add("osdHeader-hidden"); + elem.classList.add('osdHeader-hidden'); } function clearHideAnimationEventListeners(elem) { @@ -404,7 +382,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var elem = e.target; if (elem != osdBottomElement) return; - elem.classList.add("hide"); + elem.classList.add('hide'); dom.removeEventListener(elem, transitionEndEventName, onHideAnimationComplete, { once: true }); @@ -413,14 +391,14 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function showMainOsdControls() { if (!currentVisibleMenu) { var elem = osdBottomElement; - currentVisibleMenu = "osd"; + currentVisibleMenu = 'osd'; clearHideAnimationEventListeners(elem); - elem.classList.remove("hide"); - elem.classList.remove("videoOsdBottom-hidden"); + elem.classList.remove('hide'); + elem.classList.remove('videoOsdBottom-hidden'); if (!layoutManager.mobile) { setTimeout(function () { - focusManager.focus(elem.querySelector(".btnPause")); + focusManager.focus(elem.querySelector('.btnPause')); }, 50); } toggleSubtitleSync(); @@ -428,20 +406,25 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function hideMainOsdControls() { - if ("osd" === currentVisibleMenu) { + if ('osd' === currentVisibleMenu) { var elem = osdBottomElement; clearHideAnimationEventListeners(elem); - elem.classList.add("videoOsdBottom-hidden"); + elem.classList.add('videoOsdBottom-hidden'); dom.addEventListener(elem, transitionEndEventName, onHideAnimationComplete, { once: true }); currentVisibleMenu = null; - toggleSubtitleSync("hide"); + toggleSubtitleSync('hide'); + + // Firefox does not blur by itself + if (document.activeElement) { + document.activeElement.blur(); + } } } function onPointerMove(e) { - if ("mouse" === (e.pointerType || (layoutManager.mobile ? "touch" : "mouse"))) { + if ('mouse' === (e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'))) { var eventX = e.screenX || 0; var eventY = e.screenY || 0; var obj = lastPointerMoveData; @@ -468,8 +451,8 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var player = currentPlayer; switch (e.detail.command) { - case "left": - if ("osd" === currentVisibleMenu) { + case 'left': + if ('osd' === currentVisibleMenu) { showOsd(); } else { if (!currentVisibleMenu) { @@ -480,8 +463,8 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med break; - case "right": - if ("osd" === currentVisibleMenu) { + case 'right': + if ('osd' === currentVisibleMenu) { showOsd(); } else if (!currentVisibleMenu) { e.preventDefault(); @@ -490,54 +473,59 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med break; - case "pageup": + case 'pageup': playbackManager.nextChapter(player); break; - case "pagedown": + case 'pagedown': playbackManager.previousChapter(player); break; - case "up": - case "down": - case "select": - case "menu": - case "info": - case "play": - case "playpause": - case "pause": - case "fastforward": - case "rewind": - case "next": - case "previous": + case 'up': + case 'down': + case 'select': + case 'menu': + case 'info': + case 'play': + case 'playpause': + case 'pause': + case 'fastforward': + case 'rewind': + case 'next': + case 'previous': showOsd(); break; - case "record": + case 'record': onRecordingCommand(); showOsd(); break; - case "togglestats": + case 'togglestats': toggleStats(); } } function onRecordingCommand() { - var btnRecord = view.querySelector(".btnRecord"); + var btnRecord = view.querySelector('.btnRecord'); - if (!btnRecord.classList.contains("hide")) { + if (!btnRecord.classList.contains('hide')) { btnRecord.click(); } } function updateFullscreenIcon() { + const button = view.querySelector('.btnFullscreen'); + const icon = button.querySelector('.material-icons'); + + icon.classList.remove('fullscreen_exit', 'fullscreen'); + if (playbackManager.isFullscreen(currentPlayer)) { - view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("ExitFullscreen")); - view.querySelector(".btnFullscreen i").innerHTML = "fullscreen_exit"; + button.setAttribute('title', globalize.translate('ExitFullscreen') + ' (f)'); + icon.classList.add('fullscreen_exit'); } else { - view.querySelector(".btnFullscreen").setAttribute("title", globalize.translate("Fullscreen") + " (f)"); - view.querySelector(".btnFullscreen i").innerHTML = "fullscreen"; + button.setAttribute('title', globalize.translate('Fullscreen') + ' (f)'); + icon.classList.add('fullscreen'); } } @@ -570,7 +558,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function onPlaybackStart(e, state) { - console.log("nowplaying event: " + e.type); + console.debug('nowplaying event: ' + e.type); var player = this; onStateChanged.call(player, e, state); resetUpNextDialog(); @@ -589,10 +577,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function onPlaybackStopped(e, state) { currentRuntimeTicks = null; resetUpNextDialog(); - console.log("nowplaying event: " + e.type); + console.debug('nowplaying event: ' + e.type); - if ("Video" !== state.NextMediaType) { - view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + if ('Video' !== state.NextMediaType) { + view.removeEventListener('viewbeforehide', onViewHideStopPlayback); Emby.Page.back(); } } @@ -601,16 +589,16 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var player = this; var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { - type: "init" + type: 'init' }, state); } function onBeginFetch() { - document.querySelector(".osdMediaStatus").classList.remove("hide"); + document.querySelector('.osdMediaStatus').classList.remove('hide'); } function onEndFetch() { - document.querySelector(".osdMediaStatus").classList.add("hide"); + document.querySelector('.osdMediaStatus').classList.add('hide'); } function bindToPlayer(player) { @@ -621,18 +609,18 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { - type: "init" + type: 'init' }, state); - events.on(player, "playbackstart", onPlaybackStart); - 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); - events.on(player, "fullscreenchange", updateFullscreenIcon); - events.on(player, "mediastreamschange", onMediaStreamsChanged); - events.on(player, "beginFetch", onBeginFetch); - events.on(player, "endFetch", onEndFetch); + events.on(player, 'playbackstart', onPlaybackStart); + 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); + events.on(player, 'fullscreenchange', updateFullscreenIcon); + events.on(player, 'mediastreamschange', onMediaStreamsChanged); + events.on(player, 'beginFetch', onBeginFetch); + events.on(player, 'endFetch', onEndFetch); resetUpNextDialog(); if (player.isFetching) { @@ -647,20 +635,21 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var player = currentPlayer; if (player) { - events.off(player, "playbackstart", onPlaybackStart); - 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); - events.off(player, "fullscreenchange", updateFullscreenIcon); - events.off(player, "mediastreamschange", onMediaStreamsChanged); + events.off(player, 'playbackstart', onPlaybackStart); + 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); + events.off(player, 'fullscreenchange', updateFullscreenIcon); + events.off(player, 'mediastreamschange', onMediaStreamsChanged); currentPlayer = null; } } function onTimeUpdate(e) { - if (isEnabled) { + // Test for 'currentItem' is required for Firefox since its player spams 'timeupdate' events even being at breakpoint + if (isEnabled && currentItem) { var now = new Date().getTime(); if (!(now - lastUpdateTime < 700)) { @@ -677,7 +666,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function showComingUpNextIfNeeded(player, currentItem, currentTimeTicks, runtimeTicks) { - if (runtimeTicks && currentTimeTicks && !comingUpNextDisplayed && !currentVisibleMenu && "Episode" === currentItem.Type && userSettings.enableNextVideoInfoOverlay()) { + if (runtimeTicks && currentTimeTicks && !comingUpNextDisplayed && !currentVisibleMenu && 'Episode' === currentItem.Type && userSettings.enableNextVideoInfoOverlay()) { var showAtSecondsLeft = runtimeTicks >= 3e10 ? 40 : runtimeTicks >= 24e9 ? 35 : 30; var showAtTicks = runtimeTicks - 1e3 * showAtSecondsLeft * 1e4; var timeRemainingTicks = runtimeTicks - currentTimeTicks; @@ -689,30 +678,30 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function onUpNextHidden() { - if ("upnext" === currentVisibleMenu) { + if ('upnext' === currentVisibleMenu) { currentVisibleMenu = null; } } function showComingUpNext(player) { - require(["upNextDialog"], function (UpNextDialog) { + require(['upNextDialog'], function (UpNextDialog) { if (!(currentVisibleMenu || currentUpNextDialog)) { - currentVisibleMenu = "upnext"; + currentVisibleMenu = 'upnext'; comingUpNextDisplayed = true; playbackManager.nextItem(player).then(function (nextItem) { currentUpNextDialog = new UpNextDialog({ - parent: view.querySelector(".upNextContainer"), + parent: view.querySelector('.upNextContainer'), player: player, nextItem: nextItem }); - events.on(currentUpNextDialog, "hide", onUpNextHidden); + events.on(currentUpNextDialog, 'hide', onUpNextHidden); }, onUpNextHidden); } }); } function refreshProgramInfoIfNeeded(player, item) { - if ("TvChannel" === item.Type) { + if ('TvChannel' === item.Type) { var program = item.CurrentProgram; if (program && program.EndDate) { @@ -720,27 +709,31 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var endDate = datetime.parseISO8601Date(program.EndDate); if (new Date().getTime() >= endDate.getTime()) { - console.log("program info needs to be refreshed"); + console.debug('program info needs to be refreshed'); var state = playbackManager.getPlayerState(player); onStateChanged.call(player, { - type: "init" + type: 'init' }, state); } } catch (e) { - console.log("Error parsing date: " + program.EndDate); + console.error('error parsing date: ' + program.EndDate); } } } } function updatePlayPauseState(isPaused) { - var button = view.querySelector(".btnPause i"); + const btnPlayPause = view.querySelector('.btnPause'); + const btnPlayPauseIcon = btnPlayPause.querySelector('.material-icons'); + + btnPlayPauseIcon.classList.remove('play_arrow', 'pause'); + if (isPaused) { - button.innerHTML = "play_arrow"; - button.setAttribute("title", globalize.translate("ButtonPlay") + " (k)"); + btnPlayPauseIcon.classList.add('play_arrow'); + btnPlayPause.setAttribute('title', globalize.translate('ButtonPlay') + ' (k)'); } else { - button.innerHTML = "pause"; - button.setAttribute("title", globalize.translate("ButtonPause") + " (k)"); + btnPlayPauseIcon.classList.add('pause'); + btnPlayPause.setAttribute('title', globalize.translate('ButtonPause') + ' (k)'); } } @@ -749,7 +742,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med updatePlayPauseState(playState.IsPaused); var supportedCommands = playbackManager.getSupportedCommands(player); currentPlayerSupportedCommands = supportedCommands; - supportsBrightnessChange = -1 !== supportedCommands.indexOf("SetBrightness"); + supportsBrightnessChange = -1 !== supportedCommands.indexOf('SetBrightness'); updatePlayerVolumeState(player, playState.IsMuted, playState.VolumeLevel); if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) { @@ -763,10 +756,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med updateTimeDisplay(playState.PositionTicks, nowPlayingItem.RunTimeTicks, playState.PlaybackStartTimeTicks, playState.BufferedRanges || []); updateNowPlayingInfo(player, state); - if (state.MediaSource && state.MediaSource.SupportsTranscoding && -1 !== supportedCommands.indexOf("SetMaxStreamingBitrate")) { - view.querySelector(".btnVideoOsdSettings").classList.remove("hide"); + if (state.MediaSource && state.MediaSource.SupportsTranscoding && -1 !== supportedCommands.indexOf('SetMaxStreamingBitrate')) { + view.querySelector('.btnVideoOsdSettings').classList.remove('hide'); } else { - view.querySelector(".btnVideoOsdSettings").classList.add("hide"); + view.querySelector('.btnVideoOsdSettings').classList.add('hide'); } var isProgressClear = state.MediaSource && null == state.MediaSource.RunTimeTicks; @@ -777,22 +770,22 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med userSettings.skipForwardLength() * 1000000 / nowPlayingItem.RunTimeTicks); } - if (-1 === supportedCommands.indexOf("ToggleFullscreen") || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player)) { - view.querySelector(".btnFullscreen").classList.add("hide"); + if (-1 === supportedCommands.indexOf('ToggleFullscreen') || player.isLocalPlayer && layoutManager.tv && playbackManager.isFullscreen(player)) { + view.querySelector('.btnFullscreen').classList.add('hide'); } else { - view.querySelector(".btnFullscreen").classList.remove("hide"); + view.querySelector('.btnFullscreen').classList.remove('hide'); } - if (-1 === supportedCommands.indexOf("PictureInPicture")) { - view.querySelector(".btnPip").classList.add("hide"); + if (-1 === supportedCommands.indexOf('PictureInPicture')) { + view.querySelector('.btnPip').classList.add('hide'); } else { - view.querySelector(".btnPip").classList.remove("hide"); + view.querySelector('.btnPip').classList.remove('hide'); } - if (-1 === supportedCommands.indexOf("AirPlay")) { - view.querySelector(".btnAirPlay").classList.add("hide"); + if (-1 === supportedCommands.indexOf('AirPlay')) { + view.querySelector('.btnAirPlay').classList.add('hide'); } else { - view.querySelector(".btnAirPlay").classList.remove("hide"); + view.querySelector('.btnAirPlay').classList.remove('hide'); } updateFullscreenIcon(); @@ -825,8 +818,8 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } } - nowPlayingPositionText.innerHTML = ""; - nowPlayingDurationText.innerHTML = ""; + nowPlayingPositionText.innerHTML = ''; + nowPlayingDurationText.innerHTML = ''; } else { if (nowPlayingPositionSlider && !nowPlayingPositionSlider.dragging) { if (runtimeTicks) { @@ -837,10 +830,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med nowPlayingPositionSlider.value = 0; } - if (runtimeTicks && null != positionTicks && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && "Recording" !== currentItem.Type) { - endsAtText.innerHTML = "  -  " + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, true); + if (runtimeTicks && null != positionTicks && currentRuntimeTicks && !enableProgressByTimeOfDay && currentItem.RunTimeTicks && 'Recording' !== currentItem.Type) { + endsAtText.innerHTML = '  -  ' + mediaInfo.getEndsAtFromPosition(runtimeTicks, positionTicks, true); } else { - endsAtText.innerHTML = ""; + endsAtText.innerHTML = ''; } } @@ -857,45 +850,44 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var supportedCommands = currentPlayerSupportedCommands; var showMuteButton = true; var showVolumeSlider = true; - var volumeSlider = view.querySelector('.osdVolumeSliderContainer'); - var progressElement = volumeSlider.querySelector('.mdl-slider-background-lower'); - if (-1 === supportedCommands.indexOf("Mute")) { + if (-1 === supportedCommands.indexOf('Mute')) { showMuteButton = false; } - if (-1 === supportedCommands.indexOf("SetVolume")) { + if (-1 === supportedCommands.indexOf('SetVolume')) { showVolumeSlider = false; } - if (player.isLocalPlayer && appHost.supports("physicalvolumecontrol")) { + if (player.isLocalPlayer && appHost.supports('physicalvolumecontrol')) { showMuteButton = false; showVolumeSlider = false; } + const buttonMute = view.querySelector('.buttonMute'); + const buttonMuteIcon = buttonMute.querySelector('.material-icons'); + + buttonMuteIcon.classList.remove('volume_off', 'volume_up'); + if (isMuted) { - view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Unmute") + " (m)"); - view.querySelector(".buttonMute i").innerHTML = "volume_off"; + buttonMute.setAttribute('title', globalize.translate('Unmute') + ' (m)'); + buttonMuteIcon.classList.add('volume_off'); } else { - view.querySelector(".buttonMute").setAttribute("title", globalize.translate("Mute") + " (m)"); - view.querySelector(".buttonMute i").innerHTML = "volume_up"; - } - - if (progressElement) { - progressElement.style.width = (volumeLevel || 0) + '%'; + buttonMute.setAttribute('title', globalize.translate('Mute') + ' (m)'); + buttonMuteIcon.classList.add('volume_up'); } if (showMuteButton) { - view.querySelector(".buttonMute").classList.remove("hide"); + buttonMute.classList.remove('hide'); } else { - view.querySelector(".buttonMute").classList.add("hide"); + buttonMute.classList.add('hide'); } if (nowPlayingVolumeSlider) { if (showVolumeSlider) { - nowPlayingVolumeSliderContainer.classList.remove("hide"); + nowPlayingVolumeSliderContainer.classList.remove('hide'); } else { - nowPlayingVolumeSliderContainer.classList.add("hide"); + nowPlayingVolumeSliderContainer.classList.add('hide'); } if (!nowPlayingVolumeSlider.dragging) { @@ -905,24 +897,24 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function updatePlaylist(player) { - var btnPreviousTrack = view.querySelector(".btnPreviousTrack"); - var btnNextTrack = view.querySelector(".btnNextTrack"); - btnPreviousTrack.classList.remove("hide"); - btnNextTrack.classList.remove("hide"); + var btnPreviousTrack = view.querySelector('.btnPreviousTrack'); + var btnNextTrack = view.querySelector('.btnNextTrack'); + btnPreviousTrack.classList.remove('hide'); + btnNextTrack.classList.remove('hide'); btnNextTrack.disabled = false; btnPreviousTrack.disabled = false; } function updateTimeText(elem, ticks, divider) { if (null == ticks) { - elem.innerHTML = ""; + elem.innerHTML = ''; return; } var html = datetime.getDisplayRunningTime(ticks); if (divider) { - html = " / " + html; + html = ' / ' + html; } elem.innerHTML = html; @@ -931,7 +923,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med function onSettingsButtonClick(e) { var btn = this; - require(["playerSettingsMenu"], function (playerSettingsMenu) { + require(['playerSettingsMenu'], function (playerSettingsMenu) { var player = currentPlayer; if (player) { @@ -941,7 +933,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med playbackManager.canHandleOffsetOnCurrentSubtitle(player); playerSettingsMenu.show({ - mediaType: "Video", + mediaType: 'Video', player: player, positionTo: btn, stats: true, @@ -953,9 +945,9 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function onSettingsOption(selectedOption) { - if ("stats" === selectedOption) { + if ('stats' === selectedOption) { toggleStats(); - } else if ("suboffset" === selectedOption) { + } else if ('suboffset' === selectedOption) { var player = currentPlayer; if (player) { playbackManager.enableShowingSubtitleOffset(player); @@ -965,7 +957,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function toggleStats() { - require(["playerStats"], function (PlayerStats) { + require(['playerStats'], function (PlayerStats) { var player = currentPlayer; if (player) { @@ -1005,10 +997,10 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med }); var positionTo = this; - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, - title: globalize.translate("Audio"), + title: globalize.translate('Audio'), positionTo: positionTo }).then(function (id) { var index = parseInt(id); @@ -1031,7 +1023,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med streams.unshift({ Index: -1, - DisplayTitle: globalize.translate("Off") + DisplayTitle: globalize.translate('Off') }); var menuItems = streams.map(function (stream) { var opt = { @@ -1047,9 +1039,9 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med }); var positionTo = this; - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ - title: globalize.translate("Subtitles"), + title: globalize.translate('Subtitles'), items: menuItems, positionTo: positionTo }).then(function (id) { @@ -1065,7 +1057,7 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } function toggleSubtitleSync(action) { - require(["subtitleSync"], function (SubtitleSync) { + require(['subtitleSync'], function (SubtitleSync) { var player = currentPlayer; if (subtitleSyncOverlay) { subtitleSyncOverlay.toggle(action); @@ -1083,81 +1075,99 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } /** - * Keys used for keyboard navigation. + * Clicked element. + * To skip 'click' handling on Firefox/Edge. */ - var NavigationKeys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown"]; + var clickedElement; function onWindowKeyDown(e) { + clickedElement = e.srcElement; + + var key = keyboardnavigation.getKeyName(e); + if (!currentVisibleMenu && 32 === e.keyCode) { playbackManager.playPause(currentPlayer); showOsd(); return; } - if (layoutManager.tv && NavigationKeys.indexOf(e.key) != -1) { + if (layoutManager.tv && keyboardnavigation.isNavigationKey(key)) { showOsd(); return; } - switch (e.key) { - case "k": + switch (key) { + case 'Enter': + showOsd(); + break; + case 'Escape': + case 'Back': + // Ignore key when some dialog is opened + if (currentVisibleMenu === 'osd' && !document.querySelector('.dialogContainer')) { + hideOsd(); + e.stopPropagation(); + } + break; + case 'k': playbackManager.playPause(currentPlayer); showOsd(); break; - - case "l": - case "ArrowRight": - case "Right": + case 'l': + case 'ArrowRight': + case 'Right': playbackManager.fastForward(currentPlayer); showOsd(); break; - - case "j": - case "ArrowLeft": - case "Left": + case 'j': + case 'ArrowLeft': + case 'Left': playbackManager.rewind(currentPlayer); showOsd(); break; - - case "f": + case 'f': if (!e.ctrlKey && !e.metaKey) { playbackManager.toggleFullscreen(currentPlayer); showOsd(); } break; - - case "m": + case 'm': playbackManager.toggleMute(currentPlayer); showOsd(); break; - - case "NavigationLeft": - case "GamepadDPadLeft": - case "GamepadLeftThumbstickLeft": - // Ignores gamepad events that are always triggered, even when not focused. - if (document.hasFocus()) { + case 'NavigationLeft': + case 'GamepadDPadLeft': + case 'GamepadLeftThumbstickLeft': + // Ignores gamepad events that are always triggered, even when not focused. + if (document.hasFocus()) { /* eslint-disable-line compat/compat */ playbackManager.rewind(currentPlayer); showOsd(); } break; - - case "NavigationRight": - case "GamepadDPadRight": - case "GamepadLeftThumbstickRight": - // Ignores gamepad events that are always triggered, even when not focused. - if (document.hasFocus()) { + case 'NavigationRight': + case 'GamepadDPadRight': + case 'GamepadLeftThumbstickRight': + // Ignores gamepad events that are always triggered, even when not focused. + if (document.hasFocus()) { /* eslint-disable-line compat/compat */ playbackManager.fastForward(currentPlayer); showOsd(); } } } + function onWindowMouseDown(e) { + clickedElement = e.srcElement; + } + + function onWindowTouchStart(e) { + clickedElement = e.srcElement; + } + function getImgUrl(item, chapter, index, maxWidth, apiClient) { if (chapter.ImageTag) { return apiClient.getScaledImageUrl(item.Id, { maxWidth: maxWidth, tag: chapter.ImageTag, - type: "Chapter", + type: 'Chapter', index: index }); } @@ -1190,35 +1200,37 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med html += '
'; html += '
'; html += chapter.Name; - html += "
"; + html += '
'; html += '

'; html += datetime.getDisplayRunningTime(positionTicks); - html += "

"; - html += "
"; - return html + ""; + html += ''; + html += ''; + return html + ''; } return null; } + var playPauseClickTimeout; function onViewHideStopPlayback() { if (playbackManager.isPlayingVideo()) { require(['shell'], function (shell) { shell.disableFullscreen(); }); + clearTimeout(playPauseClickTimeout); var player = currentPlayer; - view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + view.removeEventListener('viewbeforehide', onViewHideStopPlayback); releaseCurrentPlayer(); playbackManager.stop(player); } } function enableStopOnBack(enabled) { - view.removeEventListener("viewbeforehide", onViewHideStopPlayback); + view.removeEventListener('viewbeforehide', onViewHideStopPlayback); if (enabled && playbackManager.isPlayingVideo(currentPlayer)) { - view.addEventListener("viewbeforehide", onViewHideStopPlayback); + view.addEventListener('viewbeforehide', onViewHideStopPlayback); } } @@ -1246,40 +1258,45 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med var programEndDateMs = 0; var playbackStartTimeTicks = 0; var subtitleSyncOverlay; - var volumeSliderTimer; - var nowPlayingVolumeSlider = view.querySelector(".osdVolumeSlider"); - var nowPlayingVolumeSliderContainer = view.querySelector(".osdVolumeSliderContainer"); - var nowPlayingPositionSlider = view.querySelector(".osdPositionSlider"); - var nowPlayingPositionText = view.querySelector(".osdPositionText"); - var nowPlayingDurationText = view.querySelector(".osdDurationText"); - var startTimeText = view.querySelector(".startTimeText"); - var endTimeText = view.querySelector(".endTimeText"); - var endsAtText = view.querySelector(".endsAtText"); - var btnRewind = view.querySelector(".btnRewind"); - var btnFastForward = view.querySelector(".btnFastForward"); + var nowPlayingVolumeSlider = view.querySelector('.osdVolumeSlider'); + var nowPlayingVolumeSliderContainer = view.querySelector('.osdVolumeSliderContainer'); + var nowPlayingPositionSlider = view.querySelector('.osdPositionSlider'); + var nowPlayingPositionText = view.querySelector('.osdPositionText'); + var nowPlayingDurationText = view.querySelector('.osdDurationText'); + var startTimeText = view.querySelector('.startTimeText'); + var endTimeText = view.querySelector('.endTimeText'); + var endsAtText = view.querySelector('.endsAtText'); + var btnRewind = view.querySelector('.btnRewind'); + var btnFastForward = view.querySelector('.btnFastForward'); var transitionEndEventName = dom.whichTransitionEvent(); - var headerElement = document.querySelector(".skinHeader"); - var osdBottomElement = document.querySelector(".videoOsdBottom-maincontrols"); + var headerElement = document.querySelector('.skinHeader'); + var osdBottomElement = document.querySelector('.videoOsdBottom-maincontrols'); if (layoutManager.tv) { - nowPlayingPositionSlider.classList.add("focusable"); + nowPlayingPositionSlider.classList.add('focusable'); nowPlayingPositionSlider.enableKeyboardDragging(); } - view.addEventListener("viewbeforeshow", function (e) { - headerElement.classList.add("osdHeader"); - Emby.Page.setTransparency("full"); + view.addEventListener('viewbeforeshow', function (e) { + headerElement.classList.add('osdHeader'); + Emby.Page.setTransparency('full'); }); - view.addEventListener("viewshow", function (e) { + view.addEventListener('viewshow', function (e) { try { - events.on(playbackManager, "playerchange", onPlayerChange); + events.on(playbackManager, 'playerchange', onPlayerChange); bindToPlayer(playbackManager.getCurrentPlayer()); - dom.addEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { + dom.addEventListener(document, window.PointerEvent ? 'pointermove' : 'mousemove', onPointerMove, { passive: true }); showOsd(); inputManager.on(window, onInputCommand); - dom.addEventListener(window, "keydown", onWindowKeyDown, { + dom.addEventListener(window, 'keydown', onWindowKeyDown, { + capture: true + }); + dom.addEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, { + passive: true + }); + dom.addEventListener(window, 'touchstart', onWindowTouchStart, { passive: true }); } catch (e) { @@ -1288,38 +1305,44 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med }); } }); - view.addEventListener("viewbeforehide", function () { + view.addEventListener('viewbeforehide', function () { if (statsOverlay) { statsOverlay.enabled(false); } - dom.removeEventListener(window, "keydown", onWindowKeyDown, { + dom.removeEventListener(window, 'keydown', onWindowKeyDown, { + capture: true + }); + dom.removeEventListener(window, window.PointerEvent ? 'pointerdown' : 'mousedown', onWindowMouseDown, { + passive: true + }); + dom.removeEventListener(window, 'touchstart', onWindowTouchStart, { passive: true }); stopOsdHideTimer(); - headerElement.classList.remove("osdHeader"); - headerElement.classList.remove("osdHeader-hidden"); - dom.removeEventListener(document, window.PointerEvent ? "pointermove" : "mousemove", onPointerMove, { + headerElement.classList.remove('osdHeader'); + headerElement.classList.remove('osdHeader-hidden'); + dom.removeEventListener(document, window.PointerEvent ? 'pointermove' : 'mousemove', onPointerMove, { passive: true }); inputManager.off(window, onInputCommand); - events.off(playbackManager, "playerchange", onPlayerChange); + events.off(playbackManager, 'playerchange', onPlayerChange); releaseCurrentPlayer(); }); - view.querySelector(".btnFullscreen").addEventListener("click", function () { + view.querySelector('.btnFullscreen').addEventListener('click', function () { playbackManager.toggleFullscreen(currentPlayer); }); - view.querySelector(".btnPip").addEventListener("click", function () { + view.querySelector('.btnPip').addEventListener('click', function () { playbackManager.togglePictureInPicture(currentPlayer); }); - view.querySelector(".btnAirPlay").addEventListener("click", function () { + view.querySelector('.btnAirPlay').addEventListener('click', function () { playbackManager.toggleAirPlay(currentPlayer); }); - view.querySelector(".btnVideoOsdSettings").addEventListener("click", onSettingsButtonClick); - view.addEventListener("viewhide", function () { - headerElement.classList.remove("hide"); + view.querySelector('.btnVideoOsdSettings').addEventListener('click', onSettingsButtonClick); + view.addEventListener('viewhide', function () { + headerElement.classList.remove('hide'); }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (self.touchHelper) { self.touchHelper.destroy(); self.touchHelper = null; @@ -1334,16 +1357,16 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med destroySubtitleSync(); }); var lastPointerDown = 0; - dom.addEventListener(view, window.PointerEvent ? "pointerdown" : "click", function (e) { - if (dom.parentWithClass(e.target, ["videoOsdBottom", "upNextContainer"])) { + dom.addEventListener(view, window.PointerEvent ? 'pointerdown' : 'click', function (e) { + if (dom.parentWithClass(e.target, ['videoOsdBottom', 'upNextContainer'])) { return void showOsd(); } - var pointerType = e.pointerType || (layoutManager.mobile ? "touch" : "mouse"); + var pointerType = e.pointerType || (layoutManager.mobile ? 'touch' : 'mouse'); var now = new Date().getTime(); switch (pointerType) { - case "touch": + case 'touch': if (now - lastPointerDown > 300) { lastPointerDown = now; toggleOsd(); @@ -1351,10 +1374,18 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med break; - case "mouse": + case 'mouse': if (!e.button) { - playbackManager.playPause(currentPlayer); - showOsd(); + if (playPauseClickTimeout) { + clearTimeout(playPauseClickTimeout); + playPauseClickTimeout = 0; + } else { + playPauseClickTimeout = setTimeout(function() { + playbackManager.playPause(currentPlayer); + showOsd(); + playPauseClickTimeout = 0; + }, 300); + } } break; @@ -1368,49 +1399,26 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med }); if (browser.touch) { - dom.addEventListener(view, "dblclick", onDoubleClick, {}); + dom.addEventListener(view, 'dblclick', onDoubleClick, {}); } else { var options = { passive: true }; - dom.addEventListener(view, "dblclick", function () { + dom.addEventListener(view, 'dblclick', function () { playbackManager.toggleFullscreen(currentPlayer); }, options); } - view.querySelector(".buttonMute").addEventListener("click", function () { + function setVolume() { + playbackManager.setVolume(this.value, currentPlayer); + } + + view.querySelector('.buttonMute').addEventListener('click', function () { playbackManager.toggleMute(currentPlayer); }); - nowPlayingVolumeSlider.addEventListener("change", function () { - if (volumeSliderTimer) { - // interupt and remove existing timer - clearTimeout(volumeSliderTimer); - volumeSliderTimer = null; - } - playbackManager.setVolume(this.value, currentPlayer); - }); - nowPlayingVolumeSlider.addEventListener("mousemove", function () { - if (!volumeSliderTimer) { - var that = this; - // register new timer - volumeSliderTimer = setTimeout(function() { - playbackManager.setVolume(that.value, currentPlayer); - // delete timer after completion - volumeSliderTimer = null; - }, 700); - } - }); - nowPlayingVolumeSlider.addEventListener("touchmove", function () { - if (!volumeSliderTimer) { - var that = this; - // register new timer - volumeSliderTimer = setTimeout(function() { - playbackManager.setVolume(that.value, currentPlayer); - // delete timer after completion - volumeSliderTimer = null; - }, 700); - } - }); + nowPlayingVolumeSlider.addEventListener('change', setVolume); + nowPlayingVolumeSlider.addEventListener('mousemove', setVolume); + nowPlayingVolumeSlider.addEventListener('touchmove', setVolume); - nowPlayingPositionSlider.addEventListener("change", function () { + nowPlayingPositionSlider.addEventListener('change', function () { var player = currentPlayer; if (player) { @@ -1435,14 +1443,14 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med ms /= 100; ms *= value; ms += programStartDateMs; - return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms)), true) + "

"; + return '

' + getDisplayTimeWithoutAmPm(new Date(parseInt(ms)), true) + '

'; } - return "--:--"; + return '--:--'; } if (!currentRuntimeTicks) { - return "--:--"; + return '--:--'; } var ticks = currentRuntimeTicks; @@ -1458,38 +1466,41 @@ define(["playbackManager", "dom", "inputManager", "datetime", "itemHelper", "med } } - return '

' + datetime.getDisplayRunningTime(ticks) + "

"; + return '

' + datetime.getDisplayRunningTime(ticks) + '

'; }; - view.querySelector(".btnPreviousTrack").addEventListener("click", function () { + view.querySelector('.btnPreviousTrack').addEventListener('click', function () { playbackManager.previousTrack(currentPlayer); }); - view.querySelector(".btnPause").addEventListener("click", function () { - playbackManager.playPause(currentPlayer); + view.querySelector('.btnPause').addEventListener('click', function () { + // Ignore 'click' if another element was originally clicked (Firefox/Edge issue) + if (this.contains(clickedElement)) { + playbackManager.playPause(currentPlayer); + } }); - view.querySelector(".btnNextTrack").addEventListener("click", function () { + view.querySelector('.btnNextTrack').addEventListener('click', function () { playbackManager.nextTrack(currentPlayer); }); - btnRewind.addEventListener("click", function () { + btnRewind.addEventListener('click', function () { playbackManager.rewind(currentPlayer); }); - btnFastForward.addEventListener("click", function () { + btnFastForward.addEventListener('click', function () { playbackManager.fastForward(currentPlayer); }); - view.querySelector(".btnAudio").addEventListener("click", showAudioTrackSelection); - view.querySelector(".btnSubtitles").addEventListener("click", showSubtitleTrackSelection); + view.querySelector('.btnAudio').addEventListener('click', showAudioTrackSelection); + view.querySelector('.btnSubtitles').addEventListener('click', showSubtitleTrackSelection); if (browser.touch) { (function () { - require(["touchHelper"], function (TouchHelper) { + require(['touchHelper'], function (TouchHelper) { self.touchHelper = new TouchHelper(view, { swipeYThreshold: 30, triggerOnMove: true, preventDefaultOnMove: true, - ignoreTagNames: ["BUTTON", "INPUT", "TEXTAREA"] + ignoreTagNames: ['BUTTON', 'INPUT', 'TEXTAREA'] }); - events.on(self.touchHelper, "swipeup", onVerticalSwipe); - events.on(self.touchHelper, "swipedown", onVerticalSwipe); + events.on(self.touchHelper, 'swipeup', onVerticalSwipe); + events.on(self.touchHelper, 'swipedown', onVerticalSwipe); }); })(); } diff --git a/src/controllers/searchpage.js b/src/controllers/searchpage.js index b260ef5751..8a138b7516 100644 --- a/src/controllers/searchpage.js +++ b/src/controllers/searchpage.js @@ -1,5 +1,5 @@ -define(["focusManager", "searchFields", "searchResults", "events"], function (focusManager, SearchFields, SearchResults, events) { - "use strict"; +define(['focusManager', 'searchFields', 'searchResults', 'events'], function (focusManager, SearchFields, SearchResults, events) { + 'use strict'; return function (view, params) { function onSearch(e, value) { @@ -7,21 +7,21 @@ define(["focusManager", "searchFields", "searchResults", "events"], function (fo } var self = this; - view.addEventListener("viewshow", function () { + view.addEventListener('viewshow', function () { if (!self.searchFields) { self.searchFields = new SearchFields({ - element: view.querySelector(".searchFields") + element: view.querySelector('.searchFields') }); self.searchResults = new SearchResults({ - element: view.querySelector(".searchResults"), + element: view.querySelector('.searchResults'), serverId: params.serverId || ApiClient.serverId(), parentId: params.parentId, collectionType: params.collectionType }); - events.on(self.searchFields, "search", onSearch); + events.on(self.searchFields, 'search', onSearch); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (self.searchFields) { self.searchFields.destroy(); self.searchFields = null; diff --git a/src/controllers/serveractivity.js b/src/controllers/serveractivity.js deleted file mode 100644 index fb3b8112dc..0000000000 --- a/src/controllers/serveractivity.js +++ /dev/null @@ -1,31 +0,0 @@ -define(["components/activitylog", "globalize"], function (ActivityLog, globalize) { - "use strict"; - - return function (view, params) { - var activityLog; - - if (params.useractivity !== "false") { - view.querySelector(".activityItems").setAttribute("data-useractivity", "true"); - view.querySelector(".sectionTitle").innerHTML = globalize.translate("HeaderActivity"); - } else { - view.querySelector(".activityItems").setAttribute("data-useractivity", "false"); - view.querySelector(".sectionTitle").innerHTML = globalize.translate("Alerts"); - } - - view.addEventListener("viewshow", function () { - if (!activityLog) { - activityLog = new ActivityLog({ - serverId: ApiClient.serverId(), - element: view.querySelector(".activityItems") - }); - } - }); - view.addEventListener("viewdestroy", function () { - if (activityLog) { - activityLog.destroy(); - } - - activityLog = null; - }); - }; -}); diff --git a/src/controllers/shows/episodes.js b/src/controllers/shows/episodes.js index 9c61ac80d8..ca9a807cbf 100644 --- a/src/controllers/shows/episodes.js +++ b/src/controllers/shows/episodes.js @@ -1,5 +1,5 @@ -define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "emby-itemscontainer"], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder) { - "use strict"; +define(['loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'userSettings', 'globalize', 'emby-itemscontainer'], function (loading, events, libraryBrowser, imageLoader, listView, cardBuilder, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -9,19 +9,23 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB if (!pageData) { pageData = data[key] = { query: { - SortBy: "SeriesSortName,SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Episode", + SortBy: 'SeriesSortName,SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Episode', Recursive: true, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,UserData", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,UserData', IsMissing: false, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", - StartIndex: 0, - Limit: pageSize + EnableImageTypes: 'Primary,Backdrop,Thumb', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -35,7 +39,7 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB function getSavedQueryKey(context) { if (!context.savedQueryKey) { - context.savedQueryKey = libraryBrowser.getSavedQueryKey("episodes"); + context.savedQueryKey = libraryBrowser.getSavedQueryKey('episodes'); } return context.savedQueryKey; @@ -43,17 +47,17 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB function onViewStyleChange() { var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems(page) { @@ -66,7 +70,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -75,7 +81,9 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -92,17 +100,17 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB filterButton: false }); var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); - if (viewStyle == "List") { + var itemsContainer = tabContent.querySelector('.itemsContainer'); + if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, sortBy: query.SortBy, showParentTitle: true }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', showTitle: true, showParentTitle: true, scalable: true, @@ -111,7 +119,7 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', showTitle: true, showParentTitle: true, overlayText: false, @@ -124,19 +132,19 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB var length; var elems; - elems = tabContent.querySelectorAll(".paging"); + elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } itemsContainer.innerHTML = html; @@ -145,25 +153,24 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); } var self = this; - var pageSize = 100; var data = {}; var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), - mode: "episodes", + mode: 'episodes', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { reloadItems(tabContent); }); filterDialog.show(); @@ -175,35 +182,35 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB }; function initPage(tabContent) { - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SeriesSortName,SortName" + name: globalize.translate('OptionNameSort'), + id: 'SeriesSortName,SortName' }, { - name: Globalize.translate("OptionTvdbRating"), - id: "CommunityRating,SeriesSortName,SortName" + name: globalize.translate('OptionTvdbRating'), + id: 'CommunityRating,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SeriesSortName,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionPremiereDate"), - id: "PremiereDate,SeriesSortName,SortName" + name: globalize.translate('OptionPremiereDate'), + id: 'PremiereDate,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SeriesSortName,SortName" + name: globalize.translate('OptionDatePlayed'), + id: 'DatePlayed,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SeriesSortName,SortName" + name: globalize.translate('OptionParentalRating'), + id: 'OfficialRating,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionPlayCount"), - id: "PlayCount,SeriesSortName,SortName" + name: globalize.translate('OptionPlayCount'), + id: 'PlayCount,SeriesSortName,SortName' }, { - name: Globalize.translate("OptionRuntime"), - id: "Runtime,SeriesSortName,SortName" + name: globalize.translate('OptionRuntime'), + id: 'Runtime,SeriesSortName,SortName' }], callback: function () { reloadItems(tabContent); @@ -212,11 +219,11 @@ define(["loading", "events", "libraryBrowser", "imageLoader", "listView", "cardB button: e.target }); }); - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "List,Poster,PosterCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'List,Poster,PosterCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; getPageData(tabContent).view = viewStyle; libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); diff --git a/src/controllers/shows/tvgenres.js b/src/controllers/shows/tvgenres.js index b6fa54f213..de38763e99 100644 --- a/src/controllers/shows/tvgenres.js +++ b/src/controllers/shows/tvgenres.js @@ -1,5 +1,5 @@ -define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader", "apphost", "globalize", "appRouter", "dom", "emby-button"], function (layoutManager, loading, libraryBrowser, cardBuilder, lazyLoader, appHost, globalize, appRouter, dom) { - "use strict"; +define(['layoutManager', 'loading', 'libraryBrowser', 'cardBuilder', 'lazyLoader', 'apphost', 'globalize', 'appRouter', 'dom', 'emby-button'], function (layoutManager, loading, libraryBrowser, cardBuilder, lazyLoader, appHost, globalize, appRouter, dom) { + 'use strict'; return function (view, params, tabContent) { function getPageData() { @@ -9,13 +9,13 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Series", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Series', Recursive: true, EnableTotalRecordCount: false }, - view: "Poster" + view: 'Poster' }; pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); @@ -29,7 +29,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader } function getSavedQueryKey() { - return libraryBrowser.getSavedQueryKey("seriesgenres"); + return libraryBrowser.getSavedQueryKey('seriesgenres'); } function getPromise() { @@ -43,29 +43,30 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function getPortraitShape() { - return enableScrollX() ? "overflowPortrait" : "portrait"; + return enableScrollX() ? 'overflowPortrait' : 'portrait'; } - function fillItemsContainer(elem) { - var id = elem.getAttribute("data-id"); + function fillItemsContainer(entry) { + var elem = entry.target; + var id = elem.getAttribute('data-id'); var viewStyle = self.getCurrentViewStyle(); - var limit = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? 5 : 9; + var limit = 'Thumb' == viewStyle || 'ThumbCard' == viewStyle ? 5 : 9; if (enableScrollX()) { limit = 10; } - var enableImageTypes = "Thumb" == viewStyle || "ThumbCard" == viewStyle ? "Primary,Backdrop,Thumb" : "Primary"; + var enableImageTypes = 'Thumb' == viewStyle || 'ThumbCard' == viewStyle ? 'Primary,Backdrop,Thumb' : 'Primary'; var query = { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Series", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Series', Recursive: true, - Fields: "PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,MediaSourceCount,BasicSyncInfo', ImageTypeLimit: 1, EnableImageTypes: enableImageTypes, Limit: limit, @@ -74,9 +75,9 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader ParentId: params.topParentId }; ApiClient.getItems(ApiClient.getCurrentUserId(), query).then(function (result) { - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getThumbShape(), @@ -87,7 +88,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader overlayMoreButton: true, allowBottomPadding: false }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getThumbShape(), @@ -98,7 +99,7 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader cardLayout: true, showYear: true }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getPortraitShape(), @@ -108,17 +109,20 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader cardLayout: true, showYear: true }); - } else if (viewStyle == "Poster") { + } else if (viewStyle == 'Poster') { cardBuilder.buildCards(result.Items, { itemsContainer: elem, shape: getPortraitShape(), scalable: true, + showTitle: true, + centerText: true, + showYear: true, overlayMoreButton: true, allowBottomPadding: false }); } if (result.Items.length >= query.Limit) { - tabContent.querySelector(".btnMoreFromGenre" + id + " i").classList.remove("hide"); + tabContent.querySelector('.btnMoreFromGenre' + id + ' .material-icons').classList.remove('hide'); } }); } @@ -126,8 +130,8 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader function reloadItems(context, promise) { var query = getQuery(); promise.then(function (result) { - var elem = context.querySelector("#items"); - var html = ""; + var elem = context.querySelector('#items'); + var html = ''; var items = result.Items; for (var i = 0, length = items.length; i < length; i++) { @@ -135,26 +139,26 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader html += '
'; html += '"; + html += ''; + html += ''; + html += ''; + html += '
'; if (enableScrollX()) { - var scrollXClass = "scrollX hiddenScrollX"; + var scrollXClass = 'scrollX hiddenScrollX'; if (layoutManager.tv) { - scrollXClass += "smoothScrollX"; + scrollXClass += 'smoothScrollX padded-top-focusscale padded-bottom-focusscale'; } html += '
'; } else { html += '
'; } - html += "
"; - html += "
"; + html += ''; + html += ''; } elem.innerHTML = html; @@ -173,16 +177,16 @@ define(["layoutManager", "loading", "libraryBrowser", "cardBuilder", "lazyLoader var data = {}; self.getViewStyles = function () { - return "Poster,PosterCard,Thumb,ThumbCard".split(","); + return 'Poster,PosterCard,Thumb,ThumbCard'.split(','); }; self.getCurrentViewStyle = function () { - return getPageData(tabContent).view; + return getPageData().view; }; self.setCurrentViewStyle = function (viewStyle) { - getPageData(tabContent).view = viewStyle; - libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); + getPageData().view = viewStyle; + libraryBrowser.saveViewSetting(getSavedQueryKey(), viewStyle); fullyReload(); }; diff --git a/src/controllers/shows/tvlatest.js b/src/controllers/shows/tvlatest.js index 5862fce45d..08e420a595 100644 --- a/src/controllers/shows/tvlatest.js +++ b/src/controllers/shows/tvlatest.js @@ -1,28 +1,28 @@ -define(["loading", "components/groupedcards", "cardBuilder", "apphost", "imageLoader"], function (loading, groupedcards, cardBuilder, appHost, imageLoader) { - "use strict"; +define(['loading', 'components/groupedcards', 'cardBuilder', 'apphost', 'imageLoader'], function (loading, groupedcards, cardBuilder, appHost, imageLoader) { + 'use strict'; function getLatestPromise(context, params) { loading.show(); var userId = ApiClient.getCurrentUserId(); var parentId = params.topParentId; var options = { - IncludeItemTypes: "Episode", + IncludeItemTypes: 'Episode', Limit: 30, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb" + EnableImageTypes: 'Primary,Backdrop,Thumb' }; - return ApiClient.getJSON(ApiClient.getUrl("Users/" + userId + "/Items/Latest", options)); + return ApiClient.getJSON(ApiClient.getUrl('Users/' + userId + '/Items/Latest', options)); } function loadLatest(context, params, promise) { promise.then(function (items) { - var html = ""; - appHost.supports("imageanalysis"); + var html = ''; + appHost.supports('imageanalysis'); html += cardBuilder.getCardsHtml({ items: items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, showTitle: true, showSeriesYear: true, @@ -36,12 +36,12 @@ define(["loading", "components/groupedcards", "cardBuilder", "apphost", "imageLo overlayPlayButton: true, lines: 2 }); - var elem = context.querySelector("#latestEpisodes"); + var elem = context.querySelector('#latestEpisodes'); elem.innerHTML = html; imageLoader.lazyChildren(elem); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(context); }); }); @@ -59,6 +59,6 @@ define(["loading", "components/groupedcards", "cardBuilder", "apphost", "imageLo loadLatest(tabContent, params, latestPromise); }; - tabContent.querySelector("#latestEpisodes").addEventListener("click", groupedcards.onItemsContainerClick); + tabContent.querySelector('#latestEpisodes').addEventListener('click', groupedcards.onItemsContainerClick); }; }); diff --git a/src/controllers/shows/tvrecommended.js b/src/controllers/shows/tvrecommended.js index d1adb04342..8087a03096 100644 --- a/src/controllers/shows/tvrecommended.js +++ b/src/controllers/shows/tvrecommended.js @@ -1,39 +1,39 @@ -define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "dom", "userSettings", "cardBuilder", "playbackManager", "mainTabsManager", "scrollStyles", "emby-itemscontainer", "emby-button"], function (events, inputManager, libraryMenu, layoutManager, loading, dom, userSettings, cardBuilder, playbackManager, mainTabsManager) { - "use strict"; +define(['events', 'inputManager', 'libraryMenu', 'layoutManager', 'loading', 'dom', 'userSettings', 'cardBuilder', 'playbackManager', 'mainTabsManager', 'globalize', 'scrollStyles', 'emby-itemscontainer', 'emby-button'], function (events, inputManager, libraryMenu, layoutManager, loading, dom, userSettings, cardBuilder, playbackManager, mainTabsManager, globalize) { + 'use strict'; function getTabs() { return [{ - name: Globalize.translate("TabShows") + name: globalize.translate('TabShows') }, { - name: Globalize.translate("TabSuggestions") + name: globalize.translate('TabSuggestions') }, { - name: Globalize.translate("TabLatest") + name: globalize.translate('TabLatest') }, { - name: Globalize.translate("TabUpcoming") + name: globalize.translate('TabUpcoming') }, { - name: Globalize.translate("TabGenres") + name: globalize.translate('TabGenres') }, { - name: Globalize.translate("TabNetworks") + name: globalize.translate('TabNetworks') }, { - name: Globalize.translate("TabEpisodes") + name: globalize.translate('TabEpisodes') }, { - name: Globalize.translate("ButtonSearch"), - cssClass: "searchTabButton" + name: globalize.translate('ButtonSearch'), + cssClass: 'searchTabButton' }]; } function getDefaultTabIndex(folderId) { - switch (userSettings.get("landing-" + folderId)) { - case "suggestions": + switch (userSettings.get('landing-' + folderId)) { + case 'suggestions': return 1; - case "latest": + case 'latest': return 2; - case "favorites": + case 'favorites': return 1; - case "genres": + case 'genres': return 4; default: @@ -43,19 +43,19 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do function setScrollClasses(elem, scrollX) { if (scrollX) { - elem.classList.add("hiddenScrollX"); + elem.classList.add('hiddenScrollX'); if (layoutManager.tv) { - elem.classList.add("smoothScrollX"); + elem.classList.add('smoothScrollX'); } - elem.classList.add("scrollX"); - elem.classList.remove("vertical-wrap"); + elem.classList.add('scrollX'); + elem.classList.remove('vertical-wrap'); } else { - elem.classList.remove("hiddenScrollX"); - elem.classList.remove("smoothScrollX"); - elem.classList.remove("scrollX"); - elem.classList.add("vertical-wrap"); + elem.classList.remove('hiddenScrollX'); + elem.classList.remove('smoothScrollX'); + elem.classList.remove('scrollX'); + elem.classList.add('vertical-wrap'); } } @@ -69,25 +69,25 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do function loadNextUp() { var query = { Limit: 24, - Fields: "PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,SeriesInfo,DateCreated,BasicSyncInfo', UserId: ApiClient.getCurrentUserId(), ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', EnableTotalRecordCount: false }; query.ParentId = libraryMenu.getTopParentId(); ApiClient.getNextUpEpisodes(query).then(function (result) { if (result.Items.length) { - view.querySelector(".noNextUpItems").classList.add("hide"); + view.querySelector('.noNextUpItems').classList.add('hide'); } else { - view.querySelector(".noNextUpItems").classList.remove("hide"); + view.querySelector('.noNextUpItems').classList.remove('hide'); } - var container = view.querySelector("#nextUpItems"); + var container = view.querySelector('#nextUpItems'); cardBuilder.buildCards(result.Items, { itemsContainer: container, preferThumb: true, - shape: "backdrop", + shape: 'backdrop', scalable: true, showTitle: true, showParentTitle: true, @@ -98,7 +98,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do }); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(view); }); }); @@ -109,7 +109,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function loadResume() { @@ -117,28 +117,28 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do var screenWidth = dom.getWindowSize().innerWidth; var limit = screenWidth >= 1600 ? 5 : 6; var options = { - SortBy: "DatePlayed", - SortOrder: "Descending", - IncludeItemTypes: "Episode", - Filters: "IsResumable", + SortBy: 'DatePlayed', + SortOrder: 'Descending', + IncludeItemTypes: 'Episode', + Filters: 'IsResumable', Limit: limit, Recursive: true, - Fields: "PrimaryImageAspectRatio,SeriesInfo,UserData,BasicSyncInfo", - ExcludeLocationTypes: "Virtual", + Fields: 'PrimaryImageAspectRatio,SeriesInfo,UserData,BasicSyncInfo', + ExcludeLocationTypes: 'Virtual', ParentId: parentId, ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Thumb", + EnableImageTypes: 'Primary,Backdrop,Thumb', EnableTotalRecordCount: false }; ApiClient.getItems(ApiClient.getCurrentUserId(), options).then(function (result) { if (result.Items.length) { - view.querySelector("#resumableSection").classList.remove("hide"); + view.querySelector('#resumableSection').classList.remove('hide'); } else { - view.querySelector("#resumableSection").classList.add("hide"); + view.querySelector('#resumableSection').classList.add('hide'); } var allowBottomPadding = !enableScrollX(); - var container = view.querySelector("#resumableItems"); + var container = view.querySelector('#resumableItems'); cardBuilder.buildCards(result.Items, { itemsContainer: container, preferThumb: true, @@ -165,7 +165,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do } function getTabContainers() { - return view.querySelectorAll(".pageTabContent"); + return view.querySelectorAll('.pageTabContent'); } function initTabs() { @@ -177,34 +177,34 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do switch (index) { case 0: - depends.push("controllers/shows/tvshows"); + depends.push('controllers/shows/tvshows'); break; case 1: break; case 2: - depends.push("controllers/shows/tvlatest"); + depends.push('controllers/shows/tvlatest'); break; case 3: - depends.push("controllers/shows/tvupcoming"); + depends.push('controllers/shows/tvupcoming'); break; case 4: - depends.push("controllers/shows/tvgenres"); + depends.push('controllers/shows/tvgenres'); break; case 5: - depends.push("controllers/shows/tvstudios"); + depends.push('controllers/shows/tvstudios'); break; case 6: - depends.push("controllers/shows/episodes"); + depends.push('controllers/shows/episodes'); break; case 7: - depends.push("scripts/searchtab"); + depends.push('scripts/searchtab'); } require(depends, function (controllerFactory) { @@ -224,7 +224,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do controller = self; } else if (index === 7) { controller = new controllerFactory(view, tabContent, { - collectionType: "tvshows", + collectionType: 'tvshows', parentId: params.topParentId }); } else { @@ -263,7 +263,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do } function onPlaybackStop(e, state) { - if (state.NowPlayingItem && state.NowPlayingItem.MediaType == "Video") { + if (state.NowPlayingItem && state.NowPlayingItem.MediaType == 'Video') { renderedTabs = []; mainTabsManager.getTabsElement().triggerTabChange(); } @@ -272,16 +272,16 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do function onWebSocketMessage(e, data) { var msg = data; - if (msg.MessageType === "UserDataChanged" && msg.Data.UserId == ApiClient.getCurrentUserId()) { + if (msg.MessageType === 'UserDataChanged' && msg.Data.UserId == ApiClient.getCurrentUserId()) { renderedTabs = []; } } function onInputCommand(e) { switch (e.detail.command) { - case "search": + case 'search': e.preventDefault(); - Dashboard.navigate("search.html?collectionType=tv&parentId=" + params.topParentId); + Dashboard.navigate('search.html?collectionType=tv&parentId=' + params.topParentId); } } @@ -292,7 +292,7 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do self.initTab = function () { var tabContent = self.tabContent; - setScrollClasses(tabContent.querySelector("#resumableItems"), enableScrollX()); + setScrollClasses(tabContent.querySelector('#resumableItems'), enableScrollX()); }; self.renderTab = function () { @@ -301,34 +301,34 @@ define(["events", "inputManager", "libraryMenu", "layoutManager", "loading", "do var tabControllers = []; var renderedTabs = []; - setScrollClasses(view.querySelector("#resumableItems"), enableScrollX()); - view.addEventListener("viewshow", function (e) { + setScrollClasses(view.querySelector('#resumableItems'), enableScrollX()); + view.addEventListener('viewshow', function (e) { isViewRestored = e.detail.isRestored; initTabs(); - if (!view.getAttribute("data-title")) { + if (!view.getAttribute('data-title')) { var parentId = params.topParentId; if (parentId) { ApiClient.getItem(ApiClient.getCurrentUserId(), parentId).then(function (item) { - view.setAttribute("data-title", item.Name); + view.setAttribute('data-title', item.Name); libraryMenu.setTitle(item.Name); }); } else { - view.setAttribute("data-title", Globalize.translate("TabShows")); - libraryMenu.setTitle(Globalize.translate("TabShows")); + view.setAttribute('data-title', globalize.translate('TabShows')); + libraryMenu.setTitle(globalize.translate('TabShows')); } } - events.on(playbackManager, "playbackstop", onPlaybackStop); - events.on(ApiClient, "message", onWebSocketMessage); + events.on(playbackManager, 'playbackstop', onPlaybackStop); + events.on(ApiClient, 'message', onWebSocketMessage); inputManager.on(window, onInputCommand); }); - view.addEventListener("viewbeforehide", function (e) { + view.addEventListener('viewbeforehide', function (e) { inputManager.off(window, onInputCommand); - events.off(playbackManager, "playbackstop", onPlaybackStop); - events.off(ApiClient, "message", onWebSocketMessage); + events.off(playbackManager, 'playbackstop', onPlaybackStop); + events.off(ApiClient, 'message', onWebSocketMessage); }); - view.addEventListener("viewdestroy", function (e) { + view.addEventListener('viewdestroy', function (e) { tabControllers.forEach(function (t) { if (t.destroy) { t.destroy(); diff --git a/src/controllers/shows/tvshows.js b/src/controllers/shows/tvshows.js index 1dec530540..753516f902 100644 --- a/src/controllers/shows/tvshows.js +++ b/src/controllers/shows/tvshows.js @@ -1,5 +1,5 @@ -define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", "listView", "cardBuilder", "alphaPicker", "emby-itemscontainer"], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, alphaPicker) { - "use strict"; +define(['layoutManager', 'loading', 'events', 'libraryBrowser', 'imageLoader', 'listView', 'cardBuilder', 'alphaPicker', 'userSettings', 'globalize', 'emby-itemscontainer'], function (layoutManager, loading, events, libraryBrowser, imageLoader, listView, cardBuilder, alphaPicker, userSettings, globalize) { + 'use strict'; return function (view, params, tabContent) { function getPageData(context) { @@ -9,18 +9,22 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Series", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Series', Recursive: true, - Fields: "PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'PrimaryImageAspectRatio,BasicSyncInfo', ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", - StartIndex: 0, - Limit: pageSize + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = params.topParentId; libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -34,7 +38,7 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " function getSavedQueryKey(context) { if (!context.savedQueryKey) { - context.savedQueryKey = libraryBrowser.getSavedQueryKey("series"); + context.savedQueryKey = libraryBrowser.getSavedQueryKey('series'); } return context.savedQueryKey; @@ -42,17 +46,17 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " function onViewStyleChange() { var viewStyle = self.getCurrentViewStyle(); - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems(page) { @@ -65,7 +69,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex += query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(tabContent); } @@ -74,7 +80,9 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " return; } - query.StartIndex -= query.Limit; + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(tabContent); } @@ -92,45 +100,45 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " filterButton: false }); var viewStyle = self.getCurrentViewStyle(); - if (viewStyle == "Thumb") { + if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "tvshows", + context: 'tvshows', overlayMoreButton: true, showTitle: true, centerText: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, - context: "tvshows", + context: 'tvshows', cardLayout: true, showTitle: true, showYear: true, centerText: true }); - } else if (viewStyle == "Banner") { + } else if (viewStyle == 'Banner') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "banner", + shape: 'banner', preferBanner: true, - context: "tvshows" + context: 'tvshows' }); - } else if (viewStyle == "List") { + } else if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, - context: "tvshows", + context: 'tvshows', sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "portrait", - context: "tvshows", + shape: 'portrait', + context: 'tvshows', showTitle: true, showYear: true, centerText: true, @@ -139,8 +147,8 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "portrait", - context: "tvshows", + shape: 'portrait', + context: 'tvshows', centerText: true, lazy: true, overlayMoreButton: true, @@ -150,30 +158,30 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } var i; var length; - var elems = tabContent.querySelectorAll(".paging"); + var elems = tabContent.querySelectorAll('.paging'); for (i = 0, length = elems.length; i < length; i++) { elems[i].innerHTML = pagingHtml; } - elems = tabContent.querySelectorAll(".btnNextPage"); + elems = tabContent.querySelectorAll('.btnNextPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onNextPageClick); + elems[i].addEventListener('click', onNextPageClick); } - elems = tabContent.querySelectorAll(".btnPreviousPage"); + elems = tabContent.querySelectorAll('.btnPreviousPage'); for (i = 0, length = elems.length; i < length; i++) { - elems[i].addEventListener("click", onPreviousPageClick); + elems[i].addEventListener('click', onPreviousPageClick); } - var itemsContainer = tabContent.querySelector(".itemsContainer"); + var itemsContainer = tabContent.querySelector('.itemsContainer'); itemsContainer.innerHTML = html; imageLoader.lazyChildren(itemsContainer); libraryBrowser.saveQueryValues(getSavedQueryKey(page), query); loading.hide(); isLoading = false; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); @@ -185,18 +193,17 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " } var self = this; - var pageSize = 100; var data = {}; var isLoading = false; self.showFilterMenu = function () { - require(["components/filterdialog/filterdialog"], function (filterDialogFactory) { + require(['components/filterdialog/filterdialog'], function (filterDialogFactory) { var filterDialog = new filterDialogFactory({ query: getQuery(tabContent), - mode: "series", + mode: 'series', serverId: ApiClient.serverId() }); - events.on(filterDialog, "filterchange", function () { + events.on(filterDialog, 'filterchange', function () { getQuery(tabContent).StartIndex = 0; reloadItems(tabContent); }); @@ -209,9 +216,10 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }; function initPage(tabContent) { - var alphaPickerElement = tabContent.querySelector(".alphaPicker"); + var alphaPickerElement = tabContent.querySelector('.alphaPicker'); + var itemsContainer = tabContent.querySelector('.itemsContainer'); - alphaPickerElement.addEventListener("alphavaluechanged", function (e) { + alphaPickerElement.addEventListener('alphavaluechanged', function (e) { var newValue = e.detail.value; var query = getQuery(tabContent); query.NameStartsWithOrGreater = newValue; @@ -220,38 +228,36 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " }); self.alphaPicker = new alphaPicker({ element: alphaPickerElement, - valueChangeEvent: "click" + valueChangeEvent: 'click' }); - if (layoutManager.desktop || layoutManager.mobile) { - tabContent.querySelector(".alphaPicker").classList.add("alphabetPicker-right"); - var itemsContainer = tabContent.querySelector(".itemsContainer"); - itemsContainer.classList.remove("padded-left-withalphapicker"); - itemsContainer.classList.add("padded-right-withalphapicker"); - } - tabContent.querySelector(".btnFilter").addEventListener("click", function () { + tabContent.querySelector('.alphaPicker').classList.add('alphabetPicker-right'); + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + itemsContainer.classList.add('padded-right-withalphapicker'); + + tabContent.querySelector('.btnFilter').addEventListener('click', function () { self.showFilterMenu(); }); - tabContent.querySelector(".btnSort").addEventListener("click", function (e) { + tabContent.querySelector('.btnSort').addEventListener('click', function (e) { libraryBrowser.showSortMenu({ items: [{ - name: Globalize.translate("OptionNameSort"), - id: "SortName" + name: globalize.translate('OptionNameSort'), + id: 'SortName' }, { - name: Globalize.translate("OptionImdbRating"), - id: "CommunityRating,SortName" + name: globalize.translate('OptionImdbRating'), + id: 'CommunityRating,SortName' }, { - name: Globalize.translate("OptionDateAdded"), - id: "DateCreated,SortName" + name: globalize.translate('OptionDateAdded'), + id: 'DateCreated,SortName' }, { - name: Globalize.translate("OptionDatePlayed"), - id: "DatePlayed,SortName" + name: globalize.translate('OptionDatePlayed'), + id: 'DatePlayed,SortName' }, { - name: Globalize.translate("OptionParentalRating"), - id: "OfficialRating,SortName" + name: globalize.translate('OptionParentalRating'), + id: 'OfficialRating,SortName' }, { - name: Globalize.translate("OptionReleaseDate"), - id: "PremiereDate,SortName" + name: globalize.translate('OptionReleaseDate'), + id: 'PremiereDate,SortName' }], callback: function () { getQuery(tabContent).StartIndex = 0; @@ -261,11 +267,11 @@ define(["layoutManager", "loading", "events", "libraryBrowser", "imageLoader", " button: e.target }); }); - var btnSelectView = tabContent.querySelector(".btnSelectView"); - btnSelectView.addEventListener("click", function (e) { - libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), "Banner,List,Poster,PosterCard,Thumb,ThumbCard".split(",")); + var btnSelectView = tabContent.querySelector('.btnSelectView'); + btnSelectView.addEventListener('click', function (e) { + libraryBrowser.showLayoutMenu(e.target, self.getCurrentViewStyle(), 'Banner,List,Poster,PosterCard,Thumb,ThumbCard'.split(',')); }); - btnSelectView.addEventListener("layoutchange", function (e) { + btnSelectView.addEventListener('layoutchange', function (e) { var viewStyle = e.detail.viewStyle; getPageData(tabContent).view = viewStyle; libraryBrowser.saveViewSetting(getSavedQueryKey(tabContent), viewStyle); diff --git a/src/controllers/shows/tvstudios.js b/src/controllers/shows/tvstudios.js index 4e715e1fd7..1051bfa10b 100644 --- a/src/controllers/shows/tvstudios.js +++ b/src/controllers/shows/tvstudios.js @@ -1,5 +1,5 @@ -define(["loading", "libraryBrowser", "cardBuilder", "apphost"], function (loading, libraryBrowser, cardBuilder, appHost) { - "use strict"; +define(['loading', 'libraryBrowser', 'cardBuilder', 'apphost'], function (loading, libraryBrowser, cardBuilder, appHost) { + 'use strict'; function getQuery(params) { var key = getSavedQueryKey(); @@ -8,11 +8,11 @@ define(["loading", "libraryBrowser", "cardBuilder", "apphost"], function (loadin if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Series", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Series', Recursive: true, - Fields: "DateCreated,PrimaryImageAspectRatio", + Fields: 'DateCreated,PrimaryImageAspectRatio', StartIndex: 0 } }; @@ -23,7 +23,7 @@ define(["loading", "libraryBrowser", "cardBuilder", "apphost"], function (loadin } function getSavedQueryKey() { - return libraryBrowser.getSavedQueryKey("studios"); + return libraryBrowser.getSavedQueryKey('studios'); } function getPromise(context, params) { @@ -34,20 +34,20 @@ define(["loading", "libraryBrowser", "cardBuilder", "apphost"], function (loadin function reloadItems(context, params, promise) { promise.then(function (result) { - var elem = context.querySelector("#items"); + var elem = context.querySelector('#items'); cardBuilder.buildCards(result.Items, { itemsContainer: elem, - shape: "backdrop", + shape: 'backdrop', preferThumb: true, showTitle: true, scalable: true, centerText: true, overlayMoreButton: true, - context: "tvshows" + context: 'tvshows' }); loading.hide(); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(context); }); }); diff --git a/src/controllers/shows/tvupcoming.js b/src/controllers/shows/tvupcoming.js index f85278195f..d57a5ae3cd 100644 --- a/src/controllers/shows/tvupcoming.js +++ b/src/controllers/shows/tvupcoming.js @@ -1,18 +1,18 @@ -define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", "apphost", "imageLoader", "scrollStyles", "emby-itemscontainer"], function (layoutManager, loading, datetime, libraryBrowser, cardBuilder, appHost, imageLoader) { - "use strict"; +define(['layoutManager', 'loading', 'datetime', 'libraryBrowser', 'cardBuilder', 'apphost', 'imageLoader', 'globalize', 'scrollStyles', 'emby-itemscontainer'], function (layoutManager, loading, datetime, libraryBrowser, cardBuilder, appHost, imageLoader, globalize) { + 'use strict'; function getUpcomingPromise(context, params) { loading.show(); var query = { Limit: 48, - Fields: "AirTime,UserData", + Fields: 'AirTime,UserData', UserId: ApiClient.getCurrentUserId(), ImageTypeLimit: 1, - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', EnableTotalRecordCount: false }; query.ParentId = params.topParentId; - return ApiClient.getJSON(ApiClient.getUrl("Shows/Upcoming", query)); + return ApiClient.getJSON(ApiClient.getUrl('Shows/Upcoming', query)); } function loadUpcoming(context, params, promise) { @@ -20,12 +20,12 @@ define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", var items = result.Items; if (items.length) { - context.querySelector(".noItemsMessage").style.display = "none"; + context.querySelector('.noItemsMessage').style.display = 'none'; } else { - context.querySelector(".noItemsMessage").style.display = "block"; + context.querySelector('.noItemsMessage').style.display = 'block'; } - renderUpcoming(context.querySelector("#upcomingItems"), items); + renderUpcoming(context.querySelector('#upcomingItems'), items); loading.hide(); }); } @@ -35,30 +35,30 @@ define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", } function getThumbShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function renderUpcoming(elem, items) { var i; var length; var groups = []; - var currentGroupName = ""; + var currentGroupName = ''; var currentGroup = []; for (i = 0, length = items.length; i < length; i++) { var item = items[i]; - var dateText = ""; + var dateText = ''; if (item.PremiereDate) { try { var premiereDate = datetime.parseISO8601Date(item.PremiereDate, true); - dateText = datetime.isRelativeDay(premiereDate, -1) ? Globalize.translate("Yesterday") : datetime.toLocaleDateString(premiereDate, { - weekday: "long", - month: "short", - day: "numeric" + dateText = datetime.isRelativeDay(premiereDate, -1) ? globalize.translate('Yesterday') : datetime.toLocaleDateString(premiereDate, { + weekday: 'long', + month: 'short', + day: 'numeric' }); } catch (err) { - console.log('error parsing timestamp for upcoming tv shows'); + console.error('error parsing timestamp for upcoming tv shows'); } } @@ -77,20 +77,20 @@ define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", } } - var html = ""; + var html = ''; for (i = 0, length = groups.length; i < length; i++) { var group = groups[i]; html += '
'; - html += '

' + group.name + "

"; + html += '

' + group.name + '

'; var allowBottomPadding = true; if (enableScrollX()) { allowBottomPadding = false; - var scrollXClass = "scrollX hiddenScrollX"; + var scrollXClass = 'scrollX hiddenScrollX'; if (layoutManager.tv) { - scrollXClass += " smoothScrollX"; + scrollXClass += ' smoothScrollX'; } html += '
'; @@ -98,7 +98,7 @@ define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", html += '
'; } - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); supportsImageAnalysis = false; html += cardBuilder.getCardsHtml({ items: group.items, @@ -116,8 +116,8 @@ define(["layoutManager", "loading", "datetime", "libraryBrowser", "cardBuilder", overlayMoreButton: true, missingIndicator: false }); - html += "
"; - html += "
"; + html += '
'; + html += ''; } elem.innerHTML = html; diff --git a/src/controllers/streamingsettings.js b/src/controllers/streamingsettings.js deleted file mode 100644 index 6c85034458..0000000000 --- a/src/controllers/streamingsettings.js +++ /dev/null @@ -1,60 +0,0 @@ -define(["jQuery", "libraryMenu", "loading"], function ($, libraryMenu, loading) { - "use strict"; - - function loadPage(page, config) { - $("#txtRemoteClientBitrateLimit", page).val(config.RemoteClientBitrateLimit / 1e6 || ""); - loading.hide(); - } - - function onSubmit() { - loading.show(); - var form = this; - ApiClient.getServerConfiguration().then(function (config) { - config.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($("#txtRemoteClientBitrateLimit", form).val() || "0")); - ApiClient.updateServerConfiguration(config).then(Dashboard.processServerConfigurationUpdateResult); - }); - return false; - } - - function getTabs() { - return [{ - href: "encodingsettings.html", - name: Globalize.translate("Transcoding") - }, { - href: "playbackconfiguration.html", - name: Globalize.translate("TabResumeSettings") - }, { - href: "streamingsettings.html", - name: Globalize.translate("TabStreaming") - }]; - } - - $(document).on("pageinit", "#streamingSettingsPage", function () { - var page = this; - $("#btnSelectTranscodingTempPath", page).on("click.selectDirectory", function () { - require(["directorybrowser"], function (directoryBrowser) { - var picker = new directoryBrowser(); - picker.show({ - callback: function (path) { - if (path) { - $("#txtTranscodingTempPath", page).val(path); - } - - picker.close(); - }, - validateWriteable: true, - header: Globalize.translate("HeaderSelectTranscodingPath"), - instruction: Globalize.translate("HeaderSelectTranscodingPathHelp") - }); - }); - }); - $(".streamingSettingsForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#streamingSettingsPage", function () { - loading.show(); - libraryMenu.setTabs("playback", 2, getTabs); - var page = this; - ApiClient.getServerConfiguration().then(function (config) { - loadPage(page, config); - }); - }); -}); diff --git a/src/controllers/user/display.js b/src/controllers/user/display.js index f348f28750..3aeb7db8ce 100644 --- a/src/controllers/user/display.js +++ b/src/controllers/user/display.js @@ -1,19 +1,19 @@ -define(["displaySettings", "userSettingsBuilder", "userSettings", "autoFocuser"], function (DisplaySettings, userSettingsBuilder, currentUserSettings, autoFocuser) { - "use strict"; +define(['displaySettings', 'userSettings', 'autoFocuser'], function (DisplaySettings, userSettings, autoFocuser) { + 'use strict'; return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { - e.returnValue = "You currently have unsaved changes. Are you sure you wish to leave?"; + e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?'; } } var settingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder(); - view.addEventListener("viewshow", function () { - window.addEventListener("beforeunload", onBeforeUnload); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + view.addEventListener('viewshow', function () { + window.addEventListener('beforeunload', onBeforeUnload); if (settingsInstance) { settingsInstance.loadData(); @@ -21,26 +21,26 @@ define(["displaySettings", "userSettingsBuilder", "userSettings", "autoFocuser"] settingsInstance = new DisplaySettings({ serverId: ApiClient.serverId(), userId: userId, - element: view.querySelector(".settingsContainer"), - userSettings: userSettings, + element: view.querySelector('.settingsContainer'), + userSettings: currentSettings, enableSaveButton: false, enableSaveConfirmation: false, autoFocus: autoFocuser.isEnabled() }); } }); - view.addEventListener("change", function () { + view.addEventListener('change', function () { hasChanges = true; }); - view.addEventListener("viewbeforehide", function () { - window.removeEventListener("beforeunload", onBeforeUnload); + view.addEventListener('viewbeforehide', function () { + window.removeEventListener('beforeunload', onBeforeUnload); hasChanges = false; if (settingsInstance) { settingsInstance.submit(); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (settingsInstance) { settingsInstance.destroy(); settingsInstance = null; diff --git a/src/controllers/user/home.js b/src/controllers/user/home.js index 7f12efc7fb..aa7d147c31 100644 --- a/src/controllers/user/home.js +++ b/src/controllers/user/home.js @@ -1,19 +1,19 @@ -define(["homescreenSettings", "userSettingsBuilder", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (HomescreenSettings, userSettingsBuilder, dom, globalize, loading, currentUserSettings, autoFocuser) { - "use strict"; +define(['homescreenSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (HomescreenSettings, dom, globalize, loading, userSettings, autoFocuser) { + 'use strict'; return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { - e.returnValue = "You currently have unsaved changes. Are you sure you wish to leave?"; + e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?'; } } var homescreenSettingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder(); - view.addEventListener("viewshow", function () { - window.addEventListener("beforeunload", onBeforeUnload); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + view.addEventListener('viewshow', function () { + window.addEventListener('beforeunload', onBeforeUnload); if (homescreenSettingsInstance) { homescreenSettingsInstance.loadData(); @@ -21,25 +21,25 @@ define(["homescreenSettings", "userSettingsBuilder", "dom", "globalize", "loadin homescreenSettingsInstance = new HomescreenSettings({ serverId: ApiClient.serverId(), userId: userId, - element: view.querySelector(".homeScreenSettingsContainer"), - userSettings: userSettings, + element: view.querySelector('.homeScreenSettingsContainer'), + userSettings: currentSettings, enableSaveButton: false, enableSaveConfirmation: false, autoFocus: autoFocuser.isEnabled() }); } }); - view.addEventListener("change", function () { + view.addEventListener('change', function () { hasChanges = true; }); - view.addEventListener("viewbeforehide", function () { + view.addEventListener('viewbeforehide', function () { hasChanges = false; if (homescreenSettingsInstance) { homescreenSettingsInstance.submit(); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (homescreenSettingsInstance) { homescreenSettingsInstance.destroy(); homescreenSettingsInstance = null; diff --git a/src/controllers/user/menu.js b/src/controllers/user/menu.js index 4e0a7824b7..df5864dbdb 100644 --- a/src/controllers/user/menu.js +++ b/src/controllers/user/menu.js @@ -1,42 +1,62 @@ -define(["apphost", "connectionManager", "listViewStyle", "emby-button"], function(appHost, connectionManager) { - "use strict"; +define(['apphost', 'connectionManager', 'layoutManager', 'listViewStyle', 'emby-button'], function(appHost, connectionManager, layoutManager) { + 'use strict'; return function(view, params) { - view.querySelector(".btnLogout").addEventListener("click", function() { + view.querySelector('.btnLogout').addEventListener('click', function() { Dashboard.logout(); }); - view.addEventListener("viewshow", function() { + view.querySelector('.selectServer').addEventListener('click', function () { + Dashboard.selectServer(); + }); + + view.querySelector('.clientSettings').addEventListener('click', function () { + window.NativeShell.openClientSettings(); + }); + + view.addEventListener('viewshow', function() { // this page can also be used by admins to change user preferences from the user edit page var userId = params.userId || Dashboard.getCurrentUserId(); var page = this; - page.querySelector(".lnkMyProfile").setAttribute("href", "myprofile.html?userId=" + userId); - page.querySelector(".lnkDisplayPreferences").setAttribute("href", "mypreferencesdisplay.html?userId=" + userId); - page.querySelector(".lnkHomePreferences").setAttribute("href", "mypreferenceshome.html?userId=" + userId); - page.querySelector(".lnkPlaybackPreferences").setAttribute("href", "mypreferencesplayback.html?userId=" + userId); - page.querySelector(".lnkSubtitlePreferences").setAttribute("href", "mypreferencessubtitles.html?userId=" + userId); + page.querySelector('.lnkMyProfile').setAttribute('href', 'myprofile.html?userId=' + userId); + page.querySelector('.lnkDisplayPreferences').setAttribute('href', 'mypreferencesdisplay.html?userId=' + userId); + page.querySelector('.lnkHomePreferences').setAttribute('href', 'mypreferenceshome.html?userId=' + userId); + page.querySelector('.lnkPlaybackPreferences').setAttribute('href', 'mypreferencesplayback.html?userId=' + userId); + page.querySelector('.lnkSubtitlePreferences').setAttribute('href', 'mypreferencessubtitles.html?userId=' + userId); - if (appHost.supports("multiserver")) { - page.querySelector(".selectServer").classList.remove("hide"); + if (window.NativeShell && window.NativeShell.AppHost.supports('clientsettings')) { + page.querySelector('.clientSettings').classList.remove('hide'); } else { - page.querySelector(".selectServer").classList.add("hide"); + page.querySelector('.clientSettings').classList.add('hide'); + } + + if (appHost.supports('multiserver')) { + page.querySelector('.selectServer').classList.remove('hide'); + } else { + page.querySelector('.selectServer').classList.add('hide'); } // hide the actions if user preferences are being edited for a different user if (params.userId && params.userId !== Dashboard.getCurrentUserId) { - page.querySelector(".userSection").classList.add("hide"); - page.querySelector(".adminSection").classList.add("hide"); + page.querySelector('.userSection').classList.add('hide'); + page.querySelector('.adminSection').classList.add('hide'); + } + + if (layoutManager.mobile) { + page.querySelector('.headerUsername').classList.add('hide'); + page.querySelector('.adminSection').classList.add('hide'); + page.querySelector('.userSection').classList.add('hide'); } ApiClient.getUser(userId).then(function(user) { - page.querySelector(".headerUsername").innerHTML = user.Name; + page.querySelector('.headerUsername').innerHTML = user.Name; if (!user.Policy.IsAdministrator) { - page.querySelector(".adminSection").classList.add("hide"); + page.querySelector('.adminSection').classList.add('hide'); } }); - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(view); }); }); diff --git a/src/controllers/user/playback.js b/src/controllers/user/playback.js index 3def9d1931..e945a46aab 100644 --- a/src/controllers/user/playback.js +++ b/src/controllers/user/playback.js @@ -1,19 +1,19 @@ -define(["playbackSettings", "userSettingsBuilder", "dom", "globalize", "loading", "userSettings", "autoFocuser", "listViewStyle"], function (PlaybackSettings, userSettingsBuilder, dom, globalize, loading, currentUserSettings, autoFocuser) { - "use strict"; +define(['playbackSettings', 'dom', 'globalize', 'loading', 'userSettings', 'autoFocuser', 'listViewStyle'], function (PlaybackSettings, dom, globalize, loading, userSettings, autoFocuser) { + 'use strict'; return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { - e.returnValue = "You currently have unsaved changes. Are you sure you wish to leave?"; + e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?'; } } var settingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder(); - view.addEventListener("viewshow", function () { - window.addEventListener("beforeunload", onBeforeUnload); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + view.addEventListener('viewshow', function () { + window.addEventListener('beforeunload', onBeforeUnload); if (settingsInstance) { settingsInstance.loadData(); @@ -21,25 +21,25 @@ define(["playbackSettings", "userSettingsBuilder", "dom", "globalize", "loading" settingsInstance = new PlaybackSettings({ serverId: ApiClient.serverId(), userId: userId, - element: view.querySelector(".settingsContainer"), - userSettings: userSettings, + element: view.querySelector('.settingsContainer'), + userSettings: currentSettings, enableSaveButton: false, enableSaveConfirmation: false, autoFocus: autoFocuser.isEnabled() }); } }); - view.addEventListener("change", function () { + view.addEventListener('change', function () { hasChanges = true; }); - view.addEventListener("viewbeforehide", function () { + view.addEventListener('viewbeforehide', function () { hasChanges = false; if (settingsInstance) { settingsInstance.submit(); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (settingsInstance) { settingsInstance.destroy(); settingsInstance = null; diff --git a/src/controllers/user/profile.js b/src/controllers/user/profile.js index 3b85cb1d8c..0f4f2c7bc2 100644 --- a/src/controllers/user/profile.js +++ b/src/controllers/user/profile.js @@ -1,31 +1,31 @@ -define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "emby-button"], function (UserPasswordPage, loading, libraryMenu, appHost) { - "use strict"; +define(['controllers/userpasswordpage', 'loading', 'libraryMenu', 'apphost', 'globalize', 'emby-button'], function (UserPasswordPage, loading, libraryMenu, appHost, globalize) { + 'use strict'; function reloadUser(page) { - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); loading.show(); ApiClient.getUser(userId).then(function (user) { - page.querySelector(".username").innerHTML = user.Name; + page.querySelector('.username').innerHTML = user.Name; libraryMenu.setTitle(user.Name); - var imageUrl = "assets/img/avatar.png"; + var imageUrl = 'assets/img/avatar.png'; if (user.PrimaryImageTag) { imageUrl = ApiClient.getUserImageUrl(user.Id, { tag: user.PrimaryImageTag, - type: "Primary" + type: 'Primary' }); } - var userImage = page.querySelector("#image"); - userImage.style.backgroundImage = "url(" + imageUrl + ")"; + var userImage = page.querySelector('#image'); + userImage.style.backgroundImage = 'url(' + imageUrl + ')'; Dashboard.getCurrentUser().then(function (loggedInUser) { if (user.PrimaryImageTag) { - page.querySelector("#btnAddImage").classList.add("hide"); - page.querySelector("#btnDeleteImage").classList.remove("hide"); - } else if (appHost.supports("fileinput") && (loggedInUser.Policy.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) { - page.querySelector("#btnDeleteImage").classList.add("hide"); - page.querySelector("#btnAddImage").classList.remove("hide"); + page.querySelector('#btnAddImage').classList.add('hide'); + page.querySelector('#btnDeleteImage').classList.remove('hide'); + } else if (appHost.supports('fileinput') && (loggedInUser.Policy.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) { + page.querySelector('#btnDeleteImage').classList.add('hide'); + page.querySelector('#btnAddImage').classList.remove('hide'); } }); loading.hide(); @@ -36,8 +36,8 @@ define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "em loading.hide(); switch (evt.target.error.code) { case evt.target.error.NOT_FOUND_ERR: - require(["toast"], function (toast) { - toast(Globalize.translate("FileNotFound")); + require(['toast'], function (toast) { + toast(globalize.translate('FileNotFound')); }); break; case evt.target.error.ABORT_ERR: @@ -45,24 +45,24 @@ define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "em break; case evt.target.error.NOT_READABLE_ERR: default: - require(["toast"], function (toast) { - toast(Globalize.translate("FileReadError")); + require(['toast'], function (toast) { + toast(globalize.translate('FileReadError')); }); } } function onFileReaderAbort(evt) { loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("FileReadCancelled")); + require(['toast'], function (toast) { + toast(globalize.translate('FileReadCancelled')); }); } function setFiles(page, files) { - var userImage = page.querySelector("#image"); + var userImage = page.querySelector('#image'); var file = files[0]; - if (!file || !file.type.match("image.*")) { + if (!file || !file.type.match('image.*')) { return false; } @@ -70,9 +70,9 @@ define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "em reader.onerror = onFileReaderError; reader.onabort = onFileReaderAbort; reader.onload = function (evt) { - userImage.style.backgroundImage = "url(" + evt.target.result + ")"; - var userId = getParameterByName("userId"); - ApiClient.uploadUserImage(userId, "Primary", file).then(function () { + userImage.style.backgroundImage = 'url(' + evt.target.result + ')'; + var userId = getParameterByName('userId'); + ApiClient.uploadUserImage(userId, 'Primary', file).then(function () { loading.hide(); reloadUser(page); }); @@ -84,22 +84,22 @@ define(["controllers/userpasswordpage", "loading", "libraryMenu", "apphost", "em return function (view, params) { reloadUser(view); new UserPasswordPage(view, params); - view.querySelector("#btnDeleteImage").addEventListener("click", function () { - require(["confirm"], function (confirm) { - confirm(Globalize.translate("DeleteImageConfirmation"), Globalize.translate("DeleteImage")).then(function () { + view.querySelector('#btnDeleteImage').addEventListener('click', function () { + require(['confirm'], function (confirm) { + confirm(globalize.translate('DeleteImageConfirmation'), globalize.translate('DeleteImage')).then(function () { loading.show(); - var userId = getParameterByName("userId"); - ApiClient.deleteUserImage(userId, "primary").then(function () { + var userId = getParameterByName('userId'); + ApiClient.deleteUserImage(userId, 'primary').then(function () { loading.hide(); reloadUser(view); }); }); }); }); - view.querySelector("#btnAddImage").addEventListener("click", function (evt) { - view.querySelector("#uploadImage").click(); + view.querySelector('#btnAddImage').addEventListener('click', function (evt) { + view.querySelector('#uploadImage').click(); }); - view.querySelector("#uploadImage").addEventListener("change", function (evt) { + view.querySelector('#uploadImage').addEventListener('change', function (evt) { setFiles(view, evt.target.files); }); }; diff --git a/src/controllers/user/subtitles.js b/src/controllers/user/subtitles.js index 1f1102194e..152301f31a 100644 --- a/src/controllers/user/subtitles.js +++ b/src/controllers/user/subtitles.js @@ -1,19 +1,19 @@ -define(["subtitleSettings", "userSettingsBuilder", "userSettings", "autoFocuser"], function (SubtitleSettings, userSettingsBuilder, currentUserSettings, autoFocuser) { - "use strict"; +define(['subtitleSettings', 'userSettings', 'autoFocuser'], function (SubtitleSettings, userSettings, autoFocuser) { + 'use strict'; return function (view, params) { function onBeforeUnload(e) { if (hasChanges) { - e.returnValue = "You currently have unsaved changes. Are you sure you wish to leave?"; + e.returnValue = 'You currently have unsaved changes. Are you sure you wish to leave?'; } } var subtitleSettingsInstance; var hasChanges; var userId = params.userId || ApiClient.getCurrentUserId(); - var userSettings = userId === ApiClient.getCurrentUserId() ? currentUserSettings : new userSettingsBuilder(); - view.addEventListener("viewshow", function () { - window.addEventListener("beforeunload", onBeforeUnload); + var currentSettings = userId === ApiClient.getCurrentUserId() ? userSettings : new userSettings(); + view.addEventListener('viewshow', function () { + window.addEventListener('beforeunload', onBeforeUnload); if (subtitleSettingsInstance) { subtitleSettingsInstance.loadData(); @@ -21,25 +21,25 @@ define(["subtitleSettings", "userSettingsBuilder", "userSettings", "autoFocuser" subtitleSettingsInstance = new SubtitleSettings({ serverId: ApiClient.serverId(), userId: userId, - element: view.querySelector(".settingsContainer"), - userSettings: userSettings, + element: view.querySelector('.settingsContainer'), + userSettings: currentSettings, enableSaveButton: false, enableSaveConfirmation: false, autoFocus: autoFocuser.isEnabled() }); } }); - view.addEventListener("change", function () { + view.addEventListener('change', function () { hasChanges = true; }); - view.addEventListener("viewbeforehide", function () { + view.addEventListener('viewbeforehide', function () { hasChanges = false; if (subtitleSettingsInstance) { subtitleSettingsInstance.submit(); } }); - view.addEventListener("viewdestroy", function () { + view.addEventListener('viewdestroy', function () { if (subtitleSettingsInstance) { subtitleSettingsInstance.destroy(); subtitleSettingsInstance = null; diff --git a/src/controllers/useredit.js b/src/controllers/useredit.js index fb6a3f94cd..21ed60cfa9 100644 --- a/src/controllers/useredit.js +++ b/src/controllers/useredit.js @@ -1,8 +1,8 @@ -define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, libraryMenu) { - "use strict"; +define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { + 'use strict'; function loadDeleteFolders(page, user, mediaFolders) { - ApiClient.getJSON(ApiClient.getUrl("Channels", { + ApiClient.getJSON(ApiClient.getUrl('Channels', { SupportsMediaDeletion: true })).then(function (channelsResult) { var i; @@ -10,138 +10,140 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, var folder; var isChecked; var checkedAttribute; - var html = ""; + var html = ''; for (i = 0, length = mediaFolders.length; i < length; i++) { folder = mediaFolders[i]; isChecked = user.Policy.EnableContentDeletion || -1 != user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id); - checkedAttribute = isChecked ? ' checked="checked"' : ""; - html += '"; + checkedAttribute = isChecked ? ' checked="checked"' : ''; + html += ''; } for (i = 0, length = channelsResult.Items.length; i < length; i++) { folder = channelsResult.Items[i]; isChecked = user.Policy.EnableContentDeletion || -1 != user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id); - checkedAttribute = isChecked ? ' checked="checked"' : ""; - html += '"; + checkedAttribute = isChecked ? ' checked="checked"' : ''; + html += ''; } - $(".deleteAccess", page).html(html).trigger("create"); - $("#chkEnableDeleteAllFolders", page).checked(user.Policy.EnableContentDeletion).trigger("change"); + $('.deleteAccess', page).html(html).trigger('create'); + $('#chkEnableDeleteAllFolders', page).checked(user.Policy.EnableContentDeletion).trigger('change'); }); } function loadAuthProviders(page, user, providers) { if (providers.length > 1) { - page.querySelector(".fldSelectLoginProvider").classList.remove("hide"); + page.querySelector('.fldSelectLoginProvider').classList.remove('hide'); } else { - page.querySelector(".fldSelectLoginProvider").classList.add("hide"); + page.querySelector('.fldSelectLoginProvider').classList.add('hide'); } var currentProviderId = user.Policy.AuthenticationProviderId; - page.querySelector(".selectLoginProvider").innerHTML = providers.map(function (provider) { - var selected = provider.Id === currentProviderId || providers.length < 2 ? " selected" : ""; - return '"; + page.querySelector('.selectLoginProvider').innerHTML = providers.map(function (provider) { + var selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : ''; + return ''; }); } function loadPasswordResetProviders(page, user, providers) { if (providers.length > 1) { - page.querySelector(".fldSelectPasswordResetProvider").classList.remove("hide"); + page.querySelector('.fldSelectPasswordResetProvider').classList.remove('hide'); } else { - page.querySelector(".fldSelectPasswordResetProvider").classList.add("hide"); + page.querySelector('.fldSelectPasswordResetProvider').classList.add('hide'); } var currentProviderId = user.Policy.PasswordResetProviderId; - page.querySelector(".selectPasswordResetProvider").innerHTML = providers.map(function (provider) { - var selected = provider.Id === currentProviderId || providers.length < 2 ? " selected" : ""; - return '"; + page.querySelector('.selectPasswordResetProvider').innerHTML = providers.map(function (provider) { + var selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : ''; + return ''; }); } function loadUser(page, user) { currentUser = user; - ApiClient.getJSON(ApiClient.getUrl("Auth/Providers")).then(function (providers) { + ApiClient.getJSON(ApiClient.getUrl('Auth/Providers')).then(function (providers) { loadAuthProviders(page, user, providers); }); - ApiClient.getJSON(ApiClient.getUrl("Auth/PasswordResetProviders")).then(function (providers) { + ApiClient.getJSON(ApiClient.getUrl('Auth/PasswordResetProviders')).then(function (providers) { loadPasswordResetProviders(page, user, providers); }); - ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders", { + ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', { IsHidden: false })).then(function (folders) { loadDeleteFolders(page, user, folders.Items); }); if (user.Policy.IsDisabled) { - $(".disabledUserBanner", page).show(); + $('.disabledUserBanner', page).show(); } else { - $(".disabledUserBanner", page).hide(); + $('.disabledUserBanner', page).hide(); } - $("#txtUserName", page).prop("disabled", "").removeAttr("disabled"); - $("#fldConnectInfo", page).show(); - $(".lnkEditUserPreferences", page).attr("href", "mypreferencesmenu.html?userId=" + user.Id); + $('#txtUserName', page).prop('disabled', '').removeAttr('disabled'); + $('#fldConnectInfo', page).show(); + $('.lnkEditUserPreferences', page).attr('href', 'mypreferencesmenu.html?userId=' + user.Id); libraryMenu.setTitle(user.Name); - page.querySelector(".username").innerHTML = user.Name; - $("#txtUserName", page).val(user.Name); - $("#chkIsAdmin", page).checked(user.Policy.IsAdministrator); - $("#chkDisabled", page).checked(user.Policy.IsDisabled); - $("#chkIsHidden", page).checked(user.Policy.IsHidden); - $("#chkRemoteControlSharedDevices", page).checked(user.Policy.EnableSharedDeviceControl); - $("#chkEnableRemoteControlOtherUsers", page).checked(user.Policy.EnableRemoteControlOfOtherUsers); - $("#chkEnableDownloading", page).checked(user.Policy.EnableContentDownloading); - $("#chkManageLiveTv", page).checked(user.Policy.EnableLiveTvManagement); - $("#chkEnableLiveTvAccess", page).checked(user.Policy.EnableLiveTvAccess); - $("#chkEnableMediaPlayback", page).checked(user.Policy.EnableMediaPlayback); - $("#chkEnableAudioPlaybackTranscoding", page).checked(user.Policy.EnableAudioPlaybackTranscoding); - $("#chkEnableVideoPlaybackTranscoding", page).checked(user.Policy.EnableVideoPlaybackTranscoding); - $("#chkEnableVideoPlaybackRemuxing", page).checked(user.Policy.EnablePlaybackRemuxing); - $("#chkRemoteAccess", page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess); - $("#chkEnableSyncTranscoding", page).checked(user.Policy.EnableSyncTranscoding); - $("#chkEnableConversion", page).checked(user.Policy.EnableMediaConversion || false); - $("#chkEnableSharing", page).checked(user.Policy.EnablePublicSharing); - $("#txtRemoteClientBitrateLimit", page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || ""); - $("#txtLoginAttemptsBeforeLockout", page).val(user.Policy.LoginAttemptsBeforeLockout || "0"); + page.querySelector('.username').innerHTML = user.Name; + $('#txtUserName', page).val(user.Name); + $('#chkIsAdmin', page).checked(user.Policy.IsAdministrator); + $('#chkDisabled', page).checked(user.Policy.IsDisabled); + $('#chkIsHidden', page).checked(user.Policy.IsHidden); + $('#chkRemoteControlSharedDevices', page).checked(user.Policy.EnableSharedDeviceControl); + $('#chkEnableRemoteControlOtherUsers', page).checked(user.Policy.EnableRemoteControlOfOtherUsers); + $('#chkEnableDownloading', page).checked(user.Policy.EnableContentDownloading); + $('#chkManageLiveTv', page).checked(user.Policy.EnableLiveTvManagement); + $('#chkEnableLiveTvAccess', page).checked(user.Policy.EnableLiveTvAccess); + $('#chkEnableMediaPlayback', page).checked(user.Policy.EnableMediaPlayback); + $('#chkEnableAudioPlaybackTranscoding', page).checked(user.Policy.EnableAudioPlaybackTranscoding); + $('#chkEnableVideoPlaybackTranscoding', page).checked(user.Policy.EnableVideoPlaybackTranscoding); + $('#chkEnableVideoPlaybackRemuxing', page).checked(user.Policy.EnablePlaybackRemuxing); + $('#chkForceRemoteSourceTranscoding', page).checked(user.Policy.ForceRemoteSourceTranscoding); + $('#chkRemoteAccess', page).checked(null == user.Policy.EnableRemoteAccess || user.Policy.EnableRemoteAccess); + $('#chkEnableSyncTranscoding', page).checked(user.Policy.EnableSyncTranscoding); + $('#chkEnableConversion', page).checked(user.Policy.EnableMediaConversion || false); + $('#chkEnableSharing', page).checked(user.Policy.EnablePublicSharing); + $('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || ''); + $('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0'); loading.hide(); } function onSaveComplete(page, user) { - Dashboard.navigate("userprofiles.html"); + Dashboard.navigate('userprofiles.html'); loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("SettingsSaved")); + require(['toast'], function (toast) { + toast(globalize.translate('SettingsSaved')); }); } function saveUser(user, page) { - user.Name = $("#txtUserName", page).val(); - user.Policy.IsAdministrator = $("#chkIsAdmin", page).checked(); - user.Policy.IsHidden = $("#chkIsHidden", page).checked(); - user.Policy.IsDisabled = $("#chkDisabled", page).checked(); - user.Policy.EnableRemoteControlOfOtherUsers = $("#chkEnableRemoteControlOtherUsers", page).checked(); - user.Policy.EnableLiveTvManagement = $("#chkManageLiveTv", page).checked(); - user.Policy.EnableLiveTvAccess = $("#chkEnableLiveTvAccess", page).checked(); - user.Policy.EnableSharedDeviceControl = $("#chkRemoteControlSharedDevices", page).checked(); - user.Policy.EnableMediaPlayback = $("#chkEnableMediaPlayback", page).checked(); - user.Policy.EnableAudioPlaybackTranscoding = $("#chkEnableAudioPlaybackTranscoding", page).checked(); - user.Policy.EnableVideoPlaybackTranscoding = $("#chkEnableVideoPlaybackTranscoding", page).checked(); - user.Policy.EnablePlaybackRemuxing = $("#chkEnableVideoPlaybackRemuxing", page).checked(); - user.Policy.EnableContentDownloading = $("#chkEnableDownloading", page).checked(); - user.Policy.EnableSyncTranscoding = $("#chkEnableSyncTranscoding", page).checked(); - user.Policy.EnableMediaConversion = $("#chkEnableConversion", page).checked(); - user.Policy.EnablePublicSharing = $("#chkEnableSharing", page).checked(); - user.Policy.EnableRemoteAccess = $("#chkRemoteAccess", page).checked(); - user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($("#txtRemoteClientBitrateLimit", page).val() || "0")); - user.Policy.LoginAttemptsBeforeLockout = parseInt($("#txtLoginAttemptsBeforeLockout", page).val() || "0"); - user.Policy.AuthenticationProviderId = page.querySelector(".selectLoginProvider").value; - user.Policy.PasswordResetProviderId = page.querySelector(".selectPasswordResetProvider").value; - user.Policy.EnableContentDeletion = $("#chkEnableDeleteAllFolders", page).checked(); - user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $(".chkFolder", page).get().filter(function (c) { + user.Name = $('#txtUserName', page).val(); + user.Policy.IsAdministrator = $('#chkIsAdmin', page).checked(); + user.Policy.IsHidden = $('#chkIsHidden', page).checked(); + user.Policy.IsDisabled = $('#chkDisabled', page).checked(); + user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).checked(); + user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).checked(); + user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).checked(); + user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).checked(); + user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).checked(); + user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).checked(); + user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).checked(); + user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).checked(); + user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).checked(); + user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).checked(); + user.Policy.EnableSyncTranscoding = $('#chkEnableSyncTranscoding', page).checked(); + user.Policy.EnableMediaConversion = $('#chkEnableConversion', page).checked(); + user.Policy.EnablePublicSharing = $('#chkEnableSharing', page).checked(); + user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).checked(); + user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0')); + user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0'); + user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value; + user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value; + user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).checked(); + user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) { return c.checked; }).map(function (c) { - return c.getAttribute("data-id"); + return c.getAttribute('data-id'); }); ApiClient.updateUser(user).then(function () { ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { @@ -151,7 +153,7 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } function onSubmit() { - var page = $(this).parents(".page")[0]; + var page = $(this).parents('.page')[0]; loading.show(); getUser().then(function (result) { saveUser(result, page); @@ -160,7 +162,7 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } function getUser() { - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); return ApiClient.getUser(userId); } @@ -172,25 +174,25 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } var currentUser; - $(document).on("pageinit", "#editUserPage", function () { - $(".editUserProfileForm").off("submit", onSubmit).on("submit", onSubmit); - this.querySelector(".sharingHelp").innerHTML = Globalize.translate("OptionAllowLinkSharingHelp", 30); + $(document).on('pageinit', '#editUserPage', function () { + $('.editUserProfileForm').off('submit', onSubmit).on('submit', onSubmit); + this.querySelector('.sharingHelp').innerHTML = globalize.translate('OptionAllowLinkSharingHelp', 30); var page = this; - $("#chkEnableDeleteAllFolders", this).on("change", function () { + $('#chkEnableDeleteAllFolders', this).on('change', function () { if (this.checked) { - $(".deleteAccess", page).hide(); + $('.deleteAccess', page).hide(); } else { - $(".deleteAccess", page).show(); + $('.deleteAccess', page).show(); } }); ApiClient.getServerConfiguration().then(function (config) { if (config.EnableRemoteAccess) { - page.querySelector(".fldRemoteAccess").classList.remove("hide"); + page.querySelector('.fldRemoteAccess').classList.remove('hide'); } else { - page.querySelector(".fldRemoteAccess").classList.add("hide"); + page.querySelector('.fldRemoteAccess').classList.add('hide'); } }); - }).on("pagebeforeshow", "#editUserPage", function () { + }).on('pagebeforeshow', '#editUserPage', function () { loadData(this); }); }); diff --git a/src/controllers/userlibraryaccess.js b/src/controllers/userlibraryaccess.js index 38418f5190..95664c1eb3 100644 --- a/src/controllers/userlibraryaccess.js +++ b/src/controllers/userlibraryaccess.js @@ -1,79 +1,79 @@ -define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, libraryMenu) { - "use strict"; +define(['jQuery', 'loading', 'libraryMenu', 'globalize', 'fnchecked'], function ($, loading, libraryMenu, globalize) { + 'use strict'; function triggerChange(select) { - var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", false, true); + var evt = document.createEvent('HTMLEvents'); + evt.initEvent('change', false, true); select.dispatchEvent(evt); } function loadMediaFolders(page, user, mediaFolders) { - var html = ""; - html += '

' + Globalize.translate("HeaderLibraries") + "

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

' + globalize.translate('HeaderLibraries') + '

'; html += '
'; for (var i = 0, length = mediaFolders.length; i < length; i++) { var folder = mediaFolders[i]; var isChecked = user.Policy.EnableAllFolders || -1 != user.Policy.EnabledFolders.indexOf(folder.Id); - var checkedAttribute = isChecked ? ' checked="checked"' : ""; - html += '"; + var checkedAttribute = isChecked ? ' checked="checked"' : ''; + html += ''; } - html += "
"; - page.querySelector(".folderAccess").innerHTML = html; - var chkEnableAllFolders = page.querySelector("#chkEnableAllFolders"); + html += ''; + page.querySelector('.folderAccess').innerHTML = html; + var chkEnableAllFolders = page.querySelector('#chkEnableAllFolders'); chkEnableAllFolders.checked = user.Policy.EnableAllFolders; triggerChange(chkEnableAllFolders); } function loadChannels(page, user, channels) { - var html = ""; - html += '

' + Globalize.translate("HeaderChannels") + "

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

' + globalize.translate('HeaderChannels') + '

'; html += '
'; for (var i = 0, length = channels.length; i < length; i++) { var folder = channels[i]; var isChecked = user.Policy.EnableAllChannels || -1 != user.Policy.EnabledChannels.indexOf(folder.Id); - var checkedAttribute = isChecked ? ' checked="checked"' : ""; - html += '"; + var checkedAttribute = isChecked ? ' checked="checked"' : ''; + html += ''; } - html += "
"; - $(".channelAccess", page).show().html(html); + html += ''; + $('.channelAccess', page).show().html(html); if (channels.length) { - $(".channelAccessContainer", page).show(); + $('.channelAccessContainer', page).show(); } else { - $(".channelAccessContainer", page).hide(); + $('.channelAccessContainer', page).hide(); } - $("#chkEnableAllChannels", page).checked(user.Policy.EnableAllChannels).trigger("change"); + $('#chkEnableAllChannels', page).checked(user.Policy.EnableAllChannels).trigger('change'); } function loadDevices(page, user, devices) { - var html = ""; - html += '

' + Globalize.translate("HeaderDevices") + "

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

' + globalize.translate('HeaderDevices') + '

'; html += '
'; for (var i = 0, length = devices.length; i < length; i++) { var device = devices[i]; - var checkedAttribute = user.Policy.EnableAllDevices || -1 != user.Policy.EnabledDevices.indexOf(device.Id) ? ' checked="checked"' : ""; - html += '"; + var checkedAttribute = user.Policy.EnableAllDevices || -1 != user.Policy.EnabledDevices.indexOf(device.Id) ? ' checked="checked"' : ''; + html += ''; } - html += "
"; - $(".deviceAccess", page).show().html(html); - $("#chkEnableAllDevices", page).checked(user.Policy.EnableAllDevices).trigger("change"); + html += ''; + $('.deviceAccess', page).show().html(html); + $('#chkEnableAllDevices', page).checked(user.Policy.EnableAllDevices).trigger('change'); if (user.Policy.IsAdministrator) { - page.querySelector(".deviceAccessContainer").classList.add("hide"); + page.querySelector('.deviceAccessContainer').classList.add('hide'); } else { - page.querySelector(".deviceAccessContainer").classList.remove("hide"); + page.querySelector('.deviceAccessContainer').classList.remove('hide'); } } function loadUser(page, user, loggedInUser, mediaFolders, channels, devices) { - page.querySelector(".username").innerHTML = user.Name; + page.querySelector('.username').innerHTML = user.Name; libraryMenu.setTitle(user.Name); loadChannels(page, user, channels); loadMediaFolders(page, user, mediaFolders); @@ -84,29 +84,29 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, function onSaveComplete(page) { loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("SettingsSaved")); + require(['toast'], function (toast) { + toast(globalize.translate('SettingsSaved')); }); } function saveUser(user, page) { - user.Policy.EnableAllFolders = $("#chkEnableAllFolders", page).checked(); - user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $(".chkFolder", page).get().filter(function (c) { + user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); + user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) { return c.checked; }).map(function (c) { - return c.getAttribute("data-id"); + return c.getAttribute('data-id'); }); - user.Policy.EnableAllChannels = $("#chkEnableAllChannels", page).checked(); - user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $(".chkChannel", page).get().filter(function (c) { + user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); + user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) { return c.checked; }).map(function (c) { - return c.getAttribute("data-id"); + return c.getAttribute('data-id'); }); - user.Policy.EnableAllDevices = $("#chkEnableAllDevices", page).checked(); - user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $(".chkDevice", page).get().filter(function (c) { + user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).checked(); + user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) { return c.checked; }).map(function (c) { - return c.getAttribute("data-id"); + return c.getAttribute('data-id'); }); user.Policy.BlockedChannels = null; user.Policy.BlockedMediaFolders = null; @@ -116,44 +116,44 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } function onSubmit() { - var page = $(this).parents(".page"); + var page = $(this).parents('.page'); loading.show(); - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); ApiClient.getUser(userId).then(function (result) { saveUser(result, page); }); return false; } - $(document).on("pageinit", "#userLibraryAccessPage", function () { + $(document).on('pageinit', '#userLibraryAccessPage', function () { var page = this; - $("#chkEnableAllDevices", page).on("change", function () { + $('#chkEnableAllDevices', page).on('change', function () { if (this.checked) { - $(".deviceAccessListContainer", page).hide(); + $('.deviceAccessListContainer', page).hide(); } else { - $(".deviceAccessListContainer", page).show(); + $('.deviceAccessListContainer', page).show(); } }); - $("#chkEnableAllChannels", page).on("change", function () { + $('#chkEnableAllChannels', page).on('change', function () { if (this.checked) { - $(".channelAccessListContainer", page).hide(); + $('.channelAccessListContainer', page).hide(); } else { - $(".channelAccessListContainer", page).show(); + $('.channelAccessListContainer', page).show(); } }); - page.querySelector("#chkEnableAllFolders").addEventListener("change", function () { + page.querySelector('#chkEnableAllFolders').addEventListener('change', function () { if (this.checked) { - page.querySelector(".folderAccessListContainer").classList.add("hide"); + page.querySelector('.folderAccessListContainer').classList.add('hide'); } else { - page.querySelector(".folderAccessListContainer").classList.remove("hide"); + page.querySelector('.folderAccessListContainer').classList.remove('hide'); } }); - $(".userLibraryAccessForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#userLibraryAccessPage", function () { + $('.userLibraryAccessForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#userLibraryAccessPage', function () { var page = this; loading.show(); var promise1; - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); if (userId) { promise1 = ApiClient.getUser(userId); @@ -166,11 +166,11 @@ define(["jQuery", "loading", "libraryMenu", "fnchecked"], function ($, loading, } var promise2 = Dashboard.getCurrentUser(); - var promise4 = ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders", { + var promise4 = ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', { IsHidden: false })); - var promise5 = ApiClient.getJSON(ApiClient.getUrl("Channels")); - var promise6 = ApiClient.getJSON(ApiClient.getUrl("Devices")); + var promise5 = ApiClient.getJSON(ApiClient.getUrl('Channels')); + var promise6 = ApiClient.getJSON(ApiClient.getUrl('Devices')); Promise.all([promise1, promise2, promise4, promise5, promise6]).then(function (responses) { loadUser(page, responses[0], responses[1], responses[2].Items, responses[3].Items, responses[4].Items); }); diff --git a/src/controllers/usernew.js b/src/controllers/usernew.js index c5d514f914..7654b67222 100644 --- a/src/controllers/usernew.js +++ b/src/controllers/usernew.js @@ -1,51 +1,51 @@ -define(["jQuery", "loading", "fnchecked", "emby-checkbox"], function ($, loading) { - "use strict"; +define(['jQuery', 'loading', 'globalize', 'fnchecked', 'emby-checkbox'], function ($, loading, globalize) { + 'use strict'; function loadMediaFolders(page, mediaFolders) { - var html = ""; - html += '

' + Globalize.translate("HeaderLibraries") + "

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

' + globalize.translate('HeaderLibraries') + '

'; html += '
'; for (var i = 0; i < mediaFolders.length; i++) { var folder = mediaFolders[i]; - html += '"; + html += ''; } - html += "
"; - $(".folderAccess", page).html(html).trigger("create"); - $("#chkEnableAllFolders", page).checked(false).trigger("change"); + html += ''; + $('.folderAccess', page).html(html).trigger('create'); + $('#chkEnableAllFolders', page).checked(true).trigger('change'); } function loadChannels(page, channels) { - var html = ""; - html += '

' + Globalize.translate("HeaderChannels") + "

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

' + globalize.translate('HeaderChannels') + '

'; html += '
'; for (var i = 0; i < channels.length; i++) { var folder = channels[i]; - html += '"; + html += ''; } - html += "
"; - $(".channelAccess", page).show().html(html).trigger("create"); + html += ''; + $('.channelAccess', page).show().html(html).trigger('create'); if (channels.length) { - $(".channelAccessContainer", page).show(); + $('.channelAccessContainer', page).show(); } else { - $(".channelAccessContainer", page).hide(); + $('.channelAccessContainer', page).hide(); } - $("#chkEnableAllChannels", page).checked(false).trigger("change"); + $('#chkEnableAllChannels', page).checked(false).trigger('change'); } function loadUser(page) { - $("#txtUsername", page).val(""); - $("#txtPassword", page).val(""); + $('#txtUsername', page).val(''); + $('#txtPassword', page).val(''); loading.show(); - var promiseFolders = ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders", { + var promiseFolders = ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', { IsHidden: false })); - var promiseChannels = ApiClient.getJSON(ApiClient.getUrl("Channels")); + var promiseChannels = ApiClient.getJSON(ApiClient.getUrl('Channels')); Promise.all([promiseFolders, promiseChannels]).then(function (responses) { loadMediaFolders(page, responses[0].Items); loadChannels(page, responses[1].Items); @@ -55,37 +55,37 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox"], function ($, loading function saveUser(page) { var user = {}; - user.Name = $("#txtUsername", page).val(); - user.Password = $("#txtPassword", page).val(); + user.Name = $('#txtUsername', page).val(); + user.Password = $('#txtPassword', page).val(); ApiClient.createUser(user).then(function (user) { - user.Policy.EnableAllFolders = $("#chkEnableAllFolders", page).checked(); + user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).checked(); user.Policy.EnabledFolders = []; if (!user.Policy.EnableAllFolders) { - user.Policy.EnabledFolders = $(".chkFolder", page).get().filter(function (i) { + user.Policy.EnabledFolders = $('.chkFolder', page).get().filter(function (i) { return i.checked; }).map(function (i) { - return i.getAttribute("data-id"); + return i.getAttribute('data-id'); }); } - user.Policy.EnableAllChannels = $("#chkEnableAllChannels", page).checked(); + user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).checked(); user.Policy.EnabledChannels = []; if (!user.Policy.EnableAllChannels) { - user.Policy.EnabledChannels = $(".chkChannel", page).get().filter(function (i) { + user.Policy.EnabledChannels = $('.chkChannel', page).get().filter(function (i) { return i.checked; }).map(function (i) { - return i.getAttribute("data-id"); + return i.getAttribute('data-id'); }); } ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () { - Dashboard.navigate("useredit.html?userId=" + user.Id); + Dashboard.navigate('useredit.html?userId=' + user.Id); }); }, function (response) { - require(["toast"], function (toast) { - toast(Globalize.translate("DefaultErrorMessage")); + require(['toast'], function (toast) { + toast(globalize.translate('DefaultErrorMessage')); }); loading.hide(); @@ -93,7 +93,7 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox"], function ($, loading } function onSubmit() { - var page = $(this).parents(".page")[0]; + var page = $(this).parents('.page')[0]; loading.show(); saveUser(page); return false; @@ -103,24 +103,24 @@ define(["jQuery", "loading", "fnchecked", "emby-checkbox"], function ($, loading loadUser(page); } - $(document).on("pageinit", "#newUserPage", function () { + $(document).on('pageinit', '#newUserPage', function () { var page = this; - $("#chkEnableAllChannels", page).on("change", function () { + $('#chkEnableAllChannels', page).on('change', function () { if (this.checked) { - $(".channelAccessListContainer", page).hide(); + $('.channelAccessListContainer', page).hide(); } else { - $(".channelAccessListContainer", page).show(); + $('.channelAccessListContainer', page).show(); } }); - $("#chkEnableAllFolders", page).on("change", function () { + $('#chkEnableAllFolders', page).on('change', function () { if (this.checked) { - $(".folderAccessListContainer", page).hide(); + $('.folderAccessListContainer', page).hide(); } else { - $(".folderAccessListContainer", page).show(); + $('.folderAccessListContainer', page).show(); } }); - $(".newUserProfileForm").off("submit", onSubmit).on("submit", onSubmit); - }).on("pageshow", "#newUserPage", function () { + $('.newUserProfileForm').off('submit', onSubmit).on('submit', onSubmit); + }).on('pageshow', '#newUserPage', function () { loadData(this); }); }); diff --git a/src/controllers/userparentalcontrol.js b/src/controllers/userparentalcontrol.js index 2a862912d5..e144271231 100644 --- a/src/controllers/userparentalcontrol.js +++ b/src/controllers/userparentalcontrol.js @@ -1,8 +1,8 @@ -define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper-icon-button-light"], function ($, datetime, loading, libraryMenu) { - "use strict"; +define(['jQuery', 'datetime', 'loading', 'libraryMenu', 'globalize', 'listViewStyle', 'paper-icon-button-light'], function ($, datetime, loading, libraryMenu, globalize) { + 'use strict'; function populateRatings(allParentalRatings, page) { - var html = ""; + var html = ''; html += ""; var i; var length; @@ -14,7 +14,7 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- var lastRating = ratings[ratings.length - 1]; if (lastRating.Value === rating.Value) { - lastRating.Name += "/" + rating.Name; + lastRating.Name += '/' + rating.Name; continue; } } @@ -27,56 +27,56 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- for (i = 0, length = ratings.length; i < length; i++) { rating = ratings[i]; - html += ""; + html += "'; } - $("#selectMaxParentalRating", page).html(html); + $('#selectMaxParentalRating', page).html(html); } function loadUnratedItems(page, user) { var items = [{ - name: Globalize.translate("OptionBlockBooks"), - value: "Book" + name: globalize.translate('OptionBlockBooks'), + value: 'Book' }, { - name: Globalize.translate("OptionBlockChannelContent"), - value: "ChannelContent" + name: globalize.translate('OptionBlockChannelContent'), + value: 'ChannelContent' }, { - name: Globalize.translate("OptionBlockLiveTvChannels"), - value: "LiveTvChannel" + name: globalize.translate('OptionBlockLiveTvChannels'), + value: 'LiveTvChannel' }, { - name: Globalize.translate("OptionBlockMovies"), - value: "Movie" + name: globalize.translate('OptionBlockMovies'), + value: 'Movie' }, { - name: Globalize.translate("OptionBlockMusic"), - value: "Music" + name: globalize.translate('OptionBlockMusic'), + value: 'Music' }, { - name: Globalize.translate("OptionBlockTrailers"), - value: "Trailer" + name: globalize.translate('OptionBlockTrailers'), + value: 'Trailer' }, { - name: Globalize.translate("OptionBlockTvShows"), - value: "Series" + name: globalize.translate('OptionBlockTvShows'), + value: 'Series' }]; - var html = ""; - html += '

' + Globalize.translate("HeaderBlockItemsWithNoRating") + "

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

' + globalize.translate('HeaderBlockItemsWithNoRating') + '

'; html += '
'; for (var i = 0, length = items.length; i < length; i++) { var item = items[i]; - var checkedAttribute = -1 != user.Policy.BlockUnratedItems.indexOf(item.value) ? ' checked="checked"' : ""; - html += '"; + var checkedAttribute = -1 != user.Policy.BlockUnratedItems.indexOf(item.value) ? ' checked="checked"' : ''; + html += ''; } - html += "
"; - $(".blockUnratedItems", page).html(html).trigger("create"); + html += ''; + $('.blockUnratedItems', page).html(html).trigger('create'); } function loadUser(page, user, allParentalRatings) { - page.querySelector(".username").innerHTML = user.Name; + page.querySelector('.username').innerHTML = user.Name; libraryMenu.setTitle(user.Name); loadUnratedItems(page, user); loadBlockedTags(page, user.Policy.BlockedTags); populateRatings(allParentalRatings, page); - var ratingValue = ""; + var ratingValue = ''; if (user.Policy.MaxParentalRating) { for (var i = 0, length = allParentalRatings.length; i < length; i++) { @@ -88,12 +88,12 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- } } - $("#selectMaxParentalRating", page).val(ratingValue); + $('#selectMaxParentalRating', page).val(ratingValue); if (user.Policy.IsAdministrator) { - $(".accessScheduleSection", page).hide(); + $('.accessScheduleSection', page).hide(); } else { - $(".accessScheduleSection", page).show(); + $('.accessScheduleSection', page).show(); } renderAccessSchedule(page, user.Policy.AccessSchedules || []); @@ -106,19 +106,19 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- li += '
'; li += '

'; li += h; - li += "

"; - li += "
"; - li += ''; - return li += ""; - }).join(""); + li += ''; + li += ''; + li += ''; + return li += ''; + }).join(''); if (html) { - html = '
' + html + "
"; + html = '
' + html + '
'; } - var elem = $(".blockedTags", page).html(html).trigger("create"); - $(".btnDeleteTag", elem).on("click", function () { - var tag = this.getAttribute("data-tag"); + var elem = $('.blockedTags', page).html(html).trigger('create'); + $('.btnDeleteTag', elem).on('click', function () { + var tag = this.getAttribute('data-tag'); var newTags = tags.filter(function (t) { return t != tag; }); @@ -132,43 +132,43 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- } function renderAccessSchedule(page, schedules) { - var html = ""; + var html = ''; var index = 0; html += schedules.map(function (a) { - var itemHtml = ""; + var itemHtml = ''; itemHtml += '
'; itemHtml += '
'; itemHtml += '

'; - itemHtml += Globalize.translate("Option" + a.DayOfWeek); - itemHtml += "

"; - itemHtml += '
' + getDisplayTime(a.StartHour) + " - " + getDisplayTime(a.EndHour) + "
"; - itemHtml += "
"; - itemHtml += ''; - itemHtml += "
"; + itemHtml += globalize.translate('Option' + a.DayOfWeek); + itemHtml += ''; + itemHtml += '
' + getDisplayTime(a.StartHour) + ' - ' + getDisplayTime(a.EndHour) + '
'; + itemHtml += ''; + itemHtml += ''; + itemHtml += ''; index++; return itemHtml; - }).join(""); - var accessScheduleList = page.querySelector(".accessScheduleList"); + }).join(''); + var accessScheduleList = page.querySelector('.accessScheduleList'); accessScheduleList.innerHTML = html; - $(".btnDelete", accessScheduleList).on("click", function () { - deleteAccessSchedule(page, schedules, parseInt(this.getAttribute("data-index"))); + $('.btnDelete', accessScheduleList).on('click', function () { + deleteAccessSchedule(page, schedules, parseInt(this.getAttribute('data-index'))); }); } function onSaveComplete(page) { loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("SettingsSaved")); + require(['toast'], function (toast) { + toast(globalize.translate('SettingsSaved')); }); } function saveUser(user, page) { - user.Policy.MaxParentalRating = $("#selectMaxParentalRating", page).val() || null; - user.Policy.BlockUnratedItems = $(".chkUnratedItem", page).get().filter(function (i) { + user.Policy.MaxParentalRating = $('#selectMaxParentalRating', page).val() || null; + user.Policy.BlockUnratedItems = $('.chkUnratedItem', page).get().filter(function (i) { return i.checked; }).map(function (i) { - return i.getAttribute("data-itemtype"); + return i.getAttribute('data-itemtype'); }); user.Policy.AccessSchedules = getSchedulesFromPage(page); user.Policy.BlockedTags = getBlockedTagsFromPage(page); @@ -191,7 +191,7 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- function showSchedulePopup(page, schedule, index) { schedule = schedule || {}; - require(["components/accessschedule/accessschedule"], function (accessschedule) { + require(['components/accessschedule/accessschedule'], function (accessschedule) { accessschedule.show({ schedule: schedule }).then(function (updatedSchedule) { @@ -208,25 +208,25 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- } function getSchedulesFromPage(page) { - return $(".liSchedule", page).map(function () { + return $('.liSchedule', page).map(function () { return { - DayOfWeek: this.getAttribute("data-day"), - StartHour: this.getAttribute("data-start"), - EndHour: this.getAttribute("data-end") + DayOfWeek: this.getAttribute('data-day'), + StartHour: this.getAttribute('data-start'), + EndHour: this.getAttribute('data-end') }; }).get(); } function getBlockedTagsFromPage(page) { - return $(".blockedTag", page).map(function () { - return this.getAttribute("data-tag"); + return $('.blockedTag', page).map(function () { + return this.getAttribute('data-tag'); }).get(); } function showBlockedTagPopup(page) { - require(["prompt"], function (prompt) { + require(['prompt'], function (prompt) { prompt({ - label: Globalize.translate("LabelTag") + label: globalize.translate('LabelTag') }).then(function (value) { var tags = getBlockedTagsFromPage(page); @@ -240,28 +240,28 @@ define(["jQuery", "datetime", "loading", "libraryMenu", "listViewStyle", "paper- window.UserParentalControlPage = { onSubmit: function () { - var page = $(this).parents(".page"); + var page = $(this).parents('.page'); loading.show(); - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); ApiClient.getUser(userId).then(function (result) { saveUser(result, page); }); return false; } }; - $(document).on("pageinit", "#userParentalControlPage", function () { + $(document).on('pageinit', '#userParentalControlPage', function () { var page = this; - $(".btnAddSchedule", page).on("click", function () { + $('.btnAddSchedule', page).on('click', function () { showSchedulePopup(page, {}, -1); }); - $(".btnAddBlockedTag", page).on("click", function () { + $('.btnAddBlockedTag', page).on('click', function () { showBlockedTagPopup(page); }); - $(".userParentalControlForm").off("submit", UserParentalControlPage.onSubmit).on("submit", UserParentalControlPage.onSubmit); - }).on("pageshow", "#userParentalControlPage", function () { + $('.userParentalControlForm').off('submit', UserParentalControlPage.onSubmit).on('submit', UserParentalControlPage.onSubmit); + }).on('pageshow', '#userParentalControlPage', function () { var page = this; loading.show(); - var userId = getParameterByName("userId"); + var userId = getParameterByName('userId'); var promise1 = ApiClient.getUser(userId); var promise2 = ApiClient.getParentalRatings(); Promise.all([promise1, promise2]).then(function (responses) { diff --git a/src/controllers/userpasswordpage.js b/src/controllers/userpasswordpage.js index eeb9b25e3e..186e39b151 100644 --- a/src/controllers/userpasswordpage.js +++ b/src/controllers/userpasswordpage.js @@ -1,67 +1,67 @@ -define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu) { - "use strict"; +define(['loading', 'libraryMenu', 'globalize', 'emby-button'], function (loading, libraryMenu, globalize) { + 'use strict'; function loadUser(page, params) { var userid = params.userId; ApiClient.getUser(userid).then(function (user) { Dashboard.getCurrentUser().then(function (loggedInUser) { libraryMenu.setTitle(user.Name); - page.querySelector(".username").innerHTML = user.Name; + page.querySelector('.username').innerHTML = user.Name; var showPasswordSection = true; var showLocalAccessSection = false; - if ("Guest" == user.ConnectLinkType) { - page.querySelector(".localAccessSection").classList.add("hide"); + if ('Guest' == user.ConnectLinkType) { + page.querySelector('.localAccessSection').classList.add('hide'); showPasswordSection = false; } else if (user.HasConfiguredPassword) { - page.querySelector("#btnResetPassword").classList.remove("hide"); - page.querySelector("#fldCurrentPassword").classList.remove("hide"); + page.querySelector('#btnResetPassword').classList.remove('hide'); + page.querySelector('#fldCurrentPassword').classList.remove('hide'); showLocalAccessSection = true; } else { - page.querySelector("#btnResetPassword").classList.add("hide"); - page.querySelector("#fldCurrentPassword").classList.add("hide"); + page.querySelector('#btnResetPassword').classList.add('hide'); + page.querySelector('#fldCurrentPassword').classList.add('hide'); } if (showPasswordSection && (loggedInUser.Policy.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) { - page.querySelector(".passwordSection").classList.remove("hide"); + page.querySelector('.passwordSection').classList.remove('hide'); } else { - page.querySelector(".passwordSection").classList.add("hide"); + page.querySelector('.passwordSection').classList.add('hide'); } if (showLocalAccessSection && (loggedInUser.Policy.IsAdministrator || user.Policy.EnableUserPreferenceAccess)) { - page.querySelector(".localAccessSection").classList.remove("hide"); + page.querySelector('.localAccessSection').classList.remove('hide'); } else { - page.querySelector(".localAccessSection").classList.add("hide"); + page.querySelector('.localAccessSection').classList.add('hide'); } - var txtEasyPassword = page.querySelector("#txtEasyPassword"); - txtEasyPassword.value = ""; + var txtEasyPassword = page.querySelector('#txtEasyPassword'); + txtEasyPassword.value = ''; if (user.HasConfiguredEasyPassword) { - txtEasyPassword.placeholder = "******"; - page.querySelector("#btnResetEasyPassword").classList.remove("hide"); + txtEasyPassword.placeholder = '******'; + page.querySelector('#btnResetEasyPassword').classList.remove('hide'); } else { - txtEasyPassword.removeAttribute("placeholder"); - txtEasyPassword.placeholder = ""; - page.querySelector("#btnResetEasyPassword").classList.add("hide"); + txtEasyPassword.removeAttribute('placeholder'); + txtEasyPassword.placeholder = ''; + page.querySelector('#btnResetEasyPassword').classList.add('hide'); } - page.querySelector(".chkEnableLocalEasyPassword").checked = user.Configuration.EnableLocalPassword; + page.querySelector('.chkEnableLocalEasyPassword').checked = user.Configuration.EnableLocalPassword; - require(["autoFocuser"], function (autoFocuser) { + require(['autoFocuser'], function (autoFocuser) { autoFocuser.autoFocus(page); }); }); }); - page.querySelector("#txtCurrentPassword").value = ""; - page.querySelector("#txtNewPassword").value = ""; - page.querySelector("#txtNewPasswordConfirm").value = ""; + page.querySelector('#txtCurrentPassword').value = ''; + page.querySelector('#txtNewPassword').value = ''; + page.querySelector('#txtNewPasswordConfirm').value = ''; } return function (view, params) { function saveEasyPassword() { var userId = params.userId; - var easyPassword = view.querySelector("#txtEasyPassword").value; + var easyPassword = view.querySelector('#txtEasyPassword').value; if (easyPassword) { ApiClient.updateEasyPassword(userId, easyPassword).then(function () { @@ -74,12 +74,12 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu function onEasyPasswordSaved(userId) { ApiClient.getUser(userId).then(function (user) { - user.Configuration.EnableLocalPassword = view.querySelector(".chkEnableLocalEasyPassword").checked; + user.Configuration.EnableLocalPassword = view.querySelector('.chkEnableLocalEasyPassword').checked; ApiClient.updateUserConfiguration(user.Id, user.Configuration).then(function () { loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("MessageSettingsSaved")); + require(['toast'], function (toast) { + toast(globalize.translate('MessageSettingsSaved')); }); loadUser(view, params); @@ -89,28 +89,28 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu function savePassword() { var userId = params.userId; - var currentPassword = view.querySelector("#txtCurrentPassword").value; - var newPassword = view.querySelector("#txtNewPassword").value; + var currentPassword = view.querySelector('#txtCurrentPassword').value; + var newPassword = view.querySelector('#txtNewPassword').value; - if (view.querySelector("#fldCurrentPassword").classList.contains("hide")) { + if (view.querySelector('#fldCurrentPassword').classList.contains('hide')) { // Firefox does not respect autocomplete=off, so clear it if the field is supposed to be hidden (and blank) // This should only happen when user.HasConfiguredPassword is false, but this information is not passed on - currentPassword = ""; + currentPassword = ''; } ApiClient.updateUserPassword(userId, currentPassword, newPassword).then(function () { loading.hide(); - require(["toast"], function (toast) { - toast(Globalize.translate("PasswordSaved")); + require(['toast'], function (toast) { + toast(globalize.translate('PasswordSaved')); }); loadUser(view, params); }, function () { loading.hide(); Dashboard.alert({ - title: Globalize.translate("HeaderLoginFailure"), - message: Globalize.translate("MessageInvalidUser") + title: globalize.translate('HeaderLoginFailure'), + message: globalize.translate('MessageInvalidUser') }); }); } @@ -118,9 +118,9 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu function onSubmit(e) { var form = this; - if (form.querySelector("#txtNewPassword").value != form.querySelector("#txtNewPasswordConfirm").value) { - require(["toast"], function (toast) { - toast(Globalize.translate("PasswordMatchError")); + if (form.querySelector('#txtNewPassword').value != form.querySelector('#txtNewPasswordConfirm').value) { + require(['toast'], function (toast) { + toast(globalize.translate('PasswordMatchError')); }); } else { loading.show(); @@ -139,17 +139,17 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu } function resetPassword() { - var msg = Globalize.translate("PasswordResetConfirmation"); + var msg = globalize.translate('PasswordResetConfirmation'); - require(["confirm"], function (confirm) { - confirm(msg, Globalize.translate("PasswordResetHeader")).then(function () { + require(['confirm'], function (confirm) { + confirm(msg, globalize.translate('PasswordResetHeader')).then(function () { var userId = params.userId; loading.show(); ApiClient.resetUserPassword(userId).then(function () { loading.hide(); Dashboard.alert({ - message: Globalize.translate("PasswordResetComplete"), - title: Globalize.translate("PasswordResetHeader") + message: globalize.translate('PasswordResetComplete'), + title: globalize.translate('PasswordResetHeader') }); loadUser(view, params); }); @@ -158,17 +158,17 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu } function resetEasyPassword() { - var msg = Globalize.translate("PinCodeResetConfirmation"); + var msg = globalize.translate('PinCodeResetConfirmation'); - require(["confirm"], function (confirm) { - confirm(msg, Globalize.translate("HeaderPinCodeReset")).then(function () { + require(['confirm'], function (confirm) { + confirm(msg, globalize.translate('HeaderPinCodeReset')).then(function () { var userId = params.userId; loading.show(); ApiClient.resetEasyPassword(userId).then(function () { loading.hide(); Dashboard.alert({ - message: Globalize.translate("PinCodeResetComplete"), - title: Globalize.translate("HeaderPinCodeReset") + message: globalize.translate('PinCodeResetComplete'), + title: globalize.translate('HeaderPinCodeReset') }); loadUser(view, params); }); @@ -176,11 +176,11 @@ define(["loading", "libraryMenu", "emby-button"], function (loading, libraryMenu }); } - view.querySelector(".updatePasswordForm").addEventListener("submit", onSubmit); - view.querySelector(".localAccessForm").addEventListener("submit", onLocalAccessSubmit); - view.querySelector("#btnResetEasyPassword").addEventListener("click", resetEasyPassword); - view.querySelector("#btnResetPassword").addEventListener("click", resetPassword); - view.addEventListener("viewshow", function () { + view.querySelector('.updatePasswordForm').addEventListener('submit', onSubmit); + view.querySelector('.localAccessForm').addEventListener('submit', onLocalAccessSubmit); + view.querySelector('#btnResetEasyPassword').addEventListener('click', resetEasyPassword); + view.querySelector('#btnResetPassword').addEventListener('click', resetPassword); + view.addEventListener('viewshow', function () { loadUser(view, params); }); }; diff --git a/src/controllers/userprofilespage.js b/src/controllers/userprofilespage.js index 7aeea9cb28..528166e847 100644 --- a/src/controllers/userprofilespage.js +++ b/src/controllers/userprofilespage.js @@ -1,15 +1,15 @@ -define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", "cardStyle", "emby-button", "indicators", "flexStyles"], function (loading, dom, globalize) { - "use strict"; +define(['loading', 'dom', 'globalize', 'date-fns', 'dfnshelper', 'paper-icon-button-light', 'cardStyle', 'emby-button', 'indicators', 'flexStyles'], function (loading, dom, globalize, datefns, dfnshelper) { + 'use strict'; function deleteUser(page, id) { - var msg = globalize.translate("DeleteUserConfirmation"); + var msg = globalize.translate('DeleteUserConfirmation'); - require(["confirm"], function (confirm) { + require(['confirm'], function (confirm) { confirm({ - title: globalize.translate("DeleteUser"), + title: globalize.translate('DeleteUser'), text: msg, - confirmText: globalize.translate("ButtonDelete"), - primary: "delete" + confirmText: globalize.translate('ButtonDelete'), + primary: 'delete' }).then(function () { loading.show(); ApiClient.deleteUser(id).then(function () { @@ -20,50 +20,50 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", } function showUserMenu(elem) { - var card = dom.parentWithClass(elem, "card"); - var page = dom.parentWithClass(card, "page"); - var userId = card.getAttribute("data-userid"); + var card = dom.parentWithClass(elem, 'card'); + var page = dom.parentWithClass(card, 'page'); + var userId = card.getAttribute('data-userid'); var menuItems = []; menuItems.push({ - name: globalize.translate("ButtonOpen"), - id: "open", - icon: "mode_edit" + name: globalize.translate('ButtonOpen'), + id: 'open', + icon: 'mode_edit' }); menuItems.push({ - name: globalize.translate("ButtonLibraryAccess"), - id: "access", - icon: "lock" + name: globalize.translate('ButtonLibraryAccess'), + id: 'access', + icon: 'lock' }); menuItems.push({ - name: globalize.translate("ButtonParentalControl"), - id: "parentalcontrol", - icon: "person" + name: globalize.translate('ButtonParentalControl'), + id: 'parentalcontrol', + icon: 'person' }); menuItems.push({ - name: globalize.translate("ButtonDelete"), - id: "delete", - icon: "delete" + name: globalize.translate('ButtonDelete'), + id: 'delete', + icon: 'delete' }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: card, callback: function (id) { switch (id) { - case "open": - Dashboard.navigate("useredit.html?userId=" + userId); + case 'open': + Dashboard.navigate('useredit.html?userId=' + userId); break; - case "access": - Dashboard.navigate("userlibraryaccess.html?userId=" + userId); + case 'access': + Dashboard.navigate('userlibraryaccess.html?userId=' + userId); break; - case "parentalcontrol": - Dashboard.navigate("userparentalcontrol.html?userId=" + userId); + case 'parentalcontrol': + Dashboard.navigate('userparentalcontrol.html?userId=' + userId); break; - case "delete": + case 'delete': deleteUser(page, userId); } } @@ -72,11 +72,11 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", } function getUserHtml(user, addConnectIndicator) { - var html = ""; - var cssClass = "card squareCard scalableCard squareCard-scalable"; + var html = ''; + var cssClass = 'card squareCard scalableCard squareCard-scalable'; if (user.Policy.IsDisabled) { - cssClass += " grayscale"; + cssClass += ' grayscale'; } html += "
"; @@ -90,78 +90,79 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", imgUrl = ApiClient.getUserImageUrl(user.Id, { width: 300, tag: user.PrimaryImageTag, - type: "Primary" + type: 'Primary' }); } - var imageClass = "cardImage"; + var imageClass = 'cardImage'; if (user.Policy.IsDisabled) { - imageClass += " disabledUser"; + imageClass += ' disabledUser'; } if (imgUrl) { html += '
"; } else { html += '
'; - html += 'person'; + html += ''; } - html += "
"; - html += ""; - html += "
"; + html += '
'; + html += ''; + html += ''; html += '
'; html += '
'; html += '
'; html += user.Name; - html += "
"; - html += ''; - html += "
"; + html += '
'; + html += ''; + html += ''; html += '
'; var lastSeen = getLastSeenText(user.LastActivityDate); - html += "" != lastSeen ? lastSeen : " "; - html += "
"; - html += ""; - html += ""; - return html + ""; + html += '' != lastSeen ? lastSeen : ' '; + html += ''; + html += ''; + html += ''; + return html + ''; } - + // FIXME: It seems that, sometimes, server sends date in the future, so date-fns displays messages like 'in less than a minute'. We should fix + // how dates are returned by the server when the session is active and show something like 'Active now', instead of past/future sentences function getLastSeenText(lastActivityDate) { if (lastActivityDate) { - return "Last seen " + humaneDate(lastActivityDate); + return globalize.translate('LastSeen', datefns.formatDistanceToNow(Date.parse(lastActivityDate), dfnshelper.localeWithSuffix)); } - return ""; + return ''; } function getUserSectionHtml(users, addConnectIndicator) { return users.map(function (u__q) { return getUserHtml(u__q, addConnectIndicator); - }).join(""); + }).join(''); } function renderUsers(page, users) { - page.querySelector(".localUsers").innerHTML = getUserSectionHtml(users, true); + page.querySelector('.localUsers').innerHTML = getUserSectionHtml(users, true); } function showPendingUserMenu(elem) { var menuItems = []; menuItems.push({ - name: globalize.translate("ButtonCancel"), - id: "delete", - icon: "delete" + name: globalize.translate('ButtonCancel'), + id: 'delete', + icon: 'delete' }); - require(["actionsheet"], function (actionsheet) { - var card = dom.parentWithClass(elem, "card"); - var page = dom.parentWithClass(card, "page"); - var id = card.getAttribute("data-id"); + require(['actionsheet'], function (actionsheet) { + var card = dom.parentWithClass(elem, 'card'); + var page = dom.parentWithClass(card, 'page'); + var id = card.getAttribute('data-id'); actionsheet.show({ items: menuItems, positionTo: card, callback: function (menuItemId) { switch (menuItemId) { - case "delete": + case 'delete': cancelAuthorization(page, id); } } @@ -170,7 +171,7 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", } function getPendingUserHtml(user) { - var html = ""; + var html = ''; html += "
"; html += '
'; html += '
'; @@ -179,41 +180,41 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", if (user.ImageUrl) { html += '
"; - html += "
"; + html += '
'; } else { - html += 'person'; + html += ''; } - html += ""; - html += "
"; + html += ''; + html += '
'; html += '
'; html += '
'; - html += ''; - html += "
"; + html += ''; + html += '
'; html += '
'; html += user.UserName; - html += "
"; - html += ""; - html += ""; - return html + ""; + html += ''; + html += ''; + html += ''; + return html + ''; } function renderPendingGuests(page, users) { if (users.length) { - page.querySelector(".sectionPendingGuests").classList.remove("hide"); + page.querySelector('.sectionPendingGuests').classList.remove('hide'); } else { - page.querySelector(".sectionPendingGuests").classList.add("hide"); + page.querySelector('.sectionPendingGuests').classList.add('hide'); } - page.querySelector(".pending").innerHTML = users.map(getPendingUserHtml).join(""); + page.querySelector('.pending').innerHTML = users.map(getPendingUserHtml).join(''); } // TODO cvium: maybe reuse for invitation system function cancelAuthorization(page, id) { loading.show(); ApiClient.ajax({ - type: "DELETE", - url: ApiClient.getUrl("Connect/Pending", { + type: 'DELETE', + url: ApiClient.getUrl('Connect/Pending', { Id: id }) }).then(function () { @@ -235,34 +236,34 @@ define(["loading", "dom", "globalize", "humanedate", "paper-icon-button-light", } function showInvitePopup(page) { - require(["components/guestinviter/guestinviter"], function (guestinviter) { + require(['components/guestinviter/guestinviter'], function (guestinviter) { guestinviter.show().then(function () { loadData(page); }); }); } - pageIdOn("pageinit", "userProfilesPage", function () { + pageIdOn('pageinit', 'userProfilesPage', function () { var page = this; - page.querySelector(".btnAddUser").addEventListener("click", function() { - Dashboard.navigate("usernew.html"); + page.querySelector('.btnAddUser').addEventListener('click', function() { + Dashboard.navigate('usernew.html'); }); - page.querySelector(".localUsers").addEventListener("click", function (e__e) { - var btnUserMenu = dom.parentWithClass(e__e.target, "btnUserMenu"); + page.querySelector('.localUsers').addEventListener('click', function (e__e) { + var btnUserMenu = dom.parentWithClass(e__e.target, 'btnUserMenu'); if (btnUserMenu) { showUserMenu(btnUserMenu); } }); - page.querySelector(".pending").addEventListener("click", function (e__r) { - var btnUserMenu = dom.parentWithClass(e__r.target, "btnUserMenu"); + page.querySelector('.pending').addEventListener('click', function (e__r) { + var btnUserMenu = dom.parentWithClass(e__r.target, 'btnUserMenu'); if (btnUserMenu) { showPendingUserMenu(btnUserMenu); } }); }); - pageIdOn("pagebeforeshow", "userProfilesPage", function () { + pageIdOn('pagebeforeshow', 'userProfilesPage', function () { loadData(this); }); }); diff --git a/src/controllers/wizard/finish.js b/src/controllers/wizard/finish.js index 8242a16cb4..c27d9a5f4b 100644 --- a/src/controllers/wizard/finish.js +++ b/src/controllers/wizard/finish.js @@ -1,18 +1,18 @@ -define(["loading"], function (loading) { - "use strict"; +define(['loading'], function (loading) { + 'use strict'; function onFinish() { loading.show(); ApiClient.ajax({ - url: ApiClient.getUrl("Startup/Complete"), - type: "POST" + url: ApiClient.getUrl('Startup/Complete'), + type: 'POST' }).then(function () { loading.hide(); - window.location.href = "index.html"; + window.location.href = 'index.html'; }); } return function (view, params) { - view.querySelector(".btnWizardNext").addEventListener("click", onFinish); + view.querySelector('.btnWizardNext').addEventListener('click', onFinish); }; }); diff --git a/src/controllers/wizard/remoteaccess.js b/src/controllers/wizard/remoteaccess.js index 554a417e57..400cd357f4 100644 --- a/src/controllers/wizard/remoteaccess.js +++ b/src/controllers/wizard/remoteaccess.js @@ -1,16 +1,16 @@ -define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loading) { - "use strict"; +define(['loading', 'emby-checkbox', 'emby-button', 'emby-select'], function (loading) { + 'use strict'; function save(page) { loading.show(); var apiClient = ApiClient; var config = {}; - config.EnableRemoteAccess = page.querySelector("#chkRemoteAccess").checked; - config.EnableAutomaticPortMapping = page.querySelector("#chkEnableUpnp").checked; + config.EnableRemoteAccess = page.querySelector('#chkRemoteAccess').checked; + config.EnableAutomaticPortMapping = page.querySelector('#chkEnableUpnp').checked; apiClient.ajax({ - type: "POST", + type: 'POST', data: config, - url: apiClient.getUrl("Startup/RemoteAccess") + url: apiClient.getUrl('Startup/RemoteAccess') }).then(function () { loading.hide(); navigateToNextPage(); @@ -18,7 +18,7 @@ define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loa } function navigateToNextPage() { - Dashboard.navigate("wizardfinish.html"); + Dashboard.navigate('wizardfinish.html'); } function onSubmit(e) { @@ -28,12 +28,12 @@ define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loa } return function (view, params) { - view.querySelector(".wizardSettingsForm").addEventListener("submit", onSubmit); - view.addEventListener("viewshow", function () { - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); + view.querySelector('.wizardSettingsForm').addEventListener('submit', onSubmit); + view.addEventListener('viewshow', function () { + document.querySelector('.skinHeader').classList.add('noHomeButtonHeader'); }); - view.addEventListener("viewhide", function () { - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); + view.addEventListener('viewhide', function () { + document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader'); }); }; }); diff --git a/src/controllers/wizard/settings.js b/src/controllers/wizard/settings.js index 487f068a40..2062e795a3 100644 --- a/src/controllers/wizard/settings.js +++ b/src/controllers/wizard/settings.js @@ -1,16 +1,16 @@ -define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loading) { - "use strict"; +define(['loading', 'emby-checkbox', 'emby-button', 'emby-select'], function (loading) { + 'use strict'; function save(page) { loading.show(); var apiClient = ApiClient; - apiClient.getJSON(apiClient.getUrl("Startup/Configuration")).then(function (config) { - config.PreferredMetadataLanguage = page.querySelector("#selectLanguage").value; - config.MetadataCountryCode = page.querySelector("#selectCountry").value; + apiClient.getJSON(apiClient.getUrl('Startup/Configuration')).then(function (config) { + config.PreferredMetadataLanguage = page.querySelector('#selectLanguage').value; + config.MetadataCountryCode = page.querySelector('#selectCountry').value; apiClient.ajax({ - type: "POST", + type: 'POST', data: config, - url: apiClient.getUrl("Startup/Configuration") + url: apiClient.getUrl('Startup/Configuration') }).then(function () { loading.hide(); navigateToNextPage(); @@ -19,41 +19,41 @@ define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loa } function populateLanguages(select, languages) { - var html = ""; + var html = ''; html += ""; for (var i = 0, length = languages.length; i < length; i++) { var culture = languages[i]; - html += ""; + html += "'; } select.innerHTML = html; } function populateCountries(select, allCountries) { - var html = ""; + var html = ''; html += ""; for (var i = 0, length = allCountries.length; i < length; i++) { var culture = allCountries[i]; - html += ""; + html += "'; } select.innerHTML = html; } function reloadData(page, config, cultures, countries) { - populateLanguages(page.querySelector("#selectLanguage"), cultures); - populateCountries(page.querySelector("#selectCountry"), countries); - page.querySelector("#selectLanguage").value = config.PreferredMetadataLanguage; - page.querySelector("#selectCountry").value = config.MetadataCountryCode; + populateLanguages(page.querySelector('#selectLanguage'), cultures); + populateCountries(page.querySelector('#selectCountry'), countries); + page.querySelector('#selectLanguage').value = config.PreferredMetadataLanguage; + page.querySelector('#selectCountry').value = config.MetadataCountryCode; loading.hide(); } function reload(page) { loading.show(); var apiClient = ApiClient; - var promise1 = apiClient.getJSON(apiClient.getUrl("Startup/Configuration")); + var promise1 = apiClient.getJSON(apiClient.getUrl('Startup/Configuration')); var promise2 = apiClient.getCultures(); var promise3 = apiClient.getCountries(); Promise.all([promise1, promise2, promise3]).then(function (responses) { @@ -62,7 +62,7 @@ define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loa } function navigateToNextPage() { - Dashboard.navigate("wizardremoteaccess.html"); + Dashboard.navigate('wizardremoteaccess.html'); } function onSubmit(e) { @@ -72,13 +72,13 @@ define(["loading", "emby-checkbox", "emby-button", "emby-select"], function (loa } return function (view, params) { - view.querySelector(".wizardSettingsForm").addEventListener("submit", onSubmit); - view.addEventListener("viewshow", function () { - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); + view.querySelector('.wizardSettingsForm').addEventListener('submit', onSubmit); + view.addEventListener('viewshow', function () { + document.querySelector('.skinHeader').classList.add('noHomeButtonHeader'); reload(this); }); - view.addEventListener("viewhide", function () { - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); + view.addEventListener('viewhide', function () { + document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader'); }); }; }); diff --git a/src/controllers/wizard/start.js b/src/controllers/wizard/start.js index 1c2917b9ec..b7fb920d45 100644 --- a/src/controllers/wizard/start.js +++ b/src/controllers/wizard/start.js @@ -1,9 +1,9 @@ -define(["jQuery", "loading", "emby-button", "emby-select"], function ($, loading) { - "use strict"; +define(['jQuery', 'loading', 'emby-button', 'emby-select'], function ($, loading) { + 'use strict'; function loadPage(page, config, languageOptions) { - $("#selectLocalizationLanguage", page).html(languageOptions.map(function (l) { - return '"; + $('#selectLocalizationLanguage', page).html(languageOptions.map(function (l) { + return ''; })).val(config.UICulture); loading.hide(); } @@ -11,38 +11,38 @@ define(["jQuery", "loading", "emby-button", "emby-select"], function ($, loading function save(page) { loading.show(); var apiClient = ApiClient; - apiClient.getJSON(apiClient.getUrl("Startup/Configuration")).then(function (config) { - config.UICulture = $("#selectLocalizationLanguage", page).val(); + apiClient.getJSON(apiClient.getUrl('Startup/Configuration')).then(function (config) { + config.UICulture = $('#selectLocalizationLanguage', page).val(); apiClient.ajax({ - type: "POST", + type: 'POST', data: config, - url: apiClient.getUrl("Startup/Configuration") + url: apiClient.getUrl('Startup/Configuration') }).then(function () { - Dashboard.navigate("wizarduser.html"); + Dashboard.navigate('wizarduser.html'); }); }); } function onSubmit() { - save($(this).parents(".page")); + save($(this).parents('.page')); return false; } return function (view, params) { - $(".wizardStartForm", view).on("submit", onSubmit); - view.addEventListener("viewshow", function () { - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); + $('.wizardStartForm', view).on('submit', onSubmit); + view.addEventListener('viewshow', function () { + document.querySelector('.skinHeader').classList.add('noHomeButtonHeader'); loading.show(); var page = this; var apiClient = ApiClient; - var promise1 = apiClient.getJSON(apiClient.getUrl("Startup/Configuration")); - var promise2 = apiClient.getJSON(apiClient.getUrl("Localization/Options")); + var promise1 = apiClient.getJSON(apiClient.getUrl('Startup/Configuration')); + var promise2 = apiClient.getJSON(apiClient.getUrl('Localization/Options')); Promise.all([promise1, promise2]).then(function (responses) { loadPage(page, responses[0], responses[1]); }); }); - view.addEventListener("viewhide", function () { - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); + view.addEventListener('viewhide', function () { + document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader'); }); }; }); diff --git a/src/controllers/wizard/user.js b/src/controllers/wizard/user.js index d29be37c13..e62edef9fe 100644 --- a/src/controllers/wizard/user.js +++ b/src/controllers/wizard/user.js @@ -1,16 +1,16 @@ -define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "emby-button"], function (loading, globalize) { - "use strict"; +define(['loading', 'globalize', 'dashboardcss', 'emby-input', 'emby-button', 'emby-button'], function (loading, globalize) { + 'use strict'; function getApiClient() { return ApiClient; } function nextWizardPage() { - Dashboard.navigate("wizardlibrary.html"); + Dashboard.navigate('wizardlibrary.html'); } function onUpdateUserComplete(result) { - console.log(result); + console.debug('user update complete: ' + result); loading.hide(); nextWizardPage(); } @@ -19,21 +19,21 @@ define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "em loading.show(); var apiClient = getApiClient(); apiClient.ajax({ - type: "POST", + type: 'POST', data: { - Name: form.querySelector("#txtUsername").value, - Password: form.querySelector("#txtManualPassword").value + Name: form.querySelector('#txtUsername').value, + Password: form.querySelector('#txtManualPassword').value }, - url: apiClient.getUrl("Startup/User") + url: apiClient.getUrl('Startup/User') }).then(onUpdateUserComplete); } function onSubmit(e) { var form = this; - if (form.querySelector("#txtManualPassword").value != form.querySelector("#txtPasswordConfirm").value) { - require(["toast"], function (toast) { - toast(Globalize.translate("PasswordMatchError")); + if (form.querySelector('#txtManualPassword').value != form.querySelector('#txtPasswordConfirm').value) { + require(['toast'], function (toast) { + toast(globalize.translate('PasswordMatchError')); }); } else { submit(form); @@ -47,21 +47,21 @@ define(["loading", "globalize", "dashboardcss", "emby-input", "emby-button", "em loading.show(); var page = this; var apiClient = getApiClient(); - apiClient.getJSON(apiClient.getUrl("Startup/User")).then(function (user) { - page.querySelector("#txtUsername").value = user.Name || ""; - page.querySelector("#txtManualPassword").value = user.Password || ""; + apiClient.getJSON(apiClient.getUrl('Startup/User')).then(function (user) { + page.querySelector('#txtUsername').value = user.Name || ''; + page.querySelector('#txtManualPassword').value = user.Password || ''; loading.hide(); }); } return function (view, params) { - view.querySelector(".wizardUserForm").addEventListener("submit", onSubmit); - view.addEventListener("viewshow", function () { - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); + view.querySelector('.wizardUserForm').addEventListener('submit', onSubmit); + view.addEventListener('viewshow', function () { + document.querySelector('.skinHeader').classList.add('noHomeButtonHeader'); }); - view.addEventListener("viewhide", function () { - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); + view.addEventListener('viewhide', function () { + document.querySelector('.skinHeader').classList.remove('noHomeButtonHeader'); }); - view.addEventListener("viewshow", onViewShow); + view.addEventListener('viewshow', onViewShow); }; }); diff --git a/src/dashboard.html b/src/dashboard.html index dc9a56abbc..9063f55965 100644 --- a/src/dashboard.html +++ b/src/dashboard.html @@ -2,10 +2,10 @@
-
+ -
+

${HeaderActiveDevices}

- chevron_right +
@@ -45,7 +45,7 @@

${HeaderActivity}

- chevron_right +
@@ -62,7 +62,7 @@

${Alerts}

- chevron_right +
@@ -71,7 +71,7 @@

${HeaderPaths}

- chevron_right +
@@ -112,7 +112,7 @@
diff --git a/src/dashboardgeneral.html b/src/dashboardgeneral.html index 6387128d5e..03bfa9af8d 100644 --- a/src/dashboardgeneral.html +++ b/src/dashboardgeneral.html @@ -5,7 +5,7 @@

${TabSettings}

- ${Help} + ${Help}
@@ -19,7 +19,7 @@
${LabelPreferredDisplayLanguageHelp}
@@ -39,7 +39,7 @@
- +
${LabelCachePathHelp}
@@ -49,28 +49,13 @@
- +
${LabelMetadataPathHelp}
-
-

${HeaderAutomaticUpdates}

- -
- -
${LabelAllowServerAutoRestartHelp}
-
-
-

${HeaderBranding}

diff --git a/src/device.html b/src/device.html index 11fc9671b1..093b311208 100644 --- a/src/device.html +++ b/src/device.html @@ -5,7 +5,7 @@
diff --git a/src/devices.html b/src/devices.html index 4e6552f05e..55f51d7e23 100644 --- a/src/devices.html +++ b/src/devices.html @@ -4,7 +4,7 @@

${TabDevices}

- ${Help} + ${Help}
diff --git a/src/dlnaprofile.html b/src/dlnaprofile.html index 2054bce3db..dbe9131d70 100644 --- a/src/dlnaprofile.html +++ b/src/dlnaprofile.html @@ -5,7 +5,7 @@

${HeaderProfileInformation}

- ${Help} + ${Help}
@@ -98,7 +98,7 @@

${HeaderHttpHeaders}

@@ -221,7 +221,7 @@

${HeaderXmlDocumentAttributes}

diff --git a/src/dlnaprofiles.html b/src/dlnaprofiles.html index ac9e961370..9f2a5e129e 100644 --- a/src/dlnaprofiles.html +++ b/src/dlnaprofiles.html @@ -9,7 +9,7 @@

${HeaderCustomDlnaProfiles}

- add + ${Help}
diff --git a/src/dlnasettings.html b/src/dlnasettings.html index 8c44f751a5..703dd66a9f 100644 --- a/src/dlnasettings.html +++ b/src/dlnasettings.html @@ -8,7 +8,7 @@

${TabSettings}

- ${Help} + ${Help}
diff --git a/src/elements/emby-button/emby-button.css b/src/elements/emby-button/emby-button.css index ee15e2e125..0963125652 100644 --- a/src/elements/emby-button/emby-button.css +++ b/src/elements/emby-button/emby-button.css @@ -8,20 +8,26 @@ font-size: inherit; font-family: inherit; color: inherit; + + /* These are getting an outline in opera tv browsers, which run chrome 30 */ + outline: none !important; outline-width: 0; + -moz-user-select: none; + -ms-user-select: none; + -webkit-user-select: none; user-select: none; cursor: pointer; z-index: 0; padding: 0.9em 1em; vertical-align: middle; border: 0; - vertical-align: middle; border-radius: 0.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; + /* Not crazy about this but it normalizes heights between anchors and buttons */ line-height: 1.35; transform-origin: center; @@ -41,12 +47,9 @@ background: transparent; } -.button-flat:hover { - opacity: .5; -} - .button-link { background: transparent; + cursor: pointer; margin: 0; padding: 0; vertical-align: initial; @@ -56,12 +59,12 @@ text-decoration: underline; } -.emby-button > i { +.emby-button > .material-icons { /* For non-fab buttons that have icons */ font-size: 1.36em; } -.button-link > i { +.button-link > .material-icons { font-size: 1em; } @@ -79,7 +82,7 @@ display: block; align-items: center; justify-content: center; - margin: .25em 0; + margin: 0.25em 0; width: 100%; } @@ -88,12 +91,15 @@ display: inline-flex; align-items: center; box-sizing: border-box; - margin: 0 .29em; + margin: 0 0.29em; 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; user-select: none; cursor: pointer; z-index: 0; @@ -101,15 +107,17 @@ min-height: initial; width: auto; height: auto; - padding: .556em; + padding: 0.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; border-radius: 50%; + + /* Disable webkit tap highlighting */ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); justify-content: center; transform-origin: center; transition: 0.2s; @@ -120,32 +128,33 @@ z-index: 1; } - .paper-icon-button-light::-moz-focus-inner { - border: 0; - } +.paper-icon-button-light::-moz-focus-inner { + border: 0; +} - .paper-icon-button-light:disabled { - opacity: 0.3; - cursor: default; - } +.paper-icon-button-light:disabled { + opacity: 0.3; + cursor: default; +} - .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 > .material-icons { + font-size: 1.66956521739130434em; - .paper-icon-button-light > div { - max-height: 100%; - transform: scale(1.8); - position: relative; - z-index: 1; - vertical-align: middle; - display: inline; - margin: 0 auto; - } + /* Make sure its on top of the ripple */ + position: relative; + z-index: 1; + vertical-align: middle; +} + +.paper-icon-button-light > div { + max-height: 100%; + transform: scale(1.8); + position: relative; + z-index: 1; + vertical-align: middle; + display: inline; + margin: 0 auto; +} .emby-button-foreground { position: relative; @@ -159,7 +168,6 @@ .filterButtonBubble { color: #fff; position: absolute; - background: #444; top: 0; right: 0; width: 1.6em; @@ -170,7 +178,7 @@ justify-content: center; font-size: 82%; border-radius: 100em; - 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; + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2); + background: #03a9f4; font-weight: bold; } diff --git a/src/elements/emby-checkbox/emby-checkbox.css b/src/elements/emby-checkbox/emby-checkbox.css index 4e27928e2a..b33a216140 100644 --- a/src/elements/emby-checkbox/emby-checkbox.css +++ b/src/elements/emby-checkbox/emby-checkbox.css @@ -32,12 +32,16 @@ .emby-checkbox { position: absolute; + /* This is for focusing purposes, so the focusManager doesn't skip over it */ width: 1px; height: 1px; margin: 0; padding: 0; opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; appearance: none; border: none; } @@ -46,14 +50,13 @@ position: absolute; top: 3px; left: 0; - display: inline-block; box-sizing: border-box; width: 1.83em; height: 1.83em; margin: 0; overflow: hidden; - border: 2px solid currentcolor; - border-radius: .14em; + border: 0.14em solid currentcolor; + border-radius: 0.14em; z-index: 2; display: flex; align-items: center; @@ -65,7 +68,8 @@ color: #fff; } -.checkboxIcon-checked { +.checkboxIcon-checked, +.emby-checkbox-label .checkboxIcon-checked { display: none; } @@ -98,18 +102,18 @@ flex-wrap: wrap; } - .checkboxList-verticalwrap > .emby-checkbox-label { - display: inline-flex; - margin: .3em 0 .3em 0; - width: 12em; - } +.checkboxList-verticalwrap > .emby-checkbox-label { + display: inline-flex; + margin: 0.3em 0 0.3em 0; + width: 12em; +} .checkboxList-paperList { padding: 1em !important; } .checkboxListLabel { - margin-bottom: .25em; + margin-bottom: 0.25em; } @keyframes repaintChrome { @@ -121,3 +125,13 @@ padding: 0; } } + +@-webkit-keyframes repaintChrome { + from { + padding: 0; + } + + to { + padding: 0; + } +} diff --git a/src/elements/emby-checkbox/emby-checkbox.js b/src/elements/emby-checkbox/emby-checkbox.js index d6276e826c..4d02d56163 100644 --- a/src/elements/emby-checkbox/emby-checkbox.js +++ b/src/elements/emby-checkbox/emby-checkbox.js @@ -5,7 +5,8 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b function onKeyDown(e) { // Don't submit form on enter - if (e.keyCode === 13) { + // Real (non-emulator) Tizen does nothing on Space + if (e.keyCode === 13 || e.keyCode === 32) { e.preventDefault(); this.checked = !this.checked; @@ -56,8 +57,8 @@ define(['browser', 'dom', 'css!./emby-checkbox', 'registerElement'], function (b var checkedIcon = this.getAttribute('data-checkedicon') || 'check'; var uncheckedIcon = this.getAttribute('data-uncheckedicon') || ''; - var checkHtml = '' + checkedIcon + ''; - var uncheckedHtml = '' + uncheckedIcon + ''; + var checkHtml = ''; + var uncheckedHtml = ''; labelElement.insertAdjacentHTML('beforeend', '' + checkHtml + uncheckedHtml + ''); labelTextElement.classList.add('checkboxLabel'); diff --git a/src/elements/emby-collapse/emby-collapse.css b/src/elements/emby-collapse/emby-collapse.css index 0a982e975d..dd22c20b5b 100644 --- a/src/elements/emby-collapse/emby-collapse.css +++ b/src/elements/emby-collapse/emby-collapse.css @@ -1,5 +1,5 @@ .emby-collapse { - margin: .5em 0; + margin: 0.5em 0; } .collapseContent { @@ -18,10 +18,9 @@ text-transform: none; width: 100%; text-align: left; - text-transform: none; - border-width: 0 0 .1em 0; + border-width: 0 0 0.1em 0; border-style: solid; - padding-left: .1em; + padding-left: 0.1em; background: transparent; box-shadow: none; } @@ -30,7 +29,7 @@ transform-origin: 50% 50%; transition: transform 180ms ease-out; position: absolute; - right: .5em; + right: 0.5em; font-size: 1.5em; } diff --git a/src/elements/emby-collapse/emby-collapse.js b/src/elements/emby-collapse/emby-collapse.js index 09b8c70d8f..707e81a786 100644 --- a/src/elements/emby-collapse/emby-collapse.js +++ b/src/elements/emby-collapse/emby-collapse.js @@ -24,7 +24,7 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun elem.style.height = 'auto'; }, 300); - var icon = button.querySelector('i'); + var icon = button.querySelector('.material-icons'); //icon.innerHTML = 'expand_less'; icon.classList.add('emby-collapse-expandIconExpanded'); } @@ -46,7 +46,7 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun } }, 300); - var icon = button.querySelector('i'); + var icon = button.querySelector('.material-icons'); //icon.innerHTML = 'expand_more'; icon.classList.remove('emby-collapse-expandIconExpanded'); } @@ -80,7 +80,7 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun var title = this.getAttribute('title'); - var html = ''; + var html = ''; this.insertAdjacentHTML('afterbegin', html); @@ -97,4 +97,4 @@ define(['browser', 'css!./emby-collapse', 'registerElement', 'emby-button'], fun prototype: EmbyButtonPrototype, extends: 'div' }); -}); \ No newline at end of file +}); diff --git a/src/elements/emby-input/emby-input.css b/src/elements/emby-input/emby-input.css index 57a46ec7b6..18ad37a87a 100644 --- a/src/elements/emby-input/emby-input.css +++ b/src/elements/emby-input/emby-input.css @@ -2,22 +2,28 @@ 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 */ + padding: 0.4em 0.25em; + + /* must the 16px or larger to prevent iOS page zoom on focus */ + font-size: 110%; + + /* prevent padding from causing width overflow */ + -webkit-box-sizing: border-box; box-sizing: border-box; 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; +} + +.emby-input:required { + box-shadow: none; +} .inputContainer { margin-bottom: 1.8em; @@ -25,13 +31,14 @@ .inputLabel { display: inline-block; - margin-bottom: .25em; + margin-bottom: 0.25em; } .emby-input + .fieldDescription { - margin-top: .25em; + margin-top: 0.25em; } .emby-input-iconbutton { + -webkit-align-self: flex-end; align-self: flex-end; } diff --git a/src/elements/emby-input/emby-input.js b/src/elements/emby-input/emby-input.js index 7d2ea63a0d..03ba2b93aa 100644 --- a/src/elements/emby-input/emby-input.js +++ b/src/elements/emby-input/emby-input.js @@ -123,4 +123,4 @@ define(['layoutManager', 'browser', 'dom', 'css!./emby-input', 'registerElement' prototype: EmbyInputPrototype, extends: 'input' }); -}); \ No newline at end of file +}); diff --git a/src/components/emby-itemrefreshindicator/emby-itemrefreshindicator.js b/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js similarity index 99% rename from src/components/emby-itemrefreshindicator/emby-itemrefreshindicator.js rename to src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js index be50abeb87..9864dbbb67 100644 --- a/src/components/emby-itemrefreshindicator/emby-itemrefreshindicator.js +++ b/src/elements/emby-itemrefreshindicator/emby-itemrefreshindicator.js @@ -74,4 +74,4 @@ define(['emby-progressring', 'dom', 'serverNotifications', 'events', 'registerEl prototype: EmbyItemRefreshIndicatorPrototype, extends: 'div' }); -}); \ No newline at end of file +}); diff --git a/src/components/emby-itemscontainer/emby-itemscontainer.js b/src/elements/emby-itemscontainer/emby-itemscontainer.js similarity index 99% rename from src/components/emby-itemscontainer/emby-itemscontainer.js rename to src/elements/emby-itemscontainer/emby-itemscontainer.js index 7cfb3e4a4a..5d3772ca93 100644 --- a/src/components/emby-itemscontainer/emby-itemscontainer.js +++ b/src/elements/emby-itemscontainer/emby-itemscontainer.js @@ -124,7 +124,7 @@ define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', var self = this; require(['sortable'], function (Sortable) { self.sortable = new Sortable(self, { - draggable: ".listItem", + draggable: '.listItem', handle: '.listViewDragHandle', // dragging ended @@ -467,7 +467,7 @@ define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', focusManager.focus(newElement); return; } catch (err) { - console.log(err); + console.error(err); } } } @@ -479,4 +479,4 @@ define(['itemShortcuts', 'inputManager', 'connectionManager', 'playbackManager', prototype: ItemsContainerPrototype, extends: 'div' }); -}); \ No newline at end of file +}); diff --git a/src/components/userdatabuttons/emby-playstatebutton.js b/src/elements/emby-playstatebutton/emby-playstatebutton.js similarity index 98% rename from src/components/userdatabuttons/emby-playstatebutton.js rename to src/elements/emby-playstatebutton/emby-playstatebutton.js index eaed128933..57f7eb76eb 100644 --- a/src/components/userdatabuttons/emby-playstatebutton.js +++ b/src/elements/emby-playstatebutton/emby-playstatebutton.js @@ -41,7 +41,7 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby function setState(button, played, updateAttribute) { var icon = button.iconElement; if (!icon) { - button.iconElement = button.querySelector('i'); + button.iconElement = button.querySelector('.material-icons'); icon = button.iconElement; } @@ -156,4 +156,4 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby prototype: EmbyPlaystateButtonPrototype, extends: 'button' }); -}); \ No newline at end of file +}); diff --git a/src/elements/emby-programcell/emby-programcell.js b/src/elements/emby-programcell/emby-programcell.js new file mode 100644 index 0000000000..a959033186 --- /dev/null +++ b/src/elements/emby-programcell/emby-programcell.js @@ -0,0 +1,16 @@ +define([], function() { + 'use strict'; + + 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' + }); +}); diff --git a/src/elements/emby-progressbar/emby-progressbar.js b/src/elements/emby-progressbar/emby-progressbar.js new file mode 100644 index 0000000000..a799f82bdd --- /dev/null +++ b/src/elements/emby-progressbar/emby-progressbar.js @@ -0,0 +1,42 @@ +define([], function() { + 'use strict'; + + var ProgressBarPrototype = Object.create(HTMLDivElement.prototype); + + 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' + }); +}); diff --git a/src/elements/emby-progressring/emby-progressring.css b/src/elements/emby-progressring/emby-progressring.css index 7bef7c35f7..014db3aedf 100644 --- a/src/elements/emby-progressring/emby-progressring.css +++ b/src/elements/emby-progressring/emby-progressring.css @@ -11,9 +11,9 @@ width: 100%; height: 100%; border-radius: 50%; - border: .25em solid rgba(0, 0, 0, 1); + border: 0.25em solid rgba(0, 0, 0, 1); box-sizing: border-box; - background: rgba(0, 0, 0, .9); + background: rgba(0, 0, 0, 0.9); display: flex; align-items: center; justify-content: center; @@ -51,7 +51,7 @@ width: 200%; height: 200%; border-radius: 50%; - border-width: .25em; + border-width: 0.25em; border-style: solid; box-sizing: border-box; } diff --git a/src/elements/emby-progressring/emby-progressring.js b/src/elements/emby-progressring/emby-progressring.js index 80c5458528..edc635947c 100644 --- a/src/elements/emby-progressring/emby-progressring.js +++ b/src/elements/emby-progressring/emby-progressring.js @@ -98,4 +98,4 @@ define(['require', 'css!./emby-progressring', 'registerElement'], function (requ }); return EmbyProgressRing; -}); \ No newline at end of file +}); diff --git a/src/elements/emby-progressring/emby-progressring.template.html b/src/elements/emby-progressring/emby-progressring.template.html index bebefe5f51..a1be620b33 100644 --- a/src/elements/emby-progressring/emby-progressring.template.html +++ b/src/elements/emby-progressring/emby-progressring.template.html @@ -20,4 +20,4 @@
-
\ No newline at end of file +
diff --git a/src/elements/emby-radio/emby-radio.css b/src/elements/emby-radio/emby-radio.css index 6b8575bc86..2d7f584171 100644 --- a/src/elements/emby-radio/emby-radio.css +++ b/src/elements/emby-radio/emby-radio.css @@ -4,90 +4,108 @@ display: inline-block; box-sizing: border-box; margin: 0; - padding-left: 0; } .radio-label-block { display: flex; align-items: center; - margin-top: .5em; - margin-bottom: .5em; -} - -.mdl-radio { - padding-left: 24px; + margin-top: 0.5em; + margin-bottom: 0.5em; } .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; padding: 0; opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; appearance: none; border: none; } -.mdl-radio__outer-circle { - position: absolute; - top: 4px; - left: 0; - display: inline-block; - box-sizing: border-box; - width: 16px; - height: 16px; - margin: 0; - cursor: pointer; - border: 2px solid currentcolor; +.mdl-radio__circles { + position: relative; + margin-right: 0.54em; + width: 1.08em; + height: 1.08em; border-radius: 50%; - z-index: 2; + cursor: pointer; } -.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle { - border: 2px solid #00a4dc; +.mdl-radio__circles svg { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + z-index: 1; + overflow: visible; } -.mdl-radio__button:disabled + .mdl-radio__label + .mdl-radio__outer-circle { - border: 2px solid rgba(0,0,0, 0.26); +.mdl-radio__button:disabled + .mdl-radio__circles { cursor: auto; } +.mdl-radio__button:disabled + .mdl-radio__circles .mdl-radio__outer-circle { + color: rgba(0, 0, 0, 0.26); +} + +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles .mdl-radio__outer-circle { + color: #00a4dc; +} + .mdl-radio__inner-circle { - position: absolute; - z-index: 1; - margin: 0; - top: 8px; - left: 4px; - box-sizing: border-box; - width: 8px; - height: 8px; - cursor: pointer; - transition-duration: 0.28s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 0.2s; + transition-property: -webkit-transform; transition-property: transform; - transform: scale3d(0, 0, 0); + transition-property: transform, -webkit-transform; + -webkit-transform: scale(0); + transform: scale(0); + transform-origin: 50% 50%; +} + +.mdl-radio__button:checked + .mdl-radio__circles .mdl-radio__inner-circle { + -webkit-transform: scale(1); + transform: scale(1); +} + +.mdl-radio__button:disabled + .mdl-radio__circles .mdl-radio__inner-circle { + color: rgba(0, 0, 0, 0.26); +} + +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles .mdl-radio__inner-circle { + color: #00a4dc; +} + +.mdl-radio__focus-circle { + position: absolute; + top: 0; + left: 0; + box-sizing: border-box; + width: 100%; + height: 100%; + margin: 0; border-radius: 50%; background: #00a4dc; + opacity: 0.26; + transition-duration: 0.2s; + transition-property: -webkit-transform; + transition-property: transform; + transition-property: transform, -webkit-transform; + -webkit-transform: scale(0); + transform: scale(0); } -.mdl-radio__button:checked + .mdl-radio__label + .mdl-radio__outer-circle + .mdl-radio__inner-circle { - 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, 0.26); - cursor: auto; -} - -.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 { - box-shadow: 0 0 0 10px rgba(0, 164, 220, 0.26) +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles .mdl-radio__focus-circle { + -webkit-transform: scale(1.75); + transform: scale(1.75); } .mdl-radio__label { @@ -95,6 +113,6 @@ } .mdl-radio__button:disabled + .mdl-radio__label { - color: rgba(0,0,0, 0.26); + color: rgba(0, 0, 0, 0.26); cursor: auto; } diff --git a/src/elements/emby-radio/emby-radio.js b/src/elements/emby-radio/emby-radio.js index 3c72f91521..46a3e3826c 100644 --- a/src/elements/emby-radio/emby-radio.js +++ b/src/elements/emby-radio/emby-radio.js @@ -1,4 +1,4 @@ -define(['css!./emby-radio', 'registerElement'], function () { +define(['layoutManager', 'css!./emby-radio', 'registerElement'], function (layoutManager) { 'use strict'; var EmbyRadioPrototype = Object.create(HTMLInputElement.prototype); @@ -6,16 +6,24 @@ define(['css!./emby-radio', 'registerElement'], function () { function onKeyDown(e) { // Don't submit form on enter - if (e.keyCode === 13) { + // Real (non-emulator) Tizen does nothing on Space + if (e.keyCode === 13 || e.keyCode === 32) { e.preventDefault(); - this.checked = true; + if (!this.checked) { + this.checked = true; + + this.dispatchEvent(new CustomEvent('change', { + bubbles: true + })); + } return false; } } EmbyRadioPrototype.attachedCallback = function () { + var showFocus = !layoutManager.mobile; if (this.getAttribute('data-radio') === 'true') { return; @@ -30,13 +38,36 @@ define(['css!./emby-radio', 'registerElement'], function () { labelElement.classList.add('mdl-radio'); labelElement.classList.add('mdl-js-radio'); labelElement.classList.add('mdl-js-ripple-effect'); + if (showFocus) { + labelElement.classList.add('show-focus'); + } var labelTextElement = labelElement.querySelector('span'); labelTextElement.classList.add('radioButtonLabel'); labelTextElement.classList.add('mdl-radio__label'); - labelElement.insertAdjacentHTML('beforeend', ''); + var html = ''; + + html += '
'; + + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + + if (showFocus) { + html += '
'; + } + + html += '
'; + + this.insertAdjacentHTML('afterend', html); this.addEventListener('keydown', onKeyDown); }; @@ -45,4 +76,4 @@ define(['css!./emby-radio', 'registerElement'], function () { prototype: EmbyRadioPrototype, extends: 'input' }); -}); \ No newline at end of file +}); diff --git a/src/components/userdatabuttons/emby-ratingbutton.js b/src/elements/emby-ratingbutton/emby-ratingbutton.js similarity index 95% rename from src/components/userdatabuttons/emby-ratingbutton.js rename to src/elements/emby-ratingbutton/emby-ratingbutton.js index 84ae780de5..142920ca15 100644 --- a/src/components/userdatabuttons/emby-ratingbutton.js +++ b/src/elements/emby-ratingbutton/emby-ratingbutton.js @@ -57,12 +57,12 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby function setState(button, likes, isFavorite, updateAttribute) { - var icon = button.querySelector('i'); + var icon = button.querySelector('.material-icons'); if (isFavorite) { if (icon) { - icon.innerHTML = 'favorite'; + icon.classList.add('favorite'); icon.classList.add('ratingbutton-icon-withrating'); } @@ -71,7 +71,7 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby } else if (likes) { if (icon) { - icon.innerHTML = 'favorite'; + icon.classList.add('favorite'); icon.classList.remove('ratingbutton-icon-withrating'); //icon.innerHTML = 'thumb_up'; } @@ -80,7 +80,7 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby } else if (likes === false) { if (icon) { - icon.innerHTML = 'favorite'; + icon.classList.add('favorite'); icon.classList.remove('ratingbutton-icon-withrating'); //icon.innerHTML = 'thumb_down'; } @@ -89,7 +89,7 @@ define(['connectionManager', 'serverNotifications', 'events', 'globalize', 'emby } else { if (icon) { - icon.innerHTML = 'favorite'; + icon.classList.add('favorite'); icon.classList.remove('ratingbutton-icon-withrating'); //icon.innerHTML = 'thumbs_up_down'; } diff --git a/src/components/emby-scrollbuttons/emby-scrollbuttons.css b/src/elements/emby-scrollbuttons/emby-scrollbuttons.css similarity index 70% rename from src/components/emby-scrollbuttons/emby-scrollbuttons.css rename to src/elements/emby-scrollbuttons/emby-scrollbuttons.css index 6786824bd6..b2e0d3bc23 100644 --- a/src/components/emby-scrollbuttons/emby-scrollbuttons.css +++ b/src/elements/emby-scrollbuttons/emby-scrollbuttons.css @@ -4,15 +4,15 @@ right: 0; align-items: center; justify-content: center; - min-width:104px; - min-height:24px; + min-width: 104px; + min-height: 24px; padding-top: 1.25em; z-index: 1; - color: #ffffff; + color: #fff; display: flex; } -.emby-scrollbuttons-button > i { +.emby-scrollbuttons-button > .material-icons { min-width: 24px; min-height: 24px; display: block; diff --git a/src/components/emby-scrollbuttons/emby-scrollbuttons.js b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js similarity index 98% rename from src/components/emby-scrollbuttons/emby-scrollbuttons.js rename to src/elements/emby-scrollbuttons/emby-scrollbuttons.js index deec96d9a2..a4c37384c8 100644 --- a/src/components/emby-scrollbuttons/emby-scrollbuttons.js +++ b/src/elements/emby-scrollbuttons/emby-scrollbuttons.js @@ -10,7 +10,7 @@ define(['layoutManager', 'dom', 'css!./emby-scrollbuttons', 'registerElement', ' var icon = direction === 'left' ? 'chevron_left' : 'chevron_right'; html += ''; return html; diff --git a/src/components/emby-scroller/emby-scroller.css b/src/elements/emby-scroller/emby-scroller.css similarity index 83% rename from src/components/emby-scroller/emby-scroller.css rename to src/elements/emby-scroller/emby-scroller.css index 11c2c73271..d4d2c69c85 100644 --- a/src/components/emby-scroller/emby-scroller.css +++ b/src/elements/emby-scroller/emby-scroller.css @@ -13,6 +13,11 @@ margin-right: 1.2em; } +.servers > .card > .cardBox { + margin-left: 0.6em; + margin-right: 0.6em; +} + .layout-tv .emby-scroller, .layout-mobile .emby-scroller { padding-left: 3.3%; diff --git a/src/components/emby-scroller/emby-scroller.js b/src/elements/emby-scroller/emby-scroller.js similarity index 91% rename from src/components/emby-scroller/emby-scroller.js rename to src/elements/emby-scroller/emby-scroller.js index 0b36483be3..3df40fa6c2 100644 --- a/src/components/emby-scroller/emby-scroller.js +++ b/src/elements/emby-scroller/emby-scroller.js @@ -96,17 +96,6 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro } } - function initHeadroom(elem) { - require(['headroom'], function (Headroom) { - var headroom = new Headroom([], { - scroller: elem - }); - - headroom.add(document.querySelector('.skinHeader')); - elem.headroom = headroom; - }); - } - ScrollerPrototype.attachedCallback = function () { if (this.getAttribute('data-navcommands')) { inputManager.on(this, onInputCommand); @@ -120,8 +109,6 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro 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'; @@ -137,7 +124,7 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro dragHandle: 1, autoImmediate: true, skipSlideToWhenVisible: this.getAttribute('data-skipfocuswhenvisible') === 'true', - dispatchScrollEvent: enableScrollButtons || bindHeader || this.getAttribute('data-scrollevent') === 'true', + dispatchScrollEvent: enableScrollButtons || this.getAttribute('data-scrollevent') === 'true', hideScrollbar: enableScrollButtons || this.getAttribute('data-hidescrollbar') === 'true', allowNativeSmoothScroll: this.getAttribute('data-allownativesmoothscroll') === 'true' && !enableScrollButtons, allowNativeScroll: !enableScrollButtons, @@ -155,10 +142,6 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro initCenterFocus(this, this.scroller); } - if (bindHeader) { - initHeadroom(this); - } - if (enableScrollButtons) { loadScrollButtons(this); } @@ -206,4 +189,4 @@ define(['scroller', 'dom', 'layoutManager', 'inputManager', 'focusManager', 'bro prototype: ScrollerPrototype, extends: 'div' }); -}); \ No newline at end of file +}); diff --git a/src/elements/emby-select/emby-select.css b/src/elements/emby-select/emby-select.css index 4aff8cab92..32aec69c46 100644 --- a/src/elements/emby-select/emby-select.css +++ b/src/elements/emby-select/emby-select.css @@ -2,52 +2,60 @@ 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; + padding: 0.5em 1.9em 0.5em 0.5em; + /* Prevent padding from causing width overflow */ box-sizing: border-box; outline: none !important; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); width: 100%; } - .emby-select[disabled] { - background: none !important; - border-color: transparent !important; - color: inherit !important; - appearance: none; - } - -.selectContainer-inline > .emby-select { - padding: .3em 1.9em .3em .5em; - font-size: inherit; +.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[disabled] { - padding-left: 0; - padding-right: 0; - } - .emby-select::-moz-focus-inner { border: 0; } +.selectContainer-inline > .emby-select { + padding: 0.3em 1.9em 0.3em 0.5em; + font-size: inherit; +} + +.selectContainer-inline > .emby-select[disabled] { + padding-left: 0; + padding-right: 0; +} + .emby-select-focusscale { transition: transform 180ms ease-out !important; + -webkit-transform-origin: center center; transform-origin: center center; } - .emby-select-focusscale:focus { - transform: scale(1.04); - z-index: 1; - } +.emby-select-focusscale:focus { + transform: scale(1.04); + z-index: 1; +} .emby-select + .fieldDescription { - margin-top: .25em; + margin-top: 0.25em; } .selectContainer { @@ -63,31 +71,36 @@ .selectLabel { display: block; - margin-bottom: .25em; + margin-bottom: 0.25em; } .selectContainer-inline > .selectLabel { margin-bottom: 0; - margin-right: .5em; + margin-right: 0.5em; flex-shrink: 0; } +.trackSelections > .selectContainer { + margin: 0.4em 0; +} + .emby-select-withcolor { + -webkit-appearance: none; appearance: none; - border-radius: .2em; + border-radius: 0.2em; } .selectArrowContainer { position: absolute; - right: .3em; - top: .2em; + right: 0.3em; + top: 0.2em; color: inherit; pointer-events: none; } .selectContainer-inline > .selectArrowContainer { top: initial; - bottom: .24em; + bottom: 0.24em; font-size: 90%; } @@ -96,7 +109,7 @@ } .selectArrow { - margin-top: .35em; + margin-top: 1.2em; font-size: 1.7em; } diff --git a/src/elements/emby-select/emby-select.js b/src/elements/emby-select/emby-select.js index 248e7ce570..2716967560 100644 --- a/src/elements/emby-select/emby-select.js +++ b/src/elements/emby-select/emby-select.js @@ -27,8 +27,8 @@ define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registe } function triggerChange(select) { - var evt = document.createEvent("HTMLEvents"); - evt.initEvent("change", false, true); + var evt = document.createEvent('HTMLEvents'); + evt.initEvent('change', false, true); select.dispatchEvent(evt); } @@ -144,7 +144,7 @@ define(['layoutManager', 'browser', 'actionsheet', 'css!./emby-select', 'registe this.parentNode.insertBefore(label, this); if (this.classList.contains('emby-select-withcolor')) { - this.parentNode.insertAdjacentHTML('beforeend', '
0
keyboard_arrow_down
'); + this.parentNode.insertAdjacentHTML('beforeend', '
0
'); } }; diff --git a/src/elements/emby-slider/emby-slider.css b/src/elements/emby-slider/emby-slider.css index 6fc861deb0..7661895f15 100644 --- a/src/elements/emby-slider/emby-slider.css +++ b/src/elements/emby-slider/emby-slider.css @@ -1,79 +1,85 @@ -_:-ms-input-placeholder { +:-ms-input-placeholder { appearance: none; + -ms-appearance: none; height: 2.223em; margin: 0; } .mdl-slider { width: 100%; + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; appearance: none; - height: 150%;/*150% is needed, else ie and edge won't display the thumb properly*/ + height: 150%;/* 150% is needed, else ie and edge won't display the thumb properly */ background: transparent; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; user-select: none; outline: 0; color: #00a4dc; + -webkit-align-self: center; + -ms-flex-item-align: center; align-self: center; z-index: 1; cursor: pointer; margin: 0; + + /* Disable webkit tap highlighting */ + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); display: block; + + font-size: inherit; /* Chrome and Firefox override font size for 'input' */ } - .mdl-slider::-moz-focus-outer { - border: 0; - } - - .mdl-slider::-ms-tooltip { - display: none; - } - - .mdl-slider::-webkit-slider-runnable-track { - background: transparent; - } - - .mdl-slider::-moz-range-track { - background: #444; - border: none; - width: calc(100% - 20px); - } - - .mdl-slider::-moz-range-progress { - background: #00a4dc; - width: calc(100% - 20px); - } - - .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-upper { - display: none; - } - - .mdl-slider::-webkit-slider-thumb { - appearance: none; - width: 1.2em; - height: 1.2em; - box-sizing: border-box; - border-radius: 50%; - background: #00a4dc; - 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 { - transform: none; +.mdl-slider::-moz-focus-outer { + border: 0; } -.mdl-slider:hover::-webkit-slider-thumb { +.mdl-slider::-ms-tooltip { + display: none; +} + +.mdl-slider::-webkit-slider-runnable-track { + background: transparent; +} + +.mdl-slider::-ms-track { + background: none; + color: transparent; + height: 0.2em; + width: 100%; + border: none; +} + +.mdl-slider::-ms-fill-lower { + display: none; +} + +.mdl-slider::-ms-fill-upper { + display: none; +} + +.slider-browser-edge { + margin-left: -0.16em; + margin-right: -0.16em; + width: 150%; /* need to occupy space */ +} + +.mdl-slider::-webkit-slider-thumb { + -webkit-appearance: none; + width: 1.08em; + height: 1.08em; + box-sizing: border-box; + border-radius: 50%; + background: #00a4dc; + border: none; + transition: 0.2s; + pointer-events: none; +} + +.mdl-slider-hoverthumb:hover::-webkit-slider-thumb { transform: scale(1.3); } @@ -81,40 +87,43 @@ _:-ms-input-placeholder { transform: scale(1.3); } -.slider-no-webkit-thumb::-webkit-slider-thumb { - opacity: 0 !important; -} - .mdl-slider::-moz-range-thumb { -moz-appearance: none; - width: 0.9em; - height: 0.9em; + width: 1.08em; + height: 1.08em; box-sizing: border-box; border-radius: 50%; - background-image: none; background: #00a4dc; + background-image: none; border: none; - transform: Scale(1.4, 1.4); + transition: 0.2s; +} + +.mdl-slider-hoverthumb:hover::-moz-range-thumb { + transform: scale(1.3); +} + +.mdl-slider.show-focus:focus::-moz-range-thumb { + transform: scale(1.3); } .mdl-slider::-ms-thumb { - appearance: none; - width: 1.8em; - height: 1.8em; + -webkit-appearance: none; + width: 1.4em; + height: 1.4em; box-sizing: border-box; border-radius: 50%; background: #00a4dc; border: none; - transform: scale(.9, .9); - 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); + transform: scale(0.771429); + transition: 0.2s; } -.mdl-slider-hoverthumb::-ms-thumb { - margin-left: -.4em; - transform: scale(.5, .5); +.mdl-slider-hoverthumb:hover::-ms-thumb { + transform: none; } -.mdl-slider:hover::-ms-thumb { +.mdl-slider.show-focus:focus::-ms-thumb { transform: none; } @@ -130,14 +139,6 @@ _:-ms-input-placeholder { display: none; } -.mdl-slider-ie-container { - height: 1.25em; - overflow: visible; - border: none; - margin: 0; - padding: 0; -} - .mdl-slider-container { height: 1.25em; position: relative; @@ -149,15 +150,16 @@ _:-ms-input-placeholder { .mdl-slider-background-flex-container { width: 100%; box-sizing: border-box; - margin-top: -.05em; top: 50%; + left: 0; position: absolute; + padding: 0 0.54em; /* half of slider thumb size */ } .mdl-slider-background-flex { background: #333; - height: .2em; - margin-top: -.08em; + height: 0.2em; + margin-top: -0.1em; width: 100%; top: 50%; left: 0; @@ -173,7 +175,7 @@ _:-ms-input-placeholder { } .mdl-slider-background-lower { - /*transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/ + /* transition: width 0.18s cubic-bezier(0.4, 0, 0.2, 1); */ position: absolute; left: 0; width: 0; @@ -188,15 +190,16 @@ _:-ms-input-placeholder { .mdl-slider-background-lower-withtransform { width: 100%; - /*transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1);*/ + + /* transition: transform 0.18s cubic-bezier(0.4, 0, 0.2, 1); */ transform-origin: left center; 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);*/ + /* 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); + background: rgba(255, 255, 255, 0.4); position: absolute; left: 0; width: 0; @@ -204,11 +207,18 @@ _:-ms-input-placeholder { bottom: 0; } +.sliderBubbleTrack { + position: absolute; + left: 0; + right: 0; + margin: 0 0.54em; /* half of slider thumb size */ +} + .sliderBubble { position: absolute; top: 0; left: 0; - transform: translate3d(-48%, -120%, 0); + transform: translate3d(-50%, -120%, 0); background: #282828; color: #fff; display: flex; @@ -218,5 +228,5 @@ _:-ms-input-placeholder { .sliderBubbleText { margin: 0; - padding: .5em .75em; + padding: 0.5em 0.75em; } diff --git a/src/elements/emby-slider/emby-slider.js b/src/elements/emby-slider/emby-slider.js index c340e79359..e37455dfe1 100644 --- a/src/elements/emby-slider/emby-slider.js +++ b/src/elements/emby-slider/emby-slider.js @@ -1,9 +1,8 @@ -define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager) { +define(['browser', 'dom', 'layoutManager', 'keyboardnavigation', 'css!./emby-slider', 'registerElement', 'emby-input'], function (browser, dom, layoutManager, keyboardnavigation) { 'use strict'; var EmbySliderPrototype = Object.create(HTMLInputElement.prototype); - var supportsNativeProgressStyle = browser.firefox; var supportsValueSetOverride = false; var enableWidthWithTransform; @@ -17,10 +16,71 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement } } - function updateValues() { + /** + * Returns slider fraction corresponding to client position. + * + * @param {Object} range slider itself + * @param {number} clientX client X-coordinate + * @return {number} slider fraction + */ + function mapClientToFraction(range, clientX) { + var rect = range.sliderBubbleTrack.getBoundingClientRect(); - // Do not update values when dragging with keyboard to keep current progress for reference - if (!!this.keyboardDragging) { + var fraction = (clientX - rect.left) / rect.width; + + // Snap to step + var valueRange = range.max - range.min; + if (range.step !== 'any' && valueRange !== 0) { + var step = (range.step || 1) / valueRange; + fraction = Math.round(fraction / step) * step; + } + + return Math.min(Math.max(fraction, 0), 1); + } + + /** + * Returns slider value corresponding to slider fraction. + * + * @param {Object} range slider itself + * @param {number} fraction slider fraction + * @return {number} slider value + */ + function mapFractionToValue(range, fraction) { + var value = (range.max - range.min) * fraction; + + // Snap to step + if (range.step !== 'any') { + var step = range.step || 1; + value = Math.round(value / step) * step; + } + + value += parseFloat(range.min); + + return Math.min(Math.max(value, range.min), range.max); + } + + /** + * Returns slider fraction corresponding to slider value. + * + * @param {Object} range slider itself + * @param {number} value slider value (snapped to step) + * @return {number} slider fraction + */ + function mapValueToFraction(range, value) { + var valueRange = range.max - range.min; + var fraction = valueRange !== 0 ? (value - range.min) / valueRange : 0; + return Math.min(Math.max(fraction, 0), 1); + } + + /** + * Updates progress bar. + * + * @param {boolean} [isValueSet] update by 'valueset' event or by timer + */ + function updateValues(isValueSet) { + + // Do not update values by 'valueset' in case of soft-implemented dragging + if (!!isValueSet && (!!this.keyboardDragging || !!this.touched)) { return; } @@ -28,7 +88,9 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement 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 () { + // Keep only one per slider frame request + cancelAnimationFrame(range.updateValuesFrame); + range.updateValuesFrame = requestAnimationFrame(function () { var backgroundLower = range.backgroundLower; @@ -48,8 +110,13 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement function updateBubble(range, value, bubble, bubbleText) { requestAnimationFrame(function () { + var bubbleTrackRect = range.sliderBubbleTrack.getBoundingClientRect(); + var bubbleRect = bubble.getBoundingClientRect(); - bubble.style.left = value + '%'; + var bubblePos = bubbleTrackRect.width * value / 100; + bubblePos = Math.min(Math.max(bubblePos, bubbleRect.width / 2), bubbleTrackRect.width - bubbleRect.width / 2); + + bubble.style.left = bubblePos + 'px'; if (range.getBubbleHtml) { value = range.getBubbleHtml(value); @@ -57,7 +124,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement if (range.getBubbleText) { value = range.getBubbleText(value); } else { - value = Math.round(value); + value = mapFractionToValue(range, value / 100).toLocaleString(); } value = '

' + value + '

'; } @@ -81,8 +148,8 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement this.classList.add('mdl-slider'); this.classList.add('mdl-js-slider'); - if (browser.noFlex) { - this.classList.add('slider-no-webkit-thumb'); + if (browser.edge || browser.msie) { + this.classList.add('slider-browser-edge'); } if (!layoutManager.mobile) { this.classList.add('mdl-slider-hoverthumb'); @@ -96,29 +163,28 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement var htmlToInsert = ''; - if (!supportsNativeProgressStyle) { - htmlToInsert += '
'; - htmlToInsert += '
'; - htmlToInsert += '
'; + htmlToInsert += '
'; + htmlToInsert += '
'; + htmlToInsert += '
'; - // the more of these, the more ranges we can display - htmlToInsert += '
'; + // the more of these, the more ranges we can display + htmlToInsert += '
'; - if (enableWidthWithTransform) { - htmlToInsert += '
'; - } else { - htmlToInsert += '
'; - } - - htmlToInsert += '
'; - htmlToInsert += '
'; - htmlToInsert += '
'; + if (enableWidthWithTransform) { + htmlToInsert += '
'; + } else { + htmlToInsert += '
'; } - htmlToInsert += '
'; + htmlToInsert += '
'; + htmlToInsert += '
'; + htmlToInsert += '
'; + + htmlToInsert += '
'; containerElement.insertAdjacentHTML('beforeend', htmlToInsert); + this.sliderBubbleTrack = containerElement.querySelector('.sliderBubbleTrack'); this.backgroundLower = containerElement.querySelector('.mdl-slider-background-lower'); this.backgroundUpper = containerElement.querySelector('.mdl-slider-background-upper'); var sliderBubble = containerElement.querySelector('.sliderBubble'); @@ -128,7 +194,12 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement dom.addEventListener(this, 'input', function (e) { this.dragging = true; - updateBubble(this, this.value, sliderBubble); + if (this.dataset.sliderKeepProgress !== 'true') { + updateValues.call(this); + } + + var bubbleValue = mapValueToFraction(this, this.value) * 100; + updateBubble(this, bubbleValue, sliderBubble); if (hasHideClass) { sliderBubble.classList.remove('hide'); @@ -140,7 +211,10 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement dom.addEventListener(this, 'change', function () { this.dragging = false; - updateValues.call(this); + + if (this.dataset.sliderKeepProgress === 'true') { + updateValues.call(this); + } sliderBubble.classList.add('hide'); hasHideClass = true; @@ -152,10 +226,8 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement 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; + var bubbleValue = mapClientToFraction(this, e.clientX) * 100; + updateBubble(this, bubbleValue, sliderBubble); if (hasHideClass) { @@ -175,13 +247,66 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement passive: true }); - if (!supportsNativeProgressStyle) { + // HACK: iPhone/iPad do not change input by touch + if (browser.iOS) { + dom.addEventListener(this, 'touchstart', function (e) { + if (e.targetTouches.length !== 1) { + return; + } - if (supportsValueSetOverride) { - this.addEventListener('valueset', updateValues); - } else { - startInterval(this); - } + this.touched = true; + + var fraction = mapClientToFraction(this, e.targetTouches[0].clientX); + this.value = mapFractionToValue(this, fraction); + + this.dispatchEvent(new Event('input', { + bubbles: true, + cancelable: false + })); + + // Prevent 'pointermove' and 'click' after 'touch*' + // FIXME: Still have some 'pointermove' and 'click' that bypass 'touchstart' + e.preventDefault(); + }, { + capture: true + }); + + dom.addEventListener(this, 'touchmove', function (e) { + if (!this.touched || e.targetTouches.length !== 1) { + return; + } + + var fraction = mapClientToFraction(this, e.targetTouches[0].clientX); + this.value = mapFractionToValue(this, fraction); + + this.dispatchEvent(new Event('input', { + bubbles: true, + cancelable: false + })); + }, { + passive: true + }); + + dom.addEventListener(this, 'touchend', function (e) { + var range = this; + + setTimeout(function () { + range.touched = false; + + range.dispatchEvent(new Event('change', { + bubbles: true, + cancelable: false + })); + }, 0); + }, { + passive: true + }); + } + + if (supportsValueSetOverride) { + this.addEventListener('valueset', updateValues.bind(this, true)); + } else { + startInterval(this); } }; @@ -250,7 +375,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement * Handle KeyDown event */ function onKeyDown(e) { - switch (e.key) { + switch (keyboardnavigation.getKeyName(e)) { case 'ArrowLeft': case 'Left': stepKeyboard(this, -this.keyboardStepDown || -1); @@ -274,7 +399,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement this.addEventListener('keydown', onKeyDown); this.keyboardDraggingEnabled = true; } - } + }; /** * Set steps for keyboard input. @@ -285,7 +410,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement EmbySliderPrototype.setKeyboardSteps = function (stepDown, stepUp) { this.keyboardStepDown = stepDown || stepUp || 1; this.keyboardStepUp = stepUp || stepDown || 1; - } + }; function setRange(elem, startPercent, endPercent) { @@ -358,7 +483,7 @@ define(['browser', 'dom', 'layoutManager', 'css!./emby-slider', 'registerElement if (interval) { clearInterval(interval); } - range.interval = setInterval(updateValues.bind(range), 100); + range.interval = setInterval(updateValues.bind(range, true), 100); } EmbySliderPrototype.detachedCallback = function () { diff --git a/src/components/emby-tabs/emby-tabs.css b/src/elements/emby-tabs/emby-tabs.css similarity index 77% rename from src/components/emby-tabs/emby-tabs.css rename to src/elements/emby-tabs/emby-tabs.css index b8831b881a..355f904cb8 100644 --- a/src/components/emby-tabs/emby-tabs.css +++ b/src/elements/emby-tabs/emby-tabs.css @@ -1,4 +1,7 @@ .emby-tab-button { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; background: transparent; box-shadow: none; cursor: pointer; @@ -10,11 +13,11 @@ vertical-align: middle; flex-shrink: 0; margin: 0; - padding: 1em 0.9em; + padding: 1.5em 1.5em; position: relative; height: auto; min-width: initial; - line-height: initial; + line-height: 1.25; border-radius: 0; overflow: hidden; font-weight: 600; @@ -31,6 +34,10 @@ overflow: hidden; } +.layout-mobile .emby-tabs-slider { + overflow: auto; +} + .tabContent:not(.is-active) { display: none; } diff --git a/src/components/emby-tabs/emby-tabs.js b/src/elements/emby-tabs/emby-tabs.js similarity index 96% rename from src/components/emby-tabs/emby-tabs.js rename to src/elements/emby-tabs/emby-tabs.js index 9fedf0bfe9..5e03c3f096 100644 --- a/src/components/emby-tabs/emby-tabs.js +++ b/src/elements/emby-tabs/emby-tabs.js @@ -46,7 +46,7 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register function triggerBeforeTabChange(tabs, index, previousIndex) { - tabs.dispatchEvent(new CustomEvent("beforetabchange", { + tabs.dispatchEvent(new CustomEvent('beforetabchange', { detail: { selectedTabIndex: index, previousIndex: previousIndex @@ -94,7 +94,7 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register tabs.selectedTabIndex = index; - tabs.dispatchEvent(new CustomEvent("tabchange", { + tabs.dispatchEvent(new CustomEvent('tabchange', { detail: { selectedTabIndex: index, previousIndex: previousIndex @@ -198,7 +198,7 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register if (!this.readyFired) { this.readyFired = true; - this.dispatchEvent(new CustomEvent("ready", {})); + this.dispatchEvent(new CustomEvent('ready', {})); } }; @@ -238,7 +238,7 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register triggerBeforeTabChange(tabs, selected, current); - tabs.dispatchEvent(new CustomEvent("tabchange", { + tabs.dispatchEvent(new CustomEvent('tabchange', { detail: { selectedTabIndex: selected } @@ -315,7 +315,7 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register var tabs = this; - tabs.dispatchEvent(new CustomEvent("tabchange", { + tabs.dispatchEvent(new CustomEvent('tabchange', { detail: { selectedTabIndex: tabs.selectedIndex() } @@ -338,4 +338,4 @@ define(['dom', 'scroller', 'browser', 'layoutManager', 'focusManager', 'register prototype: EmbyTabs, extends: 'div' }); -}); \ No newline at end of file +}); diff --git a/src/elements/emby-textarea/emby-textarea.css b/src/elements/emby-textarea/emby-textarea.css index 0dab1b1ece..0866664914 100644 --- a/src/elements/emby-textarea/emby-textarea.css +++ b/src/elements/emby-textarea/emby-textarea.css @@ -2,30 +2,35 @@ 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; + padding: 0.35em 0.25em; + /* Prevent padding from causing width overflow */ box-sizing: border-box; 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; - transition: all .2s ease-out; - margin-bottom: .25em; + transition: all 0.2s ease-out; + margin-bottom: 0.25em; } .emby-textarea + .fieldDescription { - margin-top: .25em; + margin-top: 0.25em; } diff --git a/src/elements/emby-textarea/emby-textarea.js b/src/elements/emby-textarea/emby-textarea.js index c500db6e1f..e0ce77aa51 100644 --- a/src/elements/emby-textarea/emby-textarea.js +++ b/src/elements/emby-textarea/emby-textarea.js @@ -135,4 +135,4 @@ define(['layoutManager', 'browser', 'css!./emby-textarea', 'registerElement', 'e prototype: EmbyTextAreaPrototype, extends: 'textarea' }); -}); \ No newline at end of file +}); diff --git a/src/elements/emby-toggle/emby-toggle.css b/src/elements/emby-toggle/emby-toggle.css index 3b14b8cf09..3b5c5a5f64 100644 --- a/src/elements/emby-toggle/emby-toggle.css +++ b/src/elements/emby-toggle/emby-toggle.css @@ -9,6 +9,10 @@ margin: 0; padding: 0; overflow: visible; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; user-select: none; flex-direction: row-reverse; justify-content: flex-end; @@ -24,6 +28,9 @@ margin: 0; padding: 0; opacity: 0; + -ms-appearance: none; + -moz-appearance: none; + -webkit-appearance: none; appearance: none; border: none; } @@ -34,7 +41,7 @@ } .mdl-switch__track { - background: rgba(128,128,128, 0.5); + background: rgba(128, 128, 128, 0.5); height: 1em; border-radius: 1em; cursor: pointer; @@ -45,7 +52,7 @@ } .mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__track { - background: rgba(0,0,0, 0.12); + background: rgba(0, 0, 0, 0.12); cursor: auto; } @@ -53,7 +60,7 @@ background: #999; position: absolute; left: 0; - top: -.25em; + top: -0.25em; height: 1.44em; width: 1.44em; border-radius: 50%; @@ -70,11 +77,11 @@ .mdl-switch__input:checked + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb { background: #00a4dc; left: 1.466em; - 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); + 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 0.56em 0 rgba(0, 0, 0, 0.12); } .mdl-switch__input[disabled] + .mdl-switch__label + .mdl-switch__trackContainer > .mdl-switch__thumb { - background: rgb(189,189,189); + background: rgb(189, 189, 189); cursor: auto; } @@ -82,17 +89,18 @@ position: absolute; top: 50%; left: 50%; + -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); display: inline-block; box-sizing: border-box; - width: .6em; - height: .6em; + width: 0.6em; + height: 0.6em; border-radius: 50%; background-color: transparent; } .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); + box-shadow: 0 0 0 1.39em rgba(0, 0, 0, 0.05); } .mdl-switch__input:checked:focus + .mdl-switch__label + .mdl-switch__trackContainer .mdl-switch__focus-helper { @@ -105,10 +113,10 @@ margin: 0; display: inline-flex; align-items: center; - margin-left: .7em; + margin-left: 0.7em; } .mdl-switch__input[disabled] .mdl-switch__label { - color: rgb(189,189,189); + color: rgb(189, 189, 189); cursor: auto; } diff --git a/src/elements/emby-toggle/emby-toggle.js b/src/elements/emby-toggle/emby-toggle.js index 08597164b2..bd7eba3078 100644 --- a/src/elements/emby-toggle/emby-toggle.js +++ b/src/elements/emby-toggle/emby-toggle.js @@ -47,4 +47,4 @@ define(['css!./emby-toggle', 'registerElement'], function () { prototype: EmbyTogglePrototype, extends: 'input' }); -}); \ No newline at end of file +}); diff --git a/src/encodingsettings.html b/src/encodingsettings.html index 3d67544c0b..8971957b71 100644 --- a/src/encodingsettings.html +++ b/src/encodingsettings.html @@ -5,7 +5,7 @@

${TabTranscoding}

- ${Help} + ${Help}
@@ -20,7 +20,9 @@ -
${LabelHardwareAccelerationTypeHelp}
+
@@ -94,7 +96,7 @@
- +
${LabelffmpegPathHelp}
@@ -105,7 +107,7 @@
- +
${LabelTranscodingTempPathHelp}
@@ -115,7 +117,7 @@
- @@ -127,13 +129,21 @@ -
${H264EncodingPresetHelp}
+
${EncoderPresetHelp}
${H264CrfHelp}
+
+ +
${DeinterlaceMethodHelp}
+
+
+
+ +
${AllowFfmpegThrottlingHelp}
+
+
-
\ No newline at end of file +
diff --git a/src/itemdetails.html b/src/itemdetails.html index fbe0cc50de..37f1432e23 100644 --- a/src/itemdetails.html +++ b/src/itemdetails.html @@ -1,7 +1,7 @@ -
-
+
+
@@ -15,118 +15,128 @@
- - - - - - - - - - - -
-
+
-
+
-
-
-
-
+
+
+
+
+
+ +
+
+
+
+
+ + +
-
+
-
+
-
+
@@ -176,56 +186,56 @@
-

${HeaderAdditionalParts}

-
+

${HeaderAdditionalParts}

+

-
+

-
+

${HeaderCastCrew}

-
+

${HeaderUpcomingOnTV}

-
+
-

${HeaderSpecialFeatures}

-
+

${HeaderSpecialFeatures}

+
-

${HeaderMusicVideos}

-
+

${HeaderMusicVideos}

+

${HeaderScenes}

-
+

${HeaderMoreLikeThis}

-
+
diff --git a/src/legacy/dashboard.js b/src/legacy/dashboard.js index 11ba3177b7..08c5e8330b 100644 --- a/src/legacy/dashboard.js +++ b/src/legacy/dashboard.js @@ -1,20 +1,24 @@ Dashboard.confirm = function(message, title, callback) { - "use strict"; - require(["confirm"], function(confirm) { + 'use strict'; + require(['confirm'], function(confirm) { confirm(message, title).then(function() { - callback(!0) - }, function() { - callback(!1) - }) - }) -}, Dashboard.showLoadingMsg = function() { - "use strict"; - require(["loading"], function(loading) { - loading.show() - }) -}, Dashboard.hideLoadingMsg = function() { - "use strict"; - require(["loading"], function(loading) { - loading.hide() - }) -}; \ No newline at end of file + callback(!0); + }).catch(function() { + callback(!1); + }); + }); +}; + +Dashboard.showLoadingMsg = function() { + 'use strict'; + require(['loading'], function(loading) { + loading.show(); + }); +}; + +Dashboard.hideLoadingMsg = function() { + 'use strict'; + require(['loading'], function(loading) { + loading.hide(); + }); +}; diff --git a/src/legacy/fnchecked.js b/src/legacy/fnchecked.js index 120f6e148a..c3eff813e0 100644 --- a/src/legacy/fnchecked.js +++ b/src/legacy/fnchecked.js @@ -1,10 +1,12 @@ -define(["jQuery"], function($) { - "use strict"; +define(['jQuery'], function($) { + 'use strict'; $.fn.checked = function(value) { return !0 === value || !1 === value ? $(this).each(function() { - this.checked = value - }) : this.length && this[0].checked - }, $.fn.checkboxradio = function() { - return this - } -}); \ No newline at end of file + this.checked = value; + }) : this.length && this[0].checked; + }; + + $.fn.checkboxradio = function() { + return this; + }; +}); diff --git a/src/components/polyfills/focusPreventScroll.js b/src/legacy/focusPreventScroll.js similarity index 76% rename from src/components/polyfills/focusPreventScroll.js rename to src/legacy/focusPreventScroll.js index 6511c0426c..93f53dca29 100644 --- a/src/components/polyfills/focusPreventScroll.js +++ b/src/legacy/focusPreventScroll.js @@ -4,14 +4,15 @@ if (HTMLElement.prototype.nativeFocus === undefined) { (function () { var supportsPreventScrollOption = false; try { - var focusElem = document.createElement("div"); + var focusElem = document.createElement('div'); - focusElem.addEventListener("focus", function(event) { + focusElem.addEventListener('focus', function(event) { event.preventDefault(); event.stopPropagation(); }, true); - var opts = Object.defineProperty({}, "preventScroll", { + var opts = Object.defineProperty({}, 'preventScroll', { + // eslint-disable-next-line getter-return get: function () { supportsPreventScrollOption = true; } @@ -19,7 +20,7 @@ if (HTMLElement.prototype.nativeFocus === undefined) { focusElem.focus(opts); } catch (e) { - console.log("error checking preventScroll support"); + console.error('error checking preventScroll support'); } if (!supportsPreventScrollOption) { diff --git a/src/legacy/selectmenu.js b/src/legacy/selectmenu.js index bc211b9664..f4cc5466b1 100644 --- a/src/legacy/selectmenu.js +++ b/src/legacy/selectmenu.js @@ -1,6 +1,6 @@ -define(["jQuery"], function($) { - "use strict"; +define(['jQuery'], function($) { + 'use strict'; $.fn.selectmenu = function() { - return this - } -}); \ No newline at end of file + return this; + }; +}); diff --git a/src/libraries/apiclient/apiclient.js b/src/libraries/apiclient/apiclient.js deleted file mode 100644 index 06d9cf0861..0000000000 --- a/src/libraries/apiclient/apiclient.js +++ /dev/null @@ -1,236 +0,0 @@ -//TODO: (vitorsemeano) modify this lines for webpack -define(["libraries/apiclient/apiclientcore", "localassetmanager"], function(ApiClient, localassetmanager) { - "use strict"; - - if ("cordova" !== window.appMode && "android" !== window.appMode) { - return ApiClient; - } - - function isLocalId(str) { - return startsWith(str, localPrefix) - } - - function isLocalViewId(str) { - return startsWith(str, localViewPrefix) - } - - function isTopLevelLocalViewId(str) { - return "localview" === str - } - - function stripLocalPrefix(str) { - var res = stripStart(str, localPrefix); - return res = stripStart(res, localViewPrefix) - } - - function startsWith(str, find) { - return !!(str && find && str.length > find.length && 0 === str.indexOf(find)) - } - - function stripStart(str, find) { - return startsWith(str, find) ? str.substr(find.length) : str - } - - function createEmptyList() { - return { - Items: [], - TotalRecordCount: 0 - } - } - - function convertGuidToLocal(guid) { - return guid ? isLocalId(guid) ? guid : "local:" + guid : null - } - - function adjustGuidProperties(downloadedItem) { - downloadedItem.Id = convertGuidToLocal(downloadedItem.Id), downloadedItem.SeriesId = convertGuidToLocal(downloadedItem.SeriesId), downloadedItem.SeasonId = convertGuidToLocal(downloadedItem.SeasonId), downloadedItem.AlbumId = convertGuidToLocal(downloadedItem.AlbumId), downloadedItem.ParentId = convertGuidToLocal(downloadedItem.ParentId), downloadedItem.ParentThumbItemId = convertGuidToLocal(downloadedItem.ParentThumbItemId), downloadedItem.ParentPrimaryImageItemId = convertGuidToLocal(downloadedItem.ParentPrimaryImageItemId), downloadedItem.PrimaryImageItemId = convertGuidToLocal(downloadedItem.PrimaryImageItemId), downloadedItem.ParentLogoItemId = convertGuidToLocal(downloadedItem.ParentLogoItemId), downloadedItem.ParentBackdropItemId = convertGuidToLocal(downloadedItem.ParentBackdropItemId), downloadedItem.ParentBackdropImageTags = null - } - - function getLocalView(instance, serverId, userId) { - return instance.getLocalFolders(serverId, userId).then(function(views) { - var localView = null; - return views.length > 0 && (localView = { - Name: instance.downloadsTitleText || "Downloads", - ServerId: serverId, - Id: "localview", - Type: "localview", - IsFolder: !0 - }), Promise.resolve(localView) - }) - } - - function ApiClientEx(serverAddress, clientName, applicationVersion, deviceName, deviceId, devicePixelRatio) { - ApiClient.call(this, serverAddress, clientName, applicationVersion, deviceName, deviceId, devicePixelRatio) - } - var localPrefix = "local:", - localViewPrefix = "localview:"; - return Object.assign(ApiClientEx.prototype, ApiClient.prototype), ApiClientEx.prototype.getPlaybackInfo = function(itemId, options, deviceProfile) { - var onFailure = function() { - return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile) - }; - if (isLocalId(itemId)) return localassetmanager.getLocalItem(this.serverId(), stripLocalPrefix(itemId)).then(function(item) { - return { - MediaSources: item.Item.MediaSources.map(function(m) { - return m.SupportsDirectPlay = !0, m.SupportsDirectStream = !1, m.SupportsTranscoding = !1, m.IsLocal = !0, m - }) - } - }, onFailure); - var instance = this; - return localassetmanager.getLocalItem(this.serverId(), itemId).then(function(item) { - if (item) { - var mediaSources = item.Item.MediaSources.map(function(m) { - return m.SupportsDirectPlay = !0, m.SupportsDirectStream = !1, m.SupportsTranscoding = !1, m.IsLocal = !0, m - }); - return localassetmanager.fileExists(item.LocalPath).then(function(exists) { - if (exists) { - var res = { - MediaSources: mediaSources - }; - return Promise.resolve(res) - } - return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile) - }, onFailure) - } - return ApiClient.prototype.getPlaybackInfo.call(instance, itemId, options, deviceProfile) - }, onFailure) - }, ApiClientEx.prototype.getItems = function(userId, options) { - var i, serverInfo = this.serverInfo(); - if (serverInfo && "localview" === options.ParentId) return this.getLocalFolders(serverInfo.Id, userId).then(function(items) { - var result = { - Items: items, - TotalRecordCount: items.length - }; - return Promise.resolve(result) - }); - if (serverInfo && options && (isLocalId(options.ParentId) || isLocalId(options.SeriesId) || isLocalId(options.SeasonId) || isLocalViewId(options.ParentId) || isLocalId(options.AlbumIds))) return localassetmanager.getViewItems(serverInfo.Id, userId, options).then(function(items) { - items.forEach(function(item) { - adjustGuidProperties(item) - }); - var result = { - Items: items, - TotalRecordCount: items.length - }; - return Promise.resolve(result) - }); - if (options && options.ExcludeItemIds && options.ExcludeItemIds.length) { - var exItems = options.ExcludeItemIds.split(","); - for (i = 0; i < exItems.length; i++) - if (isLocalId(exItems[i])) return Promise.resolve(createEmptyList()) - } else if (options && options.Ids && options.Ids.length) { - var ids = options.Ids.split(","), - hasLocal = !1; - for (i = 0; i < ids.length; i++) isLocalId(ids[i]) && (hasLocal = !0); - if (hasLocal) return localassetmanager.getItemsFromIds(serverInfo.Id, ids).then(function(items) { - items.forEach(function(item) { - adjustGuidProperties(item) - }); - var result = { - Items: items, - TotalRecordCount: items.length - }; - return Promise.resolve(result) - }) - } - return ApiClient.prototype.getItems.call(this, userId, options) - }, ApiClientEx.prototype.getUserViews = function(options, userId) { - var instance = this; - options = options || {}; - var basePromise = ApiClient.prototype.getUserViews.call(instance, options, userId); - return options.enableLocalView ? basePromise.then(function(result) { - var serverInfo = instance.serverInfo(); - return serverInfo ? getLocalView(instance, serverInfo.Id, userId).then(function(localView) { - return localView && (result.Items.push(localView), result.TotalRecordCount++), Promise.resolve(result) - }) : Promise.resolve(result) - }) : basePromise - }, ApiClientEx.prototype.getItem = function(userId, itemId) { - if (!itemId) throw new Error("null itemId"); - itemId && (itemId = itemId.toString()); - var serverInfo; - return isTopLevelLocalViewId(itemId) && (serverInfo = this.serverInfo()) ? getLocalView(this, serverInfo.Id, userId) : isLocalViewId(itemId) && (serverInfo = this.serverInfo()) ? this.getLocalFolders(serverInfo.Id, userId).then(function(items) { - var views = items.filter(function(item) { - return item.Id === itemId - }); - return views.length > 0 ? Promise.resolve(views[0]) : Promise.reject() - }) : isLocalId(itemId) && (serverInfo = this.serverInfo()) ? localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(itemId)).then(function(item) { - return adjustGuidProperties(item.Item), Promise.resolve(item.Item) - }) : ApiClient.prototype.getItem.call(this, userId, itemId) - }, ApiClientEx.prototype.getLocalFolders = function(userId) { - var serverInfo = this.serverInfo(); - return userId = userId || serverInfo.UserId, localassetmanager.getViews(serverInfo.Id, userId) - }, ApiClientEx.prototype.getNextUpEpisodes = function(options) { - return options.SeriesId && isLocalId(options.SeriesId) ? Promise.resolve(createEmptyList()) : ApiClient.prototype.getNextUpEpisodes.call(this, options) - }, ApiClientEx.prototype.getSeasons = function(itemId, options) { - return isLocalId(itemId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Season", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : ApiClient.prototype.getSeasons.call(this, itemId, options) - }, ApiClientEx.prototype.getEpisodes = function(itemId, options) { - return isLocalId(options.SeasonId) || isLocalId(options.seasonId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Episode", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : isLocalId(itemId) ? (options.SeriesId = itemId, options.IncludeItemTypes = "Episode", options.SortBy = "SortName", this.getItems(this.getCurrentUserId(), options)) : ApiClient.prototype.getEpisodes.call(this, itemId, options) - }, ApiClientEx.prototype.getLatestOfflineItems = function(options) { - options.SortBy = "DateCreated", options.SortOrder = "Descending"; - var serverInfo = this.serverInfo(); - return serverInfo ? localassetmanager.getViewItems(serverInfo.Id, null, options).then(function(items) { - return items.forEach(function(item) { - adjustGuidProperties(item) - }), Promise.resolve(items) - }) : Promise.resolve([]) - }, ApiClientEx.prototype.getThemeMedia = function(userId, itemId, inherit) { - return isLocalViewId(itemId) || isLocalId(itemId) || isTopLevelLocalViewId(itemId) ? Promise.reject() : ApiClient.prototype.getThemeMedia.call(this, userId, itemId, inherit) - }, ApiClientEx.prototype.getSpecialFeatures = function(userId, itemId) { - return isLocalId(itemId) ? Promise.resolve([]) : ApiClient.prototype.getSpecialFeatures.call(this, userId, itemId) - }, ApiClientEx.prototype.getSimilarItems = function(itemId, options) { - return isLocalId(itemId) ? Promise.resolve(createEmptyList()) : ApiClient.prototype.getSimilarItems.call(this, itemId, options) - }, ApiClientEx.prototype.updateFavoriteStatus = function(userId, itemId, isFavorite) { - return isLocalId(itemId) ? Promise.resolve() : ApiClient.prototype.updateFavoriteStatus.call(this, userId, itemId, isFavorite) - }, ApiClientEx.prototype.getScaledImageUrl = function(itemId, options) { - if (isLocalId(itemId) || options && options.itemid && isLocalId(options.itemid)) { - var serverInfo = this.serverInfo(), - id = stripLocalPrefix(itemId); - return localassetmanager.getImageUrl(serverInfo.Id, id, options) - } - return ApiClient.prototype.getScaledImageUrl.call(this, itemId, options) - }, ApiClientEx.prototype.reportPlaybackStart = function(options) { - if (!options) throw new Error("null options"); - return isLocalId(options.ItemId) ? Promise.resolve() : ApiClient.prototype.reportPlaybackStart.call(this, options) - }, ApiClientEx.prototype.reportPlaybackProgress = function(options) { - if (!options) throw new Error("null options"); - if (isLocalId(options.ItemId)) { - var serverInfo = this.serverInfo(); - return serverInfo ? localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(options.ItemId)).then(function(item) { - var libraryItem = item.Item; - return "Video" === libraryItem.MediaType || "AudioBook" === libraryItem.Type ? (libraryItem.UserData = libraryItem.UserData || {}, libraryItem.UserData.PlaybackPositionTicks = options.PositionTicks, libraryItem.UserData.PlayedPercentage = Math.min(libraryItem.RunTimeTicks ? (options.PositionTicks || 0) / libraryItem.RunTimeTicks * 100 : 0, 100), localassetmanager.addOrUpdateLocalItem(item)) : Promise.resolve() - }) : Promise.resolve() - } - return ApiClient.prototype.reportPlaybackProgress.call(this, options) - }, ApiClientEx.prototype.reportPlaybackStopped = function(options) { - if (!options) throw new Error("null options"); - if (isLocalId(options.ItemId)) { - var serverInfo = this.serverInfo(), - action = { - Date: (new Date).getTime(), - ItemId: stripLocalPrefix(options.ItemId), - PositionTicks: options.PositionTicks, - ServerId: serverInfo.Id, - Type: 0, - UserId: this.getCurrentUserId() - }; - return localassetmanager.recordUserAction(action) - } - return ApiClient.prototype.reportPlaybackStopped.call(this, options) - }, ApiClientEx.prototype.getIntros = function(itemId) { - return isLocalId(itemId) ? Promise.resolve({ - Items: [], - TotalRecordCount: 0 - }) : ApiClient.prototype.getIntros.call(this, itemId) - }, ApiClientEx.prototype.getInstantMixFromItem = function(itemId, options) { - return isLocalId(itemId) ? Promise.resolve({ - Items: [], - TotalRecordCount: 0 - }) : ApiClient.prototype.getInstantMixFromItem.call(this, itemId, options) - }, ApiClientEx.prototype.getItemDownloadUrl = function(itemId) { - if (isLocalId(itemId)) { - var serverInfo = this.serverInfo(); - if (serverInfo) return localassetmanager.getLocalItem(serverInfo.Id, stripLocalPrefix(itemId)).then(function(item) { - return Promise.resolve(item.LocalPath) - }) - } - return ApiClient.prototype.getItemDownloadUrl.call(this, itemId) - }, ApiClientEx -}); \ No newline at end of file diff --git a/src/libraries/apiclient/apiclientcore.js b/src/libraries/apiclient/apiclientcore.js deleted file mode 100644 index b6c98ebbd9..0000000000 --- a/src/libraries/apiclient/apiclientcore.js +++ /dev/null @@ -1,1548 +0,0 @@ -define(["events", "appStorage"], function(events, appStorage) { - "use strict"; - - function redetectBitrate(instance) { - stopBitrateDetection(instance), instance.accessToken() && !1 !== instance.enableAutomaticBitrateDetection && setTimeout(redetectBitrateInternal.bind(instance), 6e3) - } - - function redetectBitrateInternal() { - this.accessToken() && this.detectBitrate() - } - - function stopBitrateDetection(instance) { - instance.detectTimeout && clearTimeout(instance.detectTimeout) - } - - function replaceAll(originalString, strReplace, strWith) { - var reg = new RegExp(strReplace, "ig"); - return originalString.replace(reg, strWith) - } - - function onFetchFail(instance, url, response) { - events.trigger(instance, "requestfail", [{ - url: url, - status: response.status, - errorCode: response.headers ? response.headers.get("X-Application-Error-Code") : null - }]) - } - - 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)) - } - return values.join("&") - } - - function fetchWithTimeout(url, options, timeoutMs) { - 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), resolve(response) - }, function(error) { - clearTimeout(timeout), reject(error) - }) - }) - } - - function getFetchPromise(request) { - var headers = request.headers || {}; - "json" === request.dataType && (headers.accept = "application/json"); - var fetchRequest = { - headers: headers, - method: request.type, - credentials: "same-origin" - }, - contentType = request.contentType; - return 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), request.timeout ? fetchWithTimeout(request.url, fetchRequest, request.timeout) : fetch(request.url, fetchRequest) - } - - function ApiClient(serverAddress, appName, appVersion, deviceName, deviceId, devicePixelRatio) { - if (!serverAddress) throw new Error("Must supply a serverAddress"); - console.log("ApiClient serverAddress: " + serverAddress), console.log("ApiClient appName: " + appName), console.log("ApiClient appVersion: " + appVersion), console.log("ApiClient deviceName: " + deviceName), console.log("ApiClient deviceId: " + deviceId), this._serverInfo = {}, this._serverAddress = serverAddress, this._deviceId = deviceId, this._deviceName = deviceName, this._appName = appName, this._appVersion = appVersion, this._devicePixelRatio = devicePixelRatio - } - - function setSavedEndpointInfo(instance, info) { - instance._endPointInfo = info - } - - function getTryConnectPromise(instance, url, state, resolve, reject) { - console.log("getTryConnectPromise " + url), fetchWithTimeout(instance.getUrl("system/info/public", null, url), { - method: "GET", - accept: "application/json" - }, 15e3).then(function() { - state.resolved || (state.resolved = !0, console.log("Reconnect succeeded to " + url), instance.serverAddress(url), resolve()) - }, function() { - state.resolved || (console.log("Reconnect failed to " + url), ++state.rejects >= state.numAddresses && reject()) - }) - } - - function tryReconnectInternal(instance) { - var addresses = [], - addressesStrings = [], - serverInfo = instance.serverInfo(); - return serverInfo.LocalAddress && -1 === addressesStrings.indexOf(serverInfo.LocalAddress) && (addresses.push({ - url: serverInfo.LocalAddress, - timeout: 0 - }), addressesStrings.push(addresses[addresses.length - 1].url)), serverInfo.ManualAddress && -1 === addressesStrings.indexOf(serverInfo.ManualAddress) && (addresses.push({ - url: serverInfo.ManualAddress, - timeout: 100 - }), addressesStrings.push(addresses[addresses.length - 1].url)), serverInfo.RemoteAddress && -1 === addressesStrings.indexOf(serverInfo.RemoteAddress) && (addresses.push({ - url: serverInfo.RemoteAddress, - timeout: 200 - }), addressesStrings.push(addresses[addresses.length - 1].url)), console.log("tryReconnect: " + addressesStrings.join("|")), new Promise(function(resolve, reject) { - var state = {}; - state.numAddresses = addresses.length, state.rejects = 0, addresses.map(function(url) { - setTimeout(function() { - state.resolved || getTryConnectPromise(instance, url.url, state, resolve, reject) - }, url.timeout) - }) - }) - } - - function tryReconnect(instance, retryCount) { - return retryCount = retryCount || 0, retryCount >= 20 ? Promise.reject() : tryReconnectInternal(instance).catch(function(err) { - return console.log("error in tryReconnectInternal: " + (err || "")), new Promise(function(resolve, reject) { - setTimeout(function() { - tryReconnect(instance, retryCount + 1).then(resolve, reject) - }, 500) - }) - }) - } - - function getCachedUser(instance, userId) { - var serverId = instance.serverId(); - if (!serverId) return null; - var json = appStorage.getItem("user-" + userId + "-" + serverId); - return json ? JSON.parse(json) : null - } - - function onWebSocketMessage(msg) { - var instance = this; - msg = JSON.parse(msg.data), onMessageReceivedInternal(instance, msg) - } - - function onMessageReceivedInternal(instance, msg) { - var messageId = msg.MessageId; - if (messageId) { - if (messageIdsReceived[messageId]) return; - messageIdsReceived[messageId] = !0 - } - if ("UserDeleted" === msg.MessageType) instance._currentUser = null; - else if ("UserUpdated" === msg.MessageType || "UserConfigurationUpdated" === msg.MessageType) { - var user = msg.Data; - user.Id === instance.getCurrentUserId() && (instance._currentUser = null) - } - events.trigger(instance, "message", [msg]) - } - - function onWebSocketOpen() { - var instance = this; - console.log("web socket connection opened"), events.trigger(instance, "websocketopen") - } - - function onWebSocketError() { - var instance = this; - events.trigger(instance, "websocketerror") - } - - function setSocketOnClose(apiClient, socket) { - socket.onclose = function() { - console.log("web socket closed"), apiClient._webSocket === socket && (console.log("nulling out web socket"), apiClient._webSocket = null), setTimeout(function() { - events.trigger(apiClient, "websocketclose") - }, 0) - } - } - - function normalizeReturnBitrate(instance, bitrate) { - if (!bitrate) return instance.lastDetectedBitrate ? instance.lastDetectedBitrate : Promise.reject(); - var result = Math.round(.7 * bitrate); - if (instance.getMaxBandwidth) { - var maxRate = instance.getMaxBandwidth(); - maxRate && (result = Math.min(result, maxRate)) - } - return instance.lastDetectedBitrate = result, instance.lastDetectedBitrateTime = (new Date).getTime(), result - } - - function detectBitrateInternal(instance, tests, index, currentBitrate) { - if (index >= tests.length) return normalizeReturnBitrate(instance, currentBitrate); - var test = tests[index]; - return instance.getDownloadSpeed(test.bytes).then(function(bitrate) { - return bitrate < test.threshold ? normalizeReturnBitrate(instance, bitrate) : detectBitrateInternal(instance, tests, index + 1, bitrate) - }, function() { - return normalizeReturnBitrate(instance, currentBitrate) - }) - } - - function detectBitrateWithEndpointInfo(instance, endpointInfo) { - if (endpointInfo.IsInNetwork) { - return instance.lastDetectedBitrate = 14e7, instance.lastDetectedBitrateTime = (new Date).getTime(), 14e7 - } - return detectBitrateInternal(instance, [{ - bytes: 5e5, - threshold: 5e5 - }, { - bytes: 1e6, - threshold: 2e7 - }, { - bytes: 3e6, - threshold: 5e7 - }], 0) - } - - function getRemoteImagePrefix(instance, options) { - var urlPrefix; - return options.artist ? (urlPrefix = "Artists/" + instance.encodeName(options.artist), delete options.artist) : options.person ? (urlPrefix = "Persons/" + instance.encodeName(options.person), delete options.person) : options.genre ? (urlPrefix = "Genres/" + instance.encodeName(options.genre), delete options.genre) : options.musicGenre ? (urlPrefix = "MusicGenres/" + instance.encodeName(options.musicGenre), delete options.musicGenre) : options.studio ? (urlPrefix = "Studios/" + instance.encodeName(options.studio), delete options.studio) : (urlPrefix = "Items/" + options.itemId, delete options.itemId), urlPrefix - } - - function normalizeImageOptions(instance, options) { - var ratio = instance._devicePixelRatio || 1; - ratio && (options.minScale && (ratio = Math.max(options.minScale, ratio)), options.width && (options.width = Math.round(options.width * ratio)), options.height && (options.height = Math.round(options.height * ratio)), options.maxWidth && (options.maxWidth = Math.round(options.maxWidth * ratio)), options.maxHeight && (options.maxHeight = Math.round(options.maxHeight * ratio))), options.quality = options.quality || instance.getDefaultImageQuality(options.type), instance.normalizeImageOptions && instance.normalizeImageOptions(options) - } - - function compareVersions(a, b) { - a = a.split("."), b = b.split("."); - for (var i = 0, length = Math.max(a.length, b.length); i < length; i++) { - var aVal = parseInt(a[i] || "0"), - bVal = parseInt(b[i] || "0"); - if (aVal < bVal) return -1; - if (aVal > bVal) return 1 - } - return 0 - } - ApiClient.prototype.appName = function() { - return this._appName - }, ApiClient.prototype.setRequestHeaders = function(headers) { - var currentServerInfo = this.serverInfo(), - appName = this._appName, - accessToken = currentServerInfo.AccessToken, - values = []; - if (appName && values.push('Client="' + appName + '"'), this._deviceName && values.push('Device="' + this._deviceName + '"'), this._deviceId && values.push('DeviceId="' + this._deviceId + '"'), this._appVersion && values.push('Version="' + this._appVersion + '"'), accessToken && values.push('Token="' + accessToken + '"'), values.length) { - var auth = "MediaBrowser " + values.join(", "); - headers["X-Emby-Authorization"] = auth - } - }, ApiClient.prototype.appVersion = function() { - return this._appVersion - }, ApiClient.prototype.deviceName = function() { - return this._deviceName - }, ApiClient.prototype.deviceId = function() { - return this._deviceId - }, ApiClient.prototype.serverAddress = function(val) { - if (null != val) { - if (0 !== val.toLowerCase().indexOf("http")) throw new Error("Invalid url: " + val); - var changed = val !== this._serverAddress; - this._serverAddress = val, this.onNetworkChange(), changed && events.trigger(this, "serveraddresschanged") - } - return this._serverAddress - }, ApiClient.prototype.onNetworkChange = function() { - this.lastDetectedBitrate = 0, this.lastDetectedBitrateTime = 0, setSavedEndpointInfo(this, null), redetectBitrate(this) - }, ApiClient.prototype.getUrl = function(name, params, serverAddress) { - if (!name) throw new Error("Url name cannot be empty"); - var url = serverAddress || this._serverAddress; - if (!url) throw new Error("serverAddress is yet not set"); - var lowered = url.toLowerCase(); - return "/" !== name.charAt(0) && (url += "/"), url += name, params && (params = paramsToString(params)) && (url += "?" + params), url - }, ApiClient.prototype.fetchWithFailover = function(request, enableReconnection) { - console.log("Requesting " + request.url), request.timeout = 3e4; - var instance = this; - return getFetchPromise(request).then(function(response) { - return instance.lastFetch = (new Date).getTime(), 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 : (onFetchFail(instance, request.url, response), Promise.reject(response)) - }, function(error) { - if (error ? console.log("Request failed to " + request.url + " " + (error.status || "") + " " + error.toString()) : console.log("Request timed out to " + request.url), error && error.status || !enableReconnection) throw console.log("Reporting request failure"), onFetchFail(instance, request.url, {}), error; - console.log("Attempting reconnection"); - var previousServerAddress = instance.serverAddress(); - return tryReconnect(instance).then(function() { - return console.log("Reconnect succeesed"), request.url = request.url.replace(previousServerAddress, instance.serverAddress()), instance.fetchWithFailover(request, !1) - }, function(innerError) { - throw console.log("Reconnect failed"), onFetchFail(instance, request.url, {}), innerError - }) - }) - }, ApiClient.prototype.fetch = function(request, includeAuthorization) { - if (!request) throw new Error("Request cannot be null"); - if (request.headers = request.headers || {}, !1 !== includeAuthorization && this.setRequestHeaders(request.headers), !1 === this.enableAutomaticNetworking || "GET" !== request.type) { - console.log("Requesting url without automatic networking: " + request.url); - var instance = this; - return getFetchPromise(request).then(function(response) { - return instance.lastFetch = (new Date).getTime(), 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 : (onFetchFail(instance, request.url, response), Promise.reject(response)) - }, function(error) { - throw onFetchFail(instance, request.url, {}), error - }) - } - return this.fetchWithFailover(request, !0) - }, ApiClient.prototype.setAuthenticationInfo = function(accessKey, userId) { - this._currentUser = null, this._serverInfo.AccessToken = accessKey, this._serverInfo.UserId = userId, redetectBitrate(this) - }, ApiClient.prototype.serverInfo = function(info) { - return info && (this._serverInfo = info), this._serverInfo - }, ApiClient.prototype.getCurrentUserId = function() { - return this._serverInfo.UserId - }, ApiClient.prototype.accessToken = function() { - return this._serverInfo.AccessToken - }, ApiClient.prototype.serverId = function() { - return this.serverInfo().Id - }, ApiClient.prototype.serverName = function() { - return this.serverInfo().Name - }, ApiClient.prototype.ajax = function(request, includeAuthorization) { - if (!request) throw new Error("Request cannot be null"); - return this.fetch(request, includeAuthorization) - }, ApiClient.prototype.getCurrentUser = function(enableCache) { - if (this._currentUser) return Promise.resolve(this._currentUser); - var userId = this.getCurrentUserId(); - if (!userId) return Promise.reject(); - var user, instance = this, - serverPromise = this.getUser(userId).then(function(user) { - return appStorage.setItem("user-" + user.Id + "-" + user.ServerId, JSON.stringify(user)), instance._currentUser = user, user - }, function(response) { - if (!response.status && userId && instance.accessToken() && (user = getCachedUser(instance, userId))) return Promise.resolve(user); - throw response - }); - return !this.lastFetch && !1 !== enableCache && (user = getCachedUser(instance, userId)) ? Promise.resolve(user) : serverPromise - }, ApiClient.prototype.isLoggedIn = function() { - var info = this.serverInfo(); - return !!(info && info.UserId && info.AccessToken) - }, ApiClient.prototype.logout = function() { - stopBitrateDetection(this), this.closeWebSocket(); - var done = function() { - appStorage.removeItem("user-" + this._currentUser.Id + "-" + this._currentUser.ServerId) - this.setAuthenticationInfo(null, null) - }.bind(this); - if (this.accessToken()) { - var url = this.getUrl("Sessions/Logout"); - return this.ajax({ - type: "POST", - url: url - }).then(done, done) - } - return done(), Promise.resolve() - }, ApiClient.prototype.authenticateUserByName = function(name, password) { - if (!name) return Promise.reject(); - var url = this.getUrl("Users/authenticatebyname"), - instance = this; - return new Promise(function(resolve, reject) { - var postData = { - Username: name, - Pw: password || "" - }; - instance.ajax({ - type: "POST", - url: url, - data: JSON.stringify(postData), - dataType: "json", - contentType: "application/json" - }).then(function(result) { - var afterOnAuthenticated = function() { - redetectBitrate(instance), resolve(result) - }; - instance.onAuthenticated ? instance.onAuthenticated(instance, result).then(afterOnAuthenticated) : afterOnAuthenticated() - }, reject) - }) - }, ApiClient.prototype.ensureWebSocket = function() { - if (!this.isWebSocketOpenOrConnecting() && this.isWebSocketSupported()) try { - this.openWebSocket() - } catch (err) { - console.log("Error opening web socket: " + err) - } - }; - var messageIdsReceived = {}; - return ApiClient.prototype.openWebSocket = function() { - var accessToken = this.accessToken(); - if (!accessToken) throw new Error("Cannot open web socket without access token."); - var url = this.getUrl("socket"); - url = replaceAll(url, "emby/socket", "embywebsocket"), url = replaceAll(url, "https:", "wss:"), url = replaceAll(url, "http:", "ws:"), url += "?api_key=" + accessToken, url += "&deviceId=" + this.deviceId(), console.log("opening web socket with url: " + url); - var webSocket = new WebSocket(url); - webSocket.onmessage = onWebSocketMessage.bind(this), webSocket.onopen = onWebSocketOpen.bind(this), webSocket.onerror = onWebSocketError.bind(this), setSocketOnClose(this, webSocket), this._webSocket = webSocket - }, ApiClient.prototype.closeWebSocket = function() { - var socket = this._webSocket; - socket && socket.readyState === WebSocket.OPEN && socket.close() - }, ApiClient.prototype.sendWebSocketMessage = function(name, data) { - console.log("Sending web socket message: " + name); - var msg = { - MessageType: name - }; - data && (msg.Data = data), msg = JSON.stringify(msg), this._webSocket.send(msg) - }, ApiClient.prototype.sendMessage = function(name, data) { - this.isWebSocketOpen() && this.sendWebSocketMessage(name, data) - }, ApiClient.prototype.isMessageChannelOpen = function() { - return this.isWebSocketOpen() - }, ApiClient.prototype.isWebSocketOpen = function() { - var socket = this._webSocket; - return !!socket && socket.readyState === WebSocket.OPEN - }, ApiClient.prototype.isWebSocketOpenOrConnecting = function() { - var socket = this._webSocket; - return !!socket && (socket.readyState === WebSocket.OPEN || socket.readyState === WebSocket.CONNECTING) - }, ApiClient.prototype.get = function(url) { - return this.ajax({ - type: "GET", - url: url - }) - }, ApiClient.prototype.getJSON = function(url, includeAuthorization) { - return this.fetch({ - url: url, - type: "GET", - dataType: "json", - headers: { - accept: "application/json" - } - }, includeAuthorization) - }, ApiClient.prototype.updateServerInfo = function(server, serverUrl) { - if (null == server) throw new Error("server cannot be null"); - if (this.serverInfo(server), !serverUrl) throw new Error("serverUrl cannot be null. serverInfo: " + JSON.stringify(server)); - console.log("Setting server address to " + serverUrl), this.serverAddress(serverUrl) - }, ApiClient.prototype.isWebSocketSupported = function() { - try { - return null != WebSocket - } catch (err) { - return !1 - } - }, ApiClient.prototype.clearAuthenticationInfo = function() { - this.setAuthenticationInfo(null, null) - }, ApiClient.prototype.encodeName = function(name) { - name = name.split("/").join("-"), name = name.split("&").join("-"), name = name.split("?").join("-"); - var val = paramsToString({ - name: name - }); - return val.substring(val.indexOf("=") + 1).replace("'", "%27") - }, ApiClient.prototype.getDownloadSpeed = function(byteSize) { - var url = this.getUrl("Playback/BitrateTest", { - Size: byteSize - }), - now = (new Date).getTime(); - return this.ajax({ - type: "GET", - url: url, - timeout: 5e3 - }).then(function() { - var responseTimeSeconds = ((new Date).getTime() - now) / 1e3, - bytesPerSecond = byteSize / responseTimeSeconds; - return Math.round(8 * bytesPerSecond) - }) - }, ApiClient.prototype.detectBitrate = function(force) { - if (!force && this.lastDetectedBitrate && (new Date).getTime() - (this.lastDetectedBitrateTime || 0) <= 36e5) return Promise.resolve(this.lastDetectedBitrate); - var instance = this; - return this.getEndpointInfo().then(function(info) { - return detectBitrateWithEndpointInfo(instance, info) - }, function(info) { - return detectBitrateWithEndpointInfo(instance, {}) - }) - }, ApiClient.prototype.getItem = function(userId, itemId) { - if (!itemId) throw new Error("null itemId"); - var url = userId ? this.getUrl("Users/" + userId + "/Items/" + itemId) : this.getUrl("Items/" + itemId); - return this.getJSON(url) - }, ApiClient.prototype.getRootFolder = function(userId) { - if (!userId) throw new Error("null userId"); - var url = this.getUrl("Users/" + userId + "/Items/Root"); - return this.getJSON(url) - }, ApiClient.prototype.getNotificationSummary = function(userId) { - if (!userId) throw new Error("null userId"); - var url = this.getUrl("Notifications/" + userId + "/Summary"); - return this.getJSON(url) - }, ApiClient.prototype.getNotifications = function(userId, options) { - if (!userId) throw new Error("null userId"); - var url = this.getUrl("Notifications/" + userId, options || {}); - return this.getJSON(url) - }, ApiClient.prototype.markNotificationsRead = function(userId, idList, isRead) { - if (!userId) throw new Error("null userId"); - if (!idList) throw new Error("null idList"); - var suffix = isRead ? "Read" : "Unread", - params = { - UserId: userId, - Ids: idList.join(",") - }, - url = this.getUrl("Notifications/" + userId + "/" + suffix, params); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getRemoteImageProviders = function(options) { - if (!options) throw new Error("null options"); - var urlPrefix = getRemoteImagePrefix(this, options), - url = this.getUrl(urlPrefix + "/RemoteImages/Providers", options); - return this.getJSON(url) - }, ApiClient.prototype.getAvailableRemoteImages = function(options) { - if (!options) throw new Error("null options"); - var urlPrefix = getRemoteImagePrefix(this, options), - url = this.getUrl(urlPrefix + "/RemoteImages", options); - return this.getJSON(url) - }, ApiClient.prototype.downloadRemoteImage = function(options) { - if (!options) throw new Error("null options"); - var urlPrefix = getRemoteImagePrefix(this, options), - url = this.getUrl(urlPrefix + "/RemoteImages/Download", options); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getRecordingFolders = function(userId) { - var url = this.getUrl("LiveTv/Recordings/Folders", { - userId: userId - }); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvInfo = function(options) { - var url = this.getUrl("LiveTv/Info", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvGuideInfo = function(options) { - var url = this.getUrl("LiveTv/GuideInfo", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvChannel = function(id, userId) { - if (!id) throw new Error("null id"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("LiveTv/Channels/" + id, options); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvChannels = function(options) { - var url = this.getUrl("LiveTv/Channels", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvPrograms = function(options) { - return options = options || {}, options.channelIds && options.channelIds.length > 1800 ? this.ajax({ - type: "POST", - url: this.getUrl("LiveTv/Programs"), - data: JSON.stringify(options), - contentType: "application/json", - dataType: "json" - }) : this.ajax({ - type: "GET", - url: this.getUrl("LiveTv/Programs", options), - dataType: "json" - }) - }, ApiClient.prototype.getLiveTvRecommendedPrograms = function(options) { - return options = options || {}, this.ajax({ - type: "GET", - url: this.getUrl("LiveTv/Programs/Recommended", options), - dataType: "json" - }) - }, ApiClient.prototype.getLiveTvRecordings = function(options) { - var url = this.getUrl("LiveTv/Recordings", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvRecordingSeries = function(options) { - var url = this.getUrl("LiveTv/Recordings/Series", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvRecordingGroups = function(options) { - var url = this.getUrl("LiveTv/Recordings/Groups", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvRecordingGroup = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/Recordings/Groups/" + id); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvRecording = function(id, userId) { - if (!id) throw new Error("null id"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("LiveTv/Recordings/" + id, options); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvProgram = function(id, userId) { - if (!id) throw new Error("null id"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("LiveTv/Programs/" + id, options); - return this.getJSON(url) - }, ApiClient.prototype.deleteLiveTvRecording = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/Recordings/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.cancelLiveTvTimer = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/Timers/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.getLiveTvTimers = function(options) { - var url = this.getUrl("LiveTv/Timers", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvTimer = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/Timers/" + id); - return this.getJSON(url) - }, ApiClient.prototype.getNewLiveTvTimerDefaults = function(options) { - options = options || {}; - var url = this.getUrl("LiveTv/Timers/Defaults", options); - return this.getJSON(url) - }, ApiClient.prototype.createLiveTvTimer = function(item) { - if (!item) throw new Error("null item"); - var url = this.getUrl("LiveTv/Timers"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(item), - contentType: "application/json" - }) - }, ApiClient.prototype.updateLiveTvTimer = function(item) { - if (!item) throw new Error("null item"); - var url = this.getUrl("LiveTv/Timers/" + item.Id); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(item), - contentType: "application/json" - }) - }, ApiClient.prototype.resetLiveTvTuner = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/Tuners/" + id + "/Reset"); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getLiveTvSeriesTimers = function(options) { - var url = this.getUrl("LiveTv/SeriesTimers", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getLiveTvSeriesTimer = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/SeriesTimers/" + id); - return this.getJSON(url) - }, ApiClient.prototype.cancelLiveTvSeriesTimer = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("LiveTv/SeriesTimers/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.createLiveTvSeriesTimer = function(item) { - if (!item) throw new Error("null item"); - var url = this.getUrl("LiveTv/SeriesTimers"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(item), - contentType: "application/json" - }) - }, ApiClient.prototype.updateLiveTvSeriesTimer = function(item) { - if (!item) throw new Error("null item"); - var url = this.getUrl("LiveTv/SeriesTimers/" + item.Id); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(item), - contentType: "application/json" - }) - }, ApiClient.prototype.getRegistrationInfo = function(feature) { - var url = this.getUrl("Registrations/" + feature); - return this.getJSON(url) - }, ApiClient.prototype.getSystemInfo = function() { - var url = this.getUrl("System/Info"), - instance = this; - return this.getJSON(url).then(function(info) { - return instance.setSystemInfo(info), Promise.resolve(info) - }) - }, ApiClient.prototype.getSyncStatus = function(itemId) { - var url = this.getUrl("Sync/" + itemId + "/Status"); - return this.ajax({ - url: url, - type: "POST", - dataType: "json", - contentType: "application/json", - data: JSON.stringify({ - TargetId: this.deviceId() - }) - }) - }, ApiClient.prototype.getPublicSystemInfo = function() { - var url = this.getUrl("System/Info/Public"), - instance = this; - return this.getJSON(url).then(function(info) { - return instance.setSystemInfo(info), Promise.resolve(info) - }) - }, ApiClient.prototype.getInstantMixFromItem = function(itemId, options) { - var url = this.getUrl("Items/" + itemId + "/InstantMix", options); - return this.getJSON(url) - }, ApiClient.prototype.getEpisodes = function(itemId, options) { - var url = this.getUrl("Shows/" + itemId + "/Episodes", options); - return this.getJSON(url) - }, ApiClient.prototype.getDisplayPreferences = function(id, userId, app) { - var url = this.getUrl("DisplayPreferences/" + id, { - userId: userId, - client: app - }); - return this.getJSON(url) - }, ApiClient.prototype.updateDisplayPreferences = function(id, obj, userId, app) { - var url = this.getUrl("DisplayPreferences/" + id, { - userId: userId, - client: app - }); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(obj), - contentType: "application/json" - }) - }, ApiClient.prototype.getSeasons = function(itemId, options) { - var url = this.getUrl("Shows/" + itemId + "/Seasons", options); - return this.getJSON(url) - }, ApiClient.prototype.getSimilarItems = function(itemId, options) { - var url = this.getUrl("Items/" + itemId + "/Similar", options); - return this.getJSON(url) - }, ApiClient.prototype.getCultures = function() { - var url = this.getUrl("Localization/cultures"); - return this.getJSON(url) - }, ApiClient.prototype.getCountries = function() { - var url = this.getUrl("Localization/countries"); - return this.getJSON(url) - }, ApiClient.prototype.getPlaybackInfo = function(itemId, options, deviceProfile) { - var postData = { - DeviceProfile: deviceProfile - }; - return this.ajax({ - url: this.getUrl("Items/" + itemId + "/PlaybackInfo", options), - type: "POST", - data: JSON.stringify(postData), - contentType: "application/json", - dataType: "json" - }) - }, ApiClient.prototype.getLiveStreamMediaInfo = function(liveStreamId) { - var postData = { - LiveStreamId: liveStreamId - }; - return this.ajax({ - url: this.getUrl("LiveStreams/MediaInfo"), - type: "POST", - data: JSON.stringify(postData), - contentType: "application/json", - dataType: "json" - }) - }, ApiClient.prototype.getIntros = function(itemId) { - return this.getJSON(this.getUrl("Users/" + this.getCurrentUserId() + "/Items/" + itemId + "/Intros")) - }, ApiClient.prototype.getDirectoryContents = function(path, options) { - if (!path) throw new Error("null path"); - if ("string" != typeof path) throw new Error("invalid path"); - options = options || {}, options.path = path; - var url = this.getUrl("Environment/DirectoryContents", options); - return this.getJSON(url) - }, ApiClient.prototype.getNetworkShares = function(path) { - if (!path) throw new Error("null path"); - var options = {}; - options.path = path; - var url = this.getUrl("Environment/NetworkShares", options); - return this.getJSON(url) - }, ApiClient.prototype.getParentPath = function(path) { - if (!path) throw new Error("null path"); - var options = {}; - options.path = path; - var url = this.getUrl("Environment/ParentPath", options); - return this.ajax({ - type: "GET", - url: url, - dataType: "text" - }) - }, ApiClient.prototype.getDrives = function() { - var url = this.getUrl("Environment/Drives"); - return this.getJSON(url) - }, ApiClient.prototype.getNetworkDevices = function() { - var url = this.getUrl("Environment/NetworkDevices"); - return this.getJSON(url) - }, ApiClient.prototype.cancelPackageInstallation = function(installationId) { - if (!installationId) throw new Error("null installationId"); - var url = this.getUrl("Packages/Installing/" + installationId); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.refreshItem = function(itemId, options) { - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Items/" + itemId + "/Refresh", options || {}); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.installPlugin = function(name, guid, updateClass, version) { - if (!name) throw new Error("null name"); - if (!updateClass) throw new Error("null updateClass"); - var options = { - updateClass: updateClass, - AssemblyGuid: guid - }; - version && (options.version = version); - var url = this.getUrl("Packages/Installed/" + name, options); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.restartServer = function() { - var url = this.getUrl("System/Restart"); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.shutdownServer = function() { - var url = this.getUrl("System/Shutdown"); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getPackageInfo = function(name, guid) { - if (!name) throw new Error("null name"); - var options = { - AssemblyGuid: guid - }, - url = this.getUrl("Packages/" + name, options); - return this.getJSON(url) - }, ApiClient.prototype.getVirtualFolders = function() { - var url = "Library/VirtualFolders"; - return url = this.getUrl(url), this.getJSON(url) - }, ApiClient.prototype.getPhysicalPaths = function() { - var url = this.getUrl("Library/PhysicalPaths"); - return this.getJSON(url) - }, ApiClient.prototype.getServerConfiguration = function() { - var url = this.getUrl("System/Configuration"); - return this.getJSON(url) - }, ApiClient.prototype.getDevicesOptions = function() { - var url = this.getUrl("System/Configuration/devices"); - return this.getJSON(url) - }, ApiClient.prototype.getContentUploadHistory = function() { - var url = this.getUrl("Devices/CameraUploads", { - DeviceId: this.deviceId() - }); - return this.getJSON(url) - }, ApiClient.prototype.getNamedConfiguration = function(name) { - var url = this.getUrl("System/Configuration/" + name); - return this.getJSON(url) - }, ApiClient.prototype.getScheduledTasks = function(options) { - options = options || {}; - var url = this.getUrl("ScheduledTasks", options); - return this.getJSON(url) - }, ApiClient.prototype.startScheduledTask = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("ScheduledTasks/Running/" + id); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getScheduledTask = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("ScheduledTasks/" + id); - return this.getJSON(url) - }, ApiClient.prototype.getNextUpEpisodes = function(options) { - var url = this.getUrl("Shows/NextUp", options); - return this.getJSON(url) - }, ApiClient.prototype.stopScheduledTask = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("ScheduledTasks/Running/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.getPluginConfiguration = function(id) { - if (!id) throw new Error("null Id"); - var url = this.getUrl("Plugins/" + id + "/Configuration"); - return this.getJSON(url) - }, ApiClient.prototype.getAvailablePlugins = function(options) { - options = options || {}, options.PackageType = "UserInstalled"; - var url = this.getUrl("Packages", options); - return this.getJSON(url) - }, ApiClient.prototype.uninstallPlugin = function(id) { - if (!id) throw new Error("null Id"); - var url = this.getUrl("Plugins/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.removeVirtualFolder = function(name, refreshLibrary) { - if (!name) throw new Error("null name"); - var url = "Library/VirtualFolders"; - return url = this.getUrl(url, { - refreshLibrary: !!refreshLibrary, - name: name - }), this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.addVirtualFolder = function(name, type, refreshLibrary, libraryOptions) { - if (!name) throw new Error("null name"); - var options = {}; - type && (options.collectionType = type), options.refreshLibrary = !!refreshLibrary, options.name = name; - var url = "Library/VirtualFolders"; - return url = this.getUrl(url, options), this.ajax({ - type: "POST", - url: url, - data: JSON.stringify({ - LibraryOptions: libraryOptions - }), - contentType: "application/json" - }) - }, ApiClient.prototype.updateVirtualFolderOptions = function(id, libraryOptions) { - if (!id) throw new Error("null name"); - var url = "Library/VirtualFolders/LibraryOptions"; - return url = this.getUrl(url), this.ajax({ - type: "POST", - url: url, - data: JSON.stringify({ - Id: id, - LibraryOptions: libraryOptions - }), - contentType: "application/json" - }) - }, ApiClient.prototype.renameVirtualFolder = function(name, newName, refreshLibrary) { - if (!name) throw new Error("null name"); - var url = "Library/VirtualFolders/Name"; - return url = this.getUrl(url, { - refreshLibrary: !!refreshLibrary, - newName: newName, - name: name - }), this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.addMediaPath = function(virtualFolderName, mediaPath, networkSharePath, refreshLibrary) { - if (!virtualFolderName) throw new Error("null virtualFolderName"); - if (!mediaPath) throw new Error("null mediaPath"); - var url = "Library/VirtualFolders/Paths", - pathInfo = { - Path: mediaPath - }; - return networkSharePath && (pathInfo.NetworkPath = networkSharePath), url = this.getUrl(url, { - refreshLibrary: !!refreshLibrary - }), this.ajax({ - type: "POST", - url: url, - data: JSON.stringify({ - Name: virtualFolderName, - PathInfo: pathInfo - }), - contentType: "application/json" - }) - }, ApiClient.prototype.updateMediaPath = function(virtualFolderName, pathInfo) { - if (!virtualFolderName) throw new Error("null virtualFolderName"); - if (!pathInfo) throw new Error("null pathInfo"); - var url = "Library/VirtualFolders/Paths/Update"; - return url = this.getUrl(url), this.ajax({ - type: "POST", - url: url, - data: JSON.stringify({ - Name: virtualFolderName, - PathInfo: pathInfo - }), - contentType: "application/json" - }) - }, ApiClient.prototype.removeMediaPath = function(virtualFolderName, mediaPath, refreshLibrary) { - if (!virtualFolderName) throw new Error("null virtualFolderName"); - if (!mediaPath) throw new Error("null mediaPath"); - var url = "Library/VirtualFolders/Paths"; - return url = this.getUrl(url, { - refreshLibrary: !!refreshLibrary, - path: mediaPath, - name: virtualFolderName - }), this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.deleteUser = function(id) { - if (!id) throw new Error("null id"); - var url = this.getUrl("Users/" + id); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.deleteUserImage = function(userId, imageType, imageIndex) { - if (!userId) throw new Error("null userId"); - if (!imageType) throw new Error("null imageType"); - var url = this.getUrl("Users/" + userId + "/Images/" + imageType); - return null != imageIndex && (url += "/" + imageIndex), this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.deleteItemImage = function(itemId, imageType, imageIndex) { - if (!imageType) throw new Error("null imageType"); - var url = this.getUrl("Items/" + itemId + "/Images"); - return url += "/" + imageType, null != imageIndex && (url += "/" + imageIndex), this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.deleteItem = function(itemId) { - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Items/" + itemId); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.stopActiveEncodings = function(playSessionId) { - var options = { - deviceId: this.deviceId() - }; - playSessionId && (options.PlaySessionId = playSessionId); - var url = this.getUrl("Videos/ActiveEncodings", options); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.reportCapabilities = function(options) { - var url = this.getUrl("Sessions/Capabilities/Full"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(options), - contentType: "application/json" - }) - }, ApiClient.prototype.updateItemImageIndex = function(itemId, imageType, imageIndex, newIndex) { - if (!imageType) throw new Error("null imageType"); - var options = { - newIndex: newIndex - }, - url = this.getUrl("Items/" + itemId + "/Images/" + imageType + "/" + imageIndex + "/Index", options); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getItemImageInfos = function(itemId) { - var url = this.getUrl("Items/" + itemId + "/Images"); - return this.getJSON(url) - }, ApiClient.prototype.getCriticReviews = function(itemId, options) { - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Items/" + itemId + "/CriticReviews", options); - return this.getJSON(url) - }, ApiClient.prototype.getItemDownloadUrl = function(itemId) { - if (!itemId) throw new Error("itemId cannot be empty"); - var url = "Items/" + itemId + "/Download"; - return this.getUrl(url, { - api_key: this.accessToken() - }) - }, ApiClient.prototype.getSessions = function(options) { - var url = this.getUrl("Sessions", options); - return this.getJSON(url) - }, ApiClient.prototype.uploadUserImage = function(userId, imageType, file) { - if (!userId) throw new Error("null userId"); - if (!imageType) throw new Error("null imageType"); - if (!file) throw new Error("File must be an image."); - if ("image/png" !== file.type && "image/jpeg" !== file.type && "image/jpeg" !== file.type) throw new Error("File must be an image."); - var instance = this; - return new Promise(function(resolve, reject) { - var reader = new FileReader; - reader.onerror = function() { - reject() - }, reader.onabort = function() { - reject() - }, reader.onload = function(e) { - var data = e.target.result.split(",")[1], - url = instance.getUrl("Users/" + userId + "/Images/" + imageType); - instance.ajax({ - type: "POST", - url: url, - data: data, - contentType: "image/" + file.name.substring(file.name.lastIndexOf(".") + 1) - }).then(resolve, reject) - }, reader.readAsDataURL(file) - }) - }, ApiClient.prototype.uploadItemImage = function(itemId, imageType, file) { - if (!itemId) throw new Error("null itemId"); - if (!imageType) throw new Error("null imageType"); - if (!file) throw new Error("File must be an image."); - if ("image/png" !== file.type && "image/jpeg" !== file.type && "image/jpeg" !== file.type) throw new Error("File must be an image."); - var url = this.getUrl("Items/" + itemId + "/Images"); - url += "/" + imageType; - var instance = this; - return new Promise(function(resolve, reject) { - var reader = new FileReader; - reader.onerror = function() { - reject() - }, reader.onabort = function() { - reject() - }, reader.onload = function(e) { - var data = e.target.result.split(",")[1]; - instance.ajax({ - type: "POST", - url: url, - data: data, - contentType: "image/" + file.name.substring(file.name.lastIndexOf(".") + 1) - }).then(resolve, reject) - }, reader.readAsDataURL(file) - }) - }, ApiClient.prototype.getInstalledPlugins = function() { - var options = {}, - url = this.getUrl("Plugins", options); - return this.getJSON(url) - }, ApiClient.prototype.getUser = function(id) { - if (!id) throw new Error("Must supply a userId"); - var url = this.getUrl("Users/" + id); - return this.getJSON(url) - }, ApiClient.prototype.getStudio = function(name, userId) { - if (!name) throw new Error("null name"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Studios/" + this.encodeName(name), options); - return this.getJSON(url) - }, ApiClient.prototype.getGenre = function(name, userId) { - if (!name) throw new Error("null name"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Genres/" + this.encodeName(name), options); - return this.getJSON(url) - }, ApiClient.prototype.getMusicGenre = function(name, userId) { - if (!name) throw new Error("null name"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("MusicGenres/" + this.encodeName(name), options); - return this.getJSON(url) - }, ApiClient.prototype.getArtist = function(name, userId) { - if (!name) throw new Error("null name"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Artists/" + this.encodeName(name), options); - return this.getJSON(url) - }, ApiClient.prototype.getPerson = function(name, userId) { - if (!name) throw new Error("null name"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Persons/" + this.encodeName(name), options); - return this.getJSON(url) - }, ApiClient.prototype.getPublicUsers = function() { - var url = this.getUrl("users/public"); - return this.ajax({ - type: "GET", - url: url, - dataType: "json" - }, !1) - }, ApiClient.prototype.getUsers = function(options) { - var url = this.getUrl("users", options || {}); - return this.getJSON(url) - }, ApiClient.prototype.getParentalRatings = function() { - var url = this.getUrl("Localization/ParentalRatings"); - return this.getJSON(url) - }, ApiClient.prototype.getDefaultImageQuality = function(imageType) { - return "backdrop" === imageType.toLowerCase() ? 80 : 90 - }, ApiClient.prototype.getUserImageUrl = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}; - var url = "Users/" + userId + "/Images/" + options.type; - return null != options.index && (url += "/" + options.index), normalizeImageOptions(this, options), delete options.type, delete options.index, this.getUrl(url, options) - }, ApiClient.prototype.getImageUrl = function(itemId, options) { - if (!itemId) throw new Error("itemId cannot be empty"); - options = options || {}; - var url = "Items/" + itemId + "/Images/" + options.type; - return null != options.index && (url += "/" + options.index), options.quality = options.quality || this.getDefaultImageQuality(options.type), this.normalizeImageOptions && this.normalizeImageOptions(options), delete options.type, delete options.index, this.getUrl(url, options) - }, ApiClient.prototype.getScaledImageUrl = function(itemId, options) { - if (!itemId) throw new Error("itemId cannot be empty"); - options = options || {}; - var url = "Items/" + itemId + "/Images/" + options.type; - return null != options.index && (url += "/" + options.index), normalizeImageOptions(this, options), delete options.type, delete options.index, delete options.minScale, this.getUrl(url, options) - }, ApiClient.prototype.getThumbImageUrl = function(item, options) { - if (!item) throw new Error("null item"); - return options = options || {}, options.imageType = "thumb", item.ImageTags && item.ImageTags.Thumb ? (options.tag = item.ImageTags.Thumb, this.getImageUrl(item.Id, options)) : item.ParentThumbItemId ? (options.tag = item.ImageTags.ParentThumbImageTag, this.getImageUrl(item.ParentThumbItemId, options)) : null - }, ApiClient.prototype.updateUserPassword = function(userId, currentPassword, newPassword) { - if (!userId) return Promise.reject(); - var url = this.getUrl("Users/" + userId + "/Password"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify({ - CurrentPw: currentPassword || "", - NewPw: newPassword - }), - contentType: "application/json" - }) - }, ApiClient.prototype.updateEasyPassword = function(userId, newPassword) { - if (!userId) return void Promise.reject(); - var url = this.getUrl("Users/" + userId + "/EasyPassword"); - return this.ajax({ - type: "POST", - url: url, - data: { - NewPw: newPassword - } - }) - }, ApiClient.prototype.resetUserPassword = function(userId) { - if (!userId) throw new Error("null userId"); - var url = this.getUrl("Users/" + userId + "/Password"), - postData = {}; - return postData.resetPassword = !0, this.ajax({ - type: "POST", - url: url, - data: postData - }) - }, ApiClient.prototype.resetEasyPassword = function(userId) { - if (!userId) throw new Error("null userId"); - var url = this.getUrl("Users/" + userId + "/EasyPassword"), - postData = {}; - return postData.resetPassword = !0, this.ajax({ - type: "POST", - url: url, - data: postData - }) - }, ApiClient.prototype.updateServerConfiguration = function(configuration) { - if (!configuration) throw new Error("null configuration"); - var url = this.getUrl("System/Configuration"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(configuration), - contentType: "application/json" - }) - }, ApiClient.prototype.updateNamedConfiguration = function(name, configuration) { - if (!configuration) throw new Error("null configuration"); - var url = this.getUrl("System/Configuration/" + name); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(configuration), - contentType: "application/json" - }) - }, ApiClient.prototype.updateItem = function(item) { - if (!item) throw new Error("null item"); - var url = this.getUrl("Items/" + item.Id); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(item), - contentType: "application/json" - }) - }, ApiClient.prototype.updatePluginSecurityInfo = function(info) { - var url = this.getUrl("Plugins/SecurityInfo"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(info), - contentType: "application/json" - }) - }, ApiClient.prototype.createUser = function(user) { - var url = this.getUrl("Users/New"); - return this.ajax({ - type: "POST", - url: url, - data: user, - dataType: "json" - }) - }, ApiClient.prototype.updateUser = function(user) { - if (!user) throw new Error("null user"); - var url = this.getUrl("Users/" + user.Id); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(user), - contentType: "application/json" - }) - }, ApiClient.prototype.updateUserPolicy = function(userId, policy) { - if (!userId) throw new Error("null userId"); - if (!policy) throw new Error("null policy"); - var url = this.getUrl("Users/" + userId + "/Policy"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(policy), - contentType: "application/json" - }) - }, ApiClient.prototype.updateUserConfiguration = function(userId, configuration) { - if (!userId) throw new Error("null userId"); - if (!configuration) throw new Error("null configuration"); - var url = this.getUrl("Users/" + userId + "/Configuration"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(configuration), - contentType: "application/json" - }) - }, ApiClient.prototype.updateScheduledTaskTriggers = function(id, triggers) { - if (!id) throw new Error("null id"); - if (!triggers) throw new Error("null triggers"); - var url = this.getUrl("ScheduledTasks/" + id + "/Triggers"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(triggers), - contentType: "application/json" - }) - }, ApiClient.prototype.updatePluginConfiguration = function(id, configuration) { - if (!id) throw new Error("null Id"); - if (!configuration) throw new Error("null configuration"); - var url = this.getUrl("Plugins/" + id + "/Configuration"); - return this.ajax({ - type: "POST", - url: url, - data: JSON.stringify(configuration), - contentType: "application/json" - }) - }, ApiClient.prototype.getAncestorItems = function(itemId, userId) { - if (!itemId) throw new Error("null itemId"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Items/" + itemId + "/Ancestors", options); - return this.getJSON(url) - }, ApiClient.prototype.getItems = function(userId, options) { - var url; - return url = "string" === (typeof userId).toString().toLowerCase() ? this.getUrl("Users/" + userId + "/Items", options) : this.getUrl("Items", options), this.getJSON(url) - }, ApiClient.prototype.getResumableItems = function(userId, options) { - return this.isMinServerVersion("3.2.33") ? this.getJSON(this.getUrl("Users/" + userId + "/Items/Resume", options)) : this.getItems(userId, Object.assign({ - SortBy: "DatePlayed", - SortOrder: "Descending", - Filters: "IsResumable", - Recursive: !0, - CollapseBoxSetItems: !1, - ExcludeLocationTypes: "Virtual" - }, options)) - }, ApiClient.prototype.getMovieRecommendations = function(options) { - return this.getJSON(this.getUrl("Movies/Recommendations", options)) - }, ApiClient.prototype.getUpcomingEpisodes = function(options) { - return this.getJSON(this.getUrl("Shows/Upcoming", options)) - }, ApiClient.prototype.getUserViews = function(options, userId) { - options = options || {}; - var url = this.getUrl("Users/" + (userId || this.getCurrentUserId()) + "/Views", options); - return this.getJSON(url) - }, ApiClient.prototype.getArtists = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("Artists", options); - return this.getJSON(url) - }, ApiClient.prototype.getAlbumArtists = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("Artists/AlbumArtists", options); - return this.getJSON(url) - }, ApiClient.prototype.getGenres = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("Genres", options); - return this.getJSON(url) - }, ApiClient.prototype.getMusicGenres = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("MusicGenres", options); - return this.getJSON(url) - }, ApiClient.prototype.getPeople = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("Persons", options); - return this.getJSON(url) - }, ApiClient.prototype.getStudios = function(userId, options) { - if (!userId) throw new Error("null userId"); - options = options || {}, options.userId = userId; - var url = this.getUrl("Studios", options); - return this.getJSON(url) - }, ApiClient.prototype.getLocalTrailers = function(userId, itemId) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/Items/" + itemId + "/LocalTrailers"); - return this.getJSON(url) - }, ApiClient.prototype.getAdditionalVideoParts = function(userId, itemId) { - if (!itemId) throw new Error("null itemId"); - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Videos/" + itemId + "/AdditionalParts", options); - return this.getJSON(url) - }, ApiClient.prototype.getThemeMedia = function(userId, itemId, inherit) { - if (!itemId) throw new Error("null itemId"); - var options = {}; - userId && (options.userId = userId), options.InheritFromParent = inherit || !1; - var url = this.getUrl("Items/" + itemId + "/ThemeMedia", options); - return this.getJSON(url) - }, ApiClient.prototype.getSearchHints = function(options) { - var url = this.getUrl("Search/Hints", options), - serverId = this.serverId(); - return this.getJSON(url).then(function(result) { - return result.SearchHints.forEach(function(i) { - i.ServerId = serverId - }), result - }) - }, ApiClient.prototype.getSpecialFeatures = function(userId, itemId) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/Items/" + itemId + "/SpecialFeatures"); - return this.getJSON(url) - }, ApiClient.prototype.getDateParamValue = function(date) { - function formatDigit(i) { - return i < 10 ? "0" + i : i - } - var d = date; - return "" + d.getFullYear() + formatDigit(d.getMonth() + 1) + formatDigit(d.getDate()) + formatDigit(d.getHours()) + formatDigit(d.getMinutes()) + formatDigit(d.getSeconds()) - }, ApiClient.prototype.markPlayed = function(userId, itemId, date) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var options = {}; - date && (options.DatePlayed = this.getDateParamValue(date)); - var url = this.getUrl("Users/" + userId + "/PlayedItems/" + itemId, options); - return this.ajax({ - type: "POST", - url: url, - dataType: "json" - }) - }, ApiClient.prototype.markUnplayed = function(userId, itemId) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/PlayedItems/" + itemId); - return this.ajax({ - type: "DELETE", - url: url, - dataType: "json" - }) - }, ApiClient.prototype.updateFavoriteStatus = function(userId, itemId, isFavorite) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/FavoriteItems/" + itemId), - method = isFavorite ? "POST" : "DELETE"; - return this.ajax({ - type: method, - url: url, - dataType: "json" - }) - }, ApiClient.prototype.updateUserItemRating = function(userId, itemId, likes) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating", { - likes: likes - }); - return this.ajax({ - type: "POST", - url: url, - dataType: "json" - }) - }, ApiClient.prototype.getItemCounts = function(userId) { - var options = {}; - userId && (options.userId = userId); - var url = this.getUrl("Items/Counts", options); - return this.getJSON(url) - }, ApiClient.prototype.clearUserItemRating = function(userId, itemId) { - if (!userId) throw new Error("null userId"); - if (!itemId) throw new Error("null itemId"); - var url = this.getUrl("Users/" + userId + "/Items/" + itemId + "/Rating"); - return this.ajax({ - type: "DELETE", - url: url, - dataType: "json" - }) - }, ApiClient.prototype.reportPlaybackStart = function(options) { - if (!options) throw new Error("null options"); - this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, stopBitrateDetection(this); - var url = this.getUrl("Sessions/Playing"); - return this.ajax({ - type: "POST", - data: JSON.stringify(options), - contentType: "application/json", - url: url - }) - }, ApiClient.prototype.reportPlaybackProgress = function(options) { - if (!options) throw new Error("null options"); - var newPositionTicks = options.PositionTicks; - if ("timeupdate" === (options.EventName || "timeupdate")) { - var now = (new Date).getTime(), - msSinceLastReport = now - (this.lastPlaybackProgressReport || 0); - if (msSinceLastReport <= 1e4) { - if (!newPositionTicks) return Promise.resolve(); - var expectedReportTicks = 1e4 * msSinceLastReport + (this.lastPlaybackProgressReportTicks || 0); - if (Math.abs((newPositionTicks || 0) - expectedReportTicks) < 5e7) return Promise.resolve() - } - this.lastPlaybackProgressReport = now - } else this.lastPlaybackProgressReport = 0; - this.lastPlaybackProgressReportTicks = newPositionTicks; - var url = this.getUrl("Sessions/Playing/Progress"); - return this.ajax({ - type: "POST", - data: JSON.stringify(options), - contentType: "application/json", - url: url - }) - }, ApiClient.prototype.reportOfflineActions = function(actions) { - if (!actions) throw new Error("null actions"); - var url = this.getUrl("Sync/OfflineActions"); - return this.ajax({ - type: "POST", - data: JSON.stringify(actions), - contentType: "application/json", - url: url - }) - }, ApiClient.prototype.syncData = function(data) { - if (!data) throw new Error("null data"); - var url = this.getUrl("Sync/Data"); - return this.ajax({ - type: "POST", - data: JSON.stringify(data), - contentType: "application/json", - url: url, - dataType: "json" - }) - }, ApiClient.prototype.getReadySyncItems = function(deviceId) { - if (!deviceId) throw new Error("null deviceId"); - var url = this.getUrl("Sync/Items/Ready", { - TargetId: deviceId - }); - return this.getJSON(url) - }, ApiClient.prototype.reportSyncJobItemTransferred = function(syncJobItemId) { - if (!syncJobItemId) throw new Error("null syncJobItemId"); - var url = this.getUrl("Sync/JobItems/" + syncJobItemId + "/Transferred"); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.cancelSyncItems = function(itemIds, targetId) { - if (!itemIds) throw new Error("null itemIds"); - var url = this.getUrl("Sync/" + (targetId || this.deviceId()) + "/Items", { - ItemIds: itemIds.join(",") - }); - return this.ajax({ - type: "DELETE", - url: url - }) - }, ApiClient.prototype.reportPlaybackStopped = function(options) { - if (!options) throw new Error("null options"); - this.lastPlaybackProgressReport = 0, this.lastPlaybackProgressReportTicks = null, redetectBitrate(this); - var url = this.getUrl("Sessions/Playing/Stopped"); - return this.ajax({ - type: "POST", - data: JSON.stringify(options), - contentType: "application/json", - url: url - }) - }, ApiClient.prototype.sendPlayCommand = function(sessionId, options) { - if (!sessionId) throw new Error("null sessionId"); - if (!options) throw new Error("null options"); - var url = this.getUrl("Sessions/" + sessionId + "/Playing", options); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.sendCommand = function(sessionId, command) { - if (!sessionId) throw new Error("null sessionId"); - if (!command) throw new Error("null command"); - var url = this.getUrl("Sessions/" + sessionId + "/Command"), - ajaxOptions = { - type: "POST", - url: url - }; - return ajaxOptions.data = JSON.stringify(command), ajaxOptions.contentType = "application/json", this.ajax(ajaxOptions) - }, ApiClient.prototype.sendMessageCommand = function(sessionId, options) { - if (!sessionId) throw new Error("null sessionId"); - if (!options) throw new Error("null options"); - var url = this.getUrl("Sessions/" + sessionId + "/Message"), - ajaxOptions = { - type: "POST", - url: url - }; - return ajaxOptions.data = JSON.stringify(options), ajaxOptions.contentType = "application/json", this.ajax(ajaxOptions) - }, ApiClient.prototype.sendPlayStateCommand = function(sessionId, command, options) { - if (!sessionId) throw new Error("null sessionId"); - if (!command) throw new Error("null command"); - var url = this.getUrl("Sessions/" + sessionId + "/Playing/" + command, options || {}); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.createPackageReview = function(review) { - var url = this.getUrl("Packages/Reviews/" + review.id, review); - return this.ajax({ - type: "POST", - url: url - }) - }, ApiClient.prototype.getPackageReviews = function(packageId, minRating, maxRating, limit) { - if (!packageId) throw new Error("null packageId"); - var options = {}; - minRating && (options.MinRating = minRating), maxRating && (options.MaxRating = maxRating), limit && (options.Limit = limit); - var url = this.getUrl("Packages/" + packageId + "/Reviews", options); - return this.getJSON(url) - }, ApiClient.prototype.getSavedEndpointInfo = function() { - return this._endPointInfo - }, ApiClient.prototype.getEndpointInfo = function() { - var savedValue = this._endPointInfo; - if (savedValue) return Promise.resolve(savedValue); - var instance = this; - return this.getJSON(this.getUrl("System/Endpoint")).then(function(endPointInfo) { - return setSavedEndpointInfo(instance, endPointInfo), endPointInfo - }) - }, ApiClient.prototype.getLatestItems = function(options) { - return options = options || {}, this.getJSON(this.getUrl("Users/" + this.getCurrentUserId() + "/Items/Latest", options)) - }, ApiClient.prototype.getFilters = function(options) { - return this.getJSON(this.getUrl("Items/Filters2", options)) - }, ApiClient.prototype.setSystemInfo = function(info) { - this._serverVersion = info.Version - }, ApiClient.prototype.serverVersion = function() { - return this._serverVersion - }, ApiClient.prototype.isMinServerVersion = function(version) { - var serverVersion = this.serverVersion(); - return !!serverVersion && compareVersions(serverVersion, version) >= 0 - }, ApiClient.prototype.handleMessageReceived = function(msg) { - onMessageReceivedInternal(this, msg) - }, ApiClient -}); diff --git a/src/libraries/apiclient/appStorage.js b/src/libraries/apiclient/appStorage.js deleted file mode 100644 index 6083bb4953..0000000000 --- a/src/libraries/apiclient/appStorage.js +++ /dev/null @@ -1,53 +0,0 @@ -define([], function() { - "use strict"; - - function onCachePutFail(e) { - console.log(e); - } - - function updateCache(instance) { - if (instance.cache) { - instance.cache.put("data", new Response(JSON.stringify(instance.localData))).catch(onCachePutFail); - } - } - - function onCacheOpened(result) { - this.cache = result; - this.localData = {}; - } - - function MyStore() { - - this.setItem = function(name, value) { - localStorage.setItem(name, value); - - if (this.localData && this.localData[name] !== value) { - this.localData[name] = value; - updateCache(this); - } - }; - - this.getItem = function(name) { - return localStorage.getItem(name); - }; - - this.removeItem = function(name) { - localStorage.removeItem(name); - - if (this.localData) { - delete this.localData[name]; - updateCache(this); - } - }; - - try { - if (self.caches) { - self.caches.open("embydata").then(onCacheOpened.bind(this)); - } - } catch (err) { - console.log("Error opening cache: " + err); - } - } - - return new MyStore; -}); \ No newline at end of file diff --git a/src/libraries/apiclient/connectionmanager.js b/src/libraries/apiclient/connectionmanager.js deleted file mode 100644 index 7e7d578cba..0000000000 --- a/src/libraries/apiclient/connectionmanager.js +++ /dev/null @@ -1,807 +0,0 @@ -define(["events", "apiclient", "appStorage"], function (events, apiClientFactory, appStorage) { - "use strict"; - - function getServerAddress(server, mode) { - switch (mode) { - case ConnectionMode.Local: - return server.LocalAddress; - - case ConnectionMode.Manual: - return server.ManualAddress; - - case ConnectionMode.Remote: - return server.RemoteAddress; - - default: - return server.ManualAddress || server.LocalAddress || server.RemoteAddress; - } - } - - function paramsToString(params) { - var values = []; - - for (var key in params) { - var value = params[key]; - - if (null !== value && void 0 !== value && "" !== value) { - values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value)); - } - } - - return values.join("&"); - } - - function resolveFailure(instance, resolve) { - resolve({ - State: "Unavailable", - }); - } - - function mergeServers(credentialProvider, list1, list2) { - for (var i = 0, length = list2.length; i < length; i++) { - credentialProvider.addOrUpdateServer(list1, list2[i]); - } - - return list1; - } - - function updateServerInfo(server, systemInfo) { - server.Name = systemInfo.ServerName; - if (systemInfo.Id) { - server.Id = systemInfo.Id; - } - - if (systemInfo.LocalAddress) { - server.LocalAddress = systemInfo.LocalAddress; - } - } - - function getEmbyServerUrl(baseUrl, handler) { - return baseUrl + "/" + handler; - } - - function getFetchPromise(request) { - var headers = request.headers || {}; - - if ("json" === request.dataType) { - headers.accept = "application/json"; - } - - var fetchRequest = { - headers: headers, - method: request.type, - credentials: "same-origin" - }; - var contentType = request.contentType; - - if (request.data) { - if ("string" == typeof request.data) { - 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; - } - - if (request.timeout) { - return fetchWithTimeout(request.url, fetchRequest, request.timeout); - } - - return fetch(request.url, fetchRequest); - } - - function fetchWithTimeout(url, options, timeoutMs) { - 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(); - }); - }); - } - - function ajax(request) { - if (!request) { - throw new Error("Request cannot be null"); - } - - request.headers = request.headers || {}; - console.log("ConnectionManager requesting url: " + request.url); - return getFetchPromise(request).then(function (response) { - console.log("ConnectionManager response status: " + response.status + ", url: " + request.url); - - if (response.status < 400) { - if ("json" === request.dataType || "application/json" === request.headers.accept) { - return response.json(); - } - - return response; - } - - return Promise.reject(response); - }, function (err) { - console.log("ConnectionManager request failed to url: " + request.url); - throw err; - }); - } - - function replaceAll(originalString, strReplace, strWith) { - var reg = new RegExp(strReplace, "ig"); - return originalString.replace(reg, strWith); - } - - function normalizeAddress(address) { - address = address.trim(); - - if (0 !== address.toLowerCase().indexOf("http")) { - address = "http://" + address; - } - - address = replaceAll(address, "Http:", "http:"); - address = replaceAll(address, "Https:", "https:"); - - return address; - } - - function stringEqualsIgnoreCase(str1, str2) { - return (str1 || "").toLowerCase() === (str2 || "").toLowerCase(); - } - - function compareVersions(a, b) { - a = a.split("."); - b = b.split("."); - - for (var i = 0, length = Math.max(a.length, b.length); i < length; i++) { - var aVal = parseInt(a[i] || "0"); - var bVal = parseInt(b[i] || "0"); - - if (aVal < bVal) { - return -1; - } - - if (aVal > bVal) { - return 1; - } - } - - return 0; - } - - var defaultTimeout = 20000; - var ConnectionMode = { - Local: 0, - Remote: 1, - Manual: 2 - }; - - var ConnectionManager = function (credentialProvider, appName, appVersion, deviceName, deviceId, capabilities, devicePixelRatio) { - - function onAuthenticated(apiClient, result, options, saveCredentials) { - var credentials = credentialProvider.credentials(); - var servers = credentials.Servers.filter(function (s) { - return s.Id === result.ServerId; - }); - var server = servers.length ? servers[0] : apiClient.serverInfo(); - - if (false !== options.updateDateLastAccessed) { - server.DateLastAccessed = new Date().getTime(); - } - - server.Id = result.ServerId; - - if (saveCredentials) { - server.UserId = result.User.Id; - server.AccessToken = result.AccessToken; - } else { - server.UserId = null; - server.AccessToken = null; - } - - credentialProvider.addOrUpdateServer(credentials.Servers, server); - credentialProvider.credentials(credentials); - apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection; - apiClient.serverInfo(server); - afterConnected(apiClient, options); - return onLocalUserSignIn(server, apiClient.serverAddress(), result.User); - } - - function afterConnected(apiClient, options) { - options = options || {}; - - if (false !== options.reportCapabilities) { - apiClient.reportCapabilities(capabilities); - } - - apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection; - - if (false !== options.enableWebSocket) { - console.log("calling apiClient.ensureWebSocket"); - apiClient.ensureWebSocket(); - } - } - - function onLocalUserSignIn(server, serverUrl, user) { - self._getOrAddApiClient(server, serverUrl); - - var promise = self.onLocalUserSignedIn ? self.onLocalUserSignedIn.call(self, user) : Promise.resolve(); - return promise.then(function () { - events.trigger(self, "localusersignedin", [user]) - }) - } - - function validateAuthentication(server, serverUrl) { - return ajax({ - type: "GET", - url: getEmbyServerUrl(serverUrl, "System/Info"), - dataType: "json", - headers: { - "X-MediaBrowser-Token": server.AccessToken - } - }).then(function (systemInfo) { - updateServerInfo(server, systemInfo); - return Promise.resolve(); - }, function () { - server.UserId = null; - server.AccessToken = null; - return Promise.resolve(); - }); - } - - function getImageUrl(localUser) { - if (localUser && localUser.PrimaryImageTag) { - return { - url: self.getApiClient(localUser).getUserImageUrl(localUser.Id, { - tag: localUser.PrimaryImageTag, - type: "Primary" - }), - supportsParams: true - }; - } - - return { - url: null, - supportsParams: false - }; - } - - function logoutOfServer(apiClient) { - var serverInfo = apiClient.serverInfo() || {}; - var logoutInfo = { - serverId: serverInfo.Id - }; - return apiClient.logout().then(function () { - events.trigger(self, "localusersignedout", [logoutInfo]); - }, function () { - events.trigger(self, "localusersignedout", [logoutInfo]); - }); - } - - function findServers() { - return new Promise(function (resolve, reject) { - var onFinish = function (foundServers) { - var servers = foundServers.map(function (foundServer) { - var info = { - Id: foundServer.Id, - LocalAddress: convertEndpointAddressToManualAddress(foundServer) || foundServer.Address, - Name: foundServer.Name - }; - info.LastConnectionMode = info.ManualAddress ? ConnectionMode.Manual : ConnectionMode.Local; - return info; - }); - resolve(servers); - }; - - if (window.NativeShell && typeof window.NativeShell.findServers === 'function') { - window.NativeShell.findServers(1e3).then(onFinish, function () { - onFinish([]); - }); - } else { - resolve([]); - } - }); - } - - function convertEndpointAddressToManualAddress(info) { - if (info.Address && info.EndpointAddress) { - var address = info.EndpointAddress.split(":")[0]; - var parts = info.Address.split(":"); - - if (parts.length > 1) { - var portString = parts[parts.length - 1]; - - if (!isNaN(parseInt(portString))) { - address += ":" + portString; - } - } - - return normalizeAddress(address); - } - - return null; - } - - function getTryConnectPromise(url, connectionMode, state, resolve, reject) { - console.log("getTryConnectPromise " + url); - ajax({ - url: getEmbyServerUrl(url, "system/info/public"), - timeout: defaultTimeout, - type: "GET", - dataType: "json" - }).then(function (result) { - if (!state.resolved) { - state.resolved = true; - console.log("Reconnect succeeded to " + url); - resolve({ - url: url, - connectionMode: connectionMode, - data: result - }); - } - }, function () { - if (!state.resolved) { - console.log("Reconnect failed to " + url); - - if (++state.rejects >= state.numAddresses) { - reject(); - } - } - }); - } - - function tryReconnect(serverInfo) { - var addresses = []; - var addressesStrings = []; - - if (!serverInfo.manualAddressOnly && serverInfo.LocalAddress && -1 === addressesStrings.indexOf(serverInfo.LocalAddress)) { - addresses.push({ - url: serverInfo.LocalAddress, - mode: ConnectionMode.Local, - timeout: 0 - }); - addressesStrings.push(addresses[addresses.length - 1].url); - } - - if (serverInfo.ManualAddress && -1 === addressesStrings.indexOf(serverInfo.ManualAddress)) { - addresses.push({ - url: serverInfo.ManualAddress, - mode: ConnectionMode.Manual, - timeout: 100 - }); - addressesStrings.push(addresses[addresses.length - 1].url); - } - - if (!serverInfo.manualAddressOnly && serverInfo.RemoteAddress && -1 === addressesStrings.indexOf(serverInfo.RemoteAddress)) { - addresses.push({ - url: serverInfo.RemoteAddress, - mode: ConnectionMode.Remote, - timeout: 200 - }); - addressesStrings.push(addresses[addresses.length - 1].url); - } - - console.log("tryReconnect: " + addressesStrings.join("|")); - return new Promise(function (resolve, reject) { - var state = {}; - state.numAddresses = addresses.length; - state.rejects = 0; - addresses.map(function (url) { - setTimeout(function () { - if (!state.resolved) { - getTryConnectPromise(url.url, url.mode, state, resolve, reject); - } - }, url.timeout); - }); - }); - } - - function onSuccessfulConnection(server, systemInfo, connectionMode, serverUrl, options, resolve) { - var credentials = credentialProvider.credentials(); - options = options || {}; - - afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, true, options, resolve); - } - - function afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, verifyLocalAuthentication, options, resolve) { - options = options || {}; - if (false === options.enableAutoLogin) { - server.UserId = null; - server.AccessToken = null; - } else if (verifyLocalAuthentication && server.AccessToken && false !== options.enableAutoLogin) { - return void validateAuthentication(server, serverUrl).then(function () { - afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, false, options, resolve); - }); - } - - updateServerInfo(server, systemInfo); - server.LastConnectionMode = connectionMode; - - if (false !== options.updateDateLastAccessed) { - server.DateLastAccessed = new Date().getTime(); - } - - credentialProvider.addOrUpdateServer(credentials.Servers, server); - credentialProvider.credentials(credentials); - var result = { - Servers: [] - }; - result.ApiClient = self._getOrAddApiClient(server, serverUrl); - result.ApiClient.setSystemInfo(systemInfo); - result.State = server.AccessToken && false !== options.enableAutoLogin ? "SignedIn" : "ServerSignIn"; - result.Servers.push(server); - result.ApiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection; - result.ApiClient.updateServerInfo(server, serverUrl); - - var resolveActions = function () { - resolve(result); - events.trigger(self, "connected", [result]); - }; - - if ("SignedIn" === result.State) { - afterConnected(result.ApiClient, options); - result.ApiClient.getCurrentUser().then(function (user) { - onLocalUserSignIn(server, serverUrl, user).then(resolveActions, resolveActions); - }, resolveActions); - } else { - resolveActions(); - } - } - - console.log("Begin ConnectionManager constructor"); - var self = this; - this._apiClients = []; - self._minServerVersion = "3.2.33"; - - self.appVersion = function () { - return appVersion; - }; - - self.appName = function () { - return appName; - }; - - self.capabilities = function () { - return capabilities; - }; - - self.deviceId = function () { - return deviceId; - }; - - self.credentialProvider = function () { - return credentialProvider; - }; - - self.getServerInfo = function (id) { - return credentialProvider.credentials().Servers.filter(function (s) { - return s.Id === id; - })[0]; - }; - - self.getLastUsedServer = function () { - var servers = credentialProvider.credentials().Servers; - servers.sort(function (a, b) { - return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0); - }); - - if (servers.length) { - return servers[0]; - } - - return null; - }; - - self.addApiClient = function (apiClient) { - self._apiClients.push(apiClient); - - var existingServers = credentialProvider.credentials().Servers.filter(function (s) { - return stringEqualsIgnoreCase(s.ManualAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.LocalAddress, apiClient.serverAddress()) || stringEqualsIgnoreCase(s.RemoteAddress, apiClient.serverAddress()); - }); - var existingServer = existingServers.length ? existingServers[0] : apiClient.serverInfo(); - - existingServer.DateLastAccessed = new Date().getTime(); - existingServer.LastConnectionMode = ConnectionMode.Manual; - existingServer.ManualAddress = apiClient.serverAddress(); - if (apiClient.manualAddressOnly) { - existingServer.manualAddressOnly = true; - } - apiClient.serverInfo(existingServer); - apiClient.onAuthenticated = function (instance, result) { - return onAuthenticated(instance, result, {}, true); - }; - if (!existingServers.length) { - var credentials = credentialProvider.credentials(); - credentials.Servers = [existingServer]; - credentialProvider.credentials(credentials); - } - - events.trigger(self, "apiclientcreated", [apiClient]); - }; - - self.clearData = function () { - console.log("connection manager clearing data"); - var credentials = credentialProvider.credentials(); - credentials.Servers = []; - credentialProvider.credentials(credentials); - }; - - self._getOrAddApiClient = function (server, serverUrl) { - var apiClient = self.getApiClient(server.Id); - - if (!apiClient) { - apiClient = new apiClientFactory(serverUrl, appName, appVersion, deviceName, deviceId, devicePixelRatio); - self._apiClients.push(apiClient); - apiClient.serverInfo(server); - apiClient.onAuthenticated = function (instance, result) { - return onAuthenticated(instance, result, {}, true); - }; - - events.trigger(self, "apiclientcreated", [apiClient]); - } - - console.log("returning instance from getOrAddApiClient"); - return apiClient; - }; - - self.getOrCreateApiClient = function (serverId) { - var credentials = credentialProvider.credentials(); - var servers = credentials.Servers.filter(function (s) { - return stringEqualsIgnoreCase(s.Id, serverId); - }); - - if (!servers.length) { - throw new Error("Server not found: " + serverId); - } - - var server = servers[0]; - return self._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode)); - }; - - self.user = function (apiClient) { - return new Promise(function (resolve, reject) { - function onLocalUserDone(e) { - if (apiClient && apiClient.getCurrentUserId()) { - apiClient.getCurrentUser().then(function (u) { - localUser = u; - var image = getImageUrl(localUser); - resolve({ - localUser: localUser, - name: localUser ? localUser.Name : null, - imageUrl: image.url, - supportsImageParams: image.supportsParams, - }); - }, onLocalUserDone); - } - } - var localUser; - if (apiClient && apiClient.getCurrentUserId()) { - onLocalUserDone(); - } - }); - }; - - self.logout = function () { - console.log("begin connectionManager loguot"); - var promises = []; - - for (var i = 0, length = self._apiClients.length; i < length; i++) { - var apiClient = self._apiClients[i]; - - if (apiClient.accessToken()) { - promises.push(logoutOfServer(apiClient)); - } - } - - return Promise.all(promises).then(function () { - var credentials = credentialProvider.credentials(); - var servers = credentials.Servers.filter(function (u) { - return "Guest" !== u.UserLinkType; - }); - - for (var j = 0, numServers = servers.length; j < numServers; j++) { - var server = servers[j]; - server.UserId = null; - server.AccessToken = null; - server.ExchangeToken = null; - } - }); - }; - - self.getSavedServers = function () { - var credentials = credentialProvider.credentials(); - var servers = credentials.Servers.slice(0); - servers.sort(function (a, b) { - return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0); - }); - return servers; - }; - - self.getAvailableServers = function () { - console.log("Begin getAvailableServers"); - var credentials = credentialProvider.credentials(); - return Promise.all([findServers()]).then(function (responses) { - var foundServers = responses[0]; - var servers = credentials.Servers.slice(0); - mergeServers(credentialProvider, servers, foundServers); - servers.sort(function (a, b) { - return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0); - }); - credentials.Servers = servers; - credentialProvider.credentials(credentials); - return servers; - }); - }; - - self.connectToServers = function (servers, options) { - console.log("Begin connectToServers, with " + servers.length + " servers"); - var firstServer = servers.length ? servers[0] : null; - - if (firstServer) { - return self.connectToServer(firstServer, options).then(function (result) { - if ("Unavailable" === result.State) { - result.State = "ServerSelection"; - } - - console.log("resolving connectToServers with result.State: " + result.State); - return result; - }); - } - - return Promise.resolve({ - Servers: servers, - State: "ServerSelection" - }); - }; - - self.connectToServer = function (server, options) { - console.log("begin connectToServer"); - return new Promise(function (resolve, reject) { - options = options || {}; - tryReconnect(server).then(function (result) { - var serverUrl = result.url; - var connectionMode = result.connectionMode; - result = result.data; - - if (1 === compareVersions(self.minServerVersion(), result.Version)) { - console.log("minServerVersion requirement not met. Server version: " + result.Version); - resolve({ - State: "ServerUpdateNeeded", - Servers: [server] - }); - } else { - if (server.Id && result.Id !== server.Id) { - console.log("http request succeeded, but found a different server Id than what was expected"); - resolveFailure(self, resolve); - } else { - onSuccessfulConnection(server, result, connectionMode, serverUrl, options, resolve); - } - } - }, function () { - resolveFailure(self, resolve); - }); - }); - }; - - self.connectToAddress = function (address, options) { - function onFail() { - console.log("connectToAddress " + address + " failed"); - return Promise.resolve({ - State: "Unavailable", - }); - } - - if (!address) { - return Promise.reject(); - } - - address = normalizeAddress(address); - var instance = this; - var server = { - ManualAddress: address, - LastConnectionMode: ConnectionMode.Manual - }; - return self.connectToServer(server, options).catch(onFail); - }; - - self.deleteServer = function (serverId) { - if (!serverId) { - throw new Error("null serverId"); - } - - var server = credentialProvider.credentials().Servers.filter(function (s) { - return s.Id === serverId; - }); - server = server.length ? server[0] : null; - return new Promise(function (resolve, reject) { - function onDone() { - var credentials = credentialProvider.credentials(); - credentials.Servers = credentials.Servers.filter(function (s) { - return s.Id !== serverId; - }); - credentialProvider.credentials(credentials); - resolve(); - } - - if (!server.ConnectServerId) { - return void onDone(); - } - }); - }; - }; - - ConnectionManager.prototype.connect = function (options) { - console.log("Begin connect"); - var instance = this; - return instance.getAvailableServers().then(function (servers) { - return instance.connectToServers(servers, options); - }); - }; - - ConnectionManager.prototype.getApiClients = function () { - var servers = this.getSavedServers(); - - for (var i = 0, length = servers.length; i < length; i++) { - var server = servers[i]; - - if (server.Id) { - this._getOrAddApiClient(server, getServerAddress(server, server.LastConnectionMode)); - } - } - - return this._apiClients; - }; - - ConnectionManager.prototype.getApiClient = function (item) { - if (!item) { - throw new Error("item or serverId cannot be null"); - } - - if (item.ServerId) { - item = item.ServerId; - } - - return this._apiClients.filter(function (a) { - var serverInfo = a.serverInfo(); - return !serverInfo || serverInfo.Id === item; - })[0]; - }; - - ConnectionManager.prototype.minServerVersion = function (val) { - if (val) { - this._minServerVersion = val; - } - - return this._minServerVersion; - }; - - ConnectionManager.prototype.handleMessageReceived = function (msg) { - var serverId = msg.ServerId; - - if (serverId) { - var apiClient = this.getApiClient(serverId); - - if (apiClient) { - if ("string" == typeof msg.Data) { - try { - msg.Data = JSON.parse(msg.Data); - } catch (err) {} - } - - apiClient.handleMessageReceived(msg); - } - } - }; - - return ConnectionManager; -}); diff --git a/src/libraries/apiclient/credentialprovider.js b/src/libraries/apiclient/credentialprovider.js deleted file mode 100644 index 471f2b5ef1..0000000000 --- a/src/libraries/apiclient/credentialprovider.js +++ /dev/null @@ -1,29 +0,0 @@ -define(["events", "appStorage"], function(events, appStorage) { - "use strict"; - - function ensure(instance, data) { - if (!instance._credentials) { - var json = appStorage.getItem(instance.key) || "{}"; - console.log("credentials initialized with: " + json), instance._credentials = JSON.parse(json), instance._credentials.Servers = instance._credentials.Servers || [] - } - } - - function set(instance, data) { - data ? (instance._credentials = data, appStorage.setItem(instance.key, JSON.stringify(data))) : instance.clear(), events.trigger(instance, "credentialsupdated") - } - - function Credentials(key) { - this.key = key || "jellyfin_credentials" - } - return Credentials.prototype.clear = function() { - this._credentials = null, appStorage.removeItem(this.key) - }, Credentials.prototype.credentials = function(data) { - return data && set(this, data), ensure(this), this._credentials - }, Credentials.prototype.addOrUpdateServer = function(list, server) { - if (!server.Id) throw new Error("Server.Id cannot be null or empty"); - var existing = list.filter(function(s) { - return s.Id === server.Id - })[0]; - return existing ? (existing.DateLastAccessed = Math.max(existing.DateLastAccessed || 0, server.DateLastAccessed || 0), existing.UserLinkType = server.UserLinkType, server.AccessToken && (existing.AccessToken = server.AccessToken, existing.UserId = server.UserId), server.ExchangeToken && (existing.ExchangeToken = server.ExchangeToken), server.RemoteAddress && (existing.RemoteAddress = server.RemoteAddress), server.ManualAddress && (existing.ManualAddress = server.ManualAddress), server.LocalAddress && (existing.LocalAddress = server.LocalAddress), server.Name && (existing.Name = server.Name), null != server.LastConnectionMode && (existing.LastConnectionMode = server.LastConnectionMode), server.ConnectServerId && (existing.ConnectServerId = server.ConnectServerId), existing) : (list.push(server), server) - }, Credentials -}); \ No newline at end of file diff --git a/src/libraries/apiclient/events.js b/src/libraries/apiclient/events.js deleted file mode 100644 index 6204dc4d4f..0000000000 --- a/src/libraries/apiclient/events.js +++ /dev/null @@ -1,30 +0,0 @@ -define([], function() { - "use strict"; - - function getCallbacks(obj, name) { - if (!obj) throw new Error("obj cannot be null!"); - obj._callbacks = obj._callbacks || {}; - var list = obj._callbacks[name]; - return list || (obj._callbacks[name] = [], list = obj._callbacks[name]), list - } - return { - on: function(obj, eventName, fn) { - getCallbacks(obj, eventName).push(fn) - }, - off: function(obj, eventName, fn) { - var list = getCallbacks(obj, eventName), - i = list.indexOf(fn); - 1 !== i && list.splice(i, 1) - }, - trigger: function(obj, eventName) { - var eventObject = { - type: eventName - }, - eventArgs = []; - eventArgs.push(eventObject); - for (var additionalArgs = arguments[2] || [], i = 0, length = additionalArgs.length; i < length; i++) eventArgs.push(additionalArgs[i]); - getCallbacks(obj, eventName).slice(0).forEach(function(c) { - c.apply(obj, eventArgs) - }) - } - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/localassetmanager.js b/src/libraries/apiclient/localassetmanager.js deleted file mode 100644 index fbe74aae51..0000000000 --- a/src/libraries/apiclient/localassetmanager.js +++ /dev/null @@ -1,406 +0,0 @@ -define(["filerepository", "itemrepository", "useractionrepository", "transfermanager"], function(filerepository, itemrepository, useractionrepository, transfermanager) { - "use strict"; - - function getLocalItem(serverId, itemId) { - return console.log("[lcoalassetmanager] Begin getLocalItem"), itemrepository.get(serverId, itemId) - } - - function recordUserAction(action) { - return action.Id = createGuid(), useractionrepository.set(action.Id, action) - } - - function getUserActions(serverId) { - return useractionrepository.getByServerId(serverId) - } - - function deleteUserAction(action) { - return useractionrepository.remove(action.Id) - } - - function deleteUserActions(actions) { - var results = []; - return actions.forEach(function(action) { - results.push(deleteUserAction(action)) - }), Promise.all(results) - } - - function getServerItems(serverId) { - return console.log("[localassetmanager] Begin getServerItems"), itemrepository.getAll(serverId) - } - - function getItemsFromIds(serverId, ids) { - var actions = ids.map(function(id) { - var strippedId = stripStart(id, "local:"); - return getLocalItem(serverId, strippedId) - }); - return Promise.all(actions).then(function(items) { - var libItems = items.map(function(locItem) { - return locItem.Item - }); - return Promise.resolve(libItems) - }) - } - - function getViews(serverId, userId) { - return itemrepository.getServerItemTypes(serverId, userId).then(function(types) { - var item, list = []; - return types.indexOf("Audio") > -1 && (item = { - Name: "Music", - ServerId: serverId, - Id: "localview:MusicView", - Type: "MusicView", - CollectionType: "music", - IsFolder: !0 - }, list.push(item)), types.indexOf("Photo") > -1 && (item = { - Name: "Photos", - ServerId: serverId, - Id: "localview:PhotosView", - Type: "PhotosView", - CollectionType: "photos", - IsFolder: !0 - }, list.push(item)), types.indexOf("Episode") > -1 && (item = { - Name: "TV", - ServerId: serverId, - Id: "localview:TVView", - Type: "TVView", - CollectionType: "tvshows", - IsFolder: !0 - }, list.push(item)), types.indexOf("Movie") > -1 && (item = { - Name: "Movies", - ServerId: serverId, - Id: "localview:MoviesView", - Type: "MoviesView", - CollectionType: "movies", - IsFolder: !0 - }, list.push(item)), types.indexOf("Video") > -1 && (item = { - Name: "Videos", - ServerId: serverId, - Id: "localview:VideosView", - Type: "VideosView", - CollectionType: "videos", - IsFolder: !0 - }, list.push(item)), types.indexOf("MusicVideo") > -1 && (item = { - Name: "Music Videos", - ServerId: serverId, - Id: "localview:MusicVideosView", - Type: "MusicVideosView", - CollectionType: "videos", - IsFolder: !0 - }, list.push(item)), Promise.resolve(list) - }) - } - - function updateFiltersForTopLevelView(parentId, mediaTypes, includeItemTypes, query) { - switch (parentId) { - case "MusicView": - return query.Recursive ? includeItemTypes.push("Audio") : includeItemTypes.push("MusicAlbum"), !0; - case "PhotosView": - return query.Recursive ? includeItemTypes.push("Photo") : includeItemTypes.push("PhotoAlbum"), !0; - case "TVView": - return query.Recursive ? includeItemTypes.push("Episode") : includeItemTypes.push("Series"), !0; - case "VideosView": - return query.Recursive, includeItemTypes.push("Video"), !0; - case "MoviesView": - return query.Recursive, includeItemTypes.push("Movie"), !0; - case "MusicVideosView": - return query.Recursive, includeItemTypes.push("MusicVideo"), !0 - } - return !1 - } - - function normalizeId(id) { - return id ? (id = stripStart(id, "localview:"), id = stripStart(id, "local:")) : null - } - - function normalizeIdList(val) { - return val ? val.split(",").map(normalizeId) : [] - } - - function shuffle(array) { - for (var temporaryValue, randomIndex, currentIndex = array.length; 0 !== currentIndex;) randomIndex = Math.floor(Math.random() * currentIndex), currentIndex -= 1, temporaryValue = array[currentIndex], array[currentIndex] = array[randomIndex], array[randomIndex] = temporaryValue; - return array - } - - function sortItems(items, query) { - if (!query.SortBy || 0 === query.SortBy.length) return items; - if ("Random" === query.SortBy) return shuffle(items); - var sortSpec = getSortSpec(query); - return items.sort(function(a, b) { - for (var i = 0; i < sortSpec.length; i++) { - var result = compareValues(a, b, sortSpec[i].Field, sortSpec[i].OrderDescending); - if (0 !== result) return result - } - return 0 - }), items - } - - function compareValues(a, b, field, orderDesc) { - if (!a.hasOwnProperty(field) || !b.hasOwnProperty(field)) return 0; - var valA = a[field], - valB = b[field], - result = 0; - return "string" == typeof valA || "string" == typeof valB ? (valA = valA || "", valB = valB || "", result = valA.toLowerCase().localeCompare(valB.toLowerCase())) : valA > valB ? result = 1 : valA < valB && (result = -1), orderDesc && (result *= -1), result - } - - function getSortSpec(query) { - for (var sortFields = (query.SortBy || "").split(","), sortOrders = (query.SortOrder || "").split(","), sortSpec = [], i = 0; i < sortFields.length; i++) { - var orderDesc = !1; - i < sortOrders.length && -1 !== sortOrders[i].toLowerCase().indexOf("desc") && (orderDesc = !0), sortSpec.push({ - Field: sortFields[i], - OrderDescending: orderDesc - }) - } - return sortSpec - } - - function getViewItems(serverId, userId, options) { - var searchParentId = options.ParentId; - searchParentId = normalizeId(searchParentId); - var seasonId = normalizeId(options.SeasonId || options.seasonId), - seriesId = normalizeId(options.SeriesId || options.seriesId), - albumIds = normalizeIdList(options.AlbumIds || options.albumIds), - includeItemTypes = options.IncludeItemTypes ? options.IncludeItemTypes.split(",") : [], - filters = options.Filters ? options.Filters.split(",") : [], - mediaTypes = options.MediaTypes ? options.MediaTypes.split(",") : []; - return updateFiltersForTopLevelView(searchParentId, mediaTypes, includeItemTypes, options) && (searchParentId = null), getServerItems(serverId).then(function(items) { - var itemsMap = new Map, - subtreeIdSet = new Set; - if (items.forEach(function(item) { - item.Item.LocalChildren = [], itemsMap.set(item.Item.Id, item.Item) - }), itemsMap.forEach(function(item, ignored, ignored2) { - if (item.ParentId && itemsMap.has(item.ParentId)) { - itemsMap.get(item.ParentId).LocalChildren.push(item) - } - }), options.Recursive && searchParentId && itemsMap.has(searchParentId)) { - var addSubtreeIds = function(recurseItem) { - subtreeIdSet.has(recurseItem.Id) || subtreeIdSet.add(recurseItem.Id), recurseItem.LocalChildren.forEach(function(childItem) { - addSubtreeIds(childItem) - }) - }, - searchParentItem = itemsMap.get(searchParentId); - addSubtreeIds(searchParentItem) - } - var resultItems = items.filter(function(item) { - return (!item.SyncStatus || "synced" === item.SyncStatus) && ((!mediaTypes.length || -1 !== mediaTypes.indexOf(item.Item.MediaType || "")) && ((!seriesId || item.Item.SeriesId === seriesId) && ((!seasonId || item.Item.SeasonId === seasonId) && ((!albumIds.length || -1 !== albumIds.indexOf(item.Item.AlbumId || "")) && ((!item.Item.IsFolder || -1 === filters.indexOf("IsNotFolder")) && (!(!item.Item.IsFolder && -1 !== filters.indexOf("IsFolder")) && ((!includeItemTypes.length || -1 !== includeItemTypes.indexOf(item.Item.Type || "")) && (!searchParentId || (options.Recursive ? subtreeIdSet.has(item.Item.Id) : item.Item.ParentId === searchParentId))))))))) - }).map(function(item2) { - return item2.Item - }); - return resultItems = sortItems(resultItems, options), options.Limit && (resultItems = resultItems.slice(0, options.Limit)), Promise.resolve(resultItems) - }) - } - - function removeObsoleteContainerItems(serverId) { - return getServerItems(serverId).then(function(items) { - var seriesItems = items.filter(function(item) { - return "series" === (item.Item.Type || "").toLowerCase() - }), - seasonItems = items.filter(function(item) { - return "season" === (item.Item.Type || "").toLowerCase() - }), - albumItems = items.filter(function(item) { - var type = (item.Item.Type || "").toLowerCase(); - return "musicalbum" === type || "photoalbum" === type - }), - requiredSeriesIds = items.filter(function(item) { - return "episode" === (item.Item.Type || "").toLowerCase() - }).map(function(item2) { - return item2.Item.SeriesId - }).filter(filterDistinct), - requiredSeasonIds = items.filter(function(item) { - return "episode" === (item.Item.Type || "").toLowerCase() - }).map(function(item2) { - return item2.Item.SeasonId - }).filter(filterDistinct), - requiredAlbumIds = items.filter(function(item) { - var type = (item.Item.Type || "").toLowerCase(); - return "audio" === type || "photo" === type - }).map(function(item2) { - return item2.Item.AlbumId - }).filter(filterDistinct), - obsoleteItems = []; - seriesItems.forEach(function(item) { - requiredSeriesIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item) - }), seasonItems.forEach(function(item) { - requiredSeasonIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item) - }), albumItems.forEach(function(item) { - requiredAlbumIds.indexOf(item.Item.Id) < 0 && obsoleteItems.push(item) - }); - var p = Promise.resolve(); - return obsoleteItems.forEach(function(item) { - p = p.then(function() { - return itemrepository.remove(item.ServerId, item.Id) - }) - }), p - }) - } - - function removeLocalItem(localItem) { - return itemrepository.get(localItem.ServerId, localItem.Id).then(function(item) { - var onFileDeletedSuccessOrFail = function() { - return itemrepository.remove(localItem.ServerId, localItem.Id) - }, - p = Promise.resolve(); - return item.LocalPath && (p = p.then(function() { - return filerepository.deleteFile(item.LocalPath) - })), item && item.Item && item.Item.MediaSources && item.Item.MediaSources.forEach(function(mediaSource) { - mediaSource.MediaStreams && mediaSource.MediaStreams.length > 0 && mediaSource.MediaStreams.forEach(function(mediaStream) { - mediaStream.Path && (p = p.then(function() { - return filerepository.deleteFile(mediaStream.Path) - })) - }) - }), p.then(onFileDeletedSuccessOrFail, onFileDeletedSuccessOrFail) - }, function(item) { - return Promise.resolve() - }) - } - - function addOrUpdateLocalItem(localItem) { - return itemrepository.set(localItem.ServerId, localItem.Id, localItem) - } - - function getSubtitleSaveFileName(localItem, mediaPath, language, isForced, format) { - var name = getNameWithoutExtension(mediaPath); - name = filerepository.getValidFileName(name), language && (name += "." + language.toLowerCase()), isForced && (name += ".foreign"), name = name + "." + format.toLowerCase(); - var mediaFolder = filerepository.getParentPath(localItem.LocalPath); - return filerepository.combinePath(mediaFolder, name) - } - - function getItemFileSize(path) { - return filerepository.getItemFileSize(path) - } - - function getNameWithoutExtension(path) { - var fileName = path, - pos = fileName.lastIndexOf("."); - return pos > 0 && (fileName = fileName.substring(0, pos)), fileName - } - - function downloadFile(url, localItem) { - var imageUrl = getImageUrl(localItem.Item.ServerId, localItem.Item.Id, { - type: "Primary", - index: 0 - }); - return transfermanager.downloadFile(url, localItem, imageUrl) - } - - function downloadSubtitles(url, fileName) { - return transfermanager.downloadSubtitles(url, fileName) - } - - function getImageUrl(serverId, itemId, imageOptions) { - var imageType = imageOptions.type, - index = imageOptions.index, - pathArray = getImagePath(serverId, itemId, imageType, index); - return filerepository.getImageUrl(pathArray) - } - - function hasImage(serverId, itemId, imageType, index) { - var pathArray = getImagePath(serverId, itemId, imageType, index), - localFilePath = filerepository.getFullMetadataPath(pathArray); - return filerepository.fileExists(localFilePath).then(function(exists) { - return Promise.resolve(exists) - }, function(err) { - return Promise.resolve(!1) - }) - } - - function fileExists(localFilePath) { - return filerepository.fileExists(localFilePath) - } - - function downloadImage(localItem, url, serverId, itemId, imageType, index) { - var localPathParts = getImagePath(serverId, itemId, imageType, index); - return transfermanager.downloadImage(url, localPathParts) - } - - function isDownloadFileInQueue(path) { - return transfermanager.isDownloadFileInQueue(path) - } - - function getDownloadItemCount() { - return transfermanager.getDownloadItemCount() - } - - function getDirectoryPath(item) { - var parts = [], - itemtype = item.Type.toLowerCase(), - mediaType = (item.MediaType || "").toLowerCase(); - "episode" === itemtype || "series" === itemtype || "season" === itemtype ? parts.push("TV") : "video" === mediaType ? parts.push("Videos") : "audio" === itemtype || "musicalbum" === itemtype || "musicartist" === itemtype ? parts.push("Music") : "photo" === itemtype || "photoalbum" === itemtype ? parts.push("Photos") : null; - var albumArtist = item.AlbumArtist; - albumArtist && parts.push(albumArtist); - var seriesName = item.SeriesName; - seriesName && parts.push(seriesName); - var seasonName = item.SeasonName; - seasonName && parts.push(seasonName), item.Album && parts.push(item.Album), ("video" === mediaType && "episode" !== itemtype || item.IsFolder) && parts.push(item.Name); - for (var finalParts = [], i = 0; i < parts.length; i++) finalParts.push(filerepository.getValidFileName(parts[i])); - return finalParts - } - - function getImagePath(serverId, itemId, imageType, index) { - var parts = []; - parts.push("images"), index = index || 0, parts.push(itemId + "_" + imageType + "_" + index.toString()); - for (var finalParts = [], i = 0; i < parts.length; i++) finalParts.push(parts[i]); - return finalParts - } - - function getLocalFileName(item, originalFileName) { - var filename = originalFileName || item.Name; - return filerepository.getValidFileName(filename) - } - - function resyncTransfers() { - return transfermanager.resyncTransfers() - } - - function createGuid() { - var d = (new Date).getTime(); - return window.performance && "function" == typeof window.performance.now && (d += performance.now()), "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { - var r = (d + 16 * Math.random()) % 16 | 0; - return d = Math.floor(d / 16), ("x" === c ? r : 3 & r | 8).toString(16) - }) - } - - function startsWith(str, find) { - return !!(str && find && str.length > find.length && 0 === str.indexOf(find)) - } - - function stripStart(str, find) { - return startsWith(str, find) ? str.substr(find.length) : str - } - - function filterDistinct(value, index, self) { - return self.indexOf(value) === index - } - - function enableBackgroundCompletion() { - return transfermanager.enableBackgroundCompletion - } - return { - getLocalItem: getLocalItem, - getDirectoryPath: getDirectoryPath, - getLocalFileName: getLocalFileName, - recordUserAction: recordUserAction, - getUserActions: getUserActions, - deleteUserAction: deleteUserAction, - deleteUserActions: deleteUserActions, - removeLocalItem: removeLocalItem, - addOrUpdateLocalItem: addOrUpdateLocalItem, - downloadFile: downloadFile, - downloadSubtitles: downloadSubtitles, - hasImage: hasImage, - downloadImage: downloadImage, - getImageUrl: getImageUrl, - getSubtitleSaveFileName: getSubtitleSaveFileName, - getServerItems: getServerItems, - getItemFileSize: getItemFileSize, - isDownloadFileInQueue: isDownloadFileInQueue, - getDownloadItemCount: getDownloadItemCount, - getViews: getViews, - getViewItems: getViewItems, - resyncTransfers: resyncTransfers, - getItemsFromIds: getItemsFromIds, - removeObsoleteContainerItems: removeObsoleteContainerItems, - fileExists: fileExists, - enableBackgroundCompletion: enableBackgroundCompletion - } -}); diff --git a/src/libraries/apiclient/package.json b/src/libraries/apiclient/package.json deleted file mode 100644 index 0069cfc6bf..0000000000 --- a/src/libraries/apiclient/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "main": "apiclient.js" -} \ No newline at end of file diff --git a/src/libraries/apiclient/sync/filerepository.js b/src/libraries/apiclient/sync/filerepository.js deleted file mode 100644 index 198967469d..0000000000 --- a/src/libraries/apiclient/sync/filerepository.js +++ /dev/null @@ -1,45 +0,0 @@ -define([], function() { - "use strict"; - - function getValidFileName(path) { - return path - } - - function getFullLocalPath(pathArray) { - return pathArray.join("/") - } - - function getPathFromArray(pathArray) { - return pathArray.join("/") - } - - function deleteFile(path) { - return Promise.resolve() - } - - function deleteDirectory(path) { - return Promise.resolve() - } - - function fileExists(path) { - return Promise.resolve() - } - - function getItemFileSize(path) { - return Promise.resolve(0) - } - - function getImageUrl(pathParts) { - return pathParts.join("/") - } - return { - getValidFileName: getValidFileName, - getFullLocalPath: getFullLocalPath, - getPathFromArray: getPathFromArray, - deleteFile: deleteFile, - deleteDirectory: deleteDirectory, - fileExists: fileExists, - getItemFileSize: getItemFileSize, - getImageUrl: getImageUrl - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/itemrepository.js b/src/libraries/apiclient/sync/itemrepository.js deleted file mode 100644 index 5330d5d1a2..0000000000 --- a/src/libraries/apiclient/sync/itemrepository.js +++ /dev/null @@ -1,123 +0,0 @@ -define([], function() { - "use strict"; - - function ServerDatabase(dbName, readyCallback) { - var request = indexedDB.open(dbName, dbVersion); - request.onerror = function(event) {}, request.onupgradeneeded = function(event) { - var db = event.target.result; - db.createObjectStore(dbName).transaction.oncomplete = function(event) { - readyCallback(db) - } - }, request.onsuccess = function(event) { - var db = event.target.result; - readyCallback(db) - } - } - - function getDbName(serverId) { - return "items_" + serverId - } - - function getDb(serverId, callback) { - var dbName = getDbName(serverId), - db = databases[dbName]; - if (db) return void callback(db); - new ServerDatabase(dbName, function(db) { - databases[dbName] = db, callback(db) - }) - } - - function getServerItemTypes(serverId, userId) { - return getAll(serverId, userId).then(function(all) { - return all.map(function(item2) { - return item2.Item.Type || "" - }).filter(filterDistinct) - }) - } - - function getAll(serverId, userId) { - return new Promise(function(resolve, reject) { - getDb(serverId, function(db) { - var request, storeName = getDbName(serverId), - transaction = db.transaction([storeName], "readonly"), - objectStore = transaction.objectStore(storeName); - if ("getAll" in objectStore) request = objectStore.getAll(null, 1e4), request.onsuccess = function(event) { - resolve(event.target.result) - }; - else { - var results = []; - request = objectStore.openCursor(), request.onsuccess = function(event) { - var cursor = event.target.result; - cursor ? (results.push(cursor.value), cursor.continue()) : resolve(results) - } - } - request.onerror = reject - }) - }) - } - - function get(serverId, key) { - return new Promise(function(resolve, reject) { - getDb(serverId, function(db) { - var storeName = getDbName(serverId), - transaction = db.transaction([storeName], "readonly"), - objectStore = transaction.objectStore(storeName), - request = objectStore.get(key); - request.onerror = reject, request.onsuccess = function(event) { - resolve(request.result) - } - }) - }) - } - - function set(serverId, key, val) { - return new Promise(function(resolve, reject) { - getDb(serverId, function(db) { - var storeName = getDbName(serverId), - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.put(val, key); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - - function remove(serverId, key) { - return new Promise(function(resolve, reject) { - getDb(serverId, function(db) { - var storeName = getDbName(serverId), - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.delete(key); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - - function clear(serverId) { - return new Promise(function(resolve, reject) { - getDb(serverId, function(db) { - var storeName = getDbName(serverId), - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.clear(); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - - function filterDistinct(value, index, self) { - return self.indexOf(value) === index - } - var indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB, - dbVersion = (self.IDBTransaction || self.webkitIDBTransaction || self.msIDBTransaction, self.IDBKeyRange || self.webkitIDBKeyRange || self.msIDBKeyRange, 1), - databases = {}; - return { - get: get, - set: set, - remove: remove, - clear: clear, - getAll: getAll, - getServerItemTypes: getServerItemTypes - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/localsync.js b/src/libraries/apiclient/sync/localsync.js deleted file mode 100644 index cea244de08..0000000000 --- a/src/libraries/apiclient/sync/localsync.js +++ /dev/null @@ -1,17 +0,0 @@ -define(["connectionManager"], function(connectionManager) { - "use strict"; - var isSyncing; - return { - sync: function(options) { - return console.log("localSync.sync starting..."), isSyncing ? Promise.resolve() : (isSyncing = !0, new Promise(function(resolve, reject) { - require(["multiserversync", "appSettings"], function(MultiServerSync, appSettings) { - options = options || {}, options.cameraUploadServers = appSettings.cameraUploadServers(), (new MultiServerSync).sync(connectionManager, options).then(function() { - isSyncing = null, resolve() - }, function(err) { - isSyncing = null, reject(err) - }) - }) - })) - } - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/mediasync.js b/src/libraries/apiclient/sync/mediasync.js deleted file mode 100644 index 24220561ad..0000000000 --- a/src/libraries/apiclient/sync/mediasync.js +++ /dev/null @@ -1,368 +0,0 @@ -define(["localassetmanager"], function(localassetmanager) { - "use strict"; - - function processDownloadStatus(apiClient, serverInfo, options) { - return console.log("[mediasync] Begin processDownloadStatus"), localassetmanager.resyncTransfers().then(function() { - return localassetmanager.getServerItems(serverInfo.Id).then(function(items) { - console.log("[mediasync] Begin processDownloadStatus getServerItems completed"); - var p = Promise.resolve(), - cnt = 0; - return items.filter(function(item) { - return "transferring" === item.SyncStatus || "queued" === item.SyncStatus - }).forEach(function(item) { - p = p.then(function() { - return reportTransfer(apiClient, item) - }), cnt++ - }), p.then(function() { - return console.log("[mediasync] Exit processDownloadStatus. Items reported: " + cnt.toString()), Promise.resolve() - }) - }) - }) - } - - function reportTransfer(apiClient, item) { - return localassetmanager.getItemFileSize(item.LocalPath).then(function(size) { - return size > 0 ? apiClient.reportSyncJobItemTransferred(item.SyncJobItemId).then(function() { - return item.SyncStatus = "synced", console.log("[mediasync] reportSyncJobItemTransferred called for " + item.LocalPath), localassetmanager.addOrUpdateLocalItem(item) - }, function(error) { - return console.error("[mediasync] Mediasync error on reportSyncJobItemTransferred", error), item.SyncStatus = "error", localassetmanager.addOrUpdateLocalItem(item) - }) : localassetmanager.isDownloadFileInQueue(item.LocalPath).then(function(result) { - return result ? Promise.resolve() : (console.log("[mediasync] reportTransfer: Size is 0 and download no longer in queue. Deleting item."), localassetmanager.removeLocalItem(item).then(function() { - return console.log("[mediasync] reportTransfer: Item deleted."), Promise.resolve() - }, function(err2) { - return console.log("[mediasync] reportTransfer: Failed to delete item.", err2), Promise.resolve() - })) - }) - }, function(error) { - return console.error("[mediasync] reportTransfer: error on getItemFileSize. Deleting item.", error), localassetmanager.removeLocalItem(item).then(function() { - return console.log("[mediasync] reportTransfer: Item deleted."), Promise.resolve() - }, function(err2) { - return console.log("[mediasync] reportTransfer: Failed to delete item.", err2), Promise.resolve() - }) - }) - } - - function reportOfflineActions(apiClient, serverInfo) { - return console.log("[mediasync] Begin reportOfflineActions"), localassetmanager.getUserActions(serverInfo.Id).then(function(actions) { - return actions.length ? apiClient.reportOfflineActions(actions).then(function() { - return localassetmanager.deleteUserActions(actions).then(function() { - return console.log("[mediasync] Exit reportOfflineActions (actions reported and deleted.)"), Promise.resolve() - }) - }, function(err) { - return console.error("[mediasync] error on apiClient.reportOfflineActions: " + err.toString()), localassetmanager.deleteUserActions(actions) - }) : (console.log("[mediasync] Exit reportOfflineActions (no actions)"), Promise.resolve()) - }) - } - - function syncData(apiClient, serverInfo) { - return console.log("[mediasync] Begin syncData"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) { - var completedItems = items.filter(function(item) { - return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus) - }), - request = { - TargetId: apiClient.deviceId(), - LocalItemIds: completedItems.map(function(xitem) { - return xitem.ItemId - }) - }; - return apiClient.syncData(request).then(function(result) { - return afterSyncData(apiClient, serverInfo, result).then(function() { - return console.log("[mediasync] Exit syncData"), Promise.resolve() - }, function(err) { - return console.error("[mediasync] Error in syncData: " + err.toString()), Promise.resolve() - }) - }) - }) - } - - function afterSyncData(apiClient, serverInfo, syncDataResult) { - console.log("[mediasync] Begin afterSyncData"); - var p = Promise.resolve(); - return syncDataResult.ItemIdsToRemove && syncDataResult.ItemIdsToRemove.length > 0 && syncDataResult.ItemIdsToRemove.forEach(function(itemId) { - p = p.then(function() { - return removeLocalItem(itemId, serverInfo.Id) - }) - }), p = p.then(function() { - return removeObsoleteContainerItems(serverInfo.Id) - }), p.then(function() { - return console.log("[mediasync] Exit afterSyncData"), Promise.resolve() - }) - } - - function removeObsoleteContainerItems(serverId) { - return console.log("[mediasync] Begin removeObsoleteContainerItems"), localassetmanager.removeObsoleteContainerItems(serverId) - } - - function removeLocalItem(itemId, serverId) { - return console.log("[mediasync] Begin removeLocalItem"), localassetmanager.getLocalItem(serverId, itemId).then(function(item) { - return item ? localassetmanager.removeLocalItem(item) : Promise.resolve() - }, function(err2) { - return console.error("[mediasync] removeLocalItem: Failed: ", err2), Promise.resolve() - }) - } - - function getNewMedia(apiClient, downloadCount) { - return console.log("[mediasync] Begin getNewMedia"), apiClient.getReadySyncItems(apiClient.deviceId()).then(function(jobItems) { - console.log("[mediasync] getReadySyncItems returned " + jobItems.length + " items"); - var p = Promise.resolve(), - currentCount = downloadCount; - return jobItems.forEach(function(jobItem) { - currentCount++ <= 10 && (p = p.then(function() { - return getNewItem(jobItem, apiClient) - })) - }), p.then(function() { - return console.log("[mediasync] Exit getNewMedia"), Promise.resolve() - }) - }, function(err) { - return console.error("[mediasync] getReadySyncItems: Failed: ", err), Promise.resolve() - }) - } - - function afterMediaDownloaded(apiClient, jobItem, localItem) { - return console.log("[mediasync] Begin afterMediaDownloaded"), getImages(apiClient, jobItem, localItem).then(function() { - var libraryItem = jobItem.Item; - return downloadParentItems(apiClient, jobItem, libraryItem).then(function() { - return getSubtitles(apiClient, jobItem, localItem) - }) - }) - } - - function createLocalItem(libraryItem, jobItem) { - console.log("[localassetmanager] Begin createLocalItem"); - var item = { - Item: libraryItem, - ItemId: libraryItem.Id, - ServerId: libraryItem.ServerId, - Id: libraryItem.Id - }; - return jobItem && (item.SyncJobItemId = jobItem.SyncJobItemId), console.log("[localassetmanager] End createLocalItem"), item - } - - function getNewItem(jobItem, apiClient) { - console.log("[mediasync] Begin getNewItem"); - var libraryItem = jobItem.Item; - return localassetmanager.getLocalItem(libraryItem.ServerId, libraryItem.Id).then(function(existingItem) { - if (existingItem && ("queued" === existingItem.SyncStatus || "transferring" === existingItem.SyncStatus || "synced" === existingItem.SyncStatus) && (console.log("[mediasync] getNewItem: getLocalItem found existing item"), localassetmanager.enableBackgroundCompletion())) return Promise.resolve(); - libraryItem.CanDelete = !1, libraryItem.CanDownload = !1, libraryItem.SupportsSync = !1, libraryItem.People = [], libraryItem.Chapters = [], libraryItem.Studios = [], libraryItem.SpecialFeatureCount = null, libraryItem.LocalTrailerCount = null, libraryItem.RemoteTrailers = []; - var localItem = createLocalItem(libraryItem, jobItem); - return localItem.SyncStatus = "queued", downloadMedia(apiClient, jobItem, localItem) - }) - } - - function downloadParentItems(apiClient, jobItem, libraryItem) { - var p = Promise.resolve(); - return libraryItem.SeriesId && (p = p.then(function() { - return downloadItem(apiClient, libraryItem.SeriesId) - })), libraryItem.SeasonId && (p = p.then(function() { - return downloadItem(apiClient, libraryItem.SeasonId).then(function(seasonItem) { - return libraryItem.SeasonPrimaryImageTag = (seasonItem.Item.ImageTags || {}).Primary, Promise.resolve() - }) - })), libraryItem.AlbumId && (p = p.then(function() { - return downloadItem(apiClient, libraryItem.AlbumId) - })), p - } - - function downloadItem(apiClient, itemId) { - return apiClient.getItem(apiClient.getCurrentUserId(), itemId).then(function(downloadedItem) { - downloadedItem.CanDelete = !1, downloadedItem.CanDownload = !1, downloadedItem.SupportsSync = !1, downloadedItem.People = [], downloadedItem.SpecialFeatureCount = null, downloadedItem.BackdropImageTags = null, downloadedItem.ParentBackdropImageTags = null, downloadedItem.ParentArtImageTag = null, downloadedItem.ParentLogoImageTag = null; - var localItem = createLocalItem(downloadedItem, null); - return localassetmanager.addOrUpdateLocalItem(localItem).then(function() { - return Promise.resolve(localItem) - }, function(err) { - return console.error("[mediasync] downloadItem failed: " + err.toString()), Promise.resolve(null) - }) - }) - } - - function ensureLocalPathParts(localItem, jobItem) { - if (!localItem.LocalPathParts) { - var libraryItem = localItem.Item, - parts = localassetmanager.getDirectoryPath(libraryItem); - parts.push(localassetmanager.getLocalFileName(libraryItem, jobItem.OriginalFileName)), localItem.LocalPathParts = parts - } - } - - function downloadMedia(apiClient, jobItem, localItem) { - console.log("[mediasync] downloadMedia: start."); - var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/File", { - api_key: apiClient.accessToken() - }); - return ensureLocalPathParts(localItem, jobItem), localassetmanager.downloadFile(url, localItem).then(function(result) { - console.log("[mediasync] downloadMedia-downloadFile returned path: " + result.path); - var localPath = result.path, - libraryItem = localItem.Item; - if (localPath && libraryItem.MediaSources) - for (var i = 0; i < libraryItem.MediaSources.length; i++) { - var mediaSource = libraryItem.MediaSources[i]; - mediaSource.Path = localPath, mediaSource.Protocol = "File" - } - return localItem.LocalPath = localPath, localItem.SyncStatus = "transferring", localassetmanager.addOrUpdateLocalItem(localItem).then(function() { - return afterMediaDownloaded(apiClient, jobItem, localItem).then(function() { - return result.isComplete ? (localItem.SyncStatus = "synced", reportTransfer(apiClient, localItem)) : Promise.resolve() - }, function(err) { - return console.log("[mediasync] downloadMedia: afterMediaDownloaded failed: " + err), Promise.reject(err) - }) - }, function(err) { - return console.log("[mediasync] downloadMedia: addOrUpdateLocalItem failed: " + err), Promise.reject(err) - }) - }, function(err) { - return console.log("[mediasync] downloadMedia: localassetmanager.downloadFile failed: " + err), Promise.reject(err) - }) - } - - function getImages(apiClient, jobItem, localItem) { - console.log("[mediasync] Begin getImages"); - var p = Promise.resolve(), - libraryItem = localItem.Item, - serverId = libraryItem.ServerId, - mainImageTag = (libraryItem.ImageTags || {}).Primary; - libraryItem.Id && mainImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.Id, mainImageTag, "Primary") - })); - var logoImageTag = (libraryItem.ImageTags || {}).Logo; - libraryItem.Id && logoImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.Id, logoImageTag, "Logo") - })); - var artImageTag = (libraryItem.ImageTags || {}).Art; - libraryItem.Id && artImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.Id, artImageTag, "Art") - })); - var bannerImageTag = (libraryItem.ImageTags || {}).Banner; - libraryItem.Id && bannerImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.Id, bannerImageTag, "Banner") - })); - var thumbImageTag = (libraryItem.ImageTags || {}).Thumb; - if (libraryItem.Id && thumbImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.Id, thumbImageTag, "Thumb") - })), libraryItem.Id && libraryItem.BackdropImageTags) - for (var i = 0; i < libraryItem.BackdropImageTags.length; i++); - return libraryItem.SeriesId && libraryItem.SeriesPrimaryImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.SeriesId, libraryItem.SeriesPrimaryImageTag, "Primary") - })), libraryItem.SeriesId && libraryItem.SeriesThumbImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.SeriesId, libraryItem.SeriesThumbImageTag, "Thumb") - })), libraryItem.SeasonId && libraryItem.SeasonPrimaryImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.SeasonId, libraryItem.SeasonPrimaryImageTag, "Primary") - })), libraryItem.AlbumId && libraryItem.AlbumPrimaryImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.AlbumId, libraryItem.AlbumPrimaryImageTag, "Primary") - })), libraryItem.ParentThumbItemId && libraryItem.ParentThumbImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.ParentThumbItemId, libraryItem.ParentThumbImageTag, "Thumb") - })), libraryItem.ParentPrimaryImageItemId && libraryItem.ParentPrimaryImageTag && (p = p.then(function() { - return downloadImage(localItem, apiClient, serverId, libraryItem.ParentPrimaryImageItemId, libraryItem.ParentPrimaryImageTag, "Primary") - })), p.then(function() { - return console.log("[mediasync] Finished getImages"), localassetmanager.addOrUpdateLocalItem(localItem) - }, function(err) { - return console.log("[mediasync] Error getImages: " + err.toString()), Promise.resolve() - }) - } - - function downloadImage(localItem, apiClient, serverId, itemId, imageTag, imageType, index) { - return index = index || 0, localassetmanager.hasImage(serverId, itemId, imageType, index).then(function(hasImage) { - if (hasImage) return console.log("[mediasync] downloadImage - skip existing: " + itemId + " " + imageType + "_" + index.toString()), Promise.resolve(); - var maxWidth = 400; - "backdrop" === imageType && (maxWidth = null); - var imageUrl = apiClient.getScaledImageUrl(itemId, { - tag: imageTag, - type: imageType, - maxWidth: maxWidth, - api_key: apiClient.accessToken() - }); - return console.log("[mediasync] downloadImage " + itemId + " " + imageType + "_" + index.toString()), localassetmanager.downloadImage(localItem, imageUrl, serverId, itemId, imageType, index).then(function(result) { - return Promise.resolve(result) - }, function(err) { - return console.log("[mediasync] Error downloadImage: " + err.toString()), Promise.resolve() - }) - }, function(err) { - return console.log("[mediasync] Error downloadImage: " + err.toString()), Promise.resolve() - }) - } - - function getSubtitles(apiClient, jobItem, localItem) { - if (console.log("[mediasync] Begin getSubtitles"), !jobItem.Item.MediaSources.length) return console.log("[mediasync] Cannot download subtitles because video has no media source info."), Promise.resolve(); - var files = jobItem.AdditionalFiles.filter(function(f) { - return "Subtitles" === f.Type - }), - mediaSource = jobItem.Item.MediaSources[0], - p = Promise.resolve(); - return files.forEach(function(file) { - p = p.then(function() { - return getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) - }) - }), p.then(function() { - return console.log("[mediasync] Exit getSubtitles"), Promise.resolve() - }) - } - - function getItemSubtitle(file, apiClient, jobItem, localItem, mediaSource) { - console.log("[mediasync] Begin getItemSubtitle"); - var subtitleStream = mediaSource.MediaStreams.filter(function(m) { - return "Subtitle" === m.Type && m.Index === file.Index - })[0]; - if (!subtitleStream) return console.log("[mediasync] Cannot download subtitles because matching stream info was not found."), Promise.resolve(); - var url = apiClient.getUrl("Sync/JobItems/" + jobItem.SyncJobItemId + "/AdditionalFiles", { - Name: file.Name, - api_key: apiClient.accessToken() - }), - fileName = localassetmanager.getSubtitleSaveFileName(localItem, jobItem.OriginalFileName, subtitleStream.Language, subtitleStream.IsForced, subtitleStream.Codec); - return localassetmanager.downloadSubtitles(url, fileName).then(function(subtitleResult) { - return localItem.AdditionalFiles && localItem.AdditionalFiles.forEach(function(item) { - item.Name === file.Name && (item.Path = subtitleResult.path) - }), subtitleStream.Path = subtitleResult.path, subtitleStream.DeliveryMethod = "External", localassetmanager.addOrUpdateLocalItem(localItem) - }) - } - - function checkLocalFileExistence(apiClient, serverInfo, options) { - return options.checkFileExistence ? (console.log("[mediasync] Begin checkLocalFileExistence"), localassetmanager.getServerItems(serverInfo.Id).then(function(items) { - var completedItems = items.filter(function(item) { - return item && ("synced" === item.SyncStatus || "error" === item.SyncStatus) - }), - p = Promise.resolve(); - return completedItems.forEach(function(completedItem) { - p = p.then(function() { - return localassetmanager.fileExists(completedItem.LocalPath).then(function(exists) { - return exists ? Promise.resolve() : localassetmanager.removeLocalItem(completedItem).then(function() { - return Promise.resolve() - }, function() { - return Promise.resolve() - }) - }) - }) - }), p - })) : Promise.resolve() - } - return function() { - var self = this; - "string" == typeof webWorkerBaseUrl && -1 !== webWorkerBaseUrl.indexOf("ms-appx://") ? self.sync = function(apiClient, serverInfo, options) { - return console.log("[mediasync]************************************* Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() { - return processDownloadStatus(apiClient, serverInfo, options).then(function() { - return localassetmanager.getDownloadItemCount().then(function(downloadCount) { - return !0 === options.syncCheckProgressOnly && downloadCount > 2 ? Promise.resolve() : reportOfflineActions(apiClient, serverInfo).then(function() { - return getNewMedia(apiClient, downloadCount).then(function() { - return syncData(apiClient, serverInfo).then(function() { - return console.log("[mediasync]************************************* Exit sync"), Promise.resolve() - }) - }) - }) - }) - }) - }, function(err) { - console.error(err.toString()) - }) - } : self.sync = function(apiClient, serverInfo, options) { - return console.log("[mediasync]************************************* Start sync"), checkLocalFileExistence(apiClient, serverInfo, options).then(function() { - return syncData(apiClient, serverInfo).then(function() { - return processDownloadStatus(apiClient, serverInfo, options).then(function() { - return localassetmanager.getDownloadItemCount().then(function(downloadCount) { - return !0 === options.syncCheckProgressOnly && downloadCount > 2 ? Promise.resolve() : reportOfflineActions(apiClient, serverInfo).then(function() { - return getNewMedia(apiClient, downloadCount).then(function() { - return syncData(apiClient, serverInfo) - }) - }) - }) - }) - }) - }, function(err) { - console.error(err.toString()) - }) - } - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/multiserversync.js b/src/libraries/apiclient/sync/multiserversync.js deleted file mode 100644 index 0654b5615d..0000000000 --- a/src/libraries/apiclient/sync/multiserversync.js +++ /dev/null @@ -1,22 +0,0 @@ -define(["serversync"], function(ServerSync) { - "use strict"; - - function syncNext(connectionManager, servers, index, options, resolve, reject) { - var length = servers.length; - if (index >= length) return console.log("MultiServerSync.sync complete"), void resolve(); - var server = servers[index]; - console.log("Creating ServerSync to server: " + server.Id), (new ServerSync).sync(connectionManager, server, options).then(function() { - console.log("ServerSync succeeded to server: " + server.Id), syncNext(connectionManager, servers, index + 1, options, resolve, reject) - }, function(err) { - console.log("ServerSync failed to server: " + server.Id + ". " + err), syncNext(connectionManager, servers, index + 1, options, resolve, reject) - }) - } - - function MultiServerSync() {} - return MultiServerSync.prototype.sync = function(connectionManager, options) { - return console.log("MultiServerSync.sync starting..."), new Promise(function(resolve, reject) { - var servers = connectionManager.getSavedServers(); - syncNext(connectionManager, servers, 0, options, resolve, reject) - }) - }, MultiServerSync -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/serversync.js b/src/libraries/apiclient/sync/serversync.js deleted file mode 100644 index 34a1b11e8e..0000000000 --- a/src/libraries/apiclient/sync/serversync.js +++ /dev/null @@ -1,42 +0,0 @@ -define([], function() { - "use strict"; - - function performSync(connectionManager, server, options) { - console.log("ServerSync.performSync to server: " + server.Id), options = options || {}; - var cameraUploadServers = options.cameraUploadServers || []; - console.log("ServerSync cameraUploadServers: " + JSON.stringify(cameraUploadServers)); - var uploadPhotos = -1 !== cameraUploadServers.indexOf(server.Id); - return console.log("ServerSync uploadPhotos: " + uploadPhotos), (uploadPhotos ? uploadContent(connectionManager, server, options) : Promise.resolve()).then(function() { - return syncMedia(connectionManager, server, options) - }) - } - - function uploadContent(connectionManager, server, options) { - return new Promise().reject(); - } - - function syncMedia(connectionManager, server, options) { - return new Promise(function(resolve, reject) { - require(["mediasync"], function(MediaSync) { - var apiClient = connectionManager.getApiClient(server.Id); - (new MediaSync).sync(apiClient, server, options).then(resolve, reject) - }) - }) - } - - function ServerSync() {} - return ServerSync.prototype.sync = function(connectionManager, server, options) { - if (!server.AccessToken && !server.ExchangeToken) return console.log("Skipping sync to server " + server.Id + " because there is no saved authentication information."), Promise.resolve(); - var connectionOptions = { - updateDateLastAccessed: !1, - enableWebSocket: !1, - reportCapabilities: !1, - enableAutomaticBitrateDetection: !1 - }; - return connectionManager.connectToServer(server, connectionOptions).then(function(result) { - return "SignedIn" === result.State ? performSync(connectionManager, server, options) : (console.log("Unable to connect to server id: " + server.Id), Promise.reject()) - }, function(err) { - throw console.log("Unable to connect to server id: " + server.Id), err - }) - }, ServerSync -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/transfermanager.js b/src/libraries/apiclient/sync/transfermanager.js deleted file mode 100644 index 162a6a1226..0000000000 --- a/src/libraries/apiclient/sync/transfermanager.js +++ /dev/null @@ -1,30 +0,0 @@ -define([], function() { - "use strict"; - - function downloadFile(url, folder, localItem, imageUrl) { - return Promise.reject() - } - - function downloadSubtitles(url, folder, fileName) { - return Promise.reject() - } - - function downloadImage(url, folder, fileName) { - return Promise.reject() - } - - function resyncTransfers() { - return Promise.resolve() - } - - function getDownloadItemCount() { - return Promise.resolve(0) - } - return { - downloadFile: downloadFile, - downloadSubtitles: downloadSubtitles, - downloadImage: downloadImage, - resyncTransfers: resyncTransfers, - getDownloadItemCount: getDownloadItemCount - } -}); \ No newline at end of file diff --git a/src/libraries/apiclient/sync/useractionrepository.js b/src/libraries/apiclient/sync/useractionrepository.js deleted file mode 100644 index 8612b05bea..0000000000 --- a/src/libraries/apiclient/sync/useractionrepository.js +++ /dev/null @@ -1,108 +0,0 @@ -define([], function() { - "use strict"; - - function getDb(callback) { - var db = databaseInstance; - if (db) return void callback(db); - var request = indexedDB.open(dbName, dbVersion); - request.onerror = function(event) {}, request.onupgradeneeded = function(event) { - var db = event.target.result; - db.createObjectStore(dbName).transaction.oncomplete = function(event) { - callback(db) - } - }, request.onsuccess = function(event) { - var db = event.target.result; - callback(db) - } - } - - function getByServerId(serverId) { - return getAll().then(function(items) { - return items.filter(function(item) { - return item.ServerId === serverId - }) - }) - } - - function getAll() { - return new Promise(function(resolve, reject) { - getDb(function(db) { - var request, storeName = dbName, - transaction = db.transaction([storeName], "readonly"), - objectStore = transaction.objectStore(storeName); - if ("getAll" in objectStore) request = objectStore.getAll(null, 1e4), request.onsuccess = function(event) { - resolve(event.target.result) - }; - else { - var results = []; - request = objectStore.openCursor(), request.onsuccess = function(event) { - var cursor = event.target.result; - cursor ? (results.push(cursor.value), cursor.continue()) : resolve(results) - } - } - request.onerror = reject - }) - }) - } - - function get(key) { - return new Promise(function(resolve, reject) { - getDb(function(db) { - var storeName = dbName, - transaction = db.transaction([storeName], "readonly"), - objectStore = transaction.objectStore(storeName), - request = objectStore.get(key); - request.onerror = reject, request.onsuccess = function(event) { - resolve(request.result) - } - }) - }) - } - - function set(key, val) { - return new Promise(function(resolve, reject) { - getDb(function(db) { - var storeName = dbName, - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.put(val, key); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - - function remove(key) { - return new Promise(function(resolve, reject) { - getDb(function(db) { - var storeName = dbName, - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.delete(key); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - - function clear() { - return new Promise(function(resolve, reject) { - getDb(function(db) { - var storeName = dbName, - transaction = db.transaction([storeName], "readwrite"), - objectStore = transaction.objectStore(storeName), - request = objectStore.clear(); - request.onerror = reject, request.onsuccess = resolve - }) - }) - } - var databaseInstance, indexedDB = self.indexedDB || self.mozIndexedDB || self.webkitIndexedDB || self.msIndexedDB, - dbName = (self.IDBTransaction || self.webkitIDBTransaction || self.msIDBTransaction, self.IDBKeyRange || self.webkitIDBKeyRange || self.msIDBKeyRange, "useractions"), - dbVersion = 1; - return { - get: get, - set: set, - remove: remove, - clear: clear, - getAll: getAll, - getByServerId: getByServerId - } -}); \ No newline at end of file diff --git a/src/libraries/navdrawer/navdrawer.css b/src/libraries/navdrawer/navdrawer.css new file mode 100644 index 0000000000..6d5d098de2 --- /dev/null +++ b/src/libraries/navdrawer/navdrawer.css @@ -0,0 +1,52 @@ +.tmla-mask, +.touch-menu-la { + position: fixed; + top: 0; + bottom: 0; + contain: strict; +} + +.touch-menu-la { + background-color: #fff; + will-change: transform; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-transition: -webkit-transform ease-out 40ms, left ease-out 260ms; + -o-transition: transform ease-out 40ms, left ease-out 260ms; + transition: transform ease-out 40ms, left ease-out 260ms; + z-index: 1099; +} + +.touch-menu-la.transition { + -webkit-transition: -webkit-transform ease-out 240ms, left ease-out 260ms; + -o-transition: transform ease-out 240ms, left ease-out 260ms; + transition: transform ease-out 240ms, left ease-out 260ms; +} + +.drawer-open { + -webkit-box-shadow: 2px 0 12px rgba(0, 0, 0, 0.4); + box-shadow: 2px 0 12px rgba(0, 0, 0, 0.4); +} + +.scrollContainer { + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; +} + +.tmla-mask { + left: 0; + right: 0; + opacity: 0; + z-index: 1098; + -webkit-transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s; + -o-transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s; + transition: opacity ease-in-out 0.38s, visibility ease-in-out 0.38s; + will-change: opacity; + background-color: rgba(0, 0, 0, 0.3); +} + +.tmla-mask.backdrop { + opacity: 1; +} diff --git a/src/libraries/navdrawer/navdrawer.js b/src/libraries/navdrawer/navdrawer.js new file mode 100644 index 0000000000..d9c246b406 --- /dev/null +++ b/src/libraries/navdrawer/navdrawer.js @@ -0,0 +1,352 @@ +define(["browser", "dom", "css!./navdrawer", "scrollStyles"], function (browser, dom) { + "use strict"; + + return function (options) { + function getTouches(e) { + return e.changedTouches || e.targetTouches || e.touches; + } + + function onMenuTouchStart(e) { + options.target.classList.remove("transition"); + var touches = getTouches(e); + var touch = touches[0] || {}; + menuTouchStartX = touch.clientX; + menuTouchStartY = touch.clientY; + menuTouchStartTime = new Date().getTime(); + } + + function setVelocity(deltaX) { + var time = new Date().getTime() - (menuTouchStartTime || 0); + velocity = Math.abs(deltaX) / time; + } + + function onMenuTouchMove(e) { + var isOpen = self.visible; + var touches = getTouches(e); + var touch = touches[0] || {}; + var endX = touch.clientX || 0; + var endY = touch.clientY || 0; + var deltaX = endX - (menuTouchStartX || 0); + var deltaY = endY - (menuTouchStartY || 0); + setVelocity(deltaX); + + if (isOpen && 1 !== dragMode && deltaX > 0) { + dragMode = 2; + } + + if (0 === dragMode && (!isOpen || Math.abs(deltaX) >= 10) && Math.abs(deltaY) < 5) { + dragMode = 1; + scrollContainer.addEventListener("scroll", disableEvent); + self.showMask(); + } else if (0 === dragMode && Math.abs(deltaY) >= 5) { + dragMode = 2; + } + + if (1 === dragMode) { + newPos = currentPos + deltaX; + self.changeMenuPos(); + } + } + + function onMenuTouchEnd(e) { + options.target.classList.add("transition"); + scrollContainer.removeEventListener("scroll", disableEvent); + dragMode = 0; + var touches = getTouches(e); + var touch = touches[0] || {}; + var endX = touch.clientX || 0; + var endY = touch.clientY || 0; + var deltaX = endX - (menuTouchStartX || 0); + var deltaY = endY - (menuTouchStartY || 0); + currentPos = deltaX; + self.checkMenuState(deltaX, deltaY); + } + + function onEdgeTouchStart(e) { + if (isPeeking) { + onMenuTouchMove(e); + } else { + if (((getTouches(e)[0] || {}).clientX || 0) <= options.handleSize) { + isPeeking = true; + + if (e.type === "touchstart") { + dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); + dom.addEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); + } + + onMenuTouchStart(e); + } + } + } + + function onEdgeTouchMove(e) { + e.preventDefault(); + e.stopPropagation(); + onEdgeTouchStart(e); + } + + function onEdgeTouchEnd(e) { + if (isPeeking) { + isPeeking = false; + dom.removeEventListener(edgeContainer, "touchmove", onEdgeTouchMove, {}); + onMenuTouchEnd(e); + } + } + + function disableEvent(e) { + e.preventDefault(); + e.stopPropagation(); + } + + function onBackgroundTouchStart(e) { + var touches = getTouches(e); + var touch = touches[0] || {}; + backgroundTouchStartX = touch.clientX; + backgroundTouchStartTime = new Date().getTime(); + } + + function onBackgroundTouchMove(e) { + var touches = getTouches(e); + var touch = touches[0] || {}; + var endX = touch.clientX || 0; + + if (endX <= options.width && self.isVisible) { + countStart++; + var deltaX = endX - (backgroundTouchStartX || 0); + + if (countStart == 1) { + startPoint = deltaX; + } + if (deltaX < 0 && dragMode !== 2) { + dragMode = 1; + newPos = deltaX - startPoint + options.width; + self.changeMenuPos(); + var time = new Date().getTime() - (backgroundTouchStartTime || 0); + velocity = Math.abs(deltaX) / time; + } + } + + e.preventDefault(); + e.stopPropagation(); + } + + function onBackgroundTouchEnd(e) { + var touches = getTouches(e); + var touch = touches[0] || {}; + var endX = touch.clientX || 0; + var deltaX = endX - (backgroundTouchStartX || 0); + self.checkMenuState(deltaX); + countStart = 0; + } + + function onMaskTransitionEnd() { + var classList = mask.classList; + + if (!classList.contains("backdrop")) { + classList.add("hide"); + } + } + + var self; + var defaults; + var mask; + var newPos = 0; + var currentPos = 0; + var startPoint = 0; + var countStart = 0; + var velocity = 0; + options.target.classList.add("transition"); + var dragMode = 0; + var scrollContainer = options.target.querySelector(".mainDrawer-scrollContainer"); + scrollContainer.classList.add("scrollY"); + + var TouchMenuLA = function () { + self = this; + defaults = { + width: 260, + handleSize: 10, + disableMask: false, + maxMaskOpacity: 0.5 + }; + this.isVisible = false; + this.initialize(); + }; + + TouchMenuLA.prototype.initElements = function () { + options.target.classList.add("touch-menu-la"); + options.target.style.width = options.width + "px"; + options.target.style.left = -options.width + "px"; + + if (!options.disableMask) { + mask = document.createElement("div"); + mask.className = "tmla-mask hide"; + document.body.appendChild(mask); + dom.addEventListener(mask, dom.whichTransitionEvent(), onMaskTransitionEnd, { + passive: true + }); + } + }; + + var menuTouchStartX; + var menuTouchStartY; + var menuTouchStartTime; + var edgeContainer = document.querySelector(".mainDrawerHandle"); + var isPeeking = false; + + TouchMenuLA.prototype.animateToPosition = function (pos) { + requestAnimationFrame(function () { + options.target.style.transform = pos ? "translateX(" + pos + "px)" : "none"; + }); + }; + + TouchMenuLA.prototype.changeMenuPos = function () { + if (newPos <= options.width) { + this.animateToPosition(newPos); + } + }; + + TouchMenuLA.prototype.clickMaskClose = function () { + mask.addEventListener("click", function () { + self.close(); + }); + }; + + TouchMenuLA.prototype.checkMenuState = function (deltaX, deltaY) { + if (velocity >= 0.4) { + if (deltaX >= 0 || Math.abs(deltaY || 0) >= 70) { + self.open(); + } else { + self.close(); + } + } else { + if (newPos >= 100) { + self.open(); + } else { + if (newPos) { + self.close(); + } + } + } + }; + + TouchMenuLA.prototype.open = function () { + this.animateToPosition(options.width); + currentPos = options.width; + this.isVisible = true; + options.target.classList.add("drawer-open"); + self.showMask(); + self.invoke(options.onChange); + }; + + TouchMenuLA.prototype.close = function () { + this.animateToPosition(0); + currentPos = 0; + self.isVisible = false; + options.target.classList.remove("drawer-open"); + self.hideMask(); + self.invoke(options.onChange); + }; + + TouchMenuLA.prototype.toggle = function () { + if (self.isVisible) { + self.close(); + } else { + self.open(); + } + }; + + var backgroundTouchStartX; + var backgroundTouchStartTime; + + TouchMenuLA.prototype.showMask = function () { + mask.classList.remove("hide"); + mask.classList.add("backdrop"); + }; + + TouchMenuLA.prototype.hideMask = function () { + mask.classList.add("hide"); + mask.classList.remove("backdrop"); + }; + + TouchMenuLA.prototype.invoke = function (fn) { + if (fn) { + fn.apply(self); + } + }; + + var _edgeSwipeEnabled; + + TouchMenuLA.prototype.setEdgeSwipeEnabled = function (enabled) { + if (!options.disableEdgeSwipe) { + if (browser.touch) { + if (enabled) { + if (!_edgeSwipeEnabled) { + _edgeSwipeEnabled = true; + dom.addEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { + passive: true + }); + dom.addEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { + passive: true + }); + dom.addEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { + passive: true + }); + } + } else { + if (_edgeSwipeEnabled) { + _edgeSwipeEnabled = false; + dom.removeEventListener(edgeContainer, "touchstart", onEdgeTouchStart, { + passive: true + }); + dom.removeEventListener(edgeContainer, "touchend", onEdgeTouchEnd, { + passive: true + }); + dom.removeEventListener(edgeContainer, "touchcancel", onEdgeTouchEnd, { + passive: true + }); + } + } + } + } + }; + + TouchMenuLA.prototype.initialize = function () { + options = Object.assign(defaults, options || {}); + + if (browser.edge) { + options.disableEdgeSwipe = true; + } + + self.initElements(); + + if (browser.touch) { + dom.addEventListener(options.target, "touchstart", onMenuTouchStart, { + passive: true + }); + dom.addEventListener(options.target, "touchmove", onMenuTouchMove, { + passive: true + }); + dom.addEventListener(options.target, "touchend", onMenuTouchEnd, { + passive: true + }); + dom.addEventListener(options.target, "touchcancel", onMenuTouchEnd, { + passive: true + }); + dom.addEventListener(mask, "touchstart", onBackgroundTouchStart, { + passive: true + }); + dom.addEventListener(mask, "touchmove", onBackgroundTouchMove, {}); + dom.addEventListener(mask, "touchend", onBackgroundTouchEnd, { + passive: true + }); + dom.addEventListener(mask, "touchcancel", onBackgroundTouchEnd, { + passive: true + }); + } + + self.clickMaskClose(); + }; + + return new TouchMenuLA(); + }; +}); diff --git a/src/libraries/pagejs/page.js b/src/libraries/pagejs/page.js deleted file mode 100644 index ce96fd185e..0000000000 --- a/src/libraries/pagejs/page.js +++ /dev/null @@ -1,1077 +0,0 @@ -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); - } - - // 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); - } - } - - /** - * Callback functions. - */ - - 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; - }; - - /** - * 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 - */ - - 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; - } - - 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); - } - } - page.len--; - } else if (path) { - setTimeout(function () { - page.show(path, state); - }); - } else { - setTimeout(function () { - page.show(base, state); - }); - } - }; - - page.enableNativeHistory = function () { - return enableHistory; - }; - - page.canGoBack = function () { - if (enableHistory) { - return history.length > 1; - } - 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); - 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); - } - - function nextEnter() { - var fn = page.callbacks[i++]; - - if (ctx.path !== page.current) { - ctx.handled = false; - return; - } - if (!fn) { - return unhandled(ctx); - } - fn(ctx, nextEnter); - } - - 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 = []; - - /** - * 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 - }); - } - }; - - /** - * 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(); - }; - }; - - /** - * 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('?'), - pathname = ~qsIndex ? path.slice(0, qsIndex) : path, - m = this.regexp.exec(decodeURIComponent(pathname)); - - if (!m) { - return false; - } - - 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); - } - }; - })(); - /** - * 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/libraries/query-string/index.js b/src/libraries/query-string/index.js deleted file mode 100644 index 515b745bf3..0000000000 --- a/src/libraries/query-string/index.js +++ /dev/null @@ -1,18 +0,0 @@ -"use strict"; -window.queryString = {}, window.queryString.extract = function(maybeUrl) { - return maybeUrl.split("?")[1] || "" -}, window.queryString.parse = function(str) { - return "string" != typeof str ? {} : (str = str.trim().replace(/^(\?|#|&)/, ""), str ? str.split("&").reduce(function(ret, param) { - var parts = param.replace(/\+/g, " ").split("="), - key = parts[0], - val = parts[1]; - return key = decodeURIComponent(key), val = void 0 === val ? null : decodeURIComponent(val), ret.hasOwnProperty(key) ? Array.isArray(ret[key]) ? ret[key].push(val) : ret[key] = [ret[key], val] : ret[key] = val, ret - }, {}) : {}) -}, window.queryString.stringify = function(obj) { - return obj ? Object.keys(obj).sort().map(function(key) { - var val = obj[key]; - return Array.isArray(val) ? val.sort().map(function(val2) { - return encodeURIComponent(key) + "=" + encodeURIComponent(val2) - }).join("&") : encodeURIComponent(key) + "=" + encodeURIComponent(val) - }).join("&") : "" -}; \ No newline at end of file diff --git a/src/libraries/query-string/test.js b/src/libraries/query-string/test.js deleted file mode 100644 index 4e16ad17c1..0000000000 --- a/src/libraries/query-string/test.js +++ /dev/null @@ -1,83 +0,0 @@ -"use strict"; -var assert = require("assert"), - qs = require("./"); -describe(".parse()", function() { - it("query strings starting with a `?`", function() { - assert.deepEqual(qs.parse("?foo=bar"), { - foo: "bar" - }) - }), it("query strings starting with a `#`", function() { - assert.deepEqual(qs.parse("#foo=bar"), { - foo: "bar" - }) - }), it("query strings starting with a `&", function() { - assert.deepEqual(qs.parse("&foo=bar&foo=baz"), { - foo: ["bar", "baz"] - }) - }), it("parse a query string", function() { - assert.deepEqual(qs.parse("foo=bar"), { - foo: "bar" - }) - }), it("parse multiple query string", function() { - assert.deepEqual(qs.parse("foo=bar&key=val"), { - foo: "bar", - key: "val" - }) - }), it("parse query string without a value", function() { - assert.deepEqual(qs.parse("foo"), { - foo: null - }), assert.deepEqual(qs.parse("foo&key"), { - foo: null, - key: null - }), assert.deepEqual(qs.parse("foo=bar&key"), { - foo: "bar", - key: null - }) - }), it("return empty object if no qss can be found", function() { - assert.deepEqual(qs.parse("?"), {}), assert.deepEqual(qs.parse("&"), {}), assert.deepEqual(qs.parse("#"), {}), assert.deepEqual(qs.parse(" "), {}) - }), it("handle `+` correctly", function() { - assert.deepEqual(qs.parse("foo+faz=bar+baz++"), { - "foo faz": "bar baz " - }) - }), it("handle multiple of the same key", function() { - assert.deepEqual(qs.parse("foo=bar&foo=baz"), { - foo: ["bar", "baz"] - }) - }), it("query strings params including embedded `=`", function() { - assert.deepEqual(qs.parse("?param=http%3A%2F%2Fsomeurl%3Fid%3D2837"), { - param: "http://someurl?id=2837" - }) - }) -}), describe(".stringify()", function() { - it("stringify", function() { - assert.strictEqual(qs.stringify({ - foo: "bar" - }), "foo=bar"), assert.strictEqual(qs.stringify({ - foo: "bar", - bar: "baz" - }), "bar=baz&foo=bar") - }), it("different types", function() { - assert.strictEqual(qs.stringify(), ""), assert.strictEqual(qs.stringify(0), "") - }), it("URI encode", function() { - assert.strictEqual(qs.stringify({ - "foo bar": "baz faz" - }), "foo%20bar=baz%20faz") - }), it("handle array value", function() { - assert.strictEqual(qs.stringify({ - abc: "abc", - foo: ["bar", "baz"] - }), "abc=abc&foo=bar&foo=baz") - }) -}), describe(".extract()", function() { - it("should extract qs from url", function() { - assert.equal(qs.extract("http://foo.bar/?abc=def&hij=klm"), "abc=def&hij=klm"), assert.equal(qs.extract("http://foo.bar/?"), "") - }), it("should handle strings not containing qs", function() { - assert.equal(qs.extract("http://foo.bar/"), ""), assert.equal(qs.extract(""), "") - }), it("should throw for invalid values", function() { - assert.throws(function() { - qs.extract(null) - }, TypeError), assert.throws(function() { - qs.extract(void 0) - }, TypeError) - }) -}); \ No newline at end of file diff --git a/src/components/screensavermanager.js b/src/libraries/screensavermanager.js similarity index 96% rename from src/components/screensavermanager.js rename to src/libraries/screensavermanager.js index 5b7613c98d..b9d7082850 100644 --- a/src/components/screensavermanager.js +++ b/src/libraries/screensavermanager.js @@ -53,7 +53,7 @@ define(["events", "playbackManager", "pluginManager", "inputManager", "connectio throw new Error("An existing screensaver is already active."); } - console.log("Showing screensaver " + screensaver.name); + console.debug("Showing screensaver " + screensaver.name); screensaver.show(); activeScreenSaver = screensaver; @@ -71,7 +71,7 @@ define(["events", "playbackManager", "pluginManager", "inputManager", "connectio function hide() { if (activeScreenSaver) { - console.log("Hiding screensaver"); + console.debug("Hiding screensaver"); activeScreenSaver.hide(); activeScreenSaver = null; } diff --git a/src/components/scroller.js b/src/libraries/scroller.js similarity index 99% rename from src/components/scroller.js rename to src/libraries/scroller.js index 65f33b8e8d..8c67127eb3 100644 --- a/src/components/scroller.js +++ b/src/libraries/scroller.js @@ -392,7 +392,7 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc var currentStart = self._pos.cur; var currentEnd = currentStart + frameSize; - //console.log('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd); + console.debug('offset:' + offset + ' currentStart:' + currentStart + ' currentEnd:' + currentEnd); var isVisible = offset >= currentStart && (offset + size) <= currentEnd; return { @@ -574,8 +574,9 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc * @return {Int} */ function normalizeWheelDelta(event) { - // wheelDelta needed only for IE8- - scrolling.curDelta = ((o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta); + // JELLYFIN MOD: Only use deltaX for horizontal scroll and remove IE8 support + scrolling.curDelta = o.horizontal ? event.deltaX : event.deltaY; + // END JELLYFIN MOD if (transform) { scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100; @@ -928,4 +929,4 @@ define(['browser', 'layoutManager', 'dom', 'focusManager', 'ResizeObserver', 'sc }; return scrollerFactory; -}); \ No newline at end of file +}); diff --git a/src/library.html b/src/library.html index 7e313c1708..1bca607249 100644 --- a/src/library.html +++ b/src/library.html @@ -6,10 +6,10 @@ ${ButtonScanAllLibraries} - ${Help} + ${Help}
-
\ No newline at end of file +
diff --git a/src/list.html b/src/list.html index e31efa27e6..efac2d891e 100644 --- a/src/list.html +++ b/src/list.html @@ -7,45 +7,45 @@ ${HeaderPlayAll}
diff --git a/src/livetv.html b/src/livetv.html index 2ff8990e4a..fdf19bd915 100644 --- a/src/livetv.html +++ b/src/livetv.html @@ -7,7 +7,7 @@
@@ -16,7 +16,7 @@
@@ -25,7 +25,7 @@
@@ -34,7 +34,7 @@
@@ -43,7 +43,7 @@
@@ -52,7 +52,7 @@
@@ -63,7 +63,7 @@
- +
@@ -72,7 +72,7 @@
diff --git a/src/livetvguideprovider.html b/src/livetvguideprovider.html index 86bf3ea7d6..d0d52aac23 100644 --- a/src/livetvguideprovider.html +++ b/src/livetvguideprovider.html @@ -1,11 +1,7 @@
-
- -
- -
+
-
\ No newline at end of file +
diff --git a/src/livetvsettings.html b/src/livetvsettings.html index 044226a085..a3a43c792f 100644 --- a/src/livetvsettings.html +++ b/src/livetvsettings.html @@ -4,7 +4,7 @@

DVR

- ${Help} + ${Help}
@@ -34,7 +34,7 @@
- +
${LabelRecordingPathHelp}
@@ -43,7 +43,7 @@
- +
@@ -51,7 +51,7 @@
- +
@@ -84,7 +84,7 @@
- +
@@ -99,4 +99,4 @@
-
\ No newline at end of file +
diff --git a/src/livetvstatus.html b/src/livetvstatus.html index 3abd14de34..3aa27637d0 100644 --- a/src/livetvstatus.html +++ b/src/livetvstatus.html @@ -8,9 +8,9 @@ ${HeaderTunerDevices} - ${Help} + ${Help}
@@ -21,7 +21,7 @@

${HeaderGuideProviders}

diff --git a/src/livetvtuner.html b/src/livetvtuner.html index 53e8f4b01d..f45a3a1d04 100644 --- a/src/livetvtuner.html +++ b/src/livetvtuner.html @@ -5,7 +5,7 @@

${HeaderLiveTvTunerSetup}

- ${Help} + ${Help}
@@ -24,7 +24,7 @@
- + diff --git a/src/log.html b/src/log.html index dd98b0d333..5943f5dc08 100644 --- a/src/log.html +++ b/src/log.html @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/src/login.html b/src/login.html index 21c9d8a347..8e48901c11 100644 --- a/src/login.html +++ b/src/login.html @@ -8,7 +8,7 @@
- +
@@ -47,9 +47,9 @@ ${ButtonForgotPassword} - +

diff --git a/src/metadataimages.html b/src/metadataimages.html index 8250572011..8ad129256c 100644 --- a/src/metadataimages.html +++ b/src/metadataimages.html @@ -22,4 +22,4 @@ - \ No newline at end of file + diff --git a/src/metadatanfo.html b/src/metadatanfo.html index 7263952b42..4005c74f67 100644 --- a/src/metadatanfo.html +++ b/src/metadatanfo.html @@ -46,4 +46,4 @@ - \ No newline at end of file + diff --git a/src/movies.html b/src/movies.html index c211d9686a..a2221c510d 100644 --- a/src/movies.html +++ b/src/movies.html @@ -3,15 +3,15 @@
- - - + + +
-
+
-
+
@@ -46,14 +46,14 @@
- - + +
-
+
@@ -62,7 +62,7 @@
- +
@@ -74,9 +74,9 @@
- - - + + +
@@ -90,4 +90,4 @@
-
\ No newline at end of file +
diff --git a/src/music.html b/src/music.html index e86f179208..1e22ae9f3a 100644 --- a/src/music.html +++ b/src/music.html @@ -37,17 +37,17 @@
- - - - - + + + + +
-
+
-
+
@@ -56,14 +56,14 @@
- - + +
-
+
-
+
@@ -72,14 +72,14 @@
- - + +
-
+
-
+
@@ -92,8 +92,8 @@
- - + +
diff --git a/src/mypreferencesdisplay.html b/src/mypreferencesdisplay.html index 799681f061..bee49754af 100644 --- a/src/mypreferencesdisplay.html +++ b/src/mypreferencesdisplay.html @@ -1,4 +1,4 @@
-
\ No newline at end of file +
diff --git a/src/mypreferenceshome.html b/src/mypreferenceshome.html index f45a6478bf..79c5ccc4bd 100644 --- a/src/mypreferenceshome.html +++ b/src/mypreferenceshome.html @@ -1,4 +1,4 @@
-
\ No newline at end of file +
diff --git a/src/mypreferencesmenu.html b/src/mypreferencesmenu.html index 0638a49d9d..2c3ca0edd9 100644 --- a/src/mypreferencesmenu.html +++ b/src/mypreferencesmenu.html @@ -5,7 +5,7 @@

- person +
${ButtonProfile}
@@ -14,7 +14,7 @@
- tv +
${HeaderDisplay}
@@ -23,7 +23,7 @@
- home +
${HeaderHome}
@@ -32,7 +32,7 @@

${HeaderAdmin}

- dashboard +
${TabDashboard}
@@ -60,7 +69,7 @@
- mode_edit +
${Metadata}
@@ -69,9 +78,9 @@

${HeaderUser}

-
+
- wifi +
${HeaderSelectServer}
@@ -79,7 +88,7 @@
- exit_to_app +
${ButtonSignOut}
diff --git a/src/networking.html b/src/networking.html index 35468a94c9..cc824eaabb 100644 --- a/src/networking.html +++ b/src/networking.html @@ -5,7 +5,7 @@
@@ -61,7 +61,7 @@
- +
${LabelCustomCertificatePathHelp}
diff --git a/src/notificationsetting.html b/src/notificationsetting.html index 46c361910d..67b35981f1 100644 --- a/src/notificationsetting.html +++ b/src/notificationsetting.html @@ -8,7 +8,7 @@ @@ -65,4 +65,4 @@
-
\ No newline at end of file +
diff --git a/src/nowplaying.html b/src/nowplaying.html index 44b7e38163..5f235a562e 100644 --- a/src/nowplaying.html +++ b/src/nowplaying.html @@ -1,138 +1,149 @@ -
+
+ +
-

- -
- +
+

+
+
+
+
+
+
+ +
+
+
+ +
+
+
+ +
+ +
+ + + + -
- + - + - - - - - - - - - - - - -
-
-
/
-
+ + + +
+ + + + +
- -
- -
- -
-
-
-
-
-
- +
+
- -
-
-
-

${TabPlaylist}

- +
-
+
+
+
+
+
+
-
-
-
-
diff --git a/src/playbackconfiguration.html b/src/playbackconfiguration.html index 81a42231e4..9deeeebbcd 100644 --- a/src/playbackconfiguration.html +++ b/src/playbackconfiguration.html @@ -27,4 +27,4 @@
-
\ No newline at end of file +
diff --git a/src/robots.txt b/src/robots.txt index 77470cb39f..1f53798bb4 100644 --- a/src/robots.txt +++ b/src/robots.txt @@ -1,2 +1,2 @@ User-agent: * -Disallow: / \ No newline at end of file +Disallow: / diff --git a/src/scheduledtask.html b/src/scheduledtask.html index 8ecaf04dbe..f88f6a04c6 100644 --- a/src/scheduledtask.html +++ b/src/scheduledtask.html @@ -4,7 +4,7 @@ @@ -13,7 +13,7 @@

${HeaderTaskTriggers}

diff --git a/src/components/alphanumericshortcuts/alphanumericshortcuts.js b/src/scripts/alphanumericshortcuts.js similarity index 99% rename from src/components/alphanumericshortcuts/alphanumericshortcuts.js rename to src/scripts/alphanumericshortcuts.js index 03d0118cbe..2bcf3712bb 100644 --- a/src/components/alphanumericshortcuts/alphanumericshortcuts.js +++ b/src/scripts/alphanumericshortcuts.js @@ -10,7 +10,7 @@ define(['dom', 'focusManager'], function (dom, focusManager) { if (e.ctrlKey) { return; } - if (!!e.shiftKey) { + if (e.shiftKey) { return; } if (e.altKey) { @@ -127,4 +127,4 @@ define(['dom', 'focusManager'], function (dom, focusManager) { }; return AlphaNumericShortcuts; -}); \ No newline at end of file +}); diff --git a/src/scripts/apploader.js b/src/scripts/apploader.js index 4b5d2e8eec..0353c9535c 100644 --- a/src/scripts/apploader.js +++ b/src/scripts/apploader.js @@ -1,14 +1,14 @@ (function() { - "use strict"; + 'use strict'; function injectScriptElement(src, onload) { if (!src) { return; } - var script = document.createElement("script"); + var script = document.createElement('script'); if (self.dashboardVersion) { - src += "?v=" + self.dashboardVersion; + src += `?v=${self.dashboardVersion}`; } script.src = src; @@ -19,11 +19,33 @@ document.head.appendChild(script); } - injectScriptElement( - self.Promise ? "./libraries/alameda.js" : "./libraries/require.js", - function() { - // onload of require library - injectScriptElement("./scripts/site.js"); - } - ); + function loadSite() { + injectScriptElement( + './libraries/alameda.js', + function() { + // onload of require library + injectScriptElement('./scripts/site.js'); + } + ); + } + + try { + Promise.resolve(); + } catch (ex) { + // this checks for several cases actually, typical is + // Promise() being missing on some legacy browser, and a funky one + // is Promise() present but buggy on WebOS 2 + window.Promise = undefined; + self.Promise = undefined; + } + + if (!self.Promise) { + // Load Promise polyfill if they are not natively supported + injectScriptElement( + './libraries/npo.js', + loadSite + ); + } else { + loadSite(); + } })(); diff --git a/src/scripts/autobackdrops.js b/src/scripts/autobackdrops.js index 73042f83ce..abd86c9dbf 100644 --- a/src/scripts/autobackdrops.js +++ b/src/scripts/autobackdrops.js @@ -1,26 +1,28 @@ -define(["backdrop", "userSettings", "libraryMenu"], function (backdrop, userSettings, libraryMenu) { - "use strict"; +define(['backdrop', 'userSettings', 'libraryMenu'], function (backdrop, userSettings, libraryMenu) { + 'use strict'; + + var cache = {}; function enabled() { return userSettings.enableBackdrops(); } function getBackdropItemIds(apiClient, userId, types, parentId) { - var key = "backdrops2_" + userId + (types || "") + (parentId || ""); + var key = `backdrops2_${userId + (types || '') + (parentId || '')}`; var data = cache[key]; if (data) { - console.log("Found backdrop id list in cache. Key: " + key); + console.debug(`Found backdrop id list in cache. Key: ${key}`); data = JSON.parse(data); return Promise.resolve(data); } var options = { - SortBy: "IsFavoriteOrLiked,Random", + SortBy: 'IsFavoriteOrLiked,Random', Limit: 20, Recursive: true, IncludeItemTypes: types, - ImageTypes: "Backdrop", + ImageTypes: 'Backdrop', ParentId: parentId, EnableTotalRecordCount: false }; @@ -54,18 +56,17 @@ define(["backdrop", "userSettings", "libraryMenu"], function (backdrop, userSett } } - var cache = {}; - pageClassOn("pageshow", "page", function () { + pageClassOn('pageshow', 'page', function () { var page = this; - if (!page.classList.contains("selfBackdropPage")) { - if (page.classList.contains("backdropPage")) { + if (!page.classList.contains('selfBackdropPage')) { + if (page.classList.contains('backdropPage')) { if (enabled()) { - var type = page.getAttribute("data-backdroptype"); - var parentId = page.classList.contains("globalBackdropPage") ? "" : libraryMenu.getTopParentId(); + var type = page.getAttribute('data-backdroptype'); + var parentId = page.classList.contains('globalBackdropPage') ? '' : libraryMenu.getTopParentId(); showBackdrop(type, parentId); } else { - page.classList.remove("backdropPage"); + page.classList.remove('backdropPage'); backdrop.clear(); } } else { diff --git a/src/scripts/browser.js b/src/scripts/browser.js index 66c3051c8c..b1912862b3 100644 --- a/src/scripts/browser.js +++ b/src/scripts/browser.js @@ -22,7 +22,7 @@ define([], function () { return true; } - if (userAgent.indexOf('webos') !== -1) { + if (userAgent.indexOf('web0s') !== -1) { return true; } @@ -53,45 +53,6 @@ define([], function () { 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) { @@ -185,7 +146,7 @@ define([], function () { /(safari)[ \/]([\w.]+)/.exec(ua) || /(firefox)[ \/]([\w.]+)/.exec(ua) || /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; var versionMatch = /(version)[ \/]([\w.]+)/.exec(ua); @@ -196,17 +157,17 @@ define([], function () { /(android)/.exec(ua) || []; - var browser = match[1] || ""; + var browser = match[1] || ''; - if (browser === "edge") { - platform_match = [""]; + if (browser === 'edge') { + platform_match = ['']; } else { - if (ua.indexOf("windows phone") !== -1 || ua.indexOf("iemobile") !== -1) { + 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"; + 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'; } } @@ -219,7 +180,7 @@ define([], function () { version = versionMatch[2]; } - version = version || match[2] || "0"; + version = version || match[2] || '0'; var versionMajor = parseInt(version.split('.')[0]); @@ -230,7 +191,7 @@ define([], function () { return { browser: browser, version: version, - platform: platform_match[0] || "", + platform: platform_match[0] || '', versionMajor: versionMajor }; }; @@ -250,11 +211,11 @@ define([], function () { browser[matched.platform] = true; } - if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf("webkit") !== -1) { + if (!browser.chrome && !browser.msie && !browser.edge && !browser.opera && userAgent.toLowerCase().indexOf('webkit') !== -1) { browser.safari = true; } - if (userAgent.toLowerCase().indexOf("playstation 4") !== -1) { + if (userAgent.toLowerCase().indexOf('playstation 4') !== -1) { browser.ps4 = true; browser.tv = true; } @@ -271,6 +232,9 @@ define([], function () { if (!browser.tizen) { browser.orsay = userAgent.toLowerCase().indexOf('smarthub') !== -1; + } else { + var v = (navigator.appVersion).match(/Tizen (\d+).(\d+)/); + browser.tizenVersion = parseInt(v[1]); } if (browser.edgeUwp) { @@ -280,16 +244,13 @@ define([], function () { 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) { + /* eslint-disable-next-line compat/compat */ + if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0)) { browser.touch = true; } } @@ -311,4 +272,4 @@ define([], function () { browser.chromecast = browser.chrome && userAgent.toLowerCase().indexOf('crkey') !== -1; return browser; -}); \ No newline at end of file +}); diff --git a/src/scripts/browserdeviceprofile.js b/src/scripts/browserdeviceprofile.js index bc7c26769e..2668f20913 100644 --- a/src/scripts/browserdeviceprofile.js +++ b/src/scripts/browserdeviceprofile.js @@ -6,32 +6,31 @@ define(['browser'], function (browser) { } function canPlayH265(videoTestElement, options) { - if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) { return true; } 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; + if (browser.ps4) { + return false; } - return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/hevc; codecs="hevc, aac"').replace(/no/, '')); + return !!videoTestElement.canPlayType && + (videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.0.L120"').replace(/no/, '') || + videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, '')); } var _supportsTextTracks; function supportsTextTracks() { - if (browser.tizen || browser.orsay) { return true; } @@ -45,16 +44,15 @@ define(['browser'], function (browser) { } var _canPlayHls; - function canPlayHls(src) { - + function canPlayHls() { if (_canPlayHls == null) { _canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE(); } + return _canPlayHls; } function canPlayNativeHls() { - if (browser.tizen || browser.orsay) { return true; } @@ -69,42 +67,66 @@ define(['browser'], function (browser) { } function canPlayHlsWithMSE() { - if (window.MediaSource != null) { - // text tracks don’t work with this in firefox + // text tracks don’t work with this in firefox + return window.MediaSource != null; + } + + function supportsAc3(videoTestElement) { + if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) { return true; } + return videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, ''); + } + + function supportsEac3(videoTestElement) { + if (browser.tizen || browser.orsay || browser.web0s) { + return true; + } + + return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, ''); + } + + function supportsAc3InHls(videoTestElement) { + if (browser.tizen || browser.orsay || browser.web0s) { + return true; + } + + if (videoTestElement.canPlayType) { + return videoTestElement.canPlayType('application/x-mpegurl; codecs="avc1.42E01E, ac-3"').replace(/no/, '') || + videoTestElement.canPlayType('application/vnd.apple.mpegURL; codecs="avc1.42E01E, ac-3"').replace(/no/, ''); + } + return false; } function canPlayAudioFormat(format) { - var typeString; if (format === 'flac') { - if (browser.tizen || browser.orsay || browser.web0s) { - return true; - } - if (browser.edgeUwp) { + if (browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp) { return true; } } else if (format === 'wma') { - if (browser.tizen || browser.orsay) { + if (browser.tizen || browser.orsay || browser.edgeUwp) { return true; } - if (browser.edgeUwp) { + } else if (format === 'asf') { + if (browser.tizen || browser.web0s || browser.edgeUwp) { return true; } } else if (format === 'opus') { - typeString = 'audio/ogg; codecs="opus"'; - - if (document.createElement('audio').canPlayType(typeString).replace(/no/, '')) { - return true; + if (!browser.web0s) { + typeString = 'audio/ogg; codecs="opus"'; + return !!document.createElement('audio').canPlayType(typeString).replace(/no/, ''); } return false; + } else if (format === 'alac') { + if (browser.iOS || browser.osx) { + return true; + } } else if (format === 'mp2') { - // For now return false; } @@ -113,27 +135,14 @@ define(['browser'], function (browser) { 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; + return !!document.createElement('audio').canPlayType(typeString).replace(/no/, ''); } function testCanPlayMkv(videoTestElement) { - if (browser.tizen || browser.orsay || browser.web0s) { return true; } @@ -143,16 +152,15 @@ define(['browser'], function (browser) { return true; } - var userAgent = navigator.userAgent.toLowerCase(); - // Unfortunately there's no real way to detect mkv support if (browser.chrome) { - // Not supported on opera tv if (browser.operaTv) { return false; } + var userAgent = navigator.userAgent.toLowerCase(); + // Filter out browsers based on chromium that don't support mkv if (userAgent.indexOf('vivaldi') !== -1 || userAgent.indexOf('opera') !== -1) { return false; @@ -162,7 +170,6 @@ define(['browser'], function (browser) { } if (browser.edgeUwp) { - return true; } @@ -174,17 +181,15 @@ define(['browser'], function (browser) { } function supportsMpeg2Video() { - return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s; + return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; } function supportsVc1() { - return browser.orsay || browser.tizen || browser.edgeUwp || browser.web0s; + return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; } function getFlvMseDirectPlayProfile() { - var videoAudioCodecs = ['aac']; - if (!browser.edge && !browser.msie) { videoAudioCodecs.push('mp3'); } @@ -198,23 +203,30 @@ define(['browser'], function (browser) { } function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) { - var supported = false; var profileContainer = container; var videoCodecs = []; switch (container) { - case 'asf': - supported = browser.tizen || browser.orsay || browser.edgeUwp; + supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; videoAudioCodecs = []; break; case 'avi': - supported = browser.tizen || browser.orsay || browser.edgeUwp; + supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; + // New Samsung TV don't support XviD/DivX + // Explicitly add supported codecs to make other codecs be transcoded + if (browser.tizenVersion >= 4) { + videoCodecs.push('h264'); + if (canPlayH265(videoTestElement, options)) { + videoCodecs.push('h265'); + videoCodecs.push('hevc'); + } + } break; case 'mpg': case 'mpeg': - supported = browser.edgeUwp || browser.tizen || browser.orsay; + supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp; break; case 'flv': supported = browser.tizen || browser.orsay; @@ -230,7 +242,7 @@ define(['browser'], function (browser) { supported = browser.tizen || browser.orsay; break; case 'mov': - supported = browser.tizen || browser.orsay || browser.chrome || browser.edgeUwp; + supported = browser.tizen || browser.orsay || browser.web0s || browser.chrome || browser.edgeUwp; videoCodecs.push('h264'); break; case 'm2ts': @@ -266,29 +278,21 @@ define(['browser'], function (browser) { break; } - if (!supported) { - return null; - } - - return { + return supported ? { Container: profileContainer, Type: 'Video', VideoCodec: videoCodecs.join(','), AudioCodec: videoAudioCodecs.join(',') - }; + } : null; } function getMaxBitrate() { - return 120000000; } function getGlobalMaxVideoBitrate() { - var userAgent = navigator.userAgent.toLowerCase(); - if (browser.chromecast) { - var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; if (isChromecastUltra) { return null; @@ -307,9 +311,9 @@ define(['browser'], function (browser) { try { var isTizenUhd = webapis.productinfo.isUdPanelSupported(); isTizenFhd = !isTizenUhd; - console.log("isTizenFhd = " + isTizenFhd); + console.debug('isTizenFhd = ' + isTizenFhd); } catch (error) { - console.log("isUdPanelSupported() error code = " + error.code); + console.error('isUdPanelSupported() error code = ' + error.code); } } @@ -319,27 +323,9 @@ define(['browser'], function (browser) { (browser.tizen && isTizenFhd ? 20000000 : null))); } - function supportsAc3(videoTestElement) { - - 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) { - - if (browser.tizen || browser.orsay || browser.web0s) { - return true; - } - - return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, ''); - } - return function (options) { - options = options || {}; + var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2); var bitrateSetting = getMaxBitrate(); @@ -348,6 +334,7 @@ define(['browser'], function (browser) { var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, ''); var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, ''); + var canPlayAv1 = videoTestElement.canPlayType('video/webm; codecs="av1"').replace(/no/, ''); var webmAudioCodecs = ['vorbis']; var canPlayMkv = testCanPlayMkv(videoTestElement); @@ -398,8 +385,7 @@ define(['browser'], function (browser) { // This works in edge desktop, but not mobile // TODO: Retest this on mobile - var supportsAc3InHls = (!browser.edge || !browser.touch || browser.edgeUwp); - if (supportsAc3InHls) { + if (supportsAc3InHls(videoTestElement)) { hlsVideoAudioCodecs.push('ac3'); if (eAc3) { hlsVideoAudioCodecs.push('eac3'); @@ -417,7 +403,6 @@ define(['browser'], function (browser) { // 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) { @@ -425,14 +410,15 @@ define(['browser'], function (browser) { } } } - if (canPlayAacVideoAudio) { + 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) { @@ -448,13 +434,9 @@ define(['browser'], function (browser) { var supportsDts = browser.tizen || browser.orsay || browser.web0s || options.supportsDts; - if (self.tizen && self.tizen.systeminfo) { - var v = tizen.systeminfo.getCapability('http://tizen.org/feature/platform.version'); - - // DTS audio not supported in 2018 models (Tizen 4.0) - if (v && parseFloat(v) >= parseFloat('4.0')) { - supportsDts = false; - } + // DTS audio not supported in 2018 models (Tizen 4.0) + if (browser.tizenVersion >= 4) { + supportsDts = false; } if (supportsDts) { @@ -500,6 +482,7 @@ define(['browser'], function (browser) { mp4VideoCodecs.push('h264'); hlsVideoCodecs.push('h264'); } + if (canPlayH265(videoTestElement, options)) { mp4VideoCodecs.push('h265'); mp4VideoCodecs.push('hevc'); @@ -525,6 +508,7 @@ define(['browser'], function (browser) { if (canPlayVp8) { mp4VideoCodecs.push('vp8'); } + if (canPlayVp9) { mp4VideoCodecs.push('vp9'); } @@ -563,20 +547,17 @@ define(['browser'], function (browser) { ['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, @@ -584,11 +565,10 @@ define(['browser'], function (browser) { }); } - // aac also appears in the m4a container + // aac also appears in the m4a and m4b container if (audioFormat === 'aac' || audioFormat === 'alac') { - profile.DirectPlayProfiles.push({ - Container: 'm4a', + Container: 'm4a,m4b', AudioCodec: audioFormat, Type: 'Audio' }); @@ -613,13 +593,21 @@ define(['browser'], function (browser) { }); } + if (canPlayAv1) { + profile.DirectPlayProfiles.push({ + Container: 'webm', + Type: 'Video', + AudioCodec: webmAudioCodecs.join(','), + VideoCodec: 'AV1' + }); + } + 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', @@ -636,7 +624,6 @@ define(['browser'], function (browser) { // 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', @@ -648,7 +635,6 @@ define(['browser'], function (browser) { }); ['opus', 'mp3', 'aac', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) { - profile.TranscodingProfiles.push({ Container: audioFormat, Type: 'Audio', @@ -683,7 +669,7 @@ define(['browser'], function (browser) { }); } - if (canPlayHls() && options.enableHls !== false) { + if (canPlayHls() && hlsVideoAudioCodecs.length && options.enableHls !== false) { profile.TranscodingProfiles.push({ Container: 'ts', Type: 'Video', @@ -778,11 +764,26 @@ define(['browser'], function (browser) { }); } - var maxH264Level = browser.chromecast ? 42 : 51; + var maxH264Level = 42; var h264Profiles = 'high|main|baseline|constrained baseline'; - if (maxH264Level >= 51 && browser.chrome && !browser.osx) { - h264Profiles += '|high 10'; + if (browser.tizen || browser.orsay || browser.web0s || + videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) { + maxH264Level = 51; + } + + // Support H264 Level 52 (Tizen 5.0) - app only + if (browser.tizenVersion >= 5 && window.NativeShell) { + maxH264Level = 52; + } + + if (browser.tizen || browser.orsay || + videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) { + + // These tests are passing in safari, but playback is failing + if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) { + h264Profiles += '|high 10'; + } } profile.CodecProfiles.push({ @@ -798,13 +799,16 @@ define(['browser'], function (browser) { { Condition: 'EqualsAny', Property: 'VideoProfile', - Value: h264Profiles + Value: h264Profiles, + IsRequired: false }, { Condition: 'LessThanEqual', Property: 'VideoLevel', - Value: maxH264Level.toString() - }] + Value: maxH264Level.toString(), + IsRequired: false + } + ] }); if (!browser.edgeUwp && !browser.tizen && !browser.orsay && !browser.web0s) { @@ -888,15 +892,23 @@ define(['browser'], function (browser) { // External vtt or burn in profile.SubtitleProfiles = []; if (supportsTextTracks()) { - profile.SubtitleProfiles.push({ Format: 'vtt', Method: 'External' }); } + if (options.enableSsaRender) { + profile.SubtitleProfiles.push({ + Format: 'ass', + Method: 'External' + }); + profile.SubtitleProfiles.push({ + Format: 'ssa', + Method: 'External' + }); + } profile.ResponseProfiles = []; - profile.ResponseProfiles.push({ Type: 'Video', Container: 'm4v', diff --git a/src/scripts/datetime.js b/src/scripts/datetime.js index a7ee1d946a..34ff23fe63 100644 --- a/src/scripts/datetime.js +++ b/src/scripts/datetime.js @@ -41,12 +41,12 @@ define(['globalize'], function (globalize) { } // if there's a timezone, calculate it - if (d[8] !== "Z" && d[10]) { + if (d[8] !== 'Z' && d[10]) { var offset = d[10] * 60 * 60 * 1000; if (d[11]) { offset += d[11] * 60 * 1000; } - if (d[9] === "-") { + if (d[9] === '-') { ms -= offset; } else { ms += offset; @@ -159,13 +159,13 @@ define(['globalize'], function (globalize) { var optionList = getOptionList(options); if (optionList.length === 1 && optionList[0].name === 'weekday') { var weekday = []; - weekday[0] = "Sun"; - weekday[1] = "Mon"; - weekday[2] = "Tue"; - weekday[3] = "Wed"; - weekday[4] = "Thu"; - weekday[5] = "Fri"; - weekday[6] = "Sat"; + 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()]; } @@ -279,4 +279,4 @@ define(['globalize'], function (globalize) { return toLocaleTimeStringSupportsLocales; } }; -}); \ No newline at end of file +}); diff --git a/src/scripts/dfnshelper.js b/src/scripts/dfnshelper.js new file mode 100644 index 0000000000..6ad2ee9709 --- /dev/null +++ b/src/scripts/dfnshelper.js @@ -0,0 +1,62 @@ +import { ar, be, bg, ca, cs, da, de, el, enGB, enUS, es, faIR, fi, fr, frCA, he, hi, hr, hu, id, it, ja, kk, ko, lt, ms, nb, + nl, pl, ptBR, pt, ro, ru, sk, sl, sv, tr, uk, vi, zhCN, zhTW } from 'date-fns/locale'; +import globalize from 'globalize'; + +const dateLocales = (locale) => ({ + 'ar': ar, + 'be-by': be, + 'bg-bg': bg, + 'ca': ca, + 'cs': cs, + 'da': da, + 'de': de, + 'el': el, + 'en-gb': enGB, + 'en-us': enUS, + 'es': es, + 'es-ar': es, + 'es-mx': es, + 'fa': faIR, + 'fi': fi, + 'fr': fr, + 'fr-ca': frCA, + 'gsw': de, + 'he': he, + 'hi-in': hi, + 'hr': hr, + 'hu': hu, + 'id': id, + 'it': it, + 'ja': ja, + 'kk': kk, + 'ko': ko, + 'lt-lt': lt, + 'ms': ms, + 'nb': nb, + 'nl': nl, + 'pl': pl, + 'pt-br': ptBR, + 'pt-pt': pt, + 'ro': ro, + 'ru': ru, + 'sk': sk, + 'sl-si': sl, + 'sv': sv, + 'tr': tr, + 'uk': uk, + 'vi': vi, + 'zh-cn': zhCN, + 'zh-hk': zhCN, + 'zh-tw': zhTW +})[locale]; + +export function getLocale() { + return dateLocales(globalize.getCurrentLocale()) || enUS; +} + +export const localeWithSuffix = { addSuffix: true, locale: getLocale() }; + +export default { + getLocale: getLocale, + localeWithSuffix: localeWithSuffix +}; diff --git a/src/scripts/dom.js b/src/scripts/dom.js new file mode 100644 index 0000000000..a3d157f337 --- /dev/null +++ b/src/scripts/dom.js @@ -0,0 +1,278 @@ +/* eslint-disable indent */ + +/** + * Useful DOM utilities. + * @module components/dom + */ + + /** + * Returns parent of element with specified attribute value. + * @param {HTMLElement} elem - Element whose parent need to find. + * @param {string} name - Attribute name. + * @param {mixed} value - Attribute value. + * @returns {HTMLElement} Parent with specified attribute value. + */ + export function parentWithAttribute(elem, name, value) { + while ((value ? elem.getAttribute(name) !== value : !elem.getAttribute(name))) { + elem = elem.parentNode; + + if (!elem || !elem.getAttribute) { + return null; + } + } + + return elem; + } + + /** + * Returns parent of element with one of specified tag names. + * @param {HTMLElement} elem - Element whose parent need to find. + * @param {(string|Array)} tagNames - Tag name or array of tag names. + * @returns {HTMLElement} Parent with one of specified tag names. + */ + export function parentWithTag(elem, tagNames) { + // accept both string and array passed in + if (!Array.isArray(tagNames)) { + tagNames = [tagNames]; + } + + while (tagNames.indexOf(elem.tagName || '') === -1) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; + } + + /** + * Returns _true_ if class list contains one of specified names. + * @param {DOMTokenList} classList - Class list. + * @param {Array} classNames - Array of class names. + * @returns {boolean} _true_ if class list contains one of specified names. + */ + function containsAnyClass(classList, classNames) { + for (let i = 0, length = classNames.length; i < length; i++) { + if (classList.contains(classNames[i])) { + return true; + } + } + return false; + } + + /** + * Returns parent of element with one of specified class names. + * @param {HTMLElement} elem - Element whose parent need to find. + * @param {(string|Array)} classNames - Class name or array of class names. + * @returns {HTMLElement} Parent with one of specified class names. + */ + export function parentWithClass(elem, classNames) { + // accept both string and array passed in + if (!Array.isArray(classNames)) { + classNames = [classNames]; + } + + while (!elem.classList || !containsAnyClass(elem.classList, classNames)) { + elem = elem.parentNode; + + if (!elem) { + return null; + } + } + + return elem; + } + + let supportsCaptureOption = false; + try { + const opts = Object.defineProperty({}, 'capture', { + // eslint-disable-next-line getter-return + get: function () { + supportsCaptureOption = true; + } + }); + window.addEventListener('test', null, opts); + } catch (e) { + console.debug('error checking capture support'); + } + + /** + * Adds event listener to specified target. + * @param {EventTarget} target - Event target. + * @param {string} type - Event type. + * @param {function} handler - Event handler. + * @param {Object} [options] - Listener options. + */ + export function addEventListener(target, type, handler, options) { + let optionsOrCapture = options || {}; + if (!supportsCaptureOption) { + optionsOrCapture = optionsOrCapture.capture; + } + target.addEventListener(type, handler, optionsOrCapture); + } + + /** + * Removes event listener from specified target. + * @param {EventTarget} target - Event target. + * @param {string} type - Event type. + * @param {function} handler - Event handler. + * @param {Object} [options] - Listener options. + */ + export function removeEventListener(target, type, handler, options) { + let optionsOrCapture = options || {}; + if (!supportsCaptureOption) { + optionsOrCapture = optionsOrCapture.capture; + } + target.removeEventListener(type, handler, optionsOrCapture); + } + + /** + * Cached window size. + */ + let windowSize; + + /** + * Flag of event listener bound. + */ + let windowSizeEventsBound; + + /** + * Resets cached window size. + */ + function clearWindowSize() { + windowSize = null; + } + + /** + * Returns window size. + * @returns {Object} Window size. + */ + export function getWindowSize() { + if (!windowSize) { + windowSize = { + innerHeight: window.innerHeight, + innerWidth: window.innerWidth + }; + + if (!windowSizeEventsBound) { + windowSizeEventsBound = true; + addEventListener(window, 'orientationchange', clearWindowSize, { passive: true }); + addEventListener(window, 'resize', clearWindowSize, { passive: true }); + } + } + + return windowSize; + } + + /** + * Standard screen widths. + */ + const standardWidths = [480, 720, 1280, 1440, 1920, 2560, 3840, 5120, 7680]; + + /** + * Returns screen width. + * @returns {number} Screen width. + */ + export function getScreenWidth() { + let width = window.innerWidth; + const height = window.innerHeight; + + if (height > width) { + width = height * (16.0 / 9.0); + } + + const closest = standardWidths.sort(function (a, b) { + return Math.abs(width - a) - Math.abs(width - b); + })[0]; + + return closest; + } + + /** + * Name of animation end event. + */ + let _animationEvent; + + /** + * Returns name of animation end event. + * @returns {string} Name of animation end event. + */ + export function whichAnimationEvent() { + if (_animationEvent) { + return _animationEvent; + } + + const el = document.createElement('div'); + const animations = { + 'animation': 'animationend', + 'OAnimation': 'oAnimationEnd', + 'MozAnimation': 'animationend', + 'WebkitAnimation': 'webkitAnimationEnd' + }; + for (let t in animations) { + if (el.style[t] !== undefined) { + _animationEvent = animations[t]; + return animations[t]; + } + } + + _animationEvent = 'animationend'; + return _animationEvent; + } + + /** + * Returns name of animation cancel event. + * @returns {string} Name of animation cancel event. + */ + export function whichAnimationCancelEvent() { + return whichAnimationEvent().replace('animationend', 'animationcancel').replace('AnimationEnd', 'AnimationCancel'); + } + + /** + * Name of transition end event. + */ + let _transitionEvent; + + /** + * Returns name of transition end event. + * @returns {string} Name of transition end event. + */ + export function whichTransitionEvent() { + if (_transitionEvent) { + return _transitionEvent; + } + + const el = document.createElement('div'); + const transitions = { + 'transition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'MozTransition': 'transitionend', + 'WebkitTransition': 'webkitTransitionEnd' + }; + for (let t in transitions) { + if (el.style[t] !== undefined) { + _transitionEvent = transitions[t]; + return transitions[t]; + } + } + + _transitionEvent = 'transitionend'; + return _transitionEvent; + } + +/* eslint-enable indent */ + +export default { + parentWithAttribute: parentWithAttribute, + parentWithClass: parentWithClass, + parentWithTag: parentWithTag, + addEventListener: addEventListener, + removeEventListener: removeEventListener, + getWindowSize: getWindowSize, + getScreenWidth: getScreenWidth, + whichTransitionEvent: whichTransitionEvent, + whichAnimationEvent: whichAnimationEvent, + whichAnimationCancelEvent: whichAnimationCancelEvent +}; diff --git a/src/scripts/editorsidebar.js b/src/scripts/editorsidebar.js index 1ec70cc7cd..ee7788407c 100644 --- a/src/scripts/editorsidebar.js +++ b/src/scripts/editorsidebar.js @@ -1,5 +1,5 @@ -define(["datetime", "jQuery", "material-icons"], function (datetime, $) { - "use strict"; +define(['datetime', 'jQuery', 'globalize', 'material-icons'], function (datetime, $, globalize) { + 'use strict'; function getNode(item, folderState, selected) { var htmlName = getNodeInnerHtml(item); @@ -7,7 +7,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { id: item.Id, text: htmlName, state: { - opened: item.IsFolder && folderState == "open", + opened: item.IsFolder && folderState == 'open', selected: selected }, li_attr: { @@ -17,7 +17,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { }; if (item.IsFolder) { node.children = [{ - text: "Loading...", + text: 'Loading...', icon: false }]; node.icon = false; @@ -36,30 +36,30 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { function getNodeInnerHtml(item) { var name = item.Name; if (item.Number) { - name = item.Number + " - " + name; + name = item.Number + ' - ' + name; } - if (item.IndexNumber != null && item.Type != "Season") { - name = item.IndexNumber + " - " + name; + if (item.IndexNumber != null && item.Type != 'Season') { + name = item.IndexNumber + ' - ' + name; } var htmlName = "
"; if (item.IsFolder) { - htmlName += 'folder'; - } else if (item.MediaType === "Video") { - htmlName += 'movie'; - } else if (item.MediaType === "Audio") { - htmlName += 'audiotrack'; - } else if (item.Type === "TvChannel") { - htmlName += 'live_tv'; - } else if (item.MediaType === "Photo") { - htmlName += 'photo'; - } else if (item.MediaType === "Book") { - htmlName += 'book'; + htmlName += ''; + } else if (item.MediaType === 'Video') { + htmlName += ''; + } else if (item.MediaType === 'Audio') { + htmlName += ''; + } else if (item.Type === 'TvChannel') { + htmlName += ''; + } else if (item.MediaType === 'Photo') { + htmlName += ''; + } else if (item.MediaType === 'Book') { + htmlName += ''; } if (item.LockData) { - htmlName += 'lock'; + htmlName += ''; } htmlName += name; - htmlName += "
"; + htmlName += '
'; return htmlName; } @@ -69,36 +69,36 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { }).then(function (result) { var nodes = []; nodes.push({ - id: "MediaFolders", - text: Globalize.translate("HeaderMediaFolders"), + id: 'MediaFolders', + text: globalize.translate('HeaderMediaFolders'), state: { opened: true }, li_attr: { - itemtype: "mediafolders", + itemtype: 'mediafolders', loadedFromServer: true }, icon: false }); if (result.TotalRecordCount) { nodes.push({ - id: "livetv", - text: Globalize.translate("HeaderLiveTV"), + id: 'livetv', + text: globalize.translate('HeaderLiveTV'), state: { opened: false }, li_attr: { - itemtype: "livetv" + itemtype: 'livetv' }, children: [{ - text: "Loading...", + text: 'Loading...', icon: false }], icon: false }); } callback.call(scope, nodes); - nodesToLoad.push("MediaFolders"); + nodesToLoad.push('MediaFolders'); }); } @@ -108,7 +108,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { AddCurrentProgram: false }).then(function (result) { var nodes = result.Items.map(function (i) { - var state = openItems.indexOf(i.Id) == -1 ? "closed" : "open"; + var state = openItems.indexOf(i.Id) == -1 ? 'closed' : 'open'; return getNode(i, state, false); }); callback(nodes); @@ -116,9 +116,9 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { } function loadMediaFolders(page, scope, openItems, callback) { - ApiClient.getJSON(ApiClient.getUrl("Library/MediaFolders")).then(function (result) { + ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders')).then(function (result) { var nodes = result.Items.map(function (n) { - var state = openItems.indexOf(n.Id) == -1 ? "closed" : "open"; + var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; return getNode(n, state, false); }); callback.call(scope, nodes); @@ -132,21 +132,21 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { function loadNode(page, scope, node, openItems, selectedId, currentUser, callback) { var id = node.id; - if (id == "#") { + if (id == '#') { loadChildrenOfRootNode(page, scope, callback); return; } - if (id == "livetv") { + if (id == 'livetv') { loadLiveTvChannels(id, openItems, callback); return; } - if (id == "MediaFolders") { + if (id == 'MediaFolders') { loadMediaFolders(page, scope, openItems, callback); return; } var query = { ParentId: id, - Fields: "Settings", + Fields: 'Settings', IsVirtualUnaired: false, IsMissing: false, EnableTotalRecordCount: false, @@ -154,12 +154,12 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { EnableUserData: false }; var itemtype = node.li_attr.itemtype; - if (itemtype != "Season" && itemtype != "Series") { - query.SortBy = "SortName"; + if (itemtype != 'Season' && itemtype != 'Series') { + query.SortBy = 'SortName'; } ApiClient.getItems(Dashboard.getCurrentUserId(), query).then(function (result) { var nodes = result.Items.map(function (n) { - var state = openItems.indexOf(n.Id) == -1 ? "closed" : "open"; + var state = openItems.indexOf(n.Id) == -1 ? 'closed' : 'open'; return getNode(n, state, n.Id == selectedId); }); callback.call(scope, nodes); @@ -172,14 +172,14 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { } function scrollToNode(id) { - var elem = $("#" + id)[0]; + var elem = $('#' + id)[0]; if (elem) { elem.scrollIntoView(); } } function initializeTree(page, currentUser, openItems, selectedId) { - require(["jstree"], function () { + require(['jstree'], function () { initializeTreeInternal(page, currentUser, openItems, selectedId); }); } @@ -192,41 +192,41 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { serverItemType: node.li_attr.serveritemtype, collectionType: node.li_attr.collectiontype }; - if (eventData.itemType != "livetv" && eventData.itemType != "mediafolders") { + if (eventData.itemType != 'livetv' && eventData.itemType != 'mediafolders') { { - this.dispatchEvent(new CustomEvent("itemclicked", { + this.dispatchEvent(new CustomEvent('itemclicked', { detail: eventData, bubbles: true, cancelable: false })); } - document.querySelector(".editPageSidebar").classList.add("editPageSidebar-withcontent"); + document.querySelector('.editPageSidebar').classList.add('editPageSidebar-withcontent'); } else { - document.querySelector(".editPageSidebar").classList.remove("editPageSidebar-withcontent"); + document.querySelector('.editPageSidebar').classList.remove('editPageSidebar-withcontent'); } } function onNodeOpen(event, data) { - var page = $(this).parents(".page")[0]; + var page = $(this).parents('.page')[0]; var node = data.node; if (node.children && node.children) { loadNodesToLoad(page, node); } - if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) { + if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) { node.li_attr.loadedFromServer = true; - $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback); + $.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback); } } function onNodeLoad(event, data) { - var page = $(this).parents(".page")[0]; + var page = $(this).parents('.page')[0]; var node = data.node; if (node.children && node.children) { loadNodesToLoad(page, node); } - if (node.li_attr && node.id != "#" && !node.li_attr.loadedFromServer) { + if (node.li_attr && node.id != '#' && !node.li_attr.loadedFromServer) { node.li_attr.loadedFromServer = true; - $.jstree.reference(".libraryTree", page).load_node(node.id, loadNodeCallback); + $.jstree.reference('.libraryTree', page).load_node(node.id, loadNodeCallback); } } @@ -234,18 +234,18 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { nodesToLoad = []; selectedNodeId = null; $.jstree.destroy(); - $(".libraryTree", page).jstree({ - "plugins": ["wholerow"], + $('.libraryTree', page).jstree({ + 'plugins': ['wholerow'], core: { check_callback: true, data: function (node, callback) { loadNode(page, this, node, openItems, selectedId, currentUser, callback); }, themes: { - variant: "large" + variant: 'large' } } - }).off("select_node.jstree", onNodeSelect).on("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).on("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad).on("load_node.jstree", onNodeLoad); + }).off('select_node.jstree', onNodeSelect).on('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).on('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad).on('load_node.jstree', onNodeLoad); } function loadNodesToLoad(page, node) { @@ -256,7 +256,7 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { nodesToLoad = nodesToLoad.filter(function (n) { return n != child; }); - $.jstree.reference(".libraryTree", page).load_node(child, loadNodeCallback); + $.jstree.reference('.libraryTree', page).load_node(child, loadNodeCallback); } } } @@ -270,14 +270,14 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { } function updateEditorNode(page, item) { - var elem = $("#" + item.Id + ">a", page)[0]; + var elem = $('#' + item.Id + '>a', page)[0]; if (elem == null) { return; } - $(".editorNode", elem).remove(); + $('.editorNode', elem).remove(); $(elem).append(getNodeInnerHtml(item)); if (item.IsFolder) { - var tree = jQuery.jstree._reference(".libraryTree"); + var tree = jQuery.jstree._reference('.libraryTree'); var currentNode = tree._get_node(null, false); tree.refresh(currentNode); } @@ -292,15 +292,15 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { return itemId; } var url = window.location.hash || window.location.href; - return getParameterByName("id", url); + return getParameterByName('id', url); } var nodesToLoad = []; var selectedNodeId; - $(document).on("itemsaved", ".metadataEditorPage", function (e, item) { + $(document).on('itemsaved', '.metadataEditorPage', function (e, item) { updateEditorNode(this, item); - }).on("pagebeforeshow", ".metadataEditorPage", function () { - require(["css!assets/css/metadataeditor.css"]); - }).on("pagebeforeshow", ".metadataEditorPage", function () { + }).on('pagebeforeshow', '.metadataEditorPage', function () { + require(['css!assets/css/metadataeditor.css']); + }).on('pagebeforeshow', '.metadataEditorPage', function () { var page = this; Dashboard.getCurrentUser().then(function (user) { var id = getCurrentItemId(); @@ -315,9 +315,9 @@ define(["datetime", "jQuery", "material-icons"], function (datetime, $) { initializeTree(page, user, []); } }); - }).on("pagebeforehide", ".metadataEditorPage", function () { + }).on('pagebeforehide', '.metadataEditorPage', function () { var page = this; - $(".libraryTree", page).off("select_node.jstree", onNodeSelect).off("open_node.jstree", onNodeOpen).off("load_node.jstree", onNodeLoad); + $('.libraryTree', page).off('select_node.jstree', onNodeSelect).off('open_node.jstree', onNodeOpen).off('load_node.jstree', onNodeLoad); }); var itemId; window.MetadataEditor = { diff --git a/src/scripts/filesystem.js b/src/scripts/filesystem.js new file mode 100644 index 0000000000..3c14020d1a --- /dev/null +++ b/src/scripts/filesystem.js @@ -0,0 +1,13 @@ +export function fileExists(path) { + if (window.NativeShell && window.NativeShell.FileSystem) { + return window.NativeShell.FileSystem.fileExists(path); + } + return Promise.reject(); +} + +export function directoryExists(path) { + if (window.NativeShell && window.NativeShell.FileSystem) { + return window.NativeShell.FileSystem.directoryExists(path); + } + return Promise.reject(); +} diff --git a/src/components/serverNotifications/gamepadtokey.js b/src/scripts/gamepadtokey.js similarity index 58% rename from src/components/serverNotifications/gamepadtokey.js rename to src/scripts/gamepadtokey.js index abf3ddb38b..089e5c81e9 100644 --- a/src/components/serverNotifications/gamepadtokey.js +++ b/src/scripts/gamepadtokey.js @@ -20,7 +20,7 @@ // # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // # THE SOFTWARE. require(['apphost'], function (appHost) { - "use strict"; + 'use strict'; var _GAMEPAD_A_BUTTON_INDEX = 0; var _GAMEPAD_B_BUTTON_INDEX = 1; @@ -28,16 +28,16 @@ require(['apphost'], function (appHost) { var _GAMEPAD_DPAD_DOWN_BUTTON_INDEX = 13; var _GAMEPAD_DPAD_LEFT_BUTTON_INDEX = 14; var _GAMEPAD_DPAD_RIGHT_BUTTON_INDEX = 15; - var _GAMEPAD_A_KEY = "GamepadA"; - var _GAMEPAD_B_KEY = "GamepadB"; - var _GAMEPAD_DPAD_UP_KEY = "GamepadDPadUp"; - var _GAMEPAD_DPAD_DOWN_KEY = "GamepadDPadDown"; - var _GAMEPAD_DPAD_LEFT_KEY = "GamepadDPadLeft"; - var _GAMEPAD_DPAD_RIGHT_KEY = "GamepadDPadRight"; - var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = "GamepadLeftThumbStickUp"; - var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = "GamepadLeftThumbStickDown"; - var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = "GamepadLeftThumbStickLeft"; - var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = "GamepadLeftThumbStickRight"; + var _GAMEPAD_A_KEY = 'GamepadA'; + var _GAMEPAD_B_KEY = 'GamepadB'; + var _GAMEPAD_DPAD_UP_KEY = 'GamepadDPadUp'; + var _GAMEPAD_DPAD_DOWN_KEY = 'GamepadDPadDown'; + var _GAMEPAD_DPAD_LEFT_KEY = 'GamepadDPadLeft'; + var _GAMEPAD_DPAD_RIGHT_KEY = 'GamepadDPadRight'; + var _GAMEPAD_LEFT_THUMBSTICK_UP_KEY = 'GamepadLeftThumbStickUp'; + var _GAMEPAD_LEFT_THUMBSTICK_DOWN_KEY = 'GamepadLeftThumbStickDown'; + var _GAMEPAD_LEFT_THUMBSTICK_LEFT_KEY = 'GamepadLeftThumbStickLeft'; + var _GAMEPAD_LEFT_THUMBSTICK_RIGHT_KEY = 'GamepadLeftThumbStickRight'; var _GAMEPAD_A_KEYCODE = 0; var _GAMEPAD_B_KEYCODE = 27; var _GAMEPAD_DPAD_UP_KEYCODE = 38; @@ -184,7 +184,7 @@ require(['apphost'], function (appHost) { function allowInput() { // This would be nice but always seems to return true with electron - if (!isElectron && document.hidden) { + if (!isElectron && document.hidden) { /* eslint-disable-line compat/compat */ return false; } @@ -234,7 +234,7 @@ require(['apphost'], function (appHost) { } if (fire && keyCode) { - raiseEvent("keydown", key, keyCode); + raiseEvent('keydown', key, keyCode); } } else if (newPressedState === false && oldPressedState === true) { @@ -243,7 +243,7 @@ require(['apphost'], function (appHost) { // button up if (keyCode) { - raiseEvent("keyup", key, keyCode); + raiseEvent('keyup', key, keyCode); } if (clickonKeyUp) { clickElement(document.activeElement || window); @@ -251,122 +251,160 @@ require(['apphost'], function (appHost) { } } + var inputLoopTimer; function runInputLoop() { // Get the latest gamepad state. - var gamepads; - if (navigator.getGamepads) { - gamepads = navigator.getGamepads(); - } else if (navigator.webkitGetGamepads) { - gamepads = navigator.webkitGetGamepads(); - } - gamepads = gamepads || []; - var i; - var j; - var len; - for (i = 0, len = gamepads.length; i < len; i++) { + var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ + for (var i = 0, len = gamepads.length; i < len; i++) { var gamepad = gamepads[i]; - if (gamepad) { - // 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 (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; - } + if (!gamepad) { + continue; + } + // 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 (var 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; } } } } } // Schedule the next one - requestAnimationFrame(runInputLoop); + inputLoopTimer = requestAnimationFrame(runInputLoop); } - runInputLoop(); + function startInputLoop() { + if (!inputLoopTimer) { + runInputLoop(); + } + } + + function stopInputLoop() { + cancelAnimationFrame(inputLoopTimer); + inputLoopTimer = undefined; + } + + function isGamepadConnected() { + var gamepads = navigator.getGamepads(); /* eslint-disable-line compat/compat */ + for (var i = 0, len = gamepads.length; i < len; i++) { + var gamepad = gamepads[i]; + if (gamepad && gamepad.connected) { + return true; + } + } + return false; + } + + function onFocusOrGamepadAttach(e) { + /* eslint-disable-next-line compat/compat */ + if (isGamepadConnected() && document.hasFocus()) { + console.log('Gamepad connected! Starting input loop'); + startInputLoop(); + } + } + + function onFocusOrGamepadDetach(e) { + /* eslint-disable-next-line compat/compat */ + if (!isGamepadConnected() || !document.hasFocus()) { + console.log('Gamepad disconnected! No other gamepads are connected, stopping input loop'); + stopInputLoop(); + } else { + console.log('Gamepad disconnected! There are gamepads still connected.'); + } + } + + // Event listeners for any change in gamepads' state. + window.addEventListener('gamepaddisconnected', onFocusOrGamepadDetach); + window.addEventListener('gamepadconnected', onFocusOrGamepadAttach); + window.addEventListener('blur', onFocusOrGamepadDetach); + window.addEventListener('focus', onFocusOrGamepadAttach); + + onFocusOrGamepadAttach(); // 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") { + 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"; + window.navigator.gamepadInputEmulation = 'gamepad'; } -}); \ No newline at end of file +}); diff --git a/src/scripts/globalize.js b/src/scripts/globalize.js index aa3a2ef0f9..2d7d725b5d 100644 --- a/src/scripts/globalize.js +++ b/src/scripts/globalize.js @@ -1,4 +1,4 @@ -define(['connectionManager', 'userSettings', 'events'], function (connectionManager, userSettings, events) { +define(['userSettings', 'events'], function (userSettings, events) { 'use strict'; var fallbackCulture = 'en-us'; @@ -38,7 +38,7 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana try { culture = userSettings.language(); } catch (err) { - console.log('no language set in user settings'); + console.error('no language set in user settings'); } culture = culture || getDefaultLanguage(); @@ -48,7 +48,7 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana try { dateTimeCulture = userSettings.dateTimeLocale(); } catch (err) { - console.log('no date format set in user settings'); + console.error('no date format set in user settings'); } if (dateTimeCulture) { @@ -253,7 +253,6 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana updateCurrentCulture(); - events.on(connectionManager, 'localusersignedin', updateCurrentCulture); events.on(userSettings, 'change', function (e, name) { if (name === 'language' || name === 'datetimelocale') { updateCurrentCulture(); @@ -269,6 +268,7 @@ define(['connectionManager', 'userSettings', 'events'], function (connectionMana defaultModule: defaultModule, getCurrentLocale: getCurrentLocale, getCurrentDateTimeLocale: getCurrentDateTimeLocale, - register: register + register: register, + updateCurrentCulture: updateCurrentCulture }; }); diff --git a/src/scripts/imagehelper.js b/src/scripts/imagehelper.js index 96961eb0cc..be3fd2834e 100644 --- a/src/scripts/imagehelper.js +++ b/src/scripts/imagehelper.js @@ -1,71 +1,81 @@ -define(["browser"], function (browser) { - "use strict"; +/* eslint-disable indent */ - function getDeviceIcon(device) { - var baseUrl = "assets/img/devices/"; - switch (device.AppName) { - case "Samsung Smart TV": - return baseUrl + "samsung.svg"; - case "Xbox One": - return baseUrl + "xbox.svg"; - case "Sony PS4": - return baseUrl + "playstation.svg"; - case "Kodi": - return baseUrl + "kodi.svg"; - case "Jellyfin Android": - return baseUrl + "android.svg"; - case "Jellyfin Web": - switch (device.Name) { - case "Opera": - case "Opera TV": - return baseUrl + "opera.svg"; - case "Chrome": - return baseUrl + "chrome.svg"; - case "Firefox": - return baseUrl + "firefox.svg"; - case "Edge": - return baseUrl + "edge.svg"; - case "Internet Explorer": - return baseUrl + "msie.svg"; +import browser from 'browser'; + + export function getDeviceIcon(device) { + var baseUrl = 'assets/img/devices/'; + switch (device.AppName || device.Client) { + case 'Samsung Smart TV': + return baseUrl + 'samsung.svg'; + case 'Xbox One': + return baseUrl + 'xbox.svg'; + case 'Sony PS4': + return baseUrl + 'playstation.svg'; + case 'Kodi': + return baseUrl + 'kodi.svg'; + case 'Jellyfin Android': + case 'Android TV': + return baseUrl + 'android.svg'; + case 'Jellyfin Web': + switch (device.Name || device.DeviceName) { + case 'Opera': + case 'Opera TV': + case 'Opera Android': + return baseUrl + 'opera.svg'; + case 'Chrome': + case 'Chrome Android': + return baseUrl + 'chrome.svg'; + case 'Firefox': + case 'Firefox Android': + return baseUrl + 'firefox.svg'; + case 'Safari': + case 'Safari iPad': + case 'Safari iPhone': + return baseUrl + 'safari.svg'; + case 'Edge': + return baseUrl + 'edge.svg'; + case 'Internet Explorer': + return baseUrl + 'msie.svg'; default: - return baseUrl + "html5.svg"; + return baseUrl + 'html5.svg'; } default: - return baseUrl + "other.svg"; + return baseUrl + 'other.svg'; } } - function getLibraryIcon(library) { + export function getLibraryIcon(library) { switch (library) { - case "movies": - return "video_library"; - case "music": - return "library_music"; - case "photos": - return "photo_library"; - case "livetv": - return "live_tv"; - case "tvshows": - return "tv"; - case "trailers": - return "local_movies"; - case "homevideos": - return "photo_library"; - case "musicvideos": - return "music_video"; - case "books": - return "library_books"; - case "channels": - return "videocam"; - case "playlists": - return "view_list"; + case 'movies': + return 'video_library'; + case 'music': + return 'library_music'; + case 'photos': + return 'photo_library'; + case 'livetv': + return 'live_tv'; + case 'tvshows': + return 'tv'; + case 'trailers': + return 'local_movies'; + case 'homevideos': + return 'photo_library'; + case 'musicvideos': + return 'music_video'; + case 'books': + return 'library_books'; + case 'channels': + return 'videocam'; + case 'playlists': + return 'view_list'; default: - return "folder"; + return 'folder'; } } - return { - getDeviceIcon: getDeviceIcon, - getLibraryIcon: getLibraryIcon - }; -}); +/* eslint-enable indent */ + +export default { + getDeviceIcon: getDeviceIcon, + getLibraryIcon: getLibraryIcon +}; diff --git a/src/scripts/inputManager.js b/src/scripts/inputManager.js index 634b5e1b30..8af52c77e8 100644 --- a/src/scripts/inputManager.js +++ b/src/scripts/inputManager.js @@ -1,46 +1,49 @@ -define(['playbackManager', 'focusManager', 'appRouter', 'dom'], function (playbackManager, focusManager, appRouter, dom) { - 'use strict'; +import playbackManager from 'playbackManager'; +import focusManager from 'focusManager'; +import appRouter from 'appRouter'; +import dom from 'dom'; +import appHost from 'apphost'; - var lastInputTime = new Date().getTime(); +/* eslint-disable indent */ - function notify() { + let lastInputTime = new Date().getTime(); + + export function notify() { lastInputTime = new Date().getTime(); handleCommand('unknown'); } - function notifyMouseMove() { + export function notifyMouseMove() { lastInputTime = new Date().getTime(); } - function idleTime() { + export function idleTime() { return new Date().getTime() - lastInputTime; } - function select(sourceElement) { + export function select(sourceElement) { sourceElement.click(); } - var eventListenerCount = 0; - function on(scope, fn) { - if (eventListenerCount) { - eventListenerCount++; - } + let eventListenerCount = 0; + export function on(scope, fn) { + eventListenerCount++; dom.addEventListener(scope, 'command', fn, {}); } - function off(scope, fn) { + export function off(scope, fn) { if (eventListenerCount) { eventListenerCount--; } dom.removeEventListener(scope, 'command', fn, {}); } - var commandTimes = {}; + let commandTimes = {}; function checkCommandTime(command) { - var last = commandTimes[command] || 0; - var now = new Date().getTime(); + const last = commandTimes[command] || 0; + const now = new Date().getTime(); if ((now - last) < 1000) { return false; @@ -50,192 +53,203 @@ define(['playbackManager', 'focusManager', 'appRouter', 'dom'], function (playba return true; } - function handleCommand(name, options) { + export function handleCommand(commandName, options) { lastInputTime = new Date().getTime(); - var sourceElement = (options ? options.sourceElement : null); + let sourceElement = (options ? options.sourceElement : null); if (sourceElement) { sourceElement = focusManager.focusableParent(sourceElement); } - sourceElement = sourceElement || document.activeElement || window; + if (!sourceElement) { + sourceElement = document.activeElement || window; + + const dlg = document.querySelector('.dialogContainer .dialog.opened'); + + if (dlg && (!sourceElement || !dlg.contains(sourceElement))) { + sourceElement = dlg; + } + } if (eventListenerCount) { - var customEvent = new CustomEvent("command", { + const customEvent = new CustomEvent('command', { detail: { - command: name + command: commandName }, bubbles: true, cancelable: true }); - var eventResult = sourceElement.dispatchEvent(customEvent); + const eventResult = sourceElement.dispatchEvent(customEvent); if (!eventResult) { // event cancelled return; } } - switch (name) { - case 'up': + const keyActions = (command) => ({ + 'up': () => { focusManager.moveUp(sourceElement); - break; - case 'down': + }, + 'down': () => { focusManager.moveDown(sourceElement); - break; - case 'left': + }, + 'left': () => { focusManager.moveLeft(sourceElement); - break; - case 'right': + }, + 'right': () => { focusManager.moveRight(sourceElement); - break; - case 'home': + }, + 'home': () => { appRouter.goHome(); - break; - case 'settings': + }, + 'settings': () => { appRouter.showSettings(); - break; - case 'back': - appRouter.back(); - break; - case 'forward': - break; - case 'select': + }, + 'back': () => { + if (appRouter.canGoBack()) { + appRouter.back(); + } else if (appHost.supports('exit')) { + appHost.exit(); + } + }, + 'select': () => { select(sourceElement); - break; - case 'pageup': - break; - case 'pagedown': - break; - case 'end': - break; - case 'menu': - break; - case 'info': - break; - case 'nextchapter': + }, + 'nextchapter': () => { playbackManager.nextChapter(); - break; - case 'next': - case 'nexttrack': + }, + 'next': () => { playbackManager.nextTrack(); - break; - case 'previous': - case 'previoustrack': + }, + 'nexttrack': () => { + playbackManager.nextTrack(); + }, + 'previous': () => { playbackManager.previousTrack(); - break; - case 'previouschapter': + }, + 'previoustrack': () => { + playbackManager.previousTrack(); + }, + 'previouschapter': () => { playbackManager.previousChapter(); - break; - case 'guide': + }, + 'guide': () => { appRouter.showGuide(); - break; - case 'recordedtv': + }, + 'recordedtv': () => { appRouter.showRecordedTV(); - break; - case 'record': - break; - case 'livetv': + }, + 'livetv': () => { appRouter.showLiveTV(); - break; - case 'mute': + }, + 'mute': () => { playbackManager.setMute(true); - break; - case 'unmute': + }, + 'unmute': () => { playbackManager.setMute(false); - break; - case 'togglemute': + }, + 'togglemute': () => { playbackManager.toggleMute(); - break; - case 'channelup': + }, + 'channelup': () => { playbackManager.channelUp(); - break; - case 'channeldown': + }, + 'channeldown': () => { playbackManager.channelDown(); - break; - case 'volumedown': + }, + 'volumedown': () => { playbackManager.volumeDown(); - break; - case 'volumeup': + }, + 'volumeup': () => { playbackManager.volumeUp(); - break; - case 'play': + }, + 'play': () => { playbackManager.unpause(); - break; - case 'pause': + }, + 'pause': () => { playbackManager.pause(); - break; - case 'playpause': + }, + 'playpause': () => { playbackManager.playPause(); - break; - case 'stop': + }, + 'stop': () => { if (checkCommandTime('stop')) { playbackManager.stop(); } - break; - case 'changezoom': + }, + 'changezoom': () => { playbackManager.toggleAspectRatio(); - break; - case 'changeaudiotrack': + }, + 'changeaudiotrack': () => { playbackManager.changeAudioStream(); - break; - case 'changesubtitletrack': + }, + 'changesubtitletrack': () => { playbackManager.changeSubtitleStream(); - break; - case 'search': + }, + 'search': () => { appRouter.showSearch(); - break; - case 'favorites': + }, + 'favorites': () => { appRouter.showFavorites(); - break; - case 'fastforward': + }, + 'fastforward': () => { playbackManager.fastForward(); - break; - case 'rewind': + }, + 'rewind': () => { playbackManager.rewind(); - break; - case 'togglefullscreen': + }, + 'togglefullscreen': () => { playbackManager.toggleFullscreen(); - break; - case 'disabledisplaymirror': + }, + 'disabledisplaymirror': () => { playbackManager.enableDisplayMirroring(false); - break; - case 'enabledisplaymirror': + }, + 'enabledisplaymirror': () => { playbackManager.enableDisplayMirroring(true); - break; - case 'toggledisplaymirror': + }, + 'toggledisplaymirror': () => { playbackManager.toggleDisplayMirroring(); - break; - case 'nowplaying': + }, + 'nowplaying': () => { appRouter.showNowPlaying(); - break; - case 'repeatnone': + }, + 'repeatnone': () => { playbackManager.setRepeatMode('RepeatNone'); - break; - case 'repeatall': + }, + 'repeatall': () => { playbackManager.setRepeatMode('RepeatAll'); - break; - case 'repeatone': + }, + 'repeatone': () => { playbackManager.setRepeatMode('RepeatOne'); - break; - default: - break; + } + })[command]; + + const action = keyActions(commandName); + if (action !== undefined) { + action.call(); + } else { + console.debug(`inputManager: tried to process command with no action assigned: ${commandName}`); } } + // Alias for backward compatibility + export const trigger = handleCommand; + dom.addEventListener(document, 'click', notify, { passive: true }); - return { - trigger: handleCommand, - handle: handleCommand, - notify: notify, - notifyMouseMove: notifyMouseMove, - idleTime: idleTime, - on: on, - off: off - }; -}); +/* eslint-enable indent */ + +export default { + trigger: handleCommand, + handle: handleCommand, + notify: notify, + notifyMouseMove: notifyMouseMove, + idleTime: idleTime, + on: on, + off: off +}; diff --git a/src/scripts/itembynamedetailpage.js b/src/scripts/itembynamedetailpage.js index 5d3c9dedb9..44eca55589 100644 --- a/src/scripts/itembynamedetailpage.js +++ b/src/scripts/itembynamedetailpage.js @@ -1,105 +1,105 @@ -define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryBrowser", "emby-itemscontainer", "emby-button"], function (connectionManager, listView, cardBuilder, imageLoader, libraryBrowser) { - "use strict"; +define(['connectionManager', 'listView', 'cardBuilder', 'imageLoader', 'libraryBrowser', 'globalize', 'emby-itemscontainer', 'emby-button'], function (connectionManager, listView, cardBuilder, imageLoader, libraryBrowser, globalize) { + 'use strict'; function renderItems(page, item) { var sections = []; if (item.ArtistCount) { sections.push({ - name: Globalize.translate("TabArtists"), - type: "MusicArtist" + name: globalize.translate('TabArtists'), + type: 'MusicArtist' }); } - if (item.ProgramCount && "Person" == item.Type) { + if (item.ProgramCount && 'Person' == item.Type) { sections.push({ - name: Globalize.translate("HeaderUpcomingOnTV"), - type: "Program" + name: globalize.translate('HeaderUpcomingOnTV'), + type: 'Program' }); } if (item.MovieCount) { sections.push({ - name: Globalize.translate("TabMovies"), - type: "Movie" + name: globalize.translate('TabMovies'), + type: 'Movie' }); } if (item.SeriesCount) { sections.push({ - name: Globalize.translate("TabShows"), - type: "Series" + name: globalize.translate('TabShows'), + type: 'Series' }); } if (item.EpisodeCount) { sections.push({ - name: Globalize.translate("TabEpisodes"), - type: "Episode" + name: globalize.translate('TabEpisodes'), + type: 'Episode' }); } if (item.TrailerCount) { sections.push({ - name: Globalize.translate("TabTrailers"), - type: "Trailer" + name: globalize.translate('TabTrailers'), + type: 'Trailer' }); } if (item.AlbumCount) { sections.push({ - name: Globalize.translate("TabAlbums"), - type: "MusicAlbum" + name: globalize.translate('TabAlbums'), + type: 'MusicAlbum' }); } if (item.MusicVideoCount) { sections.push({ - name: Globalize.translate("TabMusicVideos"), - type: "MusicVideo" + name: globalize.translate('TabMusicVideos'), + type: 'MusicVideo' }); } - var elem = page.querySelector("#childrenContent"); + var elem = page.querySelector('#childrenContent'); elem.innerHTML = sections.map(function (section) { - var html = ""; - var sectionClass = "verticalSection"; + var html = ''; + var sectionClass = 'verticalSection'; - if ("Audio" === section.type) { - sectionClass += " verticalSection-extrabottompadding"; + if ('Audio' === section.type) { + sectionClass += ' verticalSection-extrabottompadding'; } html += '
'; html += '
'; html += '

'; html += section.name; - html += "

"; - html += '"; - html += "
"; + html += ''; + html += ''; + html += '
'; html += '
'; - html += "
"; - return html += "
"; - }).join(""); - var sectionElems = elem.querySelectorAll(".verticalSection"); + html += '
'; + return html += '
'; + }).join(''); + var sectionElems = elem.querySelectorAll('.verticalSection'); for (var i = 0, length = sectionElems.length; i < length; i++) { - renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute("data-type")); + renderSection(page, item, sectionElems[i], sectionElems[i].getAttribute('data-type')); } } function renderSection(page, item, element, type) { switch (type) { - case "Program": + case 'Program': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Program", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'Program', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 10, - SortBy: "StartDate" + SortBy: 'StartDate' }, { - shape: "backdrop", + shape: 'overflowBackdrop', showTitle: true, centerText: true, overlayMoreButton: true, @@ -111,17 +111,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB }); break; - case "Movie": + case 'Movie': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Movie", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'Movie', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 10, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "portrait", + shape: 'overflowPortrait', showTitle: true, centerText: true, overlayMoreButton: true, @@ -130,68 +130,68 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB }); break; - case "MusicVideo": + case 'MusicVideo': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "MusicVideo", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'MusicVideo', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 10, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "portrait", + shape: 'overflowPortrait', showTitle: true, centerText: true, overlayPlayButton: true }); break; - case "Trailer": + case 'Trailer': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Trailer", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'Trailer', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 10, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "portrait", + shape: 'overflowPortrait', showTitle: true, centerText: true, overlayPlayButton: true }); break; - case "Series": + case 'Series': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Series", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'Series', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 10, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "portrait", + shape: 'overflowPortrait', showTitle: true, centerText: true, overlayMoreButton: true }); break; - case "MusicAlbum": + case 'MusicAlbum': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "MusicAlbum", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", - SortOrder: "Descending", - SortBy: "ProductionYear,Sortname" + MediaTypes: '', + IncludeItemTypes: 'MusicAlbum', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', + SortOrder: 'Descending', + SortBy: 'ProductionYear,Sortname' }, { - shape: "square", + shape: 'overflowSquare', playFromHere: true, showTitle: true, showYear: true, @@ -201,17 +201,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB }); break; - case "MusicArtist": + case 'MusicArtist': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "MusicArtist", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'MusicArtist', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 8, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "square", + shape: 'overflowSquare', playFromHere: true, showTitle: true, showParentTitle: true, @@ -221,17 +221,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB }); break; - case "Episode": + case 'Episode': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Episode", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", + MediaTypes: '', + IncludeItemTypes: 'Episode', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', Limit: 6, - SortBy: "SortName" + SortBy: 'SortName' }, { - shape: "backdrop", + shape: 'overflowBackdrop', showTitle: true, showParentTitle: true, centerText: true, @@ -239,17 +239,17 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB }); break; - case "Audio": + case 'Audio': loadItems(element, item, type, { - MediaTypes: "", - IncludeItemTypes: "Audio", - PersonTypes: "", - ArtistIds: "", - AlbumArtistIds: "", - SortBy: "AlbumArtist,Album,SortName" + MediaTypes: '', + IncludeItemTypes: 'Audio', + PersonTypes: '', + ArtistIds: '', + AlbumArtistIds: '', + SortBy: 'AlbumArtist,Album,SortName' }, { playFromHere: true, - action: "playallfromhere", + action: 'playallfromhere', smallIcon: true, artist: true }); @@ -259,27 +259,27 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB function loadItems(element, item, type, query, listOptions) { query = getQuery(query, item); getItemsFunction(query, item)(query.StartIndex, query.Limit, query.Fields).then(function (result) { - var html = ""; + var html = ''; if (query.Limit && result.TotalRecordCount > query.Limit) { - var link = element.querySelector("a"); - link.classList.remove("hide"); - link.setAttribute("href", getMoreItemsHref(item, type)); + var link = element.querySelector('a'); + link.classList.remove('hide'); + link.setAttribute('href', getMoreItemsHref(item, type)); } else { - element.querySelector("a").classList.add("hide"); + element.querySelector('a').classList.add('hide'); } listOptions.items = result.Items; - var itemsContainer = element.querySelector(".itemsContainer"); + var itemsContainer = element.querySelector('.itemsContainer'); - if ("Audio" == type) { + if ('Audio' == type) { html = listView.getListViewHtml(listOptions); - itemsContainer.classList.remove("vertical-wrap"); - itemsContainer.classList.add("vertical-list"); + itemsContainer.classList.remove('vertical-wrap'); + itemsContainer.classList.add('vertical-list'); } else { html = cardBuilder.getCardsHtml(listOptions); - itemsContainer.classList.add("vertical-wrap"); - itemsContainer.classList.remove("vertical-list"); + itemsContainer.classList.add('vertical-wrap'); + itemsContainer.classList.remove('vertical-list'); } itemsContainer.innerHTML = html; @@ -288,51 +288,51 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB } function getMoreItemsHref(item, type) { - if ("Genre" == item.Type) { - return "list.html?type=" + type + "&genreId=" + item.Id + "&serverId=" + item.ServerId; + if ('Genre' == item.Type) { + return 'list.html?type=' + type + '&genreId=' + item.Id + '&serverId=' + item.ServerId; } - if ("MusicGenre" == item.Type) { - return "list.html?type=" + type + "&musicGenreId=" + item.Id + "&serverId=" + item.ServerId; + if ('MusicGenre' == item.Type) { + return 'list.html?type=' + type + '&musicGenreId=' + item.Id + '&serverId=' + item.ServerId; } - if ("Studio" == item.Type) { - return "list.html?type=" + type + "&studioId=" + item.Id + "&serverId=" + item.ServerId; + if ('Studio' == item.Type) { + return 'list.html?type=' + type + '&studioId=' + item.Id + '&serverId=' + item.ServerId; } - if ("MusicArtist" == item.Type) { - return "list.html?type=" + type + "&artistId=" + item.Id + "&serverId=" + item.ServerId; + if ('MusicArtist' == item.Type) { + return 'list.html?type=' + type + '&artistId=' + item.Id + '&serverId=' + item.ServerId; } - if ("Person" == item.Type) { - return "list.html?type=" + type + "&personId=" + item.Id + "&serverId=" + item.ServerId; + if ('Person' == item.Type) { + return 'list.html?type=' + type + '&personId=' + item.Id + '&serverId=' + item.ServerId; } - return "list.html?type=" + type + "&parentId=" + item.Id + "&serverId=" + item.ServerId; + return 'list.html?type=' + type + '&parentId=' + item.Id + '&serverId=' + item.ServerId; } function addCurrentItemToQuery(query, item) { - if (item.Type == "Person") { + if (item.Type == 'Person') { query.PersonIds = item.Id; - } else if (item.Type == "Genre") { + } else if (item.Type == 'Genre') { query.Genres = item.Name; - } else if (item.Type == "MusicGenre") { + } else if (item.Type == 'MusicGenre') { query.Genres = item.Name; - } else if (item.Type == "GameGenre") { + } else if (item.Type == 'GameGenre') { query.Genres = item.Name; - } else if (item.Type == "Studio") { + } else if (item.Type == 'Studio') { query.StudioIds = item.Id; - } else if (item.Type == "MusicArtist") { + } else if (item.Type == 'MusicArtist') { query.AlbumArtistIds = item.Id; } } function getQuery(options, item) { var query = { - SortOrder: "Ascending", - IncludeItemTypes: "", + SortOrder: 'Ascending', + IncludeItemTypes: '', Recursive: true, - Fields: "AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo", + Fields: 'AudioInfo,SeriesInfo,ParentId,PrimaryImageAspectRatio,BasicSyncInfo', Limit: 100, StartIndex: 0, CollapseBoxSetItems: false @@ -349,12 +349,12 @@ define(["connectionManager", "listView", "cardBuilder", "imageLoader", "libraryB query.Limit = limit; if (fields) { - query.Fields += "," + fields; + query.Fields += ',' + fields; } var apiClient = connectionManager.getApiClient(item.ServerId); - if ("MusicArtist" === query.IncludeItemTypes) { + if ('MusicArtist' === query.IncludeItemTypes) { query.IncludeItemTypes = null; return apiClient.getAlbumArtists(apiClient.getCurrentUserId(), query); } diff --git a/src/scripts/keyboardnavigation.js b/src/scripts/keyboardnavigation.js new file mode 100644 index 0000000000..6664afed53 --- /dev/null +++ b/src/scripts/keyboardnavigation.js @@ -0,0 +1,170 @@ +/** + * Module for performing keyboard navigation. + * @module components/input/keyboardnavigation + */ + +import inputManager from 'inputManager'; +import layoutManager from 'layoutManager'; + +/** + * Key name mapping. + */ +const KeyNames = { + 13: 'Enter', + 19: 'Pause', + 27: 'Escape', + 32: 'Space', + 37: 'ArrowLeft', + 38: 'ArrowUp', + 39: 'ArrowRight', + 40: 'ArrowDown', + // MediaRewind (Tizen/WebOS) + 412: 'MediaRewind', + // MediaStop (Tizen/WebOS) + 413: 'MediaStop', + // MediaPlay (Tizen/WebOS) + 415: 'MediaPlay', + // MediaFastForward (Tizen/WebOS) + 417: 'MediaFastForward', + // Back (WebOS) + 461: 'Back', + // Back (Tizen) + 10009: 'Back', + // MediaTrackPrevious (Tizen) + 10232: 'MediaTrackPrevious', + // MediaTrackNext (Tizen) + 10233: 'MediaTrackNext', + // MediaPlayPause (Tizen) + 10252: 'MediaPlayPause' +}; + +/** + * Keys used for keyboard navigation. + */ +const NavigationKeys = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; + +let hasFieldKey = false; +try { + hasFieldKey = 'key' in new KeyboardEvent('keydown'); +} catch (e) { + console.error("error checking 'key' field"); +} + +if (!hasFieldKey) { + // Add [a..z] + for (let i = 65; i <= 90; i++) { + KeyNames[i] = String.fromCharCode(i).toLowerCase(); + } +} + +/** + * Returns key name from event. + * + * @param {KeyboardEvent} event - Keyboard event. + * @return {string} Key name. + */ +export function getKeyName(event) { + return KeyNames[event.keyCode] || event.key; +} + +/** + * Returns _true_ if key is used for navigation. + * + * @param {string} key - Key name. + * @return {boolean} _true_ if key is used for navigation. + */ +export function isNavigationKey(key) { + return NavigationKeys.indexOf(key) != -1; +} + +export function enable() { + document.addEventListener('keydown', function (e) { + const key = getKeyName(e); + + // Ignore navigation keys for non-TV + if (!layoutManager.tv && isNavigationKey(key)) { + return; + } + + let capture = true; + + switch (key) { + case 'ArrowLeft': + inputManager.handle('left'); + break; + case 'ArrowUp': + inputManager.handle('up'); + break; + case 'ArrowRight': + inputManager.handle('right'); + break; + case 'ArrowDown': + inputManager.handle('down'); + break; + + case 'Back': + inputManager.handle('back'); + break; + + case 'Escape': + if (layoutManager.tv) { + inputManager.handle('back'); + } else { + capture = false; + } + break; + + case 'MediaPlay': + inputManager.handle('play'); + break; + case 'Pause': + inputManager.handle('pause'); + break; + case 'MediaPlayPause': + inputManager.handle('playpause'); + break; + case 'MediaRewind': + inputManager.handle('rewind'); + break; + case 'MediaFastForward': + inputManager.handle('fastforward'); + break; + case 'MediaStop': + inputManager.handle('stop'); + break; + case 'MediaTrackPrevious': + inputManager.handle('previoustrack'); + break; + case 'MediaTrackNext': + inputManager.handle('nexttrack'); + break; + + default: + capture = false; + } + + if (capture) { + console.debug('disabling default event handling'); + e.preventDefault(); + } + }); +} + +// Gamepad initialisation. No script is required if no gamepads are present at init time, saving a bit of resources. +// Whenever the gamepad is connected, we hand all the control of the gamepad to gamepadtokey.js by removing the event handler +function attachGamepadScript(e) { + console.log('Gamepad connected! Attaching gamepadtokey.js script'); + window.removeEventListener('gamepadconnected', attachGamepadScript); + require(['scripts/gamepadtokey']); +} + +// No need to check for gamepads manually at load time, the eventhandler will be fired for that +if (navigator.getGamepads) { /* eslint-disable-line compat/compat */ + window.addEventListener('gamepadconnected', attachGamepadScript); +} + +export default { + enable: enable, + getKeyName: getKeyName, + isNavigationKey: isNavigationKey +}; diff --git a/src/scripts/librarybrowser.js b/src/scripts/librarybrowser.js index b9f3b92471..f9e5e23596 100644 --- a/src/scripts/librarybrowser.js +++ b/src/scripts/librarybrowser.js @@ -1,9 +1,9 @@ -define(["userSettings"], function (userSettings) { - "use strict"; +define(['userSettings', 'globalize'], function (userSettings, globalize) { + 'use strict'; var libraryBrowser = { getSavedQueryKey: function (modifier) { - return window.location.href.split("#")[0] + (modifier || ""); + return window.location.href.split('#')[0] + (modifier || ''); }, loadSavedQueryValues: function (key, query) { var values = userSettings.get(key); @@ -29,34 +29,34 @@ define(["userSettings"], function (userSettings) { userSettings.set(key, JSON.stringify(values)); }, saveViewSetting: function (key, value) { - userSettings.set(key + "-_view", value); + userSettings.set(key + '-_view', value); }, getSavedView: function (key) { - return userSettings.get(key + "-_view"); + return userSettings.get(key + '-_view'); }, showLayoutMenu: function (button, currentLayout, views) { var dispatchEvent = true; if (!views) { dispatchEvent = false; - views = button.getAttribute("data-layouts"); - views = views ? views.split(",") : ["List", "Poster", "PosterCard", "Thumb", "ThumbCard"]; + views = button.getAttribute('data-layouts'); + views = views ? views.split(',') : ['List', 'Poster', 'PosterCard', 'Thumb', 'ThumbCard']; } var menuItems = views.map(function (v) { return { - name: Globalize.translate("Option" + v), + name: globalize.translate('Option' + v), id: v, selected: currentLayout == v }; }); - require(["actionsheet"], function (actionsheet) { + require(['actionsheet'], function (actionsheet) { actionsheet.show({ items: menuItems, positionTo: button, callback: function (id) { - button.dispatchEvent(new CustomEvent("layoutchange", { + button.dispatchEvent(new CustomEvent('layoutchange', { detail: { viewStyle: id }, @@ -66,7 +66,7 @@ define(["userSettings"], function (userSettings) { if (!dispatchEvent) { if (window.$) { - $(button).trigger("layoutchange", [id]); + $(button).trigger('layoutchange', [id]); } } } @@ -77,49 +77,49 @@ define(["userSettings"], function (userSettings) { var startIndex = options.startIndex; var limit = options.limit; var totalRecordCount = options.totalRecordCount; - var html = ""; + var html = ''; var recordsEnd = Math.min(startIndex + limit, totalRecordCount); var showControls = limit < totalRecordCount; if (html += '
', showControls) { html += ''; - html += (totalRecordCount ? startIndex + 1 : 0) + "-" + recordsEnd + " of " + totalRecordCount; - html += ""; + html += globalize.translate('ListPaging', (totalRecordCount ? startIndex + 1 : 0), recordsEnd, totalRecordCount); + html += ''; } if (showControls || options.viewButton || options.filterButton || options.sortButton || options.addLayoutButton) { html += '
'; if (showControls) { - html += ''; - html += ''; + html += ''; + html += ''; } if (options.addLayoutButton) { - html += ''; + html += ''; } if (options.sortButton) { - html += ''; + html += ''; } if (options.filterButton) { - html += ''; + html += ''; } - html += "
"; + html += '
'; } - return html += "
"; + return html += '
'; }, showSortMenu: function (options) { - require(["dialogHelper", "emby-radio"], function (dialogHelper) { + require(['dialogHelper', 'emby-radio'], function (dialogHelper) { function onSortByChange() { var newValue = this.value; if (this.checked) { var changed = options.query.SortBy != newValue; - options.query.SortBy = newValue.replace("_", ","); + options.query.SortBy = newValue.replace('_', ','); options.query.StartIndex = 0; if (options.callback && changed) { @@ -148,48 +148,48 @@ define(["userSettings"], function (userSettings) { entryAnimationDuration: 160, exitAnimationDuration: 200 }); - dlg.classList.add("ui-body-a"); - dlg.classList.add("background-theme-a"); - dlg.classList.add("formDialog"); - var html = ""; + dlg.classList.add('ui-body-a'); + dlg.classList.add('background-theme-a'); + dlg.classList.add('formDialog'); + var html = ''; html += '
'; html += '

'; - html += Globalize.translate("HeaderSortBy"); - html += "

"; + html += globalize.translate('HeaderSortBy'); + html += ''; var i; var length; var isChecked; html += '
'; for (i = 0, length = options.items.length; i < length; i++) { var option = options.items[i]; - var radioValue = option.id.replace(",", "_"); - isChecked = (options.query.SortBy || "").replace(",", "_") == radioValue ? " checked" : ""; - html += '"; + var radioValue = option.id.replace(',', '_'); + isChecked = (options.query.SortBy || '').replace(',', '_') == radioValue ? ' checked' : ''; + html += ''; } - html += "
"; + html += '
'; html += '

'; - html += Globalize.translate("HeaderSortOrder"); - html += "

"; - html += "
"; - isChecked = "Ascending" == options.query.SortOrder ? " checked" : ""; - html += '"; - isChecked = "Descending" == options.query.SortOrder ? " checked" : ""; - html += '"; - html += "
"; - html += "
"; + html += globalize.translate('HeaderSortOrder'); + html += ''; + html += '
'; + isChecked = 'Ascending' == options.query.SortOrder ? ' checked' : ''; + html += ''; + isChecked = 'Descending' == options.query.SortOrder ? ' checked' : ''; + html += ''; + html += '
'; + html += '
'; dlg.innerHTML = html; dialogHelper.open(dlg); - var sortBys = dlg.querySelectorAll(".menuSortBy"); + var sortBys = dlg.querySelectorAll('.menuSortBy'); for (i = 0, length = sortBys.length; i < length; i++) { - sortBys[i].addEventListener("change", onSortByChange); + sortBys[i].addEventListener('change', onSortByChange); } - var sortOrders = dlg.querySelectorAll(".menuSortOrder"); + var sortOrders = dlg.querySelectorAll('.menuSortOrder'); for (i = 0, length = sortOrders.length; i < length; i++) { - sortOrders[i].addEventListener("change", onSortOrderChange); + sortOrders[i].addEventListener('change', onSortOrderChange); } }); } diff --git a/src/scripts/librarymenu.js b/src/scripts/librarymenu.js index a1129599e1..81a381bff2 100644 --- a/src/scripts/librarymenu.js +++ b/src/scripts/librarymenu.js @@ -1,5 +1,39 @@ -define(["dom", "layoutManager", "inputManager", "connectionManager", "events", "viewManager", "libraryBrowser", "appRouter", "apphost", "playbackManager", "browser", "globalize", "scripts/imagehelper", "paper-icon-button-light", "material-icons", "scrollStyles", "flexStyles"], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, browser, globalize, imageHelper) { - "use strict"; +define(['dom', 'layoutManager', 'inputManager', 'connectionManager', 'events', 'viewManager', 'libraryBrowser', 'appRouter', 'apphost', 'playbackManager', 'browser', 'globalize', 'scripts/imagehelper', 'paper-icon-button-light', 'material-icons', 'scrollStyles', 'flexStyles'], function (dom, layoutManager, inputManager, connectionManager, events, viewManager, libraryBrowser, appRouter, appHost, playbackManager, browser, globalize, imageHelper) { + 'use strict'; + + function renderHeader() { + var html = ''; + html += '
'; + html += '
'; + html += ''; + html += ''; + html += ''; + html += '

'; + html += '
'; + html += '
'; + html += ''; + html += ''; + html += ''; + html += ''; + html += ''; + html += '
'; + html += '
'; + html += '
'; + html += '
'; + + skinHeader.classList.add('skinHeader-withBackground'); + skinHeader.classList.add('skinHeader-blurred'); + skinHeader.innerHTML = html; + + headerHomeButton = skinHeader.querySelector('.headerHomeButton'); + headerUserButton = skinHeader.querySelector('.headerUserButton'); + headerCastButton = skinHeader.querySelector('.headerCastButton'); + headerAudioPlayerButton = skinHeader.querySelector('.headerAudioPlayerButton'); + headerSearchButton = skinHeader.querySelector('.headerSearchButton'); + + lazyLoadViewMenuBarImages(); + bindMenuEvents(); + } function getCurrentApiClient() { if (currentUser && currentUser.localUser) { @@ -10,7 +44,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } function lazyLoadViewMenuBarImages() { - require(["imageLoader"], function (imageLoader) { + require(['imageLoader'], function (imageLoader) { imageLoader.lazyChildren(skinHeader); }); } @@ -29,9 +63,9 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " hasImage = true; } - headerUserButton.classList.remove("hide"); + headerUserButton.classList.remove('hide'); } else { - headerUserButton.classList.add("hide"); + headerUserButton.classList.add('hide'); } if (!hasImage) { @@ -40,22 +74,22 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " if (user && user.localUser) { if (headerHomeButton) { - headerHomeButton.classList.remove("hide"); + headerHomeButton.classList.remove('hide'); } if (headerSearchButton) { - headerSearchButton.classList.remove("hide"); + headerSearchButton.classList.remove('hide'); } if (!layoutManager.tv) { - headerCastButton.classList.remove("hide"); + headerCastButton.classList.remove('hide'); } } else { - headerHomeButton.classList.add("hide"); - headerCastButton.classList.add("hide"); + headerHomeButton.classList.add('hide'); + headerCastButton.classList.add('hide'); if (headerSearchButton) { - headerSearchButton.classList.add("hide"); + headerSearchButton.classList.add('hide'); } } @@ -64,57 +98,81 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " function updateHeaderUserButton(src) { if (src) { - headerUserButton.classList.add("headerUserButtonRound"); + headerUserButton.classList.add('headerUserButtonRound'); headerUserButton.innerHTML = '
"; } else { - headerUserButton.classList.remove("headerUserButtonRound"); - headerUserButton.innerHTML = 'person'; + headerUserButton.classList.remove('headerUserButtonRound'); + headerUserButton.innerHTML = ''; } } function showSearch() { - inputManager.trigger("search"); + inputManager.trigger('search'); } function onHeaderUserButtonClick(e) { - Dashboard.navigate("mypreferencesmenu.html"); + Dashboard.navigate('mypreferencesmenu.html'); } function onHeaderHomeButtonClick() { - Dashboard.navigate("home.html"); + Dashboard.navigate('home.html'); + } + + function showAudioPlayer() { + return appRouter.showNowPlaying(); } function bindMenuEvents() { - mainDrawerButton = document.querySelector(".mainDrawerButton"); + mainDrawerButton = document.querySelector('.mainDrawerButton'); if (mainDrawerButton) { - mainDrawerButton.addEventListener("click", toggleMainDrawer); + mainDrawerButton.addEventListener('click', toggleMainDrawer); } - var headerBackButton = skinHeader.querySelector(".headerBackButton"); + var headerBackButton = skinHeader.querySelector('.headerBackButton'); if (headerBackButton) { - headerBackButton.addEventListener("click", onBackClick); + headerBackButton.addEventListener('click', onBackClick); } if (headerSearchButton) { - headerSearchButton.addEventListener("click", showSearch); + headerSearchButton.addEventListener('click', showSearch); } - headerUserButton.addEventListener("click", onHeaderUserButtonClick); - headerHomeButton.addEventListener("click", onHeaderHomeButtonClick); + headerUserButton.addEventListener('click', onHeaderUserButtonClick); + headerHomeButton.addEventListener('click', onHeaderHomeButtonClick); if (!layoutManager.tv) { - headerCastButton.addEventListener("click", onCastButtonClicked); + headerCastButton.addEventListener('click', onCastButtonClicked); } - initHeadRoom(skinHeader); + headerAudioPlayerButton.addEventListener('click', showAudioPlayer); + + if (layoutManager.mobile) { + initHeadRoom(skinHeader); + } + events.on(playbackManager, 'playbackstart', onPlaybackStart); + events.on(playbackManager, 'playbackstop', onPlaybackStop); + } + + function onPlaybackStart(e) { + if (playbackManager.isPlayingAudio() && layoutManager.tv) { + headerAudioPlayerButton.classList.remove('hide'); + } else { + headerAudioPlayerButton.classList.add('hide'); + } + } + + function onPlaybackStop(e, stopInfo) { + if (stopInfo.nextMediaType != 'Audio') { + headerAudioPlayerButton.classList.add('hide'); + } } function onCastButtonClicked() { var btn = this; - require(["playerSelectionMenu"], function (playerSelectionMenu) { + require(['playerSelectionMenu'], function (playerSelectionMenu) { playerSelectionMenu.show(btn); }); } @@ -140,7 +198,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " function onMainDrawerOpened() { if (layoutManager.mobile) { - document.body.classList.add("bodyWithPopupOpen"); + document.body.classList.add('bodyWithPopupOpen'); } } @@ -152,58 +210,63 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " if (navDrawerInstance.isVisible) { onMainDrawerOpened(); } else { - document.body.classList.remove("bodyWithPopupOpen"); + document.body.classList.remove('bodyWithPopupOpen'); } } function refreshLibraryInfoInDrawer(user, drawer) { - var html = ""; + var html = ''; html += '
'; - html += 'home' + globalize.translate("ButtonHome") + ""; + html += '' + globalize.translate('ButtonHome') + ''; // libraries are added here html += '
'; - html += "
"; + html += '
'; if (user.localUser && user.localUser.Policy.IsAdministrator) { html += '
'; html += '

'; - html += globalize.translate("HeaderAdmin"); - html += "

"; - html += 'dashboard' + globalize.translate("TabDashboard") + ""; - html += 'mode_edit' + globalize.translate("Metadata") + ""; - html += "
"; + html += globalize.translate('HeaderAdmin'); + html += ''; + html += '' + globalize.translate('TabDashboard') + ''; + html += '' + globalize.translate('Metadata') + ''; + html += '
'; } if (user.localUser) { html += '
'; html += '

'; - html += globalize.translate("HeaderUser"); - html += "

"; + html += globalize.translate('HeaderUser'); + html += ''; - if (appHost.supports("multiserver")) { - html += 'wifi' + globalize.translate("ButtonSelectServer") + ""; + if (appHost.supports('multiserver')) { + html += '' + globalize.translate('ButtonSelectServer') + ''; } - html += 'exit_to_app' + globalize.translate("ButtonSignOut") + ""; - html += "
"; + html += '' + globalize.translate('ButtonSettings') + ''; + html += '' + globalize.translate('ButtonSignOut') + ''; + html += '
'; } // add buttons to navigation drawer navDrawerScrollContainer.innerHTML = html; - // bind logout button click to method - var btnLogout = navDrawerScrollContainer.querySelector(".btnLogout"); + var btnSettings = navDrawerScrollContainer.querySelector('.btnSettings'); + if (btnSettings) { + btnSettings.addEventListener('click', onSettingsClick); + } + + var btnLogout = navDrawerScrollContainer.querySelector('.btnLogout'); if (btnLogout) { - btnLogout.addEventListener("click", onLogoutClick); + btnLogout.addEventListener('click', onLogoutClick); } } function refreshDashboardInfoInDrawer(apiClient) { - currentDrawerType = "admin"; + currentDrawerType = 'admin'; loadNavDrawer(); - if (navDrawerScrollContainer.querySelector(".adminDrawerLogo")) { + if (navDrawerScrollContainer.querySelector('.adminDrawerLogo')) { updateDashboardMenuSelectedItem(); } else { createDashboardMenu(apiClient); @@ -215,145 +278,145 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } function updateDashboardMenuSelectedItem() { - var links = navDrawerScrollContainer.querySelectorAll(".navMenuOption"); + var links = navDrawerScrollContainer.querySelectorAll('.navMenuOption'); var currentViewId = viewManager.currentView().id; for (var i = 0, length = links.length; i < length; i++) { var link = links[i]; var selected = false; - var pageIds = link.getAttribute("data-pageids"); + var pageIds = link.getAttribute('data-pageids'); if (pageIds) { - pageIds = pageIds.split("|"); + pageIds = pageIds.split('|'); selected = -1 != pageIds.indexOf(currentViewId); } - var pageUrls = link.getAttribute("data-pageurls"); + var pageUrls = link.getAttribute('data-pageurls'); if (pageUrls) { - pageUrls = pageUrls.split("|"); + pageUrls = pageUrls.split('|'); selected = pageUrls.filter(isUrlInCurrentView).length > 0; } if (selected) { - link.classList.add("navMenuOption-selected"); - var title = ""; - link = link.querySelector("span") || link; + link.classList.add('navMenuOption-selected'); + var title = ''; + link = link.querySelector('.navMenuOptionText') || link; title += (link.innerText || link.textContent).trim(); LibraryMenu.setTitle(title); } else { - link.classList.remove("navMenuOption-selected"); + link.classList.remove('navMenuOption-selected'); } } } function createToolsMenuList(pluginItems) { var links = [{ - name: globalize.translate("TabServer") + name: globalize.translate('TabServer') }, { - name: globalize.translate("TabDashboard"), - href: "dashboard.html", - pageIds: ["dashboardPage"], - icon: "dashboard" + name: globalize.translate('TabDashboard'), + href: 'dashboard.html', + pageIds: ['dashboardPage'], + icon: 'dashboard' }, { - name: globalize.translate("General"), - href: "dashboardgeneral.html", - pageIds: ["dashboardGeneralPage"], - icon: "settings" + name: globalize.translate('General'), + href: 'dashboardgeneral.html', + pageIds: ['dashboardGeneralPage'], + icon: 'settings' }, { - name: globalize.translate("TabUsers"), - href: "userprofiles.html", - pageIds: ["userProfilesPage", "newUserPage", "editUserPage", "userLibraryAccessPage", "userParentalControlPage", "userPasswordPage"], - icon: "people" + name: globalize.translate('TabUsers'), + href: 'userprofiles.html', + pageIds: ['userProfilesPage', 'newUserPage', 'editUserPage', 'userLibraryAccessPage', 'userParentalControlPage', 'userPasswordPage'], + icon: 'people' }, { - name: globalize.translate("HeaderLibraries"), - href: "library.html", - pageIds: ["mediaLibraryPage", "librarySettingsPage", "libraryDisplayPage", "metadataImagesConfigurationPage", "metadataNfoPage"], - icon: "folder" + name: globalize.translate('HeaderLibraries'), + href: 'library.html', + pageIds: ['mediaLibraryPage', 'librarySettingsPage', 'libraryDisplayPage', 'metadataImagesConfigurationPage', 'metadataNfoPage'], + icon: 'folder' }, { - name: globalize.translate("TabPlayback"), - icon: "play_arrow", - href: "encodingsettings.html", - pageIds: ["encodingSettingsPage", "playbackConfigurationPage", "streamingSettingsPage"] + name: globalize.translate('TabPlayback'), + icon: 'play_arrow', + href: 'encodingsettings.html', + pageIds: ['encodingSettingsPage', 'playbackConfigurationPage', 'streamingSettingsPage'] }]; - addPluginPagesToMainMenu(links, pluginItems, "server"); + addPluginPagesToMainMenu(links, pluginItems, 'server'); links.push({ divider: true, - name: globalize.translate("TabDevices") + name: globalize.translate('TabDevices') }); links.push({ - name: globalize.translate("TabDevices"), - href: "devices.html", - pageIds: ["devicesPage", "devicePage"], - icon: "devices" + name: globalize.translate('TabDevices'), + href: 'devices.html', + pageIds: ['devicesPage', 'devicePage'], + icon: 'devices' }); links.push({ - name: globalize.translate("HeaderActivity"), - href: "serveractivity.html", - pageIds: ["serverActivityPage"], - icon: "assessment" + name: globalize.translate('HeaderActivity'), + href: 'serveractivity.html', + pageIds: ['serverActivityPage'], + icon: 'assessment' }); links.push({ - name: globalize.translate("DLNA"), - href: "dlnasettings.html", - pageIds: ["dlnaSettingsPage", "dlnaProfilesPage", "dlnaProfilePage"], - icon: "input" + name: globalize.translate('DLNA'), + href: 'dlnasettings.html', + pageIds: ['dlnaSettingsPage', 'dlnaProfilesPage', 'dlnaProfilePage'], + icon: 'input' }); links.push({ divider: true, - name: globalize.translate("TabLiveTV") + name: globalize.translate('TabLiveTV') }); links.push({ - name: globalize.translate("TabLiveTV"), - href: "livetvstatus.html", - pageIds: ["liveTvStatusPage", "liveTvTunerPage"], - icon: "live_tv" + name: globalize.translate('TabLiveTV'), + href: 'livetvstatus.html', + pageIds: ['liveTvStatusPage', 'liveTvTunerPage'], + icon: 'live_tv' }); links.push({ - name: globalize.translate("DVR"), - href: "livetvsettings.html", - pageIds: ["liveTvSettingsPage"], - icon: "dvr" + name: globalize.translate('DVR'), + href: 'livetvsettings.html', + pageIds: ['liveTvSettingsPage'], + icon: 'dvr' }); links.push({ divider: true, - name: globalize.translate("TabAdvanced") + name: globalize.translate('TabAdvanced') }); links.push({ - name: globalize.translate("TabNetworking"), - icon: "cloud", - href: "networking.html", - pageIds: ["networkingPage"] + name: globalize.translate('TabNetworking'), + icon: 'cloud', + href: 'networking.html', + pageIds: ['networkingPage'] }); links.push({ - name: globalize.translate("HeaderApiKeys"), - icon: "vpn_key", - href: "apikeys.html", - pageIds: ["apiKeysPage"] + name: globalize.translate('HeaderApiKeys'), + icon: 'vpn_key', + href: 'apikeys.html', + pageIds: ['apiKeysPage'] }); links.push({ - name: globalize.translate("TabLogs"), - href: "log.html", - pageIds: ["logPage"], - icon: "bug_report" + name: globalize.translate('TabLogs'), + href: 'log.html', + pageIds: ['logPage'], + icon: 'bug_report' }); links.push({ - name: globalize.translate("TabNotifications"), - icon: "notifications", - href: "notificationsettings.html", - pageIds: ["notificationSettingsPage", "notificationSettingPage"] + name: globalize.translate('TabNotifications'), + icon: 'notifications', + href: 'notificationsettings.html', + pageIds: ['notificationSettingsPage', 'notificationSettingPage'] }); links.push({ - name: globalize.translate("TabPlugins"), - icon: "shopping_cart", - href: "installedplugins.html", - pageIds: ["pluginsPage", "pluginCatalogPage"] + name: globalize.translate('TabPlugins'), + icon: 'shopping_cart', + href: 'installedplugins.html', + pageIds: ['pluginsPage', 'pluginCatalogPage'] }); links.push({ - name: globalize.translate("TabScheduledTasks"), - href: "scheduledtasks.html", - pageIds: ["scheduledTasksPage", "scheduledTaskPage"], - icon: "schedule" + name: globalize.translate('TabScheduledTasks'), + href: 'scheduledtasks.html', + pageIds: ['scheduledTasksPage', 'scheduledTaskPage'], + icon: 'schedule' }); addPluginPagesToMainMenu(links, pluginItems); return links; @@ -366,7 +429,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " if (pluginItem.EnableInMainMenu && pluginItem.MenuSection === section) { links.push({ name: pluginItem.DisplayName, - icon: pluginItem.MenuIcon || "folder", + icon: pluginItem.MenuIcon || 'folder', href: Dashboard.getConfigurationPageUrl(pluginItem.Name), pageUrls: [Dashboard.getConfigurationPageUrl(pluginItem.Name)] }); @@ -375,33 +438,33 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } function getToolsMenuLinks(apiClient) { - return apiClient.getJSON(apiClient.getUrl("web/configurationpages") + "?pageType=PluginConfiguration&EnableInMainMenu=true").then(createToolsMenuList, function (err) { + return apiClient.getJSON(apiClient.getUrl('web/configurationpages') + '?pageType=PluginConfiguration&EnableInMainMenu=true').then(createToolsMenuList, function (err) { return createToolsMenuList([]); }); } function getToolsLinkHtml(item) { - var menuHtml = ""; - var pageIds = item.pageIds ? item.pageIds.join("|") : ""; - pageIds = pageIds ? ' data-pageids="' + pageIds + '"' : ""; - var pageUrls = item.pageUrls ? item.pageUrls.join("|") : ""; - pageUrls = pageUrls ? ' data-pageurls="' + pageUrls + '"' : ""; - menuHtml += '"; + var menuHtml = ''; + var pageIds = item.pageIds ? item.pageIds.join('|') : ''; + pageIds = pageIds ? ' data-pageids="' + pageIds + '"' : ''; + var pageUrls = item.pageUrls ? item.pageUrls.join('|') : ''; + pageUrls = pageUrls ? ' data-pageurls="' + pageUrls + '"' : ''; + menuHtml += ''; if (item.icon) { - menuHtml += '' + item.icon + ""; + menuHtml += ''; } menuHtml += ''; menuHtml += item.name; - menuHtml += ""; - return menuHtml + ""; + menuHtml += ''; + return menuHtml + ''; } function getToolsMenuHtml(apiClient) { return getToolsMenuLinks(apiClient).then(function (items) { var item; - var menuHtml = ""; + var menuHtml = ''; menuHtml += '
'; for (var i = 0; i < items.length; i++) { @@ -412,20 +475,20 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } else if (item.name) { menuHtml += '

'; menuHtml += item.name; - menuHtml += "

"; + menuHtml += ''; } } - return menuHtml + "
"; + return menuHtml + '
'; }); } function createDashboardMenu(apiClient) { return getToolsMenuHtml(apiClient).then(function (toolsMenuHtml) { - var html = ""; + var html = ''; html += '"; + html += ''; + html += ''; html += toolsMenuHtml; navDrawerScrollContainer.innerHTML = html; updateDashboardMenuSelectedItem(); @@ -433,7 +496,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } function onSidebarLinkClick() { - var section = this.getElementsByClassName("sectionName")[0]; + var section = this.getElementsByClassName('sectionName')[0]; var text = section ? section.innerHTML : this.innerHTML; LibraryMenu.setTitle(text); } @@ -447,14 +510,14 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " var view = items[i]; list.push(view); - if ("livetv" == view.CollectionType) { + if ('livetv' == view.CollectionType) { view.ImageTags = {}; - view.icon = "live_tv"; + view.icon = 'live_tv'; var guideView = Object.assign({}, view); - guideView.Name = globalize.translate("ButtonGuide"); + guideView.Name = globalize.translate('ButtonGuide'); guideView.ImageTags = {}; - guideView.icon = "dvr"; - guideView.url = "livetv.html?tab=1"; + guideView.icon = 'dvr'; + guideView.url = 'livetv.html?tab=1'; list.push(guideView); } } @@ -468,9 +531,9 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " if (elem) { if (show) { - elem.classList.remove("hide"); + elem.classList.remove('hide'); } else { - elem.classList.add("hide"); + elem.classList.add('hide'); } } } @@ -479,35 +542,35 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " // FIXME: Potential equivalent might be // showBySelector(".lnkSyncToOtherDevices", !!user.Policy.EnableContentDownloading); if (!user) { - showBySelector(".libraryMenuDownloads", false); - showBySelector(".lnkSyncToOtherDevices", false); - return void showBySelector(".userMenuOptions", false); + showBySelector('.libraryMenuDownloads', false); + showBySelector('.lnkSyncToOtherDevices', false); + return void showBySelector('.userMenuOptions', false); } // FIXME: Potentially the same as above if (user.Policy.EnableContentDownloading) { - showBySelector(".lnkSyncToOtherDevices", true); + showBySelector('.lnkSyncToOtherDevices', true); } else { - showBySelector(".lnkSyncToOtherDevices", false); + showBySelector('.lnkSyncToOtherDevices', false); } - if (user.Policy.EnableContentDownloading && appHost.supports("sync")) { - showBySelector(".libraryMenuDownloads", true); + if (user.Policy.EnableContentDownloading && appHost.supports('sync')) { + showBySelector('.libraryMenuDownloads', true); } else { - showBySelector(".libraryMenuDownloads", false); + showBySelector('.libraryMenuDownloads', false); } var userId = Dashboard.getCurrentUserId(); var apiClient = getCurrentApiClient(); - var libraryMenuOptions = document.querySelector(".libraryMenuOptions"); + var libraryMenuOptions = document.querySelector('.libraryMenuOptions'); if (libraryMenuOptions) { getUserViews(apiClient, userId).then(function (result) { var items = result; - var html = ""; + var html = ''; html += '

'; - html += globalize.translate("HeaderMedia"); - html += "

"; + html += globalize.translate('HeaderMedia'); + html += ''; html += items.map(function (i) { var icon = i.icon || imageHelper.getLibraryIcon(i.CollectionType); var itemId = i.Id; @@ -516,30 +579,34 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " i.onclick; } - return '' + icon + '' + i.Name + ""; - }).join(""); + return '' + i.Name + ''; + }).join(''); libraryMenuOptions.innerHTML = html; var elem = libraryMenuOptions; - var sidebarLinks = elem.querySelectorAll(".navMenuOption"); + var sidebarLinks = elem.querySelectorAll('.navMenuOption'); for (var i = 0, length = sidebarLinks.length; i < length; i++) { - sidebarLinks[i].removeEventListener("click", onSidebarLinkClick); - sidebarLinks[i].addEventListener("click", onSidebarLinkClick); + sidebarLinks[i].removeEventListener('click', onSidebarLinkClick); + sidebarLinks[i].addEventListener('click', onSidebarLinkClick); } }); } } function getTopParentId() { - return getParameterByName("topParentId") || null; + return getParameterByName('topParentId') || null; } function onMainDrawerClick(e) { - if (dom.parentWithTag(e.target, "A")) { + if (dom.parentWithTag(e.target, 'A')) { setTimeout(closeMainDrawer, 30); } } + function onSettingsClick() { + Dashboard.navigate('mypreferencesmenu.html'); + } + function onLogoutClick() { Dashboard.logout(); } @@ -547,47 +614,49 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " function updateCastIcon() { var context = document; var info = playbackManager.getPlayerInfo(); - var icon = headerCastButton.querySelector("i"); + var icon = headerCastButton.querySelector('.material-icons'); + + icon.classList.remove('cast_connected', 'cast'); if (info && !info.isLocalPlayer) { - icon.innerHTML = "cast_connected"; - headerCastButton.classList.add("castButton-active"); - context.querySelector(".headerSelectedPlayer").innerHTML = info.deviceName || info.name; + icon.classList.add('cast_connected'); + headerCastButton.classList.add('castButton-active'); + context.querySelector('.headerSelectedPlayer').innerHTML = info.deviceName || info.name; } else { - icon.innerHTML = "cast"; - headerCastButton.classList.remove("castButton-active"); - context.querySelector(".headerSelectedPlayer").innerHTML = ""; + icon.classList.add('cast'); + headerCastButton.classList.remove('castButton-active'); + context.querySelector('.headerSelectedPlayer').innerHTML = ''; } } function updateLibraryNavLinks(page) { var i; var length; - var isLiveTvPage = page.classList.contains("liveTvPage"); - var isChannelsPage = page.classList.contains("channelsPage"); - var isEditorPage = page.classList.contains("metadataEditorPage"); - var isMySyncPage = page.classList.contains("mySyncPage"); - var id = isLiveTvPage || isChannelsPage || isEditorPage || isMySyncPage || page.classList.contains("allLibraryPage") ? "" : getTopParentId() || ""; - var elems = document.getElementsByClassName("lnkMediaFolder"); + var isLiveTvPage = page.classList.contains('liveTvPage'); + var isChannelsPage = page.classList.contains('channelsPage'); + var isEditorPage = page.classList.contains('metadataEditorPage'); + var isMySyncPage = page.classList.contains('mySyncPage'); + var id = isLiveTvPage || isChannelsPage || isEditorPage || isMySyncPage || page.classList.contains('allLibraryPage') ? '' : getTopParentId() || ''; + var elems = document.getElementsByClassName('lnkMediaFolder'); for (var i = 0, length = elems.length; i < length; i++) { var lnkMediaFolder = elems[i]; - var itemId = lnkMediaFolder.getAttribute("data-itemid"); + var itemId = lnkMediaFolder.getAttribute('data-itemid'); - if (isChannelsPage && "channels" === itemId) { - lnkMediaFolder.classList.add("navMenuOption-selected"); - } else if (isLiveTvPage && "livetv" === itemId) { - lnkMediaFolder.classList.add("navMenuOption-selected"); - } else if (isEditorPage && "editor" === itemId) { - lnkMediaFolder.classList.add("navMenuOption-selected"); - } else if (isMySyncPage && "manageoffline" === itemId && -1 != window.location.href.toString().indexOf("mode=download")) { - lnkMediaFolder.classList.add("navMenuOption-selected"); - } else if (isMySyncPage && "syncotherdevices" === itemId && -1 == window.location.href.toString().indexOf("mode=download")) { - lnkMediaFolder.classList.add("navMenuOption-selected"); + if (isChannelsPage && 'channels' === itemId) { + lnkMediaFolder.classList.add('navMenuOption-selected'); + } else if (isLiveTvPage && 'livetv' === itemId) { + lnkMediaFolder.classList.add('navMenuOption-selected'); + } else if (isEditorPage && 'editor' === itemId) { + lnkMediaFolder.classList.add('navMenuOption-selected'); + } else if (isMySyncPage && 'manageoffline' === itemId && -1 != window.location.href.toString().indexOf('mode=download')) { + lnkMediaFolder.classList.add('navMenuOption-selected'); + } else if (isMySyncPage && 'syncotherdevices' === itemId && -1 == window.location.href.toString().indexOf('mode=download')) { + lnkMediaFolder.classList.add('navMenuOption-selected'); } else if (id && itemId == id) { - lnkMediaFolder.classList.add("navMenuOption-selected"); + lnkMediaFolder.classList.add('navMenuOption-selected'); } else { - lnkMediaFolder.classList.remove("navMenuOption-selected"); + lnkMediaFolder.classList.remove('navMenuOption-selected'); } } } @@ -599,34 +668,34 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " currentPageType = newPageType; if (isDashboardPage && !layoutManager.mobile) { - skinHeader.classList.add("headroomDisabled"); + skinHeader.classList.add('headroomDisabled'); } else { - skinHeader.classList.remove("headroomDisabled"); + skinHeader.classList.remove('headroomDisabled'); } var bodyClassList = document.body.classList; if (isLibraryPage) { - bodyClassList.add("libraryDocument"); - bodyClassList.remove("dashboardDocument"); - bodyClassList.remove("hideMainDrawer"); + bodyClassList.add('libraryDocument'); + bodyClassList.remove('dashboardDocument'); + bodyClassList.remove('hideMainDrawer'); if (navDrawerInstance) { navDrawerInstance.setEdgeSwipeEnabled(true); } } else { if (isDashboardPage) { - bodyClassList.remove("libraryDocument"); - bodyClassList.add("dashboardDocument"); - bodyClassList.remove("hideMainDrawer"); + bodyClassList.remove('libraryDocument'); + bodyClassList.add('dashboardDocument'); + bodyClassList.remove('hideMainDrawer'); if (navDrawerInstance) { navDrawerInstance.setEdgeSwipeEnabled(true); } } else { - bodyClassList.remove("libraryDocument"); - bodyClassList.remove("dashboardDocument"); - bodyClassList.add("hideMainDrawer"); + bodyClassList.remove('libraryDocument'); + bodyClassList.remove('dashboardDocument'); + bodyClassList.add('hideMainDrawer'); if (navDrawerInstance) { navDrawerInstance.setEdgeSwipeEnabled(false); @@ -641,39 +710,39 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " } function updateTitle(page) { - var title = page.getAttribute("data-title"); + var title = page.getAttribute('data-title'); if (title) { LibraryMenu.setTitle(title); - } else if (page.classList.contains("standalonePage")) { + } else if (page.classList.contains('standalonePage')) { LibraryMenu.setDefaultTitle(); } } function updateBackButton(page) { if (!headerBackButton) { - headerBackButton = document.querySelector(".headerBackButton"); + headerBackButton = document.querySelector('.headerBackButton'); } if (headerBackButton) { - if ("false" !== page.getAttribute("data-backbutton") && appRouter.canGoBack()) { - headerBackButton.classList.remove("hide"); + if ('false' !== page.getAttribute('data-backbutton') && appRouter.canGoBack()) { + headerBackButton.classList.remove('hide'); } else { - headerBackButton.classList.add("hide"); + headerBackButton.classList.add('hide'); } } } function initHeadRoom(elem) { - require(["headroom"], function (Headroom) { - var headroom = new Headroom([], {}); - headroom.add(elem); + require(['headroom'], function (Headroom) { + var headroom = new Headroom(elem); + headroom.init(); }); } function refreshLibraryDrawer(user) { loadNavDrawer(); - currentDrawerType = "library"; + currentDrawerType = 'library'; if (user) { Promise.resolve(user); @@ -701,15 +770,15 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " return Promise.resolve(navDrawerInstance); } - navDrawerElement = document.querySelector(".mainDrawer"); - navDrawerScrollContainer = navDrawerElement.querySelector(".scrollContainer"); - navDrawerScrollContainer.addEventListener("click", onMainDrawerClick); + navDrawerElement = document.querySelector('.mainDrawer'); + navDrawerScrollContainer = navDrawerElement.querySelector('.scrollContainer'); + navDrawerScrollContainer.addEventListener('click', onMainDrawerClick); return new Promise(function (resolve, reject) { - require(["navdrawer"], function (navdrawer) { + require(['navdrawer'], function (navdrawer) { navDrawerInstance = new navdrawer(getNavDrawerOptions()); if (!layoutManager.tv) { - navDrawerElement.classList.remove("hide"); + navDrawerElement.classList.remove('hide'); } resolve(navDrawerInstance); @@ -729,8 +798,9 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " var currentUser; var headerCastButton; var headerSearchButton; - var enableLibraryNavDrawer = !layoutManager.tv; - var skinHeader = document.querySelector(".skinHeader"); + var headerAudioPlayerButton; + var enableLibraryNavDrawer = layoutManager.desktop; + var skinHeader = document.querySelector('.skinHeader'); var requiresUserRefresh = true; var lastOpenTime = new Date().getTime(); window.LibraryMenu = { @@ -739,7 +809,7 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " toggleMainDrawer(); }, setTabs: function (type, selectedIndex, builder) { - require(["mainTabsManager"], function (mainTabsManager) { + require(['mainTabsManager'], function (mainTabsManager) { if (type) { mainTabsManager.setTabs(viewManager.currentView(), selectedIndex, builder, function () { return []; @@ -751,78 +821,79 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " }, setDefaultTitle: function () { if (!pageTitleElement) { - pageTitleElement = document.querySelector(".pageTitle"); + pageTitleElement = document.querySelector('.pageTitle'); } if (pageTitleElement) { - pageTitleElement.classList.add("pageTitleWithLogo"); - pageTitleElement.classList.add("pageTitleWithDefaultLogo"); + pageTitleElement.classList.add('pageTitleWithLogo'); + pageTitleElement.classList.add('pageTitleWithDefaultLogo'); pageTitleElement.style.backgroundImage = null; - pageTitleElement.innerHTML = ""; + pageTitleElement.innerHTML = ''; } - document.title = "Jellyfin"; + document.title = 'Jellyfin'; }, setTitle: function (title) { if (null == title) { return void LibraryMenu.setDefaultTitle(); } - if ("-" === title) { - title = ""; + if ('-' === title) { + title = ''; } var html = title; if (!pageTitleElement) { - pageTitleElement = document.querySelector(".pageTitle"); + pageTitleElement = document.querySelector('.pageTitle'); } if (pageTitleElement) { - pageTitleElement.classList.remove("pageTitleWithLogo"); - pageTitleElement.classList.remove("pageTitleWithDefaultLogo"); + pageTitleElement.classList.remove('pageTitleWithLogo'); + pageTitleElement.classList.remove('pageTitleWithDefaultLogo'); pageTitleElement.style.backgroundImage = null; - pageTitleElement.innerHTML = html || ""; + pageTitleElement.innerHTML = html || ''; } - document.title = title || "Jellyfin"; + document.title = title || 'Jellyfin'; }, setTransparentMenu: function (transparent) { if (transparent) { - skinHeader.classList.add("semiTransparent"); + skinHeader.classList.add('semiTransparent'); } else { - skinHeader.classList.remove("semiTransparent"); + skinHeader.classList.remove('semiTransparent'); } } }; var currentPageType; - pageClassOn("pagebeforeshow", "page", function (e) { - if (!this.classList.contains("withTabs")) { + pageClassOn('pagebeforeshow', 'page', function (e) { + if (!this.classList.contains('withTabs')) { LibraryMenu.setTabs(null); } }); - pageClassOn("pageshow", "page", function (e) { + pageClassOn('pageshow', 'page', function (e) { var page = this; - var isDashboardPage = page.classList.contains("type-interior"); - var isLibraryPage = !isDashboardPage && page.classList.contains("libraryPage"); + var isDashboardPage = page.classList.contains('type-interior'); + var isHomePage = page.classList.contains('homePage'); + var isLibraryPage = !isDashboardPage && page.classList.contains('libraryPage'); var apiClient = getCurrentApiClient(); if (isDashboardPage) { if (mainDrawerButton) { - mainDrawerButton.classList.remove("hide"); + mainDrawerButton.classList.remove('hide'); } refreshDashboardInfoInDrawer(apiClient); } else { if (mainDrawerButton) { - if (enableLibraryNavDrawer) { - mainDrawerButton.classList.remove("hide"); + if (enableLibraryNavDrawer || isHomePage) { + mainDrawerButton.classList.remove('hide'); } else { - mainDrawerButton.classList.add("hide"); + mainDrawerButton.classList.add('hide'); } } - if ("library" !== currentDrawerType) { + if ('library' !== currentDrawerType) { refreshLibraryDrawer(); } } @@ -838,54 +909,28 @@ define(["dom", "layoutManager", "inputManager", "connectionManager", "events", " updateLibraryNavLinks(page); }); - (function () { - var html = ""; - html += '
'; - html += '
'; - html += '"; - html += ''; - html += ''; - html += '

'; - html += "
"; - html += '
'; - html += ''; - html += ''; - html += ''; - html += ''; - html += "
"; - html += "
"; - html += '
'; - html += "
"; + renderHeader(); - skinHeader.classList.add("skinHeader-withBackground"); - skinHeader.classList.add("skinHeader-blurred"); - skinHeader.innerHTML = html; + events.on(connectionManager, 'localusersignedin', function (e, user) { + var currentApiClient = connectionManager.getApiClient(user.ServerId); - headerHomeButton = skinHeader.querySelector(".headerHomeButton"); - headerUserButton = skinHeader.querySelector(".headerUserButton"); - headerCastButton = skinHeader.querySelector(".headerCastButton"); - headerSearchButton = skinHeader.querySelector(".headerSearchButton"); - - lazyLoadViewMenuBarImages(); - bindMenuEvents(); - })(); - - events.on(connectionManager, "localusersignedin", function (e, user) { currentDrawerType = null; currentUser = { localUser: user }; + loadNavDrawer(); - connectionManager.user(connectionManager.getApiClient(user.ServerId)).then(function (user) { + + connectionManager.user(currentApiClient).then(function (user) { currentUser = user; updateUserInHeader(user); }); }); - events.on(connectionManager, "localusersignedout", function () { + events.on(connectionManager, 'localusersignedout', function () { currentUser = {}; updateUserInHeader(); }); - events.on(playbackManager, "playerchange", updateCastIcon); + events.on(playbackManager, 'playerchange', updateCastIcon); loadNavDrawer(); return LibraryMenu; }); diff --git a/src/scripts/livetvcomponents.js b/src/scripts/livetvcomponents.js index 4215de4cbe..fd4a46c0f1 100644 --- a/src/scripts/livetvcomponents.js +++ b/src/scripts/livetvcomponents.js @@ -1,12 +1,12 @@ -define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layoutManager, datetime, cardBuilder, appHost) { - "use strict"; +define(['layoutManager', 'datetime', 'cardBuilder', 'apphost'], function (layoutManager, datetime, cardBuilder, appHost) { + 'use strict'; function enableScrollX() { return !layoutManager.desktop; } function getBackdropShape() { - return enableScrollX() ? "overflowBackdrop" : "backdrop"; + return enableScrollX() ? 'overflowBackdrop' : 'backdrop'; } function getTimersHtml(timers, options) { @@ -14,27 +14,27 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout var i; var length; var items = timers.map(function (t) { - t.Type = "Timer"; + t.Type = 'Timer'; return t; }); var groups = []; - var currentGroupName = ""; + var currentGroupName = ''; var currentGroup = []; for (i = 0, length = items.length; i < length; i++) { var item = items[i]; - var dateText = ""; + var dateText = ''; if (options.indexByDate !== false && item.StartDate) { try { var premiereDate = datetime.parseISO8601Date(item.StartDate, true); dateText = datetime.toLocaleDateString(premiereDate, { - weekday: "long", - month: "short", - day: "numeric" + weekday: 'long', + month: 'short', + day: 'numeric' }); } catch (err) { - console.log("Error parsing premiereDate:" + item.StartDate + "; error: " + err); + console.error('error parsing premiereDate:' + item.StartDate + '; error: ' + err); } } @@ -60,23 +60,23 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout }); } - var html = ""; + var html = ''; for (i = 0, length = groups.length; i < length; i++) { var group = groups[i]; - var supportsImageAnalysis = appHost.supports("imageanalysis"); + var supportsImageAnalysis = appHost.supports('imageanalysis'); var cardLayout = appHost.preferVisualCards || supportsImageAnalysis; cardLayout = true; if (group.name) { html += '
'; - html += '

' + group.name + "

"; + html += '

' + group.name + '

'; } if (enableScrollX()) { - var scrollXClass = "scrollX hiddenScrollX"; + var scrollXClass = 'scrollX hiddenScrollX'; if (layoutManager.tv) { - scrollXClass += " smoothScrollX"; + scrollXClass += ' smoothScrollX'; } html += '
'; @@ -86,26 +86,26 @@ define(["layoutManager", "datetime", "cardBuilder", "apphost"], function (layout html += cardBuilder.getCardsHtml({ items: group.items, - shape: cardLayout ? getBackdropShape() : enableScrollX() ? "autoOverflow" : "autoVertical", + shape: cardLayout ? getBackdropShape() : enableScrollX() ? 'autoOverflow' : 'autoVertical', showParentTitleOrTitle: true, showAirTime: true, showAirEndTime: true, showChannelName: !cardLayout, cardLayout: cardLayout, centerText: !cardLayout, - action: "edit", - cardFooterAside: "none", - preferThumb: !!cardLayout || "auto", - defaultShape: cardLayout ? null : "portrait", + action: 'edit', + cardFooterAside: 'none', + preferThumb: !!cardLayout || 'auto', + defaultShape: cardLayout ? null : 'portrait', coverImage: true, allowBottomPadding: false, overlayText: false, showChannelLogo: cardLayout }); - html += "
"; + html += '
'; if (group.name) { - html += "
"; + html += '
'; } } diff --git a/src/components/serverNotifications/mouseManager.js b/src/scripts/mouseManager.js similarity index 97% rename from src/components/serverNotifications/mouseManager.js rename to src/scripts/mouseManager.js index ffea3b01ff..e6117fa851 100644 --- a/src/components/serverNotifications/mouseManager.js +++ b/src/scripts/mouseManager.js @@ -41,7 +41,7 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd var eventY = e.screenY; // if coord don't exist how could it move - if (typeof eventX === "undefined" && typeof eventY === "undefined") { + if (typeof eventX === 'undefined' && typeof eventY === 'undefined') { return; } @@ -166,4 +166,4 @@ define(['inputManager', 'focusManager', 'browser', 'layoutManager', 'events', 'd events.on(layoutManager, 'modechange', initMouse); return self; -}); \ No newline at end of file +}); diff --git a/src/scripts/playlistedit.js b/src/scripts/playlistedit.js index 32a3a960a4..636a7ef056 100644 --- a/src/scripts/playlistedit.js +++ b/src/scripts/playlistedit.js @@ -1,14 +1,14 @@ -define(["listView"], function (listView) { - "use strict"; +define(['listView'], function (listView) { + 'use strict'; function getFetchPlaylistItemsFn(itemId) { return function () { var query = { - Fields: "PrimaryImageAspectRatio,UserData", - EnableImageTypes: "Primary,Backdrop,Banner,Thumb", + Fields: 'PrimaryImageAspectRatio,UserData', + EnableImageTypes: 'Primary,Backdrop,Banner,Thumb', UserId: ApiClient.getCurrentUserId() }; - return ApiClient.getJSON(ApiClient.getUrl("Playlists/" + itemId + "/Items", query)); + return ApiClient.getJSON(ApiClient.getUrl(`Playlists/${itemId}/Items`, query)); }; } @@ -19,7 +19,7 @@ define(["listView"], function (listView) { showIndex: false, showRemoveFromPlaylist: true, playFromHere: true, - action: "playallfromhere", + action: 'playallfromhere', smallIcon: true, dragHandle: true, playlistId: itemId @@ -28,9 +28,9 @@ define(["listView"], function (listView) { } function init(page, item) { - var elem = page.querySelector("#childrenContent .itemsContainer"); - elem.classList.add("vertical-list"); - elem.classList.remove("vertical-wrap"); + var elem = page.querySelector('#childrenContent .itemsContainer'); + elem.classList.add('vertical-list'); + elem.classList.remove('vertical-wrap'); elem.enableDragReordering(true); elem.fetchData = getFetchPlaylistItemsFn(item.Id); elem.getItemsHtml = getItemsHtmlFn(item.Id); @@ -43,8 +43,8 @@ define(["listView"], function (listView) { init(page, item); } - page.querySelector("#childrenContent").classList.add("verticalSection-extrabottompadding"); - page.querySelector("#childrenContent .itemsContainer").refreshItems(); + page.querySelector('#childrenContent').classList.add('verticalSection-extrabottompadding'); + page.querySelector('#childrenContent .itemsContainer').refreshItems(); } }; }); diff --git a/src/scripts/playlists.js b/src/scripts/playlists.js index 91c49017da..52e7ccb3bd 100644 --- a/src/scripts/playlists.js +++ b/src/scripts/playlists.js @@ -1,5 +1,5 @@ -define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", "apphost", "imageLoader", "emby-itemscontainer"], function (loading, listView, cardBuilder, libraryMenu, libraryBrowser, appHost, imageLoader) { - "use strict"; +define(['loading', 'listView', 'cardBuilder', 'libraryMenu', 'libraryBrowser', 'apphost', 'imageLoader', 'userSettings', 'emby-itemscontainer'], function (loading, listView, cardBuilder, libraryMenu, libraryBrowser, appHost, imageLoader, userSettings) { + 'use strict'; return function (view, params) { function getPageData(context) { @@ -9,16 +9,20 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " if (!pageData) { pageData = data[key] = { query: { - SortBy: "SortName", - SortOrder: "Ascending", - IncludeItemTypes: "Playlist", + SortBy: 'SortName', + SortOrder: 'Ascending', + IncludeItemTypes: 'Playlist', Recursive: true, - Fields: "PrimaryImageAspectRatio,SortName,CumulativeRunTimeTicks,CanDelete", - StartIndex: 0, - Limit: 100 + Fields: 'PrimaryImageAspectRatio,SortName,CumulativeRunTimeTicks,CanDelete', + StartIndex: 0 }, - view: libraryBrowser.getSavedView(key) || "Poster" + view: libraryBrowser.getSavedView(key) || 'Poster' }; + + if (userSettings.libraryPageSize() > 0) { + pageData.query['Limit'] = userSettings.libraryPageSize(); + } + pageData.query.ParentId = libraryMenu.getTopParentId(); libraryBrowser.loadSavedQueryValues(key, pageData.query); } @@ -48,17 +52,17 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " function onViewStyleChange() { var viewStyle = getPageData(view).view; - var itemsContainer = view.querySelector(".itemsContainer"); + var itemsContainer = view.querySelector('.itemsContainer'); - if ("List" == viewStyle) { - itemsContainer.classList.add("vertical-list"); - itemsContainer.classList.remove("vertical-wrap"); + if ('List' == viewStyle) { + itemsContainer.classList.add('vertical-list'); + itemsContainer.classList.remove('vertical-wrap'); } else { - itemsContainer.classList.remove("vertical-list"); - itemsContainer.classList.add("vertical-wrap"); + itemsContainer.classList.remove('vertical-list'); + itemsContainer.classList.add('vertical-wrap'); } - itemsContainer.innerHTML = ""; + itemsContainer.innerHTML = ''; } function reloadItems() { @@ -70,9 +74,9 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " var result = responses[0]; responses[1]; window.scrollTo(0, 0); - var html = ""; + var html = ''; var viewStyle = getPageData(view).view; - view.querySelector(".listTopPaging").innerHTML = libraryBrowser.getQueryPagingHtml({ + view.querySelector('.listTopPaging').innerHTML = libraryBrowser.getQueryPagingHtml({ startIndex: query.StartIndex, limit: query.Limit, totalRecordCount: result.TotalRecordCount, @@ -80,37 +84,37 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " showLimit: false, updatePageSizeSetting: false, addLayoutButton: true, - layouts: "List,Poster,PosterCard,Thumb,ThumbCard", + layouts: 'List,Poster,PosterCard,Thumb,ThumbCard', currentLayout: viewStyle }); if (result.TotalRecordCount) { - if (viewStyle == "List") { + if (viewStyle == 'List') { html = listView.getListViewHtml({ items: result.Items, sortBy: query.SortBy }); - } else if (viewStyle == "PosterCard") { + } else if (viewStyle == 'PosterCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", + shape: 'square', coverImage: true, showTitle: true, cardLayout: true }); - } else if (viewStyle == "Thumb") { + } else if (viewStyle == 'Thumb') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', showTitle: true, centerText: true, preferThumb: true, overlayPlayButton: true }); - } else if (viewStyle == "ThumbCard") { + } else if (viewStyle == 'ThumbCard') { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "backdrop", + shape: 'backdrop', showTitle: true, preferThumb: true, cardLayout: true @@ -118,43 +122,47 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " } else { html = cardBuilder.getCardsHtml({ items: result.Items, - shape: "square", + shape: 'square', showTitle: true, coverImage: true, centerText: true, overlayPlayButton: true }); } - view.querySelector(".noItemsMessage").classList.add("hide"); + view.querySelector('.noItemsMessage').classList.add('hide'); } else { - view.querySelector(".noItemsMessage").classList.remove("hide"); + view.querySelector('.noItemsMessage').classList.remove('hide'); } - var elem = view.querySelector(".itemsContainer"); + var elem = view.querySelector('.itemsContainer'); elem.innerHTML = html; imageLoader.lazyChildren(elem); - var btnNextPage = view.querySelector(".btnNextPage"); + var btnNextPage = view.querySelector('.btnNextPage'); if (btnNextPage) { - btnNextPage.addEventListener("click", function () { - query.StartIndex += query.Limit; + btnNextPage.addEventListener('click', function () { + if (userSettings.libraryPageSize() > 0) { + query.StartIndex += query.Limit; + } reloadItems(); }); } - var btnPreviousPage = view.querySelector(".btnPreviousPage"); + var btnPreviousPage = view.querySelector('.btnPreviousPage'); if (btnPreviousPage) { - btnPreviousPage.addEventListener("click", function () { - query.StartIndex -= query.Limit; + btnPreviousPage.addEventListener('click', function () { + if (userSettings.libraryPageSize() > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + } reloadItems(); }); } - var btnChangeLayout = view.querySelector(".btnChangeLayout"); + var btnChangeLayout = view.querySelector('.btnChangeLayout'); if (btnChangeLayout) { - btnChangeLayout.addEventListener("layoutchange", function (e) { + btnChangeLayout.addEventListener('layoutchange', function (e) { var layout = e.detail.viewStyle; getPageData(view).view = layout; libraryBrowser.saveViewSetting(getSavedQueryKey(view), layout); @@ -169,11 +177,11 @@ define(["loading", "listView", "cardBuilder", "libraryMenu", "libraryBrowser", " } var data = {}; - view.addEventListener("viewbeforeshow", function () { + view.addEventListener('viewbeforeshow', function () { reloadItems(); }); - view.querySelector(".btnNewPlaylist").addEventListener("click", function () { - require(["playlistEditor"], function (playlistEditor) { + view.querySelector('.btnNewPlaylist').addEventListener('click', function () { + require(['playlistEditor'], function (playlistEditor) { var serverId = ApiClient.serverInfo().Id; new playlistEditor().show({ items: [], diff --git a/src/scripts/routes.js b/src/scripts/routes.js index a3427c6551..a5ed0a00af 100644 --- a/src/scripts/routes.js +++ b/src/scripts/routes.js @@ -1,437 +1,436 @@ define([ - "jQuery", - "emby-button", - "emby-input", - "scripts/livetvcomponents", - "paper-icon-button-light", - "emby-itemscontainer", - "emby-collapse", - "emby-select", - "livetvcss", - "emby-checkbox", - "emby-slider", - "listViewStyle", - "dashboardcss", - "detailtablecss"], function () { + 'jQuery', + 'emby-button', + 'emby-input', + 'scripts/livetvcomponents', + 'paper-icon-button-light', + 'emby-itemscontainer', + 'emby-collapse', + 'emby-select', + 'livetvcss', + 'emby-checkbox', + 'emby-slider', + 'listViewStyle', + 'dashboardcss', + 'detailtablecss'], function () { function defineRoute(newRoute) { var path = newRoute.path; - console.log("defining route: " + path); - newRoute.dictionary = "core"; + console.debug('defining route: ' + path); + newRoute.dictionary = 'core'; Emby.Page.addRoute(path, newRoute); } - console.log("defining core routes"); + console.debug('defining core routes'); defineRoute({ - path: "/addplugin.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/plugins/add" - }); - defineRoute({ - path: "/mypreferencesmenu.html", - autoFocus: false, - transition: "fade", - controller: "user/menu" - }); - defineRoute({ - path: "/myprofile.html", - autoFocus: false, - transition: "fade", - controller: "user/profile" - }); - defineRoute({ - path: "/addserver.html", + path: '/addserver.html', autoFocus: false, anonymous: true, startup: true, - controller: "auth/addserver" + controller: 'auth/addserver' }); defineRoute({ - path: "/mypreferencesdisplay.html", + path: '/selectserver.html', autoFocus: false, - transition: "fade", - controller: "user/display" + anonymous: true, + startup: true, + controller: 'auth/selectserver', + type: 'selectserver' }); defineRoute({ - path: "/mypreferenceshome.html", + path: '/login.html', autoFocus: false, - transition: "fade", - controller: "user/home" + anonymous: true, + startup: true, + controller: 'auth/login', + type: 'login' }); defineRoute({ - path: "/mypreferencesplayback.html", - autoFocus: false, - transition: "fade", - controller: "user/playback" + path: '/forgotpassword.html', + anonymous: true, + startup: true, + controller: 'auth/forgotpassword' }); defineRoute({ - path: "/mypreferencessubtitles.html", + path: '/forgotpasswordpin.html', autoFocus: false, - transition: "fade", - controller: "user/subtitles" + anonymous: true, + startup: true, + controller: 'auth/forgotpasswordpin' }); defineRoute({ - path: "/dashboard.html", + path: '/mypreferencesmenu.html', autoFocus: false, - roles: "admin", - controller: "dashboard/dashboard" + transition: 'fade', + controller: 'user/menu' }); defineRoute({ - path: "/dashboardgeneral.html", - controller: "dashboard/general", + path: '/myprofile.html', autoFocus: false, - roles: "admin" + transition: 'fade', + controller: 'user/profile' }); defineRoute({ - path: "/networking.html", + path: '/mypreferencesdisplay.html', autoFocus: false, - roles: "admin", - controller: "dashboard/networking" + transition: 'fade', + controller: 'user/display' }); defineRoute({ - path: "/devices.html", + path: '/mypreferenceshome.html', autoFocus: false, - roles: "admin", - controller: "devices" + transition: 'fade', + controller: 'user/home' }); defineRoute({ - path: "/device.html", + path: '/mypreferencesplayback.html', autoFocus: false, - roles: "admin", - controller: "device" + transition: 'fade', + controller: 'user/playback' }); defineRoute({ - path: "/dlnaprofile.html", + path: '/mypreferencessubtitles.html', autoFocus: false, - roles: "admin", - controller: "dlnaprofile" + transition: 'fade', + controller: 'user/subtitles' + }); + + defineRoute({ + path: '/dashboard.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/dashboard' }); defineRoute({ - path: "/dlnaprofiles.html", + path: '/dashboardgeneral.html', + controller: 'dashboard/general', autoFocus: false, - roles: "admin", - controller: "dlnaprofiles" + roles: 'admin' }); defineRoute({ - path: "/dlnasettings.html", + path: '/networking.html', autoFocus: false, - roles: "admin", - controller: "dlnasettings" + roles: 'admin', + controller: 'dashboard/networking' }); defineRoute({ - path: "/edititemmetadata.html", - controller: "edititemmetadata", + path: '/devices.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/devices/devices' + }); + defineRoute({ + path: '/device.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/devices/device' + }); + defineRoute({ + path: '/dlnaprofile.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/dlna/dlnaprofile' + }); + defineRoute({ + path: '/dlnaprofiles.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/dlna/dlnaprofiles' + }); + defineRoute({ + path: '/addplugin.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/plugins/add' + }); + defineRoute({ + path: '/library.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/medialibrarypage' + }); + defineRoute({ + path: '/librarydisplay.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/librarydisplay' + }); + defineRoute({ + path: '/dlnasettings.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/dlna/dlnasettings' + }); + defineRoute({ + path: '/edititemmetadata.html', + controller: 'edititemmetadata', autoFocus: false }); defineRoute({ - path: "/encodingsettings.html", + path: '/encodingsettings.html', autoFocus: false, - roles: "admin", - controller: "encodingsettings" - }); - defineRoute({ - path: "/forgotpassword.html", - anonymous: true, - startup: true, - controller: "auth/forgotpassword" - }); - defineRoute({ - path: "/forgotpasswordpin.html", - autoFocus: false, - anonymous: true, - startup: true, - controller: "auth/forgotpasswordpin" - }); - defineRoute({ - path: "/home.html", - autoFocus: false, - controller: "home", - transition: "fade", - type: "home" - }); - defineRoute({ - path: "/list.html", - autoFocus: false, - controller: "list", - transition: "fade" - }); - defineRoute({ - path: "/index.html", - autoFocus: false, - isDefaultRoute: true - }); - defineRoute({ - path: "/itemdetails.html", - controller: "itemdetailpage", - autoFocus: false, - transition: "fade" - }); - defineRoute({ - path: "/library.html", - autoFocus: false, - roles: "admin", - controller: "medialibrarypage" - }); - defineRoute({ - path: "/librarydisplay.html", - autoFocus: false, - roles: "admin", - controller: "librarydisplay" - }); - defineRoute({ - path: "/librarysettings.html", - autoFocus: false, - roles: "admin", - controller: "librarysettings" - }); - defineRoute({ - path: "/livetv.html", - controller: "livetv/livetvsuggested", - autoFocus: false, - transition: "fade" - }); - defineRoute({ - path: "/livetvguideprovider.html", - autoFocus: false, - roles: "admin", - controller: "livetvguideprovider" - }); - defineRoute({ - path: "/livetvsettings.html", - autoFocus: false, - controller: "livetvsettings" - }); - defineRoute({ - path: "/livetvstatus.html", - autoFocus: false, - roles: "admin", - controller: "livetvstatus" - }); - defineRoute({ - path: "/livetvtuner.html", - autoFocus: false, - roles: "admin", - controller: "livetvtuner" - }); - defineRoute({ - path: "/log.html", - roles: "admin", - controller: "dashboard/logs" - }); - defineRoute({ - path: "/login.html", - autoFocus: false, - anonymous: true, - startup: true, - controller: "auth/login" - }); - defineRoute({ - path: "/metadataimages.html", - autoFocus: false, - roles: "admin", - controller: "metadataimagespage" - }); - defineRoute({ - path: "/metadatanfo.html", - autoFocus: false, - roles: "admin", - controller: "metadatanfo" - }); - defineRoute({ - path: "/movies.html", - autoFocus: false, - controller: "movies/moviesrecommended", - transition: "fade" - }); - defineRoute({ - path: "/music.html", - controller: "music/musicrecommended", - autoFocus: false, - transition: "fade" - }); - defineRoute({ - path: "/notificationsetting.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/notifications/notification" - }); - defineRoute({ - path: "/notificationsettings.html", - controller: "dashboard/notifications/notifications", - autoFocus: false, - roles: "admin" - }); - defineRoute({ - path: "/nowplaying.html", - controller: "playback/nowplaying", - autoFocus: false, - transition: "fade", - fullscreen: true, - supportsThemeMedia: true, - enableMediaControl: false - }); - defineRoute({ - path: "/playbackconfiguration.html", - autoFocus: false, - roles: "admin", - controller: "playbackconfiguration" - }); - defineRoute({ - path: "/availableplugins.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/plugins/available" - }); - defineRoute({ - path: "/installedplugins.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/plugins/installed" - }); - defineRoute({ - path: "/scheduledtask.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/scheduledtasks/scheduledtask" - }); - defineRoute({ - path: "/scheduledtasks.html", - autoFocus: false, - roles: "admin", - controller: "dashboard/scheduledtasks/scheduledtasks" - }); - defineRoute({ - path: "/search.html", - controller: "searchpage" - }); - defineRoute({ - path: "/selectserver.html", - autoFocus: false, - anonymous: true, - startup: true, - controller: "auth/selectserver" - }); - defineRoute({ - path: "/serveractivity.html", - autoFocus: false, - roles: "admin", - controller: "serveractivity" - }); - defineRoute({ - path: "/apikeys.html", - autoFocus: false, - roles: "admin", - controller: "apikeys" - }); - defineRoute({ - path: "/streamingsettings.html", - autoFocus: false, - roles: "admin", - controller: "streamingsettings" - }); - defineRoute({ - path: "/tv.html", - autoFocus: false, - controller: "shows/tvrecommended", - transition: "fade" - }); - defineRoute({ - path: "/useredit.html", - autoFocus: false, - roles: "admin", - controller: "useredit" - }); - defineRoute({ - path: "/userlibraryaccess.html", - autoFocus: false, - roles: "admin", - controller: "userlibraryaccess" - }); - defineRoute({ - path: "/usernew.html", - autoFocus: false, - roles: "admin", - controller: "usernew" - }); - defineRoute({ - path: "/userparentalcontrol.html", - autoFocus: false, - roles: "admin", - controller: "userparentalcontrol" - }); - defineRoute({ - path: "/userpassword.html", - autoFocus: false, - controller: "userpasswordpage" - }); - defineRoute({ - path: "/userprofiles.html", - autoFocus: false, - roles: "admin", - controller: "userprofilespage" + roles: 'admin', + controller: 'dashboard/encodingsettings' }); defineRoute({ - path: "/wizardremoteaccess.html", + path: '/home.html', autoFocus: false, - anonymous: true, - controller: "wizard/remoteaccess" + controller: 'home', + transition: 'fade', + type: 'home' }); defineRoute({ - path: "/wizardfinish.html", - autoFocus: false, - anonymous: true, - controller: "wizard/finish" + path: '/search.html', + controller: 'searchpage' }); defineRoute({ - path: "/wizardlibrary.html", + path: '/list.html', autoFocus: false, - anonymous: true, - controller: "medialibrarypage" + controller: 'list', + transition: 'fade' }); defineRoute({ - path: "/wizardsettings.html", + path: '/itemdetails.html', + controller: 'itemdetailpage', autoFocus: false, - anonymous: true, - controller: "wizard/settings" + transition: 'fade' }); defineRoute({ - path: "/wizardstart.html", + path: '/livetv.html', + controller: 'livetv/livetvsuggested', autoFocus: false, - anonymous: true, - controller: "wizard/start" + transition: 'fade' }); defineRoute({ - path: "/wizarduser.html", - controller: "wizard/user", + path: '/livetvguideprovider.html', + autoFocus: false, + roles: 'admin', + controller: 'livetvguideprovider' + }); + defineRoute({ + path: '/livetvsettings.html', + autoFocus: false, + controller: 'livetvsettings' + }); + defineRoute({ + path: '/livetvstatus.html', + autoFocus: false, + roles: 'admin', + controller: 'livetvstatus' + }); + defineRoute({ + path: '/livetvtuner.html', + autoFocus: false, + roles: 'admin', + controller: 'livetvtuner' + }); + defineRoute({ + path: '/log.html', + roles: 'admin', + controller: 'dashboard/logs' + }); + defineRoute({ + path: '/metadataimages.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/metadataimagespage' + }); + defineRoute({ + path: '/metadatanfo.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/metadatanfo' + }); + defineRoute({ + path: '/movies.html', + autoFocus: false, + controller: 'movies/moviesrecommended', + transition: 'fade' + }); + defineRoute({ + path: '/music.html', + controller: 'music/musicrecommended', + autoFocus: false, + transition: 'fade' + }); + defineRoute({ + path: '/notificationsetting.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/notifications/notification' + }); + defineRoute({ + path: '/notificationsettings.html', + controller: 'dashboard/notifications/notifications', + autoFocus: false, + roles: 'admin' + }); + defineRoute({ + path: '/playbackconfiguration.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/playbackconfiguration' + }); + defineRoute({ + path: '/availableplugins.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/plugins/available' + }); + defineRoute({ + path: '/installedplugins.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/plugins/installed' + }); + defineRoute({ + path: '/scheduledtask.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/scheduledtasks/scheduledtask' + }); + defineRoute({ + path: '/scheduledtasks.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/scheduledtasks/scheduledtasks' + }); + defineRoute({ + path: '/serveractivity.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/serveractivity' + }); + defineRoute({ + path: '/apikeys.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/apikeys' + }); + defineRoute({ + path: '/streamingsettings.html', + autoFocus: false, + roles: 'admin', + controller: 'dashboard/streamingsettings' + }); + defineRoute({ + path: '/tv.html', + autoFocus: false, + controller: 'shows/tvrecommended', + transition: 'fade' + }); + + defineRoute({ + path: '/useredit.html', + autoFocus: false, + roles: 'admin', + controller: 'useredit' + }); + defineRoute({ + path: '/userlibraryaccess.html', + autoFocus: false, + roles: 'admin', + controller: 'userlibraryaccess' + }); + defineRoute({ + path: '/usernew.html', + autoFocus: false, + roles: 'admin', + controller: 'usernew' + }); + defineRoute({ + path: '/userparentalcontrol.html', + autoFocus: false, + roles: 'admin', + controller: 'userparentalcontrol' + }); + defineRoute({ + path: '/userpassword.html', + autoFocus: false, + controller: 'userpasswordpage' + }); + defineRoute({ + path: '/userprofiles.html', + autoFocus: false, + roles: 'admin', + controller: 'userprofilespage' + }); + + defineRoute({ + path: '/wizardremoteaccess.html', + autoFocus: false, + anonymous: true, + controller: 'wizard/remoteaccess' + }); + defineRoute({ + path: '/wizardfinish.html', + autoFocus: false, + anonymous: true, + controller: 'wizard/finish' + }); + defineRoute({ + path: '/wizardlibrary.html', + autoFocus: false, + anonymous: true, + controller: 'dashboard/medialibrarypage' + }); + defineRoute({ + path: '/wizardsettings.html', + autoFocus: false, + anonymous: true, + controller: 'wizard/settings' + }); + defineRoute({ + path: '/wizardstart.html', + autoFocus: false, + anonymous: true, + controller: 'wizard/start' + }); + defineRoute({ + path: '/wizarduser.html', + controller: 'wizard/user', autoFocus: false, anonymous: true }); defineRoute({ - path: "/videoosd.html", - transition: "fade", - controller: "playback/videoosd", + path: '/videoosd.html', + transition: 'fade', + controller: 'playback/videoosd', autoFocus: false, - type: "video-osd", + type: 'video-osd', supportsThemeMedia: true, fullscreen: true, enableMediaControl: false }); defineRoute({ - path: "/configurationpage", + path: '/nowplaying.html', + controller: 'playback/nowplaying', + autoFocus: false, + transition: 'fade', + fullscreen: true, + supportsThemeMedia: true, + enableMediaControl: false + }); + defineRoute({ + path: '/configurationpage', autoFocus: false, enableCache: false, enableContentQueryString: true, - roles: "admin" + roles: 'admin' }); defineRoute({ - path: "/", + path: '/', isDefaultRoute: true, autoFocus: false }); + defineRoute({ + path: '/index.html', + autoFocus: false, + isDefaultRoute: true + }); }); diff --git a/src/scripts/searchtab.js b/src/scripts/searchtab.js index c0852bfc77..95b1e5a7c3 100644 --- a/src/scripts/searchtab.js +++ b/src/scripts/searchtab.js @@ -1,18 +1,18 @@ -define(["searchFields", "searchResults", "events"], function (SearchFields, SearchResults, events) { - "use strict"; +define(['searchFields', 'searchResults', 'events'], function (SearchFields, SearchResults, events) { + 'use strict'; function init(instance, tabContent, options) { tabContent.innerHTML = '
'; instance.searchFields = new SearchFields({ - element: tabContent.querySelector(".searchFields") + element: tabContent.querySelector('.searchFields') }); instance.searchResults = new SearchResults({ - element: tabContent.querySelector(".searchResults"), + element: tabContent.querySelector('.searchResults'), serverId: ApiClient.serverId(), parentId: options.parentId, collectionType: options.collectionType }); - events.on(instance.searchFields, "search", function (e, value) { + events.on(instance.searchFields, 'search', function (e, value) { instance.searchResults.search(value); }); } diff --git a/src/components/appSettings.js b/src/scripts/settings/appSettings.js similarity index 61% rename from src/components/appSettings.js rename to src/scripts/settings/appSettings.js index d1a981148c..6f0975e98c 100644 --- a/src/components/appSettings.js +++ b/src/scripts/settings/appSettings.js @@ -1,5 +1,7 @@ -define(['appStorage', 'events'], function (appStorage, events) { - 'use strict'; +/* eslint-disable indent */ + +import appStorage from 'appStorage'; +import events from 'events'; function getKey(name, userId) { if (userId) { @@ -9,20 +11,25 @@ define(['appStorage', 'events'], function (appStorage, events) { return name; } - function AppSettings() { - - } - - AppSettings.prototype.enableAutoLogin = function (val) { - if (val != null) { + export function enableAutoLogin(val) { + if (val !== undefined) { this.set('enableAutoLogin', val.toString()); } - return this.get('enableAutoLogin') !== 'false'; - }; - AppSettings.prototype.enableAutomaticBitrateDetection = function (isInNetwork, mediaType, val) { + return this.get('enableAutoLogin') !== 'false'; + } + + export function enableSystemExternalPlayers(val) { + if (val !== undefined) { + this.set('enableSystemExternalPlayers', val.toString()); + } + + return this.get('enableSystemExternalPlayers') === 'true'; + } + + export function enableAutomaticBitrateDetection(isInNetwork, mediaType, val) { var key = 'enableautobitratebitrate-' + mediaType + '-' + isInNetwork; - if (val != null) { + if (val !== undefined) { if (isInNetwork && mediaType === 'Audio') { val = true; } @@ -35,11 +42,11 @@ define(['appStorage', 'events'], function (appStorage, events) { } else { return this.get(key) !== 'false'; } - }; + } - AppSettings.prototype.maxStreamingBitrate = function (isInNetwork, mediaType, val) { + export function maxStreamingBitrate(isInNetwork, mediaType, val) { var key = 'maxbitrate-' + mediaType + '-' + isInNetwork; - if (val != null) { + if (val !== undefined) { if (isInNetwork && mediaType === 'Audio') { // nothing to do, this is always a max value } else { @@ -53,44 +60,44 @@ define(['appStorage', 'events'], function (appStorage, events) { } else { return parseInt(this.get(key) || '0') || 1500000; } - }; + } - AppSettings.prototype.maxStaticMusicBitrate = function (val) { + export function maxStaticMusicBitrate(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) { + export function maxChromecastBitrate(val) { + if (val !== undefined) { this.set('chromecastBitrate1', val); } val = this.get('chromecastBitrate1'); return val ? parseInt(val) : null; - }; + } - AppSettings.prototype.syncOnlyOnWifi = function (val) { - if (val != null) { + export function syncOnlyOnWifi(val) { + if (val !== undefined) { this.set('syncOnlyOnWifi', val.toString()); } return this.get('syncOnlyOnWifi') !== 'false'; - }; + } - AppSettings.prototype.syncPath = function (val) { - if (val != null) { + export function syncPath(val) { + if (val !== undefined) { this.set('syncPath', val); } return this.get('syncPath'); - }; + } - AppSettings.prototype.cameraUploadServers = function (val) { - if (val != null) { + export function cameraUploadServers(val) { + if (val !== undefined) { this.set('cameraUploadServers', val.join(',')); } @@ -100,36 +107,42 @@ define(['appStorage', 'events'], function (appStorage, events) { } return []; - }; + } - AppSettings.prototype.runAtStartup = function (val) { - if (val != null) { + export function runAtStartup(val) { + if (val !== undefined) { this.set('runatstartup', val.toString()); } return this.get('runatstartup') === 'true'; - }; + } - AppSettings.prototype.set = function (name, value, userId) { + export function set(name, value, userId) { var currentValue = this.get(name, userId); appStorage.setItem(getKey(name, userId), value); if (currentValue !== value) { events.trigger(this, 'change', [name]); } - }; + } - AppSettings.prototype.get = function (name, userId) { + export function get(name, userId) { return appStorage.getItem(getKey(name, userId)); - }; + } - AppSettings.prototype.enableSystemExternalPlayers = function (val) { - if (val != null) { - this.set('enableSystemExternalPlayers', val.toString()); - } +/* eslint-enable indent */ - return this.get('enableSystemExternalPlayers') === 'true'; - }; - - return new AppSettings(); -}); \ No newline at end of file +export default { + enableAutoLogin: enableAutoLogin, + enableSystemExternalPlayers: enableSystemExternalPlayers, + enableAutomaticBitrateDetection: enableAutomaticBitrateDetection, + maxStreamingBitrate: maxStreamingBitrate, + maxStaticMusicBitrate: maxStaticMusicBitrate, + maxChromecastBitrate: maxChromecastBitrate, + syncOnlyOnWifi: syncOnlyOnWifi, + syncPath: syncPath, + cameraUploadServers: cameraUploadServers, + runAtStartup: runAtStartup, + set: set, + get: get +}; diff --git a/src/components/usersettings/usersettingsbuilder.js b/src/scripts/settings/userSettings.js similarity index 57% rename from src/components/usersettings/usersettingsbuilder.js rename to src/scripts/settings/userSettings.js index f852dacc43..072e3f3062 100644 --- a/src/components/usersettings/usersettingsbuilder.js +++ b/src/scripts/settings/userSettings.js @@ -1,5 +1,7 @@ -define(['appSettings', 'events'], function (appSettings, events) { - 'use strict'; +/* eslint-disable indent */ + +import appSettings from 'appSettings'; +import events from 'events'; function onSaveTimeout() { var self = this; @@ -15,10 +17,7 @@ define(['appSettings', 'events'], function (appSettings, events) { instance.saveTimeout = setTimeout(onSaveTimeout.bind(instance), 50); } - function UserSettings() { - } - - UserSettings.prototype.setUserInfo = function (userId, apiClient) { + export function setUserInfo(userId, apiClient) { if (this.saveTimeout) { clearTimeout(this.saveTimeout); } @@ -37,17 +36,17 @@ define(['appSettings', 'events'], function (appSettings, events) { result.CustomPrefs = result.CustomPrefs || {}; self.displayPrefs = result; }); - }; + } - UserSettings.prototype.getData = function () { + export function getData() { return this.displayPrefs; - }; + } - UserSettings.prototype.importFrom = function (instance) { + export function importFrom(instance) { this.displayPrefs = instance.getData(); - }; + } - UserSettings.prototype.set = function (name, value, enableOnServer) { + export function set(name, value, enableOnServer) { var userId = this.currentUserId; var currentValue = this.get(name, enableOnServer); var result = appSettings.set(name, value, userId); @@ -62,18 +61,18 @@ define(['appSettings', 'events'], function (appSettings, events) { } return result; - }; + } - UserSettings.prototype.get = function (name, enableOnServer) { + export function get(name, enableOnServer) { var userId = this.currentUserId; if (enableOnServer !== false && this.displayPrefs) { return this.displayPrefs.CustomPrefs[name]; } return appSettings.get(name, userId); - }; + } - UserSettings.prototype.serverConfig = function (config) { + export function serverConfig(config) { var apiClient = this.currentApiClient; if (config) { return apiClient.updateUserConfiguration(this.currentUserId, config); @@ -82,126 +81,149 @@ define(['appSettings', 'events'], function (appSettings, events) { return apiClient.getUser(this.currentUserId).then(function (user) { return user.Configuration; }); - }; + } - UserSettings.prototype.enableCinemaMode = function (val) { - if (val != null) { + export function enableCinemaMode(val) { + if (val !== undefined) { return this.set('enableCinemaMode', val.toString(), false); } val = this.get('enableCinemaMode', false); return val !== 'false'; - }; + } - UserSettings.prototype.enableNextVideoInfoOverlay = function (val) { - if (val != null) { + export function enableNextVideoInfoOverlay(val) { + if (val !== undefined) { return this.set('enableNextVideoInfoOverlay', val.toString()); } val = this.get('enableNextVideoInfoOverlay', false); return val !== 'false'; - }; + } - UserSettings.prototype.enableThemeSongs = function (val) { - if (val != null) { + export function enableThemeSongs(val) { + if (val !== undefined) { return this.set('enableThemeSongs', val.toString(), false); } val = this.get('enableThemeSongs', false); return val !== 'false'; - }; + } - UserSettings.prototype.enableThemeVideos = function (val) { - if (val != null) { + export function enableThemeVideos(val) { + if (val !== undefined) { return this.set('enableThemeVideos', val.toString(), false); } val = this.get('enableThemeVideos', false); return val !== 'false'; - }; + } - UserSettings.prototype.enableBackdrops = function (val) { - if (val != null) { + export function enableFastFadein(val) { + if (val !== undefined) { + return this.set('fastFadein', val.toString(), false); + } + + val = this.get('fastFadein', false); + return val !== 'false'; + } + + export function enableBackdrops(val) { + if (val !== undefined) { return this.set('enableBackdrops', val.toString(), false); } val = this.get('enableBackdrops', false); return val !== 'false'; - }; + } - UserSettings.prototype.language = function (val) { - if (val != null) { + export function language(val) { + if (val !== undefined) { return this.set('language', val.toString(), false); } return this.get('language', false); - }; + } - UserSettings.prototype.dateTimeLocale = function (val) { - if (val != null) { + export function dateTimeLocale(val) { + if (val !== undefined) { return this.set('datetimelocale', val.toString(), false); } return this.get('datetimelocale', false); - }; + } - UserSettings.prototype.skipBackLength = function (val) { - if (val != null) { + export function skipBackLength(val) { + if (val !== undefined) { return this.set('skipBackLength', val.toString()); } return parseInt(this.get('skipBackLength') || '10000'); - }; + } - UserSettings.prototype.skipForwardLength = function (val) { - if (val != null) { + export function skipForwardLength(val) { + if (val !== undefined) { return this.set('skipForwardLength', val.toString()); } return parseInt(this.get('skipForwardLength') || '30000'); - }; + } - UserSettings.prototype.dashboardTheme = function (val) { - if (val != null) { + export function dashboardTheme(val) { + if (val !== undefined) { return this.set('dashboardTheme', val); } return this.get('dashboardTheme'); - }; + } - UserSettings.prototype.skin = function (val) { - if (val != null) { + export function skin(val) { + if (val !== undefined) { return this.set('skin', val, false); } return this.get('skin', false); - }; + } - UserSettings.prototype.theme = function (val) { - if (val != null) { + export function theme(val) { + if (val !== undefined) { return this.set('appTheme', val, false); } return this.get('appTheme', false); - }; + } - UserSettings.prototype.screensaver = function (val) { - if (val != null) { + export function screensaver(val) { + if (val !== undefined) { return this.set('screensaver', val, false); } return this.get('screensaver', false); - }; + } - UserSettings.prototype.soundEffects = function (val) { - if (val != null) { + export function libraryPageSize(val) { + if (val !== undefined) { + return this.set('libraryPageSize', parseInt(val, 10), false); + } + + var libraryPageSize = parseInt(this.get('libraryPageSize', false), 10); + if (libraryPageSize === 0) { + // Explicitly return 0 to avoid returning 100 because 0 is falsy. + return 0; + } else { + return libraryPageSize || 100; + } + } + + export function soundEffects(val) { + if (val !== undefined) { return this.set('soundeffects', val, false); } return this.get('soundeffects', false); - }; + } - UserSettings.prototype.loadQuerySettings = function (key, query) { + export function loadQuerySettings(key, query) { var values = this.get(key); if (values) { values = JSON.parse(values); @@ -209,9 +231,9 @@ define(['appSettings', 'events'], function (appSettings, events) { } return query; - }; + } - UserSettings.prototype.saveQuerySettings = function (key, query) { + export function saveQuerySettings(key, query) { var values = {}; if (query.SortBy) { values.SortBy = query.SortBy; @@ -222,25 +244,54 @@ define(['appSettings', 'events'], function (appSettings, events) { } return this.set(key, JSON.stringify(values)); - }; + } - UserSettings.prototype.getSubtitleAppearanceSettings = function (key) { + export function getSubtitleAppearanceSettings(key) { key = key || 'localplayersubtitleappearance3'; return JSON.parse(this.get(key, false) || '{}'); - }; + } - UserSettings.prototype.setSubtitleAppearanceSettings = function (value, key) { + export function setSubtitleAppearanceSettings(value, key) { key = key || 'localplayersubtitleappearance3'; return this.set(key, JSON.stringify(value), false); - }; + } - UserSettings.prototype.setFilter = function (key, value) { + export function setFilter(key, value) { return this.set(key, value, true); - }; + } - UserSettings.prototype.getFilter = function (key) { + export function getFilter(key) { return this.get(key, true); - }; + } - return UserSettings; -}); +/* eslint-enable indent */ +export default { + setUserInfo: setUserInfo, + getData: getData, + importFrom: importFrom, + set: set, + get: get, + serverConfig: serverConfig, + enableCinemaMode: enableCinemaMode, + enableNextVideoInfoOverlay: enableNextVideoInfoOverlay, + enableThemeSongs: enableThemeSongs, + enableThemeVideos: enableThemeVideos, + enableFastFadein: enableFastFadein, + enableBackdrops: enableBackdrops, + language: language, + dateTimeLocale: dateTimeLocale, + skipBackLength: skipBackLength, + skipForwardLength: skipForwardLength, + dashboardTheme: dashboardTheme, + skin: skin, + theme: theme, + screensaver: screensaver, + libraryPageSize: libraryPageSize, + soundEffects: soundEffects, + loadQuerySettings: loadQuerySettings, + saveQuerySettings: saveQuerySettings, + getSubtitleAppearanceSettings: getSubtitleAppearanceSettings, + setSubtitleAppearanceSettings: setSubtitleAppearanceSettings, + setFilter: setFilter, + getFilter: getFilter +}; diff --git a/src/scripts/settings/webSettings.js b/src/scripts/settings/webSettings.js new file mode 100644 index 0000000000..d999724aff --- /dev/null +++ b/src/scripts/settings/webSettings.js @@ -0,0 +1,28 @@ +let data; + +function getConfig() { + if (data) return Promise.resolve(data); + return fetch('/config.json?nocache=' + new Date().getUTCMilliseconds()).then(response => { + data = response.json(); + return data; + }).catch(error => { + console.warn('web config file is missing so the template will be used'); + return getDefaultConfig(); + }); +} + +function getDefaultConfig() { + return fetch('/config.template.json').then(function (response) { + data = response.json(); + return data; + }); +} + +export function enableMultiServer() { + return getConfig().then(config => { + return config.multiserver; + }).catch(error => { + console.log('cannot get web config:', error); + return false; + }); +} diff --git a/src/scripts/site.js b/src/scripts/site.js index d7c3a1c8a4..c00169d224 100644 --- a/src/scripts/site.js +++ b/src/scripts/site.js @@ -1,36 +1,36 @@ function getWindowLocationSearch(win) { - "use strict"; + 'use strict'; var search = (win || window).location.search; if (!search) { - var index = window.location.href.indexOf("?"); + var index = window.location.href.indexOf('?'); if (-1 != index) { search = window.location.href.substring(index); } } - return search || ""; + return search || ''; } function getParameterByName(name, url) { - "use strict"; + 'use strict'; - name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); - var regexS = "[\\?&]" + name + "=([^&#]*)"; - var regex = new RegExp(regexS, "i"); + name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + var regexS = '[\\?&]' + name + '=([^&#]*)'; + var regex = new RegExp(regexS, 'i'); var results = regex.exec(url || getWindowLocationSearch()); if (null == results) { - return ""; + return ''; } - return decodeURIComponent(results[1].replace(/\+/g, " ")); + return decodeURIComponent(results[1].replace(/\+/g, ' ')); } function pageClassOn(eventName, className, fn) { - "use strict"; + 'use strict'; document.addEventListener(eventName, function (event) { var target = event.target; @@ -42,7 +42,7 @@ function pageClassOn(eventName, className, fn) { } function pageIdOn(eventName, id, fn) { - "use strict"; + 'use strict'; document.addEventListener(eventName, function (event) { var target = event.target; @@ -71,17 +71,17 @@ var Dashboard = { } var urlLower = window.location.href.toLowerCase(); - var index = urlLower.lastIndexOf("/web"); + var index = urlLower.lastIndexOf('/web'); if (-1 != index) { return urlLower.substring(0, index); } var loc = window.location; - var address = loc.protocol + "//" + loc.hostname; + var address = loc.protocol + '//' + loc.hostname; if (loc.port) { - address += ":" + loc.port; + address += ':' + loc.port; } return address; @@ -104,21 +104,21 @@ var Dashboard = { var loginPage; if (AppInfo.isNativeApp) { - loginPage = "selectserver.html"; + loginPage = 'selectserver.html'; window.ApiClient = null; } else { - loginPage = "login.html"; + loginPage = 'login.html'; } Dashboard.navigate(loginPage); }); }, getConfigurationPageUrl: function (name) { - return "configurationpage?name=" + encodeURIComponent(name); + return 'configurationpage?name=' + encodeURIComponent(name); }, getConfigurationResourceUrl: function (name) { if (AppInfo.isNativeApp) { - return ApiClient.getUrl("web/ConfigurationPage", { + return ApiClient.getUrl('web/ConfigurationPage', { name: name }); } @@ -127,7 +127,7 @@ var Dashboard = { }, navigate: function (url, preserveQueryString) { if (!url) { - throw new Error("url cannot be null or empty"); + throw new Error('url cannot be null or empty'); } var queryString = getWindowLocationSearch(); @@ -137,36 +137,36 @@ var Dashboard = { } return new Promise(function (resolve, reject) { - require(["appRouter"], function (appRouter) { + require(['appRouter'], function (appRouter) { return appRouter.show(url).then(resolve, reject); }); }); }, navigate_direct: function (path) { return new Promise(function (resolve, reject) { - require(["appRouter"], function (appRouter) { + require(['appRouter'], function (appRouter) { return appRouter.showDirect(path).then(resolve, reject); }); }); }, processPluginConfigurationUpdateResult: function () { - require(["loading", "toast"], function (loading, toast) { + require(['loading', 'toast'], function (loading, toast) { loading.hide(); - toast(Globalize.translate("MessageSettingsSaved")); + toast(Globalize.translate('MessageSettingsSaved')); }); }, processServerConfigurationUpdateResult: function (result) { - require(["loading", "toast"], function (loading, toast) { + require(['loading', 'toast'], function (loading, toast) { loading.hide(); - toast(Globalize.translate("MessageSettingsSaved")); + toast(Globalize.translate('MessageSettingsSaved')); }); }, processErrorResponse: function (response) { - require(["loading"], function (loading) { + require(['loading'], function (loading) { loading.hide(); }); - var status = "" + response.status; + var status = '' + response.status; if (response.statusText) { status = response.statusText; @@ -174,21 +174,21 @@ var Dashboard = { Dashboard.alert({ title: status, - message: response.headers ? response.headers.get("X-Application-Error-Code") : null + message: response.headers ? response.headers.get('X-Application-Error-Code') : null }); }, alert: function (options) { - if ("string" == typeof options) { - return void require(["toast"], function (toast) { + if ('string' == typeof options) { + return void require(['toast'], function (toast) { toast({ text: options }); }); } - require(["alert"], function (alert) { + require(['alert'], function (alert) { alert({ - title: options.title || Globalize.translate("HeaderAlert"), + title: options.title || Globalize.translate('HeaderAlert'), text: options.message }).then(options.callback || function () {}); }); @@ -197,11 +197,11 @@ var Dashboard = { var apiClient = window.ApiClient; if (apiClient) { - require(["serverRestartDialog", "events"], function (ServerRestartDialog, events) { + require(['serverRestartDialog', 'events'], function (ServerRestartDialog, events) { var dialog = new ServerRestartDialog({ apiClient: apiClient }); - events.on(dialog, "restarted", function () { + events.on(dialog, 'restarted', function () { if (AppInfo.isNativeApp) { apiClient.ensureWebSocket(); } else { @@ -214,24 +214,31 @@ var Dashboard = { }, capabilities: function (appHost) { var capabilities = { - PlayableMediaTypes: ["Audio", "Video"], - SupportedCommands: ["MoveUp", "MoveDown", "MoveLeft", "MoveRight", "PageUp", "PageDown", "PreviousLetter", "NextLetter", "ToggleOsd", "ToggleContextMenu", "Select", "Back", "SendKey", "SendString", "GoHome", "GoToSettings", "VolumeUp", "VolumeDown", "Mute", "Unmute", "ToggleMute", "SetVolume", "SetAudioStreamIndex", "SetSubtitleStreamIndex", "DisplayContent", "GoToSearch", "DisplayMessage", "SetRepeatMode", "ChannelUp", "ChannelDown", "PlayMediaSource", "PlayTrailers"], - SupportsPersistentIdentifier: "cordova" === self.appMode || "android" === self.appMode, + PlayableMediaTypes: ['Audio', 'Video'], + SupportedCommands: ['MoveUp', 'MoveDown', 'MoveLeft', 'MoveRight', 'PageUp', 'PageDown', 'PreviousLetter', 'NextLetter', 'ToggleOsd', 'ToggleContextMenu', 'Select', 'Back', 'SendKey', 'SendString', 'GoHome', 'GoToSettings', 'VolumeUp', 'VolumeDown', 'Mute', 'Unmute', 'ToggleMute', 'SetVolume', 'SetAudioStreamIndex', 'SetSubtitleStreamIndex', 'DisplayContent', 'GoToSearch', 'DisplayMessage', 'SetRepeatMode', 'ChannelUp', 'ChannelDown', 'PlayMediaSource', 'PlayTrailers'], + SupportsPersistentIdentifier: 'cordova' === self.appMode || 'android' === self.appMode, SupportsMediaControl: true }; appHost.getPushTokenInfo(); return capabilities = Object.assign(capabilities, appHost.getPushTokenInfo()); + }, + selectServer: function () { + if (window.NativeShell && typeof window.NativeShell.selectServer === 'function') { + window.NativeShell.selectServer(); + } else { + Dashboard.navigate('selectserver.html'); + } } }; var AppInfo = {}; !function () { - "use strict"; + 'use strict'; function defineConnectionManager(connectionManager) { window.ConnectionManager = connectionManager; - define("connectionManager", [], function () { + define('connectionManager', [], function () { return connectionManager; }); } @@ -257,13 +264,13 @@ var AppInfo = {}; return userSettings.setUserInfo(user.Id, localApiClient); }; - events.on(connectionManager, "localusersignedout", function () { + events.on(connectionManager, 'localusersignedout', function () { userSettings.setUserInfo(null, null); }); } function createConnectionManager() { - return require(["connectionManagerFactory", "apphost", "credentialprovider", "events", "userSettings"], function (ConnectionManager, apphost, credentialProvider, events, userSettings) { + return require(['connectionManagerFactory', 'apphost', 'credentialprovider', 'events', 'userSettings'], function (ConnectionManager, apphost, credentialProvider, events, userSettings) { var credentialProviderInstance = new credentialProvider(); var promises = [apphost.getSyncProfile(), apphost.init()]; @@ -273,18 +280,18 @@ var AppInfo = {}; capabilities.DeviceProfile = deviceProfile; - var connectionManager = new ConnectionManager(credentialProviderInstance, apphost.appName(), apphost.appVersion(), apphost.deviceName(), apphost.deviceId(), capabilities, window.devicePixelRatio); + var connectionManager = new ConnectionManager(credentialProviderInstance, apphost.appName(), apphost.appVersion(), apphost.deviceName(), apphost.deviceId(), capabilities); defineConnectionManager(connectionManager); bindConnectionManagerEvents(connectionManager, events, userSettings); if (!AppInfo.isNativeApp) { - console.log("loading ApiClient singleton"); + console.debug('loading ApiClient singleton'); - return require(["apiclient"], function (apiClientFactory) { - console.log("creating ApiClient singleton"); + return require(['apiclient'], function (apiClientFactory) { + console.debug('creating ApiClient singleton'); - var apiClient = new apiClientFactory(Dashboard.serverAddress(), apphost.appName(), apphost.appVersion(), apphost.deviceName(), apphost.deviceId(), window.devicePixelRatio); + var apiClient = new apiClientFactory(Dashboard.serverAddress(), apphost.appName(), apphost.appVersion(), apphost.deviceName(), apphost.deviceId()); apiClient.enableAutomaticNetworking = false; apiClient.manualAddressOnly = true; @@ -294,7 +301,7 @@ var AppInfo = {}; window.ApiClient = apiClient; localApiClient = apiClient; - console.log("loaded ApiClient singleton"); + console.debug('loaded ApiClient singleton'); }); } @@ -308,19 +315,27 @@ var AppInfo = {}; } function getBowerPath() { - return "libraries"; + return 'libraries'; } function getComponentsPath() { - return "components"; + return 'components'; + } + + function getElementsPath() { + return 'elements'; + } + + function getScriptsPath() { + return 'scripts'; } function getPlaybackManager(playbackManager) { - window.addEventListener("beforeunload", function () { + window.addEventListener('beforeunload', function () { try { playbackManager.onAppClose(); } catch (err) { - console.log("error in onAppClose: " + err); + console.error('error in onAppClose: ' + err); } }); return playbackManager; @@ -335,189 +350,126 @@ var AppInfo = {}; return layoutManager; } - function createWindowHeadroom(Headroom) { - var headroom = new Headroom([], {}); - return headroom; - } - - function getCastSenderApiLoader() { - var ccLoaded = false; - return { - load: function () { - if (ccLoaded) { - return Promise.resolve(); - } - - return new Promise(function (resolve, reject) { - var fileref = document.createElement("script"); - fileref.setAttribute("type", "text/javascript"); - - fileref.onload = function () { - ccLoaded = true; - resolve(); - }; - - fileref.setAttribute("src", "https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"); - document.querySelector("head").appendChild(fileref); - }); - } - }; - } - - function getDummyCastSenderApiLoader() { - return { - load: function () { - window.chrome = window.chrome || {}; - return Promise.resolve(); - } - }; - } - function createSharedAppFooter(appFooter) { return new appFooter({}); } function onRequireJsError(requireType, requireModules) { - console.log("RequireJS error: " + (requireType || "unknown") + ". Failed modules: " + (requireModules || []).join(",")); + console.error('RequireJS error: ' + (requireType || 'unknown') + '. Failed modules: ' + (requireModules || []).join(',')); } function defineResizeObserver() { if (self.ResizeObserver) { - define("ResizeObserver", [], function () { + define('ResizeObserver', [], function () { return self.ResizeObserver; }); } else { - define("ResizeObserver", ["resize-observer-polyfill"], returnFirstDependency); + define('ResizeObserver', ['resize-observer-polyfill'], returnFirstDependency); } } function initRequireWithBrowser(browser) { var bowerPath = getBowerPath(); var componentsPath = getComponentsPath(); + var scriptsPath = getScriptsPath(); - define("filesystem", [componentsPath + "/filesystem"], returnFirstDependency); + define('filesystem', [scriptsPath + '/filesystem'], returnFirstDependency); - if (window.IntersectionObserver && !browser.edge) { - define("lazyLoader", [componentsPath + "/lazyloader/lazyloader-intersectionobserver"], returnFirstDependency); - } else { - define("lazyLoader", [componentsPath + "/lazyloader/lazyloader-scroll"], returnFirstDependency); - } + define('lazyLoader', [componentsPath + '/lazyloader/lazyloader-intersectionobserver'], returnFirstDependency); + define('shell', [componentsPath + '/shell'], returnFirstDependency); - define("shell", [componentsPath + "/shell"], returnFirstDependency); - - define("apiclient", [bowerPath + "/apiclient/apiclient"], returnFirstDependency); - - if ("registerElement" in document) { - define("registerElement", []); + if ('registerElement' in document) { + define('registerElement', []); } else if (browser.msie) { - define("registerElement", ["webcomponents"], returnFirstDependency); + define('registerElement', ['webcomponents'], returnFirstDependency); } else { - define("registerElement", ["document-register-element"], returnFirstDependency); + define('registerElement', ['document-register-element'], returnFirstDependency); } - define("imageFetcher", [componentsPath + "/images/imageFetcher"], returnFirstDependency); - - var preferNativeAlerts = browser.tv; - - define("alert", [componentsPath + "/alert"], returnFirstDependency); + define('alert', [componentsPath + '/alert'], returnFirstDependency); defineResizeObserver(); - define("dialog", [componentsPath + "/dialog/dialog"], returnFirstDependency); - if (preferNativeAlerts && window.confirm) { - define("confirm", [componentsPath + "/confirm/nativeconfirm"], returnFirstDependency); - } else { - define("confirm", [componentsPath + "/confirm/confirm"], returnFirstDependency); - } + define('dialog', [componentsPath + '/dialog/dialog'], returnFirstDependency); - if ((preferNativeAlerts || browser.xboxOne) && window.confirm) { - define("prompt", [componentsPath + "/prompt/nativeprompt"], returnFirstDependency); - } else { - define("prompt", [componentsPath + "/prompt/prompt"], returnFirstDependency); - } + define('confirm', [componentsPath + '/confirm/confirm'], returnFirstDependency); - define("loading", [componentsPath + "/loading/loading"], returnFirstDependency); - define("multi-download", [componentsPath + "/multidownload"], returnFirstDependency); - define("fileDownloader", [componentsPath + "/filedownloader"], returnFirstDependency); - define("localassetmanager", [bowerPath + "/apiclient/localassetmanager"], returnFirstDependency); + define('prompt', [componentsPath + '/prompt/prompt'], returnFirstDependency); - if ("cordova" === self.appMode || "android" === self.appMode) { - define("castSenderApiLoader", [], getDummyCastSenderApiLoader); - } else { - define("castSenderApiLoader", [], getCastSenderApiLoader); - } + define('loading', [componentsPath + '/loading/loading'], returnFirstDependency); + define('multi-download', [componentsPath + '/multidownload'], returnFirstDependency); + define('fileDownloader', [componentsPath + '/filedownloader'], returnFirstDependency); - define("transfermanager", [bowerPath + "/apiclient/sync/transfermanager"], returnFirstDependency); - define("filerepository", [bowerPath + "/apiclient/sync/filerepository"], returnFirstDependency); - define("localsync", [bowerPath + "/apiclient/sync/localsync"], returnFirstDependency); + define('castSenderApiLoader', [componentsPath + '/castSenderApi'], returnFirstDependency); } function init() { - define("livetvcss", ["css!assets/css/livetv.css"], returnFirstDependency); - define("detailtablecss", ["css!assets/css/detailtable.css"], returnFirstDependency); + define('livetvcss', ['css!assets/css/livetv.css'], returnFirstDependency); + define('detailtablecss', ['css!assets/css/detailtable.css'], returnFirstDependency); var promises = []; if (!window.fetch) { - promises.push(require(["fetch"])); - } - if ("function" != typeof Object.assign) { - promises.push(require(["objectassign"])); + promises.push(require(['fetch'])); } Promise.all(promises).then(function () { createConnectionManager().then(function () { - console.log("initAfterDependencies promises resolved"); + console.debug('initAfterDependencies promises resolved'); - require(["globalize", "browser"], function (globalize, browser) { + require(['globalize', 'browser'], function (globalize, browser) { window.Globalize = globalize; loadCoreDictionary(globalize).then(function () { onGlobalizeInit(browser); }); }); - require(["keyboardnavigation"], function(keyboardnavigation) { + require(['keyboardnavigation'], function(keyboardnavigation) { keyboardnavigation.enable(); }); - require(["focusPreventScroll"]); - require(["autoFocuser"], function(autoFocuser) { + require(['mouseManager']); + require(['focusPreventScroll']); + require(['autoFocuser'], function(autoFocuser) { autoFocuser.enable(); }); + require(['globalize', 'connectionManager', 'events'], function (globalize, connectionManager, events) { + events.on(connectionManager, 'localusersignedin', globalize.updateCurrentCulture); + }); }); }); } function loadCoreDictionary(globalize) { - var languages = ["ar", "be-by", "bg-bg", "ca", "cs", "da", "de", "el", "en-gb", "en-us", "es", "es-ar", "es-mx", "fa", "fi", "fr", "fr-ca", "gsw", "he", "hi-in", "hr", "hu", "id", "it", "kk", "ko", "lt-lt", "ms", "nb", "nl", "pl", "pt-br", "pt-pt", "ro", "ru", "sk", "sl-si", "sv", "tr", "uk", "vi", "zh-cn", "zh-hk", "zh-tw"]; + var languages = ['ar', 'be-by', 'bg-bg', 'ca', 'cs', 'da', 'de', 'el', 'en-gb', 'en-us', 'es', 'es-ar', 'es-mx', 'fa', 'fi', 'fr', 'fr-ca', 'gsw', 'he', 'hi-in', 'hr', 'hu', 'id', 'it', 'kk', 'ko', 'lt-lt', 'ms', 'nb', 'nl', 'pl', 'pt-br', 'pt-pt', 'ro', 'ru', 'sk', 'sl-si', 'sv', 'tr', 'uk', 'vi', 'zh-cn', 'zh-hk', 'zh-tw']; var translations = languages.map(function (language) { return { lang: language, - path: "strings/" + language + ".json" + path: 'strings/' + language + '.json' }; }); - globalize.defaultModule("core"); + globalize.defaultModule('core'); return globalize.loadStrings({ - name: "core", + name: 'core', translations: translations }); } function onGlobalizeInit(browser) { - if ("android" === self.appMode) { - if (-1 !== self.location.href.toString().toLowerCase().indexOf("start=backgroundsync")) { + if ('android' === self.appMode) { + if (-1 !== self.location.href.toString().toLowerCase().indexOf('start=backgroundsync')) { return onAppReady(browser); } } - document.title = Globalize.translateDocument(document.title, "core"); + document.title = Globalize.translateDocument(document.title, 'core'); if (browser.tv && !browser.android) { - console.log("Using system fonts with explicit sizes"); - require(["systemFontsSizedCss"]); + console.debug('using system fonts with explicit sizes'); + require(['systemFontsSizedCss']); } else { - console.log("Using default fonts"); - require(["systemFontsCss"]); + console.debug('using default fonts'); + require(['systemFontsCss']); } - require(["apphost", "css!assets/css/librarybrowser"], function (appHost) { + require(['apphost', 'css!assets/css/librarybrowser'], function (appHost) { loadPlugins(appHost, browser).then(function () { onAppReady(browser); }); @@ -525,23 +477,23 @@ var AppInfo = {}; } function loadPlugins(appHost, browser, shell) { - console.log("Loading installed plugins"); + console.debug('loading installed plugins'); var list = [ - "components/playback/playaccessvalidation", - "components/playback/experimentalwarnings", - "components/htmlaudioplayer/plugin", - "components/htmlvideoplayer/plugin", - "components/photoplayer/plugin", - "components/youtubeplayer/plugin", - "components/backdropscreensaver/plugin", - "components/logoscreensaver/plugin" + 'components/playback/playaccessvalidation', + 'components/playback/experimentalwarnings', + 'components/htmlaudioplayer/plugin', + 'components/htmlvideoplayer/plugin', + 'components/photoplayer/plugin', + 'components/youtubeplayer/plugin', + 'components/backdropscreensaver/plugin', + 'components/logoscreensaver/plugin' ]; - if (appHost.supports("remotecontrol")) { - list.push("components/sessionplayer"); + if (appHost.supports('remotecontrol')) { + list.push('components/sessionplayer'); if (browser.chrome || browser.opera) { - list.push("components/chromecast/chromecastplayer"); + list.push('components/chromecast/chromecastplayer'); } } @@ -551,7 +503,7 @@ var AppInfo = {}; return new Promise(function (resolve, reject) { Promise.all(list.map(loadPlugin)).then(function () { - require(["packageManager"], function (packageManager) { + require(['packageManager'], function (packageManager) { packageManager.init().then(resolve, reject); }); }, reject); @@ -560,20 +512,20 @@ var AppInfo = {}; function loadPlugin(url) { return new Promise(function (resolve, reject) { - require(["pluginManager"], function (pluginManager) { + require(['pluginManager'], function (pluginManager) { pluginManager.loadPlugin(url).then(resolve, reject); }); }); } function onAppReady(browser) { - console.log("Begin onAppReady"); + console.debug('begin onAppReady'); // ensure that appHost is loaded in this point require(['apphost', 'appRouter'], function (appHost, appRouter) { window.Emby = {}; - console.log("onAppReady - loading dependencies"); + console.debug('onAppReady: loading dependencies'); if (browser.iOS) { require(['css!assets/css/ios.css']); } @@ -586,50 +538,75 @@ var AppInfo = {}; hashbang: true }); - require(["components/thememediaplayer", "scripts/autobackdrops"]); + require(['components/thememediaplayer', 'scripts/autobackdrops']); if (!browser.tv && !browser.xboxOne && !browser.ps4) { - require(["components/nowplayingbar/nowplayingbar"]); + require(['components/nowplayingbar/nowplayingbar']); } - if (appHost.supports("remotecontrol")) { - require(["playerSelectionMenu", "components/playback/remotecontrolautoplay"]); + if (appHost.supports('remotecontrol')) { + require(['playerSelectionMenu', 'components/playback/remotecontrolautoplay']); } - require(["components/screensavermanager"]); + require(['libraries/screensavermanager']); - if (!appHost.supports("physicalvolumecontrol") || browser.touch) { - require(["components/playback/volumeosd"]); + if (!appHost.supports('physicalvolumecontrol') || browser.touch) { + require(['components/playback/volumeosd']); } - require(["mediaSession", "serverNotifications"]); + if (navigator.mediaSession || window.NativeShell) { + require(['mediaSession']); + } + require(['serverNotifications']); + require(['date-fns', 'date-fns/locale']); if (!browser.tv && !browser.xboxOne) { - require(["components/playback/playbackorientation"]); + require(['components/playback/playbackorientation']); registerServiceWorker(); if (window.Notification) { - require(["components/notifications/notifications"]); + require(['components/notifications/notifications']); } } - require(["playerSelectionMenu", "fullscreenManager"]); + require(['playerSelectionMenu']); - if (!AppInfo.isNativeApp && window.ApiClient) { - require(["css!" + ApiClient.getUrl("Branding/Css")]); + var apiClient = window.ConnectionManager && window.ConnectionManager.currentApiClient(); + if (apiClient) { + fetch(apiClient.getUrl('Branding/Css')) + .then(function(response) { + if (!response.ok) { + throw new Error(response.status + ' ' + response.statusText); + } + return response.text(); + }) + .then(function(css) { + // Inject the branding css as a dom element in body so it will take + // precedence over other stylesheets + var style = document.createElement('style'); + style.appendChild(document.createTextNode(css)); + document.body.appendChild(style); + }) + .catch(function(err) { + console.warn('Error applying custom css', err); + }); } }); }); } function registerServiceWorker() { - if (navigator.serviceWorker && "cordova" !== self.appMode && "android" !== self.appMode) { + /* eslint-disable compat/compat */ + if (navigator.serviceWorker && self.appMode !== 'cordova' && self.appMode !== 'android') { try { - navigator.serviceWorker.register("serviceworker.js"); + navigator.serviceWorker.register('serviceworker.js'); } catch (err) { - console.log("Error registering serviceWorker: " + err); + console.error('error registering serviceWorker: ' + err); } + } else { + console.warn('serviceWorker unsupported'); } + /* eslint-enable compat/compat */ } function onWebComponentsReady(browser) { @@ -639,71 +616,85 @@ var AppInfo = {}; AppInfo.isNativeApp = true; } - if (!window.Promise || browser.web0s) { - require(["native-promise-only"], init); - } else { - init(); - } + init(); } var localApiClient; (function () { - var urlArgs = "v=" + (window.dashboardVersion || new Date().getDate()); + var urlArgs = 'v=' + (window.dashboardVersion || new Date().getDate()); + var bowerPath = getBowerPath(); var componentsPath = getComponentsPath(); + var elementsPath = getElementsPath(); + var scriptsPath = getScriptsPath(); + var paths = { - browserdeviceprofile: "scripts/browserdeviceprofile", - browser: "scripts/browser", - libraryBrowser: "scripts/librarybrowser", - inputManager: "scripts/inputManager", - datetime: "scripts/datetime", - globalize: "scripts/globalize", - libraryMenu: "scripts/librarymenu", - playlisteditor: componentsPath + "/playlisteditor/playlisteditor", - medialibrarycreator: componentsPath + "/medialibrarycreator/medialibrarycreator", - medialibraryeditor: componentsPath + "/medialibraryeditor/medialibraryeditor", - imageoptionseditor: componentsPath + "/imageoptionseditor/imageoptionseditor", - humanedate: componentsPath + "/humanedate", - apphost: componentsPath + "/apphost", - visibleinviewport: componentsPath + "/visibleinviewport", - qualityoptions: componentsPath + "/qualityoptions", - focusManager: componentsPath + "/focusManager", - itemHelper: componentsPath + "/itemhelper", - itemShortcuts: componentsPath + "/shortcuts", - playQueueManager: componentsPath + "/playback/playqueuemanager", - autoPlayDetect: componentsPath + "/playback/autoplaydetect", - nowPlayingHelper: componentsPath + "/playback/nowplayinghelper", - pluginManager: componentsPath + "/pluginManager", - packageManager: componentsPath + "/packagemanager", - screensaverManager: componentsPath + "/screensavermanager" + browserdeviceprofile: 'scripts/browserdeviceprofile', + browser: 'scripts/browser', + libraryBrowser: 'scripts/librarybrowser', + inputManager: 'scripts/inputManager', + datetime: 'scripts/datetime', + globalize: 'scripts/globalize', + dfnshelper: 'scripts/dfnshelper', + libraryMenu: 'scripts/librarymenu', + playlisteditor: componentsPath + '/playlisteditor/playlisteditor', + medialibrarycreator: componentsPath + '/medialibrarycreator/medialibrarycreator', + medialibraryeditor: componentsPath + '/medialibraryeditor/medialibraryeditor', + imageoptionseditor: componentsPath + '/imageoptionseditor/imageoptionseditor', + apphost: componentsPath + '/apphost', + visibleinviewport: bowerPath + '/visibleinviewport', + qualityoptions: componentsPath + '/qualityoptions', + focusManager: componentsPath + '/focusManager', + itemHelper: componentsPath + '/itemhelper', + itemShortcuts: componentsPath + '/shortcuts', + playQueueManager: componentsPath + '/playback/playqueuemanager', + nowPlayingHelper: componentsPath + '/playback/nowplayinghelper', + pluginManager: componentsPath + '/pluginManager', + packageManager: componentsPath + '/packagemanager', + screensaverManager: componentsPath + '/screensavermanager' }; requirejs.onError = onRequireJsError; requirejs.config({ waitSeconds: 0, map: { - "*": { - css: "components/require/requirecss", - text: "components/require/requiretext" + '*': { + css: 'components/require/requirecss', + text: 'components/require/requiretext' } }, bundles: { bundle: [ - "document-register-element", - "fetch", - "flvjs", - "jstree", - "jQuery", - "hlsjs", - "howler", - "native-promise-only", - "resize-observer-polyfill", - "shaka", - "swiper", - "sortable", - "libjass", - "webcomponents" + 'document-register-element', + 'fetch', + 'flvjs', + 'jstree', + 'jQuery', + 'hlsjs', + 'howler', + 'native-promise-only', + 'resize-observer-polyfill', + 'shaka', + 'swiper', + 'queryString', + 'sortable', + 'webcomponents', + 'material-icons', + 'jellyfin-noto', + 'date-fns', + 'page', + 'polyfill', + 'fast-text-encoding', + 'intersection-observer', + 'classlist-polyfill', + 'screenfull', + 'headroom', + 'apiclient', + 'events', + 'credentialprovider', + 'connectionManagerFactory', + 'appStorage' ] }, urlArgs: urlArgs, @@ -711,184 +702,174 @@ var AppInfo = {}; onError: onRequireJsError }); + require(['fetch']); + require(['polyfill']); + require(['fast-text-encoding']); + require(['intersection-observer']); + require(['classlist-polyfill']); + // Expose jQuery globally - require(["jQuery"], function(jQuery) { + require(['jQuery'], function(jQuery) { window.$ = jQuery; window.jQuery = jQuery; }); - require(["css!assets/css/site"]); + require(['css!assets/css/site']); + require(['jellyfin-noto']); // define styles // TODO determine which of these files can be moved to the components themselves - define("material-icons", ["css!assets/css/material-icons/style"], returnFirstDependency); - define("systemFontsCss", ["css!assets/css/fonts"], returnFirstDependency); - define("systemFontsSizedCss", ["css!assets/css/fonts.sized"], returnFirstDependency); - define("scrollStyles", ["css!assets/css/scrollstyles"], returnFirstDependency); - define("dashboardcss", ["css!assets/css/dashboard"], returnFirstDependency); - define("programStyles", ["css!" + componentsPath + "/guide/programs"], returnFirstDependency); - define("listViewStyle", ["css!" + componentsPath + "/listview/listview"], returnFirstDependency); - define("formDialogStyle", ["css!" + componentsPath + "/formdialog"], returnFirstDependency); - define("clearButtonStyle", ["css!assets/css/clearbutton"], returnFirstDependency); - define("cardStyle", ["css!" + componentsPath + "/cardbuilder/card"], returnFirstDependency); - define("flexStyles", ["css!assets/css/flexstyles"], returnFirstDependency); + define('systemFontsCss', ['css!assets/css/fonts'], returnFirstDependency); + define('systemFontsSizedCss', ['css!assets/css/fonts.sized'], returnFirstDependency); + define('scrollStyles', ['css!assets/css/scrollstyles'], returnFirstDependency); + define('dashboardcss', ['css!assets/css/dashboard'], returnFirstDependency); + define('programStyles', ['css!' + componentsPath + '/guide/programs'], returnFirstDependency); + define('listViewStyle', ['css!' + componentsPath + '/listview/listview'], returnFirstDependency); + define('formDialogStyle', ['css!' + componentsPath + '/formdialog'], returnFirstDependency); + define('clearButtonStyle', ['css!assets/css/clearbutton'], returnFirstDependency); + define('cardStyle', ['css!' + componentsPath + '/cardbuilder/card'], returnFirstDependency); + define('flexStyles', ['css!assets/css/flexstyles'], returnFirstDependency); // define legacy features // TODO delete the rest of these - define("fnchecked", ["legacy/fnchecked"], returnFirstDependency); - define("legacyDashboard", ["legacy/dashboard"], returnFirstDependency); - define("legacySelectMenu", ["legacy/selectmenu"], returnFirstDependency); + define('fnchecked', ['legacy/fnchecked'], returnFirstDependency); + define('legacyDashboard', ['legacy/dashboard'], returnFirstDependency); + define('legacySelectMenu', ['legacy/selectmenu'], returnFirstDependency); // there are several objects that need to be instantiated // TODO find a better way to do this - define("appFooter", [componentsPath + "/appfooter/appfooter"], returnFirstDependency); - define("appFooter-shared", ["appFooter"], createSharedAppFooter); - - // TODO pull apiclient out of this repository - define('events', [bowerPath + "/apiclient/events"], returnFirstDependency); - define('credentialprovider', [bowerPath + "/apiclient/credentialprovider"], returnFirstDependency); - define('connectionManagerFactory', [bowerPath + "/apiclient/connectionmanager"], returnFirstDependency); - define('appStorage', [bowerPath + "/apiclient/appStorage"], returnFirstDependency); - define("serversync", [bowerPath + "/apiclient/sync/serversync"], returnFirstDependency); - define("multiserversync", [bowerPath + "/apiclient/sync/multiserversync"], returnFirstDependency); - define("mediasync", [bowerPath + "/apiclient/sync/mediasync"], returnFirstDependency); - define("itemrepository", [bowerPath + "/apiclient/sync/itemrepository"], returnFirstDependency); - define("useractionrepository", [bowerPath + "/apiclient/sync/useractionrepository"], returnFirstDependency); + define('appFooter', [componentsPath + '/appfooter/appfooter'], returnFirstDependency); + define('appFooter-shared', ['appFooter'], createSharedAppFooter); // TODO remove these libraries // all of these have been modified so we need to fix that first - define("page", [bowerPath + "/pagejs/page"], returnFirstDependency); - define("headroom", [componentsPath + "/headroom/headroom"], returnFirstDependency); - define("scroller", [componentsPath + "/scroller"], returnFirstDependency); - define("navdrawer", [componentsPath + "/navdrawer/navdrawer"], returnFirstDependency); - define("queryString", [bowerPath + "/query-string/index"], function () { - return queryString; - }); + define('scroller', [bowerPath + '/scroller'], returnFirstDependency); + define('navdrawer', [bowerPath + '/navdrawer/navdrawer'], returnFirstDependency); - var elementsPath = "elements" - define("emby-button", [elementsPath + "/emby-button/emby-button"], returnFirstDependency); - define("paper-icon-button-light", [elementsPath + "/emby-button/paper-icon-button-light"], returnFirstDependency); - define("emby-checkbox", [elementsPath + "/emby-checkbox/emby-checkbox"], returnFirstDependency); - define("emby-collapse", [elementsPath + "/emby-collapse/emby-collapse"], returnFirstDependency); - define("emby-input", [elementsPath + "/emby-input/emby-input"], returnFirstDependency); - define("emby-progressring", [elementsPath + "/emby-progressring/emby-progressring"], returnFirstDependency); - define("emby-radio", [elementsPath + "/emby-radio/emby-radio"], returnFirstDependency); - define("emby-select", [elementsPath + "/emby-select/emby-select"], returnFirstDependency); - define("emby-slider", [elementsPath + "/emby-slider/emby-slider"], returnFirstDependency); - define("emby-textarea", [elementsPath + "/emby-textarea/emby-textarea"], returnFirstDependency); - define("emby-toggle", [elementsPath + "/emby-toggle/emby-toggle"], returnFirstDependency); + define('emby-button', [elementsPath + '/emby-button/emby-button'], returnFirstDependency); + define('paper-icon-button-light', [elementsPath + '/emby-button/paper-icon-button-light'], returnFirstDependency); + define('emby-checkbox', [elementsPath + '/emby-checkbox/emby-checkbox'], returnFirstDependency); + define('emby-collapse', [elementsPath + '/emby-collapse/emby-collapse'], returnFirstDependency); + define('emby-input', [elementsPath + '/emby-input/emby-input'], returnFirstDependency); + define('emby-progressring', [elementsPath + '/emby-progressring/emby-progressring'], returnFirstDependency); + define('emby-radio', [elementsPath + '/emby-radio/emby-radio'], returnFirstDependency); + define('emby-select', [elementsPath + '/emby-select/emby-select'], returnFirstDependency); + define('emby-slider', [elementsPath + '/emby-slider/emby-slider'], returnFirstDependency); + define('emby-textarea', [elementsPath + '/emby-textarea/emby-textarea'], returnFirstDependency); + define('emby-toggle', [elementsPath + '/emby-toggle/emby-toggle'], returnFirstDependency); + define('emby-scroller', [elementsPath + '/emby-scroller/emby-scroller'], returnFirstDependency); + define('emby-tabs', [elementsPath + '/emby-tabs/emby-tabs'], returnFirstDependency); + define('emby-scrollbuttons', [elementsPath + '/emby-scrollbuttons/emby-scrollbuttons'], returnFirstDependency); + define('emby-itemrefreshindicator', [elementsPath + '/emby-itemrefreshindicator/emby-itemrefreshindicator'], returnFirstDependency); + define('emby-itemscontainer', [elementsPath + '/emby-itemscontainer/emby-itemscontainer'], returnFirstDependency); + define('emby-playstatebutton', [elementsPath + '/emby-playstatebutton/emby-playstatebutton'], returnFirstDependency); + define('emby-ratingbutton', [elementsPath + '/emby-ratingbutton/emby-ratingbutton'], returnFirstDependency); + define('emby-progressbar', [elementsPath + '/emby-progressbar/emby-progressbar'], returnFirstDependency); + define('emby-programcell', [elementsPath + '/emby-programcell/emby-programcell'], returnFirstDependency); - define("chromecastHelper", [componentsPath + "/chromecast/chromecasthelpers"], returnFirstDependency); - define("mediaSession", [componentsPath + "/playback/mediasession"], returnFirstDependency); - define("actionsheet", [componentsPath + "/actionsheet/actionsheet"], returnFirstDependency); - define("tunerPicker", [componentsPath + "/tunerpicker"], returnFirstDependency); - define("mainTabsManager", [componentsPath + "/maintabsmanager"], returnFirstDependency); - define("imageLoader", [componentsPath + "/images/imageLoader"], returnFirstDependency); - define("directorybrowser", [componentsPath + "/directorybrowser/directorybrowser"], returnFirstDependency); - define("metadataEditor", [componentsPath + "/metadataeditor/metadataeditor"], returnFirstDependency); - define("personEditor", [componentsPath + "/metadataeditor/personeditor"], returnFirstDependency); - define("playerSelectionMenu", [componentsPath + "/playback/playerSelectionMenu"], returnFirstDependency); - define("playerSettingsMenu", [componentsPath + "/playback/playersettingsmenu"], returnFirstDependency); - define("playMethodHelper", [componentsPath + "/playback/playmethodhelper"], returnFirstDependency); - define("brightnessOsd", [componentsPath + "/playback/brightnessosd"], returnFirstDependency); - define("emby-itemscontainer", [componentsPath + "/emby-itemscontainer/emby-itemscontainer"], returnFirstDependency); - define("alphaNumericShortcuts", [componentsPath + "/alphanumericshortcuts/alphanumericshortcuts"], returnFirstDependency); - define("emby-scroller", [componentsPath + "/emby-scroller/emby-scroller"], returnFirstDependency); - define("emby-tabs", [componentsPath + "/emby-tabs/emby-tabs"], returnFirstDependency); - define("emby-scrollbuttons", [componentsPath + "/emby-scrollbuttons/emby-scrollbuttons"], returnFirstDependency); - define("emby-itemrefreshindicator", [componentsPath + "/emby-itemrefreshindicator/emby-itemrefreshindicator"], returnFirstDependency); - define("multiSelect", [componentsPath + "/multiselect/multiselect"], returnFirstDependency); - define("alphaPicker", [componentsPath + "/alphapicker/alphapicker"], returnFirstDependency); - define("tabbedView", [componentsPath + "/tabbedview/tabbedview"], returnFirstDependency); - define("itemsTab", [componentsPath + "/tabbedview/itemstab"], returnFirstDependency); - define("collectionEditor", [componentsPath + "/collectioneditor/collectioneditor"], returnFirstDependency); - define("serverRestartDialog", [componentsPath + "/serverRestartDialog"], returnFirstDependency); - define("playlistEditor", [componentsPath + "/playlisteditor/playlisteditor"], returnFirstDependency); - define("recordingCreator", [componentsPath + "/recordingcreator/recordingcreator"], returnFirstDependency); - define("recordingEditor", [componentsPath + "/recordingcreator/recordingeditor"], returnFirstDependency); - define("seriesRecordingEditor", [componentsPath + "/recordingcreator/seriesrecordingeditor"], returnFirstDependency); - define("recordingFields", [componentsPath + "/recordingcreator/recordingfields"], returnFirstDependency); - define("recordingButton", [componentsPath + "/recordingcreator/recordingbutton"], returnFirstDependency); - define("recordingHelper", [componentsPath + "/recordingcreator/recordinghelper"], returnFirstDependency); - define("subtitleEditor", [componentsPath + "/subtitleeditor/subtitleeditor"], returnFirstDependency); - define("subtitleSync", [componentsPath + "/subtitlesync/subtitlesync"], returnFirstDependency); - define("itemIdentifier", [componentsPath + "/itemidentifier/itemidentifier"], returnFirstDependency); - define("itemMediaInfo", [componentsPath + "/itemMediaInfo/itemMediaInfo"], returnFirstDependency); - define("mediaInfo", [componentsPath + "/mediainfo/mediainfo"], returnFirstDependency); - define("itemContextMenu", [componentsPath + "/itemcontextmenu"], returnFirstDependency); - define("imageEditor", [componentsPath + "/imageeditor/imageeditor"], returnFirstDependency); - define("imageDownloader", [componentsPath + "/imagedownloader/imagedownloader"], returnFirstDependency); - define("dom", [componentsPath + "/dom"], returnFirstDependency); - define("playerStats", [componentsPath + "/playerstats/playerstats"], returnFirstDependency); - define("searchFields", [componentsPath + "/search/searchfields"], returnFirstDependency); - define("searchResults", [componentsPath + "/search/searchresults"], returnFirstDependency); - define("upNextDialog", [componentsPath + "/upnextdialog/upnextdialog"], returnFirstDependency); - define("fullscreen-doubleclick", [componentsPath + "/fullscreen/fullscreen-dc"], returnFirstDependency); - define("fullscreenManager", [componentsPath + "/fullscreenManager", "events"], returnFirstDependency); - define("subtitleAppearanceHelper", [componentsPath + "/subtitlesettings/subtitleappearancehelper"], returnFirstDependency); - define("subtitleSettings", [componentsPath + "/subtitlesettings/subtitlesettings"], returnFirstDependency); - define("displaySettings", [componentsPath + "/displaysettings/displaysettings"], returnFirstDependency); - define("playbackSettings", [componentsPath + "/playbacksettings/playbacksettings"], returnFirstDependency); - define("homescreenSettings", [componentsPath + "/homescreensettings/homescreensettings"], returnFirstDependency); - define("playbackManager", [componentsPath + "/playback/playbackmanager"], getPlaybackManager); - define("layoutManager", [componentsPath + "/layoutManager", "apphost"], getLayoutManager); - define("homeSections", [componentsPath + "/homesections/homesections"], returnFirstDependency); - define("playMenu", [componentsPath + "/playmenu"], returnFirstDependency); - define("refreshDialog", [componentsPath + "/refreshdialog/refreshdialog"], returnFirstDependency); - define("backdrop", [componentsPath + "/backdrop/backdrop"], returnFirstDependency); - define("fetchHelper", [componentsPath + "/fetchhelper"], returnFirstDependency); - define("cardBuilder", [componentsPath + "/cardbuilder/cardBuilder"], returnFirstDependency); - define("peoplecardbuilder", [componentsPath + "/cardbuilder/peoplecardbuilder"], returnFirstDependency); - define("chaptercardbuilder", [componentsPath + "/cardbuilder/chaptercardbuilder"], returnFirstDependency); - define("deleteHelper", [componentsPath + "/deletehelper"], returnFirstDependency); - define("tvguide", [componentsPath + "/guide/guide"], returnFirstDependency); - define("guide-settings-dialog", [componentsPath + "/guide/guide-settings"], returnFirstDependency); - define("loadingDialog", [componentsPath + "/loadingdialog/loadingdialog"], returnFirstDependency); - define("viewManager", [componentsPath + "/viewManager/viewManager"], function (viewManager) { + define('webSettings', [scriptsPath + '/settings/webSettings'], returnFirstDependency); + define('appSettings', [scriptsPath + '/settings/appSettings'], returnFirstDependency); + define('userSettings', [scriptsPath + '/settings/userSettings'], returnFirstDependency); + + define('chromecastHelper', [componentsPath + '/chromecast/chromecasthelpers'], returnFirstDependency); + define('mediaSession', [componentsPath + '/playback/mediasession'], returnFirstDependency); + define('actionsheet', [componentsPath + '/actionsheet/actionsheet'], returnFirstDependency); + define('tunerPicker', [componentsPath + '/tunerpicker'], returnFirstDependency); + define('mainTabsManager', [componentsPath + '/maintabsmanager'], returnFirstDependency); + define('imageLoader', [componentsPath + '/images/imageLoader'], returnFirstDependency); + define('directorybrowser', [componentsPath + '/directorybrowser/directorybrowser'], returnFirstDependency); + define('metadataEditor', [componentsPath + '/metadataeditor/metadataeditor'], returnFirstDependency); + define('personEditor', [componentsPath + '/metadataeditor/personeditor'], returnFirstDependency); + define('playerSelectionMenu', [componentsPath + '/playback/playerSelectionMenu'], returnFirstDependency); + define('playerSettingsMenu', [componentsPath + '/playback/playersettingsmenu'], returnFirstDependency); + define('playMethodHelper', [componentsPath + '/playback/playmethodhelper'], returnFirstDependency); + define('brightnessOsd', [componentsPath + '/playback/brightnessosd'], returnFirstDependency); + define('alphaNumericShortcuts', [scriptsPath + '/alphanumericshortcuts'], returnFirstDependency); + define('multiSelect', [componentsPath + '/multiselect/multiselect'], returnFirstDependency); + define('alphaPicker', [componentsPath + '/alphapicker/alphapicker'], returnFirstDependency); + define('tabbedView', [componentsPath + '/tabbedview/tabbedview'], returnFirstDependency); + define('itemsTab', [componentsPath + '/tabbedview/itemstab'], returnFirstDependency); + define('collectionEditor', [componentsPath + '/collectioneditor/collectioneditor'], returnFirstDependency); + define('serverRestartDialog', [componentsPath + '/serverRestartDialog'], returnFirstDependency); + define('playlistEditor', [componentsPath + '/playlisteditor/playlisteditor'], returnFirstDependency); + define('recordingCreator', [componentsPath + '/recordingcreator/recordingcreator'], returnFirstDependency); + define('recordingEditor', [componentsPath + '/recordingcreator/recordingeditor'], returnFirstDependency); + define('seriesRecordingEditor', [componentsPath + '/recordingcreator/seriesrecordingeditor'], returnFirstDependency); + define('recordingFields', [componentsPath + '/recordingcreator/recordingfields'], returnFirstDependency); + define('recordingButton', [componentsPath + '/recordingcreator/recordingbutton'], returnFirstDependency); + define('recordingHelper', [componentsPath + '/recordingcreator/recordinghelper'], returnFirstDependency); + define('subtitleEditor', [componentsPath + '/subtitleeditor/subtitleeditor'], returnFirstDependency); + define('subtitleSync', [componentsPath + '/subtitlesync/subtitlesync'], returnFirstDependency); + define('itemIdentifier', [componentsPath + '/itemidentifier/itemidentifier'], returnFirstDependency); + define('itemMediaInfo', [componentsPath + '/itemMediaInfo/itemMediaInfo'], returnFirstDependency); + define('mediaInfo', [componentsPath + '/mediainfo/mediainfo'], returnFirstDependency); + define('itemContextMenu', [componentsPath + '/itemcontextmenu'], returnFirstDependency); + define('imageEditor', [componentsPath + '/imageeditor/imageeditor'], returnFirstDependency); + define('imageDownloader', [componentsPath + '/imagedownloader/imagedownloader'], returnFirstDependency); + define('dom', [scriptsPath + '/dom'], returnFirstDependency); + define('playerStats', [componentsPath + '/playerstats/playerstats'], returnFirstDependency); + define('searchFields', [componentsPath + '/search/searchfields'], returnFirstDependency); + define('searchResults', [componentsPath + '/search/searchresults'], returnFirstDependency); + define('upNextDialog', [componentsPath + '/upnextdialog/upnextdialog'], returnFirstDependency); + define('subtitleAppearanceHelper', [componentsPath + '/subtitlesettings/subtitleappearancehelper'], returnFirstDependency); + define('subtitleSettings', [componentsPath + '/subtitlesettings/subtitlesettings'], returnFirstDependency); + define('displaySettings', [componentsPath + '/displaysettings/displaysettings'], returnFirstDependency); + define('playbackSettings', [componentsPath + '/playbacksettings/playbacksettings'], returnFirstDependency); + define('homescreenSettings', [componentsPath + '/homescreensettings/homescreensettings'], returnFirstDependency); + define('playbackManager', [componentsPath + '/playback/playbackmanager'], getPlaybackManager); + define('layoutManager', [componentsPath + '/layoutManager', 'apphost'], getLayoutManager); + define('homeSections', [componentsPath + '/homesections/homesections'], returnFirstDependency); + define('playMenu', [componentsPath + '/playmenu'], returnFirstDependency); + define('refreshDialog', [componentsPath + '/refreshdialog/refreshdialog'], returnFirstDependency); + define('backdrop', [componentsPath + '/backdrop/backdrop'], returnFirstDependency); + define('fetchHelper', [componentsPath + '/fetchhelper'], returnFirstDependency); + define('cardBuilder', [componentsPath + '/cardbuilder/cardBuilder'], returnFirstDependency); + define('peoplecardbuilder', [componentsPath + '/cardbuilder/peoplecardbuilder'], returnFirstDependency); + define('chaptercardbuilder', [componentsPath + '/cardbuilder/chaptercardbuilder'], returnFirstDependency); + define('deleteHelper', [componentsPath + '/deletehelper'], returnFirstDependency); + define('tvguide', [componentsPath + '/guide/guide'], returnFirstDependency); + define('guide-settings-dialog', [componentsPath + '/guide/guide-settings'], returnFirstDependency); + define('loadingDialog', [componentsPath + '/loadingdialog/loadingdialog'], returnFirstDependency); + define('viewManager', [componentsPath + '/viewManager/viewManager'], function (viewManager) { window.ViewManager = viewManager; viewManager.dispatchPageEvents(true); return viewManager; }); - define("slideshow", [componentsPath + "/slideshow/slideshow"], returnFirstDependency); - define("objectassign", [componentsPath + "/polyfills/objectassign"], returnFirstDependency); - define("focusPreventScroll", [componentsPath + "/polyfills/focusPreventScroll"], returnFirstDependency); - define("userdataButtons", [componentsPath + "/userdatabuttons/userdatabuttons"], returnFirstDependency); - define("emby-playstatebutton", [componentsPath + "/userdatabuttons/emby-playstatebutton"], returnFirstDependency); - define("emby-ratingbutton", [componentsPath + "/userdatabuttons/emby-ratingbutton"], returnFirstDependency); - define("listView", [componentsPath + "/listview/listview"], returnFirstDependency); - define("indicators", [componentsPath + "/indicators/indicators"], returnFirstDependency); - define("viewSettings", [componentsPath + "/viewsettings/viewsettings"], returnFirstDependency); - define("filterMenu", [componentsPath + "/filtermenu/filtermenu"], returnFirstDependency); - define("sortMenu", [componentsPath + "/sortmenu/sortmenu"], returnFirstDependency); - define("idb", [componentsPath + "/idb"], returnFirstDependency); - define("sanitizefilename", [componentsPath + "/sanitizefilename"], returnFirstDependency); - define("toast", [componentsPath + "/toast/toast"], returnFirstDependency); - define("scrollHelper", [componentsPath + "/scrollhelper"], returnFirstDependency); - define("touchHelper", [componentsPath + "/touchhelper"], returnFirstDependency); - define("appSettings", [componentsPath + "/appSettings"], returnFirstDependency); - define("userSettings", [componentsPath + "/usersettings/usersettings"], returnFirstDependency); - define("userSettingsBuilder", [componentsPath + "/usersettings/usersettingsbuilder", "layoutManager", "browser"], returnFirstDependency); - define("imageUploader", [componentsPath + "/imageuploader/imageuploader"], returnFirstDependency); - define("htmlMediaHelper", [componentsPath + "/htmlMediaHelper"], returnFirstDependency); - define("viewContainer", [componentsPath + "/viewContainer"], returnFirstDependency); - define("dialogHelper", [componentsPath + "/dialogHelper/dialogHelper"], returnFirstDependency); - define("serverNotifications", [componentsPath + "/serverNotifications/serverNotifications"], returnFirstDependency); - define("skinManager", [componentsPath + "/skinManager"], returnFirstDependency); - define("keyboardnavigation", [componentsPath + "/keyboardnavigation"], returnFirstDependency); - define("scrollManager", [componentsPath + "/scrollManager"], returnFirstDependency); - define("autoFocuser", [componentsPath + "/autoFocuser"], returnFirstDependency); - define("connectionManager", [], function () { + define('slideshow', [componentsPath + '/slideshow/slideshow'], returnFirstDependency); + define('focusPreventScroll', ['legacy/focusPreventScroll'], returnFirstDependency); + define('userdataButtons', [componentsPath + '/userdatabuttons/userdatabuttons'], returnFirstDependency); + define('listView', [componentsPath + '/listview/listview'], returnFirstDependency); + define('indicators', [componentsPath + '/indicators/indicators'], returnFirstDependency); + define('viewSettings', [componentsPath + '/viewsettings/viewsettings'], returnFirstDependency); + define('filterMenu', [componentsPath + '/filtermenu/filtermenu'], returnFirstDependency); + define('sortMenu', [componentsPath + '/sortmenu/sortmenu'], returnFirstDependency); + define('idb', [componentsPath + '/idb'], returnFirstDependency); + define('sanitizefilename', [componentsPath + '/sanitizefilename'], returnFirstDependency); + define('toast', [componentsPath + '/toast/toast'], returnFirstDependency); + define('scrollHelper', [componentsPath + '/scrollhelper'], returnFirstDependency); + define('touchHelper', [componentsPath + '/touchhelper'], returnFirstDependency); + define('imageUploader', [componentsPath + '/imageuploader/imageuploader'], returnFirstDependency); + define('htmlMediaHelper', [componentsPath + '/htmlMediaHelper'], returnFirstDependency); + define('viewContainer', [componentsPath + '/viewContainer'], returnFirstDependency); + define('dialogHelper', [componentsPath + '/dialogHelper/dialogHelper'], returnFirstDependency); + define('serverNotifications', [componentsPath + '/serverNotifications'], returnFirstDependency); + define('skinManager', [componentsPath + '/skinManager'], returnFirstDependency); + define('keyboardnavigation', [scriptsPath + '/keyboardnavigation'], returnFirstDependency); + define('mouseManager', [scriptsPath + '/mouseManager'], returnFirstDependency); + define('scrollManager', [componentsPath + '/scrollManager'], returnFirstDependency); + define('autoFocuser', [componentsPath + '/autoFocuser'], returnFirstDependency); + define('connectionManager', [], function () { return ConnectionManager; }); - define("apiClientResolver", [], function () { + define('apiClientResolver', [], function () { return function () { return window.ApiClient; }; }); - define("appRouter", [componentsPath + "/appRouter", "itemHelper"], function (appRouter, itemHelper) { + define('appRouter', [componentsPath + '/appRouter', 'itemHelper'], function (appRouter, itemHelper) { function showItem(item, serverId, options) { - if ("string" == typeof item) { - require(["connectionManager"], function (connectionManager) { + if ('string' == typeof item) { + require(['connectionManager'], function (connectionManager) { var apiClient = connectionManager.currentApiClient(); apiClient.getItem(apiClient.getCurrentUserId(), item).then(function (item) { appRouter.showItem(item, options); @@ -899,62 +880,58 @@ var AppInfo = {}; options = arguments[1]; } - appRouter.show("/" + appRouter.getRouteUrl(item, options), { + appRouter.show('/' + appRouter.getRouteUrl(item, options), { item: item }); } } appRouter.showLocalLogin = function (serverId, manualLogin) { - Dashboard.navigate("login.html?serverid=" + serverId); + Dashboard.navigate('login.html?serverid=' + serverId); }; appRouter.showVideoOsd = function () { - return Dashboard.navigate("videoosd.html"); + return Dashboard.navigate('videoosd.html'); }; appRouter.showSelectServer = function () { - Dashboard.navigate(AppInfo.isNativeApp ? "selectserver.html" : "login.html"); + Dashboard.navigate(AppInfo.isNativeApp ? 'selectserver.html' : 'login.html'); }; appRouter.showWelcome = function () { - Dashboard.navigate(AppInfo.isNativeApp ? "selectserver.html" : "login.html"); + Dashboard.navigate(AppInfo.isNativeApp ? 'selectserver.html' : 'login.html'); }; appRouter.showSettings = function () { - Dashboard.navigate("mypreferencesmenu.html"); + Dashboard.navigate('mypreferencesmenu.html'); }; appRouter.showGuide = function () { - Dashboard.navigate("livetv.html?tab=1"); + Dashboard.navigate('livetv.html?tab=1'); }; appRouter.goHome = function () { - Dashboard.navigate("home.html"); + Dashboard.navigate('home.html'); }; appRouter.showSearch = function () { - Dashboard.navigate("search.html"); + Dashboard.navigate('search.html'); }; appRouter.showLiveTV = function () { - Dashboard.navigate("livetv.html"); + Dashboard.navigate('livetv.html'); }; appRouter.showRecordedTV = function () { - Dashboard.navigate("livetv.html?tab=3"); + Dashboard.navigate('livetv.html?tab=3'); }; appRouter.showFavorites = function () { - Dashboard.navigate("home.html?tab=1"); + Dashboard.navigate('home.html?tab=1'); }; appRouter.showSettings = function () { - Dashboard.navigate("mypreferencesmenu.html"); - }; - - appRouter.showNowPlaying = function () { - Dashboard.navigate("nowplaying.html"); + Dashboard.navigate('mypreferencesmenu.html'); }; appRouter.setTitle = function (title) { @@ -963,7 +940,7 @@ var AppInfo = {}; appRouter.getRouteUrl = function (item, options) { if (!item) { - throw new Error("item cannot be null"); + throw new Error('item cannot be null'); } if (item.url) { @@ -981,168 +958,168 @@ var AppInfo = {}; var itemType = item.Type || (options ? options.itemType : null); var serverId = item.ServerId || options.serverId; - if ("settings" === item) { - return "mypreferencesmenu.html"; + if ('settings' === item) { + return 'mypreferencesmenu.html'; } - if ("wizard" === item) { - return "wizardstart.html"; + if ('wizard' === item) { + return 'wizardstart.html'; } - if ("manageserver" === item) { - return "dashboard.html"; + if ('manageserver' === item) { + return 'dashboard.html'; } - if ("recordedtv" === item) { - return "livetv.html?tab=3&serverId=" + options.serverId; + if ('recordedtv' === item) { + return 'livetv.html?tab=3&serverId=' + options.serverId; } - if ("nextup" === item) { - return "list.html?type=nextup&serverId=" + options.serverId; + if ('nextup' === item) { + return 'list.html?type=nextup&serverId=' + options.serverId; } - if ("list" === item) { - var url = "list.html?serverId=" + options.serverId + "&type=" + options.itemTypes; + if ('list' === item) { + var url = 'list.html?serverId=' + options.serverId + '&type=' + options.itemTypes; if (options.isFavorite) { - url += "&IsFavorite=true"; + url += '&IsFavorite=true'; } return url; } - if ("livetv" === item) { - if ("programs" === options.section) { - return "livetv.html?tab=0&serverId=" + options.serverId; + if ('livetv' === item) { + if ('programs' === options.section) { + return 'livetv.html?tab=0&serverId=' + options.serverId; } - if ("guide" === options.section) { - return "livetv.html?tab=1&serverId=" + options.serverId; + if ('guide' === options.section) { + return 'livetv.html?tab=1&serverId=' + options.serverId; } - if ("movies" === options.section) { - return "list.html?type=Programs&IsMovie=true&serverId=" + options.serverId; + if ('movies' === options.section) { + return 'list.html?type=Programs&IsMovie=true&serverId=' + options.serverId; } - if ("shows" === options.section) { - return "list.html?type=Programs&IsSeries=true&IsMovie=false&IsNews=false&serverId=" + options.serverId; + if ('shows' === options.section) { + return 'list.html?type=Programs&IsSeries=true&IsMovie=false&IsNews=false&serverId=' + options.serverId; } - if ("sports" === options.section) { - return "list.html?type=Programs&IsSports=true&serverId=" + options.serverId; + if ('sports' === options.section) { + return 'list.html?type=Programs&IsSports=true&serverId=' + options.serverId; } - if ("kids" === options.section) { - return "list.html?type=Programs&IsKids=true&serverId=" + options.serverId; + if ('kids' === options.section) { + return 'list.html?type=Programs&IsKids=true&serverId=' + options.serverId; } - if ("news" === options.section) { - return "list.html?type=Programs&IsNews=true&serverId=" + options.serverId; + if ('news' === options.section) { + return 'list.html?type=Programs&IsNews=true&serverId=' + options.serverId; } - if ("onnow" === options.section) { - return "list.html?type=Programs&IsAiring=true&serverId=" + options.serverId; + if ('onnow' === options.section) { + return 'list.html?type=Programs&IsAiring=true&serverId=' + options.serverId; } - if ("dvrschedule" === options.section) { - return "livetv.html?tab=4&serverId=" + options.serverId; + if ('dvrschedule' === options.section) { + return 'livetv.html?tab=4&serverId=' + options.serverId; } - if ("seriesrecording" === options.section) { - return "livetv.html?tab=5&serverId=" + options.serverId; + if ('seriesrecording' === options.section) { + return 'livetv.html?tab=5&serverId=' + options.serverId; } - return "livetv.html?serverId=" + options.serverId; + return 'livetv.html?serverId=' + options.serverId; } - if ("SeriesTimer" == itemType) { - return "itemdetails.html?seriesTimerId=" + id + "&serverId=" + serverId; + if ('SeriesTimer' == itemType) { + return 'itemdetails.html?seriesTimerId=' + id + '&serverId=' + serverId; } - if ("livetv" == item.CollectionType) { - return "livetv.html"; + if ('livetv' == item.CollectionType) { + return 'livetv.html'; } - if ("Genre" === item.Type) { - url = "list.html?genreId=" + item.Id + "&serverId=" + serverId; + if ('Genre' === item.Type) { + url = 'list.html?genreId=' + item.Id + '&serverId=' + serverId; - if ("livetv" === context) { - url += "&type=Programs"; + if ('livetv' === context) { + url += '&type=Programs'; } if (options.parentId) { - url += "&parentId=" + options.parentId; + url += '&parentId=' + options.parentId; } return url; } - if ("MusicGenre" === item.Type) { - url = "list.html?musicGenreId=" + item.Id + "&serverId=" + serverId; + if ('MusicGenre' === item.Type) { + url = 'list.html?musicGenreId=' + item.Id + '&serverId=' + serverId; if (options.parentId) { - url += "&parentId=" + options.parentId; + url += '&parentId=' + options.parentId; } return url; } - if ("Studio" === item.Type) { - url = "list.html?studioId=" + item.Id + "&serverId=" + serverId; + if ('Studio' === item.Type) { + url = 'list.html?studioId=' + item.Id + '&serverId=' + serverId; if (options.parentId) { - url += "&parentId=" + options.parentId; + url += '&parentId=' + options.parentId; } return url; } - if ("folders" !== context && !itemHelper.isLocalItem(item)) { - if ("movies" == item.CollectionType) { - url = "movies.html?topParentId=" + item.Id; + if ('folders' !== context && !itemHelper.isLocalItem(item)) { + if ('movies' == item.CollectionType) { + url = 'movies.html?topParentId=' + item.Id; - if (options && "latest" === options.section) { - url += "&tab=1"; + if (options && 'latest' === options.section) { + url += '&tab=1'; } return url; } - if ("tvshows" == item.CollectionType) { - url = "tv.html?topParentId=" + item.Id; + if ('tvshows' == item.CollectionType) { + url = 'tv.html?topParentId=' + item.Id; - if (options && "latest" === options.section) { - url += "&tab=2"; + if (options && 'latest' === options.section) { + url += '&tab=2'; } return url; } - if ("music" == item.CollectionType) { - return "music.html?topParentId=" + item.Id; + if ('music' == item.CollectionType) { + return 'music.html?topParentId=' + item.Id; } } - var itemTypes = ["Playlist", "TvChannel", "Program", "BoxSet", "MusicAlbum", "MusicGenre", "Person", "Recording", "MusicArtist"]; + var itemTypes = ['Playlist', 'TvChannel', 'Program', 'BoxSet', 'MusicAlbum', 'MusicGenre', 'Person', 'Recording', 'MusicArtist']; if (itemTypes.indexOf(itemType) >= 0) { - return "itemdetails.html?id=" + id + "&serverId=" + serverId; + return 'itemdetails.html?id=' + id + '&serverId=' + serverId; } - var contextSuffix = context ? "&context=" + context : ""; + var contextSuffix = context ? '&context=' + context : ''; - if ("Series" == itemType || "Season" == itemType || "Episode" == itemType) { - return "itemdetails.html?id=" + id + contextSuffix + "&serverId=" + serverId; + if ('Series' == itemType || 'Season' == itemType || 'Episode' == itemType) { + return 'itemdetails.html?id=' + id + contextSuffix + '&serverId=' + serverId; } if (item.IsFolder) { if (id) { - return "list.html?parentId=" + id + "&serverId=" + serverId; + return 'list.html?parentId=' + id + '&serverId=' + serverId; } - return "#"; + return '#'; } - return "itemdetails.html?id=" + id + "&serverId=" + serverId; + return 'itemdetails.html?id=' + id + '&serverId=' + serverId; }; appRouter.showItem = showItem; @@ -1150,13 +1127,13 @@ var AppInfo = {}; }); })(); - return require(["browser"], onWebComponentsReady); + return require(['browser'], onWebComponentsReady); }(); -pageClassOn("viewshow", "standalonePage", function () { - document.querySelector(".skinHeader").classList.add("noHeaderRight"); +pageClassOn('viewshow', 'standalonePage', function () { + document.querySelector('.skinHeader').classList.add('noHeaderRight'); }); -pageClassOn("viewhide", "standalonePage", function () { - document.querySelector(".skinHeader").classList.remove("noHeaderRight"); +pageClassOn('viewhide', 'standalonePage', function () { + document.querySelector('.skinHeader').classList.remove('noHeaderRight'); }); diff --git a/src/scripts/taskbutton.js b/src/scripts/taskbutton.js index f9774167c0..8facaf8900 100644 --- a/src/scripts/taskbutton.js +++ b/src/scripts/taskbutton.js @@ -1,5 +1,5 @@ -define(["events", "userSettings", "serverNotifications", "connectionManager", "emby-button"], function (events, userSettings, serverNotifications, connectionManager) { - "use strict"; +define(['events', 'userSettings', 'serverNotifications', 'connectionManager', 'globalize', 'emby-button'], function (events, userSettings, serverNotifications, connectionManager, globalize) { + 'use strict'; return function (options) { function pollTasks() { @@ -26,12 +26,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e } if (task.State == 'Idle') { - button.removeAttribute("disabled"); + button.removeAttribute('disabled'); } else { - button.setAttribute("disabled", "disabled"); + button.setAttribute('disabled', 'disabled'); } - button.setAttribute("data-taskid", task.Id); + button.setAttribute('data-taskid', task.Id); var progress = (task.CurrentProgressPercentage || 0).toFixed(1); if (options.progressElem) { @@ -47,12 +47,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e if (options.lastResultElem) { var lastResult = task.LastExecutionResult ? task.LastExecutionResult.Status : ''; - if (lastResult == "Failed") { - options.lastResultElem.html('(' + Globalize.translate('LabelFailed') + ')'); - } else if (lastResult == "Cancelled") { - options.lastResultElem.html('(' + Globalize.translate('LabelCancelled') + ')'); - } else if (lastResult == "Aborted") { - options.lastResultElem.html('' + Globalize.translate('LabelAbortedByServerShutdown') + ''); + if (lastResult == 'Failed') { + options.lastResultElem.html('(' + globalize.translate('LabelFailed') + ')'); + } else if (lastResult == 'Cancelled') { + options.lastResultElem.html('(' + globalize.translate('LabelCancelled') + ')'); + } else if (lastResult == 'Aborted') { + options.lastResultElem.html('' + globalize.translate('LabelAbortedByServerShutdown') + ''); } else { options.lastResultElem.html(lastResult); } @@ -64,7 +64,7 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e } function onButtonClick() { - onScheduledTaskMessageConfirmed(this.getAttribute("data-taskid")); + onScheduledTaskMessageConfirmed(this.getAttribute('data-taskid')); } function onScheduledTasksUpdate(e, apiClient, info) { @@ -89,12 +89,12 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e if (pollInterval) { clearInterval(pollInterval); } - apiClient.sendMessage("ScheduledTasksInfoStart", "1000,1000"); + apiClient.sendMessage('ScheduledTasksInfoStart', '1000,1000'); pollInterval = setInterval(onPollIntervalFired, 5000); } function stopInterval() { - connectionManager.getApiClient(serverId).sendMessage("ScheduledTasksInfoStop"); + connectionManager.getApiClient(serverId).sendMessage('ScheduledTasksInfoStop'); if (pollInterval) { clearInterval(pollInterval); @@ -102,18 +102,18 @@ define(["events", "userSettings", "serverNotifications", "connectionManager", "e } if (options.panel) { - options.panel.classList.add("hide"); + options.panel.classList.add('hide'); } if (options.mode == 'off') { - button.removeEventListener("click", onButtonClick); - events.off(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + button.removeEventListener('click', onButtonClick); + events.off(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); stopInterval(); } else { - button.addEventListener("click", onButtonClick); + button.addEventListener('click', onButtonClick); pollTasks(); startInterval(); - events.on(serverNotifications, "ScheduledTasksInfo", onScheduledTasksUpdate); + events.on(serverNotifications, 'ScheduledTasksInfo', onScheduledTasksUpdate); } }; }); diff --git a/src/scripts/themeloader.js b/src/scripts/themeloader.js index ea7ff57f9a..f75d6d0e29 100644 --- a/src/scripts/themeloader.js +++ b/src/scripts/themeloader.js @@ -1,19 +1,19 @@ -define(["userSettings", "skinManager", "connectionManager", "events"], function (userSettings, skinManager, connectionManager, events) { - "use strict"; +define(['userSettings', 'skinManager', 'connectionManager', 'events'], function (userSettings, skinManager, connectionManager, events) { + 'use strict'; var currentViewType; - pageClassOn("viewbeforeshow", "page", function () { + pageClassOn('viewbeforeshow', 'page', function () { var classList = this.classList; - var viewType = classList.contains("type-interior") || classList.contains("wizardPage") ? "a" : "b"; + var viewType = classList.contains('type-interior') || classList.contains('wizardPage') ? 'a' : 'b'; if (viewType !== currentViewType) { currentViewType = viewType; var theme; var context; - if ("a" === viewType) { + if ('a' === viewType) { theme = userSettings.dashboardTheme(); - context = "serverdashboard"; + context = 'serverdashboard'; } else { theme = userSettings.theme(); } @@ -21,7 +21,7 @@ define(["userSettings", "skinManager", "connectionManager", "events"], function skinManager.setTheme(theme, context); } }); - events.on(connectionManager, "localusersignedin", function (e, user) { + events.on(connectionManager, 'localusersignedin', function (e, user) { currentViewType = null; }); }); diff --git a/src/scripts/userpassword.js b/src/scripts/userpassword.js deleted file mode 100644 index 52e06e6cec..0000000000 --- a/src/scripts/userpassword.js +++ /dev/null @@ -1,30 +0,0 @@ -define(["jQuery", "loading", "libraryMenu"], function ($, loading, libraryMenu) { - "use strict"; - - function loadUser(page, user) { - libraryMenu.setTitle(user.Name); - - if ("Guest" == user.ConnectLinkType) { - $(".connectMessage", page).show(); - } else { - $(".connectMessage", page).hide(); - } - - loading.hide(); - } - - function loadData(page) { - loading.show(); - var userId = getParameterByName("userId"); - ApiClient.getUser(userId).then(function (user) { - loadUser(page, user); - }); - } - - $(document).on("pageinit", "#userPasswordPage", function () { - $(".adminUpdatePasswordForm").off("submit", UpdatePasswordPage.onSubmit).on("submit", UpdatePasswordPage.onSubmit); - $(".adminLocalAccessForm").off("submit", UpdatePasswordPage.onLocalAccessSubmit).on("submit", UpdatePasswordPage.onLocalAccessSubmit); - }).on("pagebeforeshow", "#userPasswordPage", function () { - loadData(this); - }); -}); diff --git a/src/scripts/wizardagreement.js b/src/scripts/wizardagreement.js deleted file mode 100644 index 148b0ef39a..0000000000 --- a/src/scripts/wizardagreement.js +++ /dev/null @@ -1,27 +0,0 @@ -define(["dom", "emby-button"], function (dom) { - "use strict"; - - function onSubmit(e) { - if (dom.parentWithClass(this, "page").querySelector(".chkAccept").checked) { - Dashboard.navigate("wizardfinish.html"); - } else { - Dashboard.alert({ - message: Globalize.translate("MessagePleaseAcceptTermsOfServiceBeforeContinuing"), - title: "" - }); - } - - e.preventDefault(); - return false; - } - - return function (view, params) { - view.querySelector(".wizardAgreementForm").addEventListener("submit", onSubmit); - view.addEventListener("viewshow", function () { - document.querySelector(".skinHeader").classList.add("noHomeButtonHeader"); - }); - view.addEventListener("viewhide", function () { - document.querySelector(".skinHeader").classList.remove("noHomeButtonHeader"); - }); - }; -}); diff --git a/src/selectserver.html b/src/selectserver.html index dd52467bfe..2c84525174 100644 --- a/src/selectserver.html +++ b/src/selectserver.html @@ -3,7 +3,7 @@

${HeaderSelectServer}

-
+
diff --git a/src/serviceworker.js b/src/serviceworker.js index 4d9e12ee6a..2210183148 100644 --- a/src/serviceworker.js +++ b/src/serviceworker.js @@ -1 +1,2 @@ -importScripts("components/serviceworker/notifications.js"); \ No newline at end of file +/* eslint-env serviceworker */ +importScripts('components/serviceworker/notifications.js'); diff --git a/src/standalone.js b/src/standalone.js index 04d40d6b11..237872703a 100644 --- a/src/standalone.js +++ b/src/standalone.js @@ -1,4 +1,4 @@ (function() { - "use strict"; + 'use strict'; window.appMode = 'standalone'; })(); diff --git a/src/strings/af.json b/src/strings/af.json index 6ac71790f6..5c4e13dc7c 100644 --- a/src/strings/af.json +++ b/src/strings/af.json @@ -40,5 +40,129 @@ "Add": "Voeg by", "Actor": "Akteur", "AccessRestrictedTryAgainLater": "Toegang is beperk. Probeer weer later .", - "Absolute": "Absoluut" + "Absolute": "Absoluut", + "AlbumArtist": "Album Kunstenaar", + "TabLatest": "Nuutste", + "TabInfo": "Inligting", + "TabGuide": "Gids", + "TabGenres": "Genres", + "TabFavorites": "Gunstellinge", + "TabEpisodes": "Episodes", + "TabDisplay": "Vertoon", + "TabDirectPlay": "Speel Direk", + "TabDevices": "Toestelle", + "TabDashboard": "Paneelbord", + "TabContainers": "Houers", + "Collections": "Versamelings", + "TabCollections": "Versamelings", + "UnsupportedPlayback": "Jellyfin kan nie inhoud wat beskerm word deur DRM ontsuifer nie, maar daar sal 'n poging aangwend word inelkgeval, insluitend beskermde titels. Sommige leêrs mag geheel en al swart verksyn weens enkripsie of ander on-ondersteunde funksies, byvoorbeeld interaktiewe titels.", + "OnApplicationStartup": "Op applikasie begin", + "EveryXHours": "Elke {0} ure", + "EveryHour": "Elke uur", + "EveryXMinutes": "Elke {0} minute", + "OnWakeFromSleep": "Op wakker word van slaap", + "WeeklyAt": "{0}s teen {1}", + "DailyAt": "Daagliks teen {0}", + "LastSeen": "Laas gekyk {0}", + "PersonRole": "soos {0}", + "ListPaging": "{0}-{1} van {2}", + "WriteAccessRequired": "Jellyfin Bediener benodig skryf toegang tot die leêr. Maak asseblief seker dat dit skryf toegang het en probeer weer.", + "PathNotFound": "Die pad kon nie gevind word nie. Maak asseblief seker dat die pad geldig is en probeer weer.", + "Yesterday": "Gister", + "Yes": "Ja", + "XmlTvSportsCategoriesHelp": "Programme met die kategorieë sal vertoon word as sport programme. Verdeel met veelvuldige '|'.", + "XmlTvPathHelp": "'n Pad tot 'n XMLTV lêer. Jellyfin sal die lêer lees en van tyd tot tyd soek vir opdaterings. Jy is verantwoordelik vir die maak en opdatering van die lêer.", + "XmlTvNewsCategoriesHelp": "Programme met die kategorieë sal vertoon word as nuus programme. Verdeel met veelvuldige '|'.", + "XmlTvMovieCategoriesHelp": "Programme met die kategorieë sal vertoon word as replprente. Verdeel met veelvuldige '|'.", + "XmlTvKidsCategoriesHelp": "Programme met die kategorieë sal vertoon word as programme vir kinders. Verdeel met veelvuldige '|'.", + "XmlDocumentAttributeListHelp": "Hierdie kenmerke word toegepas tot die wortel element van elke XML reaksie.", + "Writer": "Skrywer", + "WizardCompleted": "Dit is al wat ons benodig vir nou. Jellyfin het begin om inligting van jou media biblioteek te versamel. Kyk na van ons apps, en dan klik Finaliseer om die Paneelbord.", + "Whitelist": "Witlys", + "WelcomeToProject": "Welkom tot Jellyfin!", + "Wednesday": "Woensdag", + "Watched": "Gekyk", + "ViewPlaybackInfo": "Beskou terugspeel inligting", + "ViewArtist": "Beskou kunstenaar", + "ViewAlbum": "Beskou album", + "VideoRange": "Video reekse", + "Vertical": "Vertikaal", + "ValueVideoCodec": "Video Kodek: {0}", + "ValueTimeLimitSingleHour": "Tyd limiet: 1 uur", + "ValueTimeLimitMultiHour": "Tyd limiet: {0} ure", + "ValueSpecialEpisodeName": "Spesiale - {0}", + "ValueSongCount": "{0} liedjies", + "ValueSeriesCount": "{0} reekse", + "ValueSeconds": "{0} sekondes", + "ValueOneSong": "1 liedjie", + "ValueOneSeries": "1 reeks", + "ValueOneMusicVideo": "1 musiek video", + "ValueOneMovie": "1 rolprent", + "ValueMusicVideoCount": "{0} musiek videos", + "ValueMovieCount": "{0} rolprente", + "ValueMinutes": "{0} minute", + "ValueDiscNumber": "Skyf {0}", + "ValueContainer": "Houers: {0}", + "ValueConditions": "Kondisies: {0}", + "ValueCodec": "Kodek: {0}", + "ValueAudioCodec": "Audio Kodec: {0}", + "ValueAlbumCount": "{0} albums", + "UserProfilesIntro": "Jellyfin verskaf ondersteuning vir gebruiker profiele met pas instellings vir vertoon, speel staat, en ouer-beheer.", + "UserAgentHelp": "Verskaf 'n pas gebruiker-agent HTTP opskrif.", + "Upload": "Oplaai", + "Up": "Op", + "Unplayed": "Ongespeel", + "Unmute": "Ontstom", + "UninstallPluginHeader": "Oninstalleer Plugin", + "UninstallPluginConfirmation": "Is jy seker jy wil voortgaan met die oninstallasie {0}?", + "Uniform": "Uniform", + "TvLibraryHelp": "Hersien die {0}TV benamings gids{1}.", + "Tuesday": "Dinsdag", + "Transcoding": "Trankodering", + "Trailers": "Voorprente", + "TrackCount": "{0} nommers", + "Track": "Nommer", + "TitlePlayback": "Terugspeel", + "TitleHostingSettings": "Hosting Instellings", + "TitleHardwareAcceleration": "Hardeware Versnelling", + "Thursday": "Donderdag", + "Thumb": "Duim", + "ThisWizardWillGuideYou": "Hierdie gids sal jou deur die opstel proses help. Om te begin, kies asseblief jou taal van voorkeur.", + "TheseSettingsAffectSubtitlesOnThisDevice": "Hierdie instellings affekteer die sub-titels vie hierdie toestel", + "ThemeVideos": "Tema Videos", + "ThemeSongs": "Tema Liedjies", + "TellUsAboutYourself": "Vertel ons van jouself", + "TabUsers": "Gebruikers", + "TabUpcoming": "Komende", + "TabTranscoding": "Transkodering", + "TabTrailers": "Voorprente", + "TabSuggestions": "Voorstelle", + "TabStreaming": "Stroom", + "TabSongs": "Liedjies", + "TabShows": "Programme", + "TabSettings": "Instellings", + "TabServer": "Bediener", + "TabSeries": "Reekse", + "TabScheduledTasks": "Geskeduleerde Take", + "TabResumeSettings": "Hervat", + "TabResponses": "Reaksies", + "TabRecordings": "Opnames", + "TabProfiles": "Profiele", + "TabProfile": "Profiel", + "TabPlaylists": "Speel lyste", + "TabPlaylist": "Speel lys", + "TabPlayback": "Terugspeel", + "TabPassword": "Wagwoord", + "TabParentalControl": "Ouer Beheer", + "TabOther": "Ander", + "TabNotifications": "Kennisgewings", + "TabNfoSettings": "NFO Instellings", + "TabNetworking": "Netwerking", + "TabNetworks": "Netwerke", + "TabMusicVideos": "Musiek Videos", + "TabMusic": "Musiek", + "TabMovies": "Rolprente", + "TabMetadata": "Meta Inligting", + "TabLogs": "Logs", + "TabLiveTV": "Lewendige TV" } diff --git a/src/strings/ar.json b/src/strings/ar.json index d9e0040d9d..50b93a830a 100644 --- a/src/strings/ar.json +++ b/src/strings/ar.json @@ -92,7 +92,7 @@ "CinemaModeConfigurationHelp": "الطور السينمائي يوفر أجواء سينمائية إلى قلب صالتك مع إمكانية تشغيل عروض إعلانية لأفلام أخرى وعرض مقدمات أخرى من انتقاءاتك قبل تشغيل الفيلم الرئيسي.", "CustomDlnaProfilesHelp": "إنشاء عرائض مخصوصه تستهدف جهازاً جديداً أو يمتطي حساباً نظامياً.", "DeathDateValue": "توفي: {0}", - "DefaultErrorMessage": "كان هناك خطأ في معالجة الطلب. الرجاء المحاولة لاحقاً", + "DefaultErrorMessage": "كان هناك خطأ في معالجة الطلب. الرجاء المحاولة لاحقاً.", "Delete": "حذف", "DeleteDeviceConfirmation": "هل أنت متأكد أنك تريد حذف هذا الجهاز؟ سيظهر الجهاز من جديد في المرة القادمة التي يسجل فها مستخدم دخوله عبره.", "DeleteImage": "حذف صورة", @@ -103,13 +103,13 @@ "DeviceAccessHelp": "هذه الميزة تنطبق حصرياً على الأجهزة التي يمكن التعرف عليها فردياً ولن تمنع المتصفح من الدخول عليها. ترشيح الوصول لأجهزة المستخدم ستمنع المستخدمين من استعمال الأجهزة الجديدة إلى أن يتم اعتمادهم من هنا.", "DrmChannelsNotImported": "القنوات المجهزة بإدارة الحقوق الرقمية DRM لن تورّد.", "EasyPasswordHelp": "الرمز الشخصي الميسرالخاص بك يمكنك من الاتصال إلى خادم مكتبتك، عبر تطبيقات أمبي على الأجهزة أو الدخول على حسابك في الشبكة الداخلية.", - "EnablePhotos": "تفعيل الصور", + "EnablePhotos": "عرض الصور", "EnablePhotosHelp": "سيتم اكتشاف الصور وعرضها مع ملفات الوسائط الأخرى", "ErrorAddingListingsToSchedulesDirect": "كان هناك خطأ في إضافة الاصطفاف لخدمة \"Schedules Direct\" الخاصة بك. خدمة \"Schedules Direct\" لا تسمح إلا بعدد محدود من الاصطفافات لكل حساب. قد تحتاج إلى تسجيل الدخول إلى موقع \"Schedules Direct\" لإزالة الاصطفافات الأخرى من حسابك قبل المتابعة.", "ErrorAddingMediaPathToVirtualFolder": "كان هناك خطأ في إضافة مسار الوسائط. الرجاء التأكد من صحة المسار وأن خادم أمبي لديه صلاحية الوصول إلى الموقع.", "ErrorAddingTunerDevice": "كان هناك خطأ في إضافة جهاز المولف. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.", - "ErrorAddingXmlTvFile": "كان هناك خطأ في محاولة الوصول إلى ملف XmlTV . الرجاء التأكد من وجود الملف ثم حاول مرة أخرى.", - "ErrorGettingTvLineups": "كان هناك خطأ في إنزال اصطفافات التلفزة. الرجاء التأكد من أن بياناتك صحيحة ثم عاود المحاولة.", + "ErrorAddingXmlTvFile": "كان هناك خطأ في محاولة الوصول إلى ملف XMLTV. الرجاء التأكد من وجود الملف ثم حاول مرة أخرى.", + "ErrorGettingTvLineups": "كان هناك خطأ في إنزال اصطفافات التلفاز. الرجاء التأكد من أن بياناتك صحيحة ثم عاود المحاولة.", "ErrorMessageStartHourGreaterThanEnd": "وقت النهاية يجب أن يكون أكبر من وقت البداية.", "ErrorPleaseSelectLineup": "الرجاء اختيار اصطفاف ثم المحاولة مرة أخرى. إن لم تتوفر أية اصطفافات، فالرجاء التأكد من اسم المستخدم وكلمة المرور الخاصة بك، وتأكد من صحة رمزك البريدي.", "ErrorSavingTvProvider": "كان هناك خطأ في حفظ مزود التلفزة. الرجاء التأكد من صلاحية الوصول إليه ثم عاود المحاولة.", @@ -131,7 +131,7 @@ "GuideProviderLogin": "تسجيل الدخول", "GuideProviderSelectListings": "إختر المبوبات", "H264CrfHelp": "معامل المعدل الثابت CRF هو الجودة الافتراضية لإعدادات مشفر x264. بإمكانك إعطاء قيمة تتراوح بين 0 و 51، وكلما قلت القيمة فسينتج عن ذلك جودة أفضل (على حساب حجم تخزين أعلى). القيم المعقول تتراوح بين 18 و 28. الافتراضي لـ x264 هي 23، لذا فبإمكانك استخدام هذه القيمة كنقطة بداية.", - "H264EncodingPresetHelp": "اختر قيمة أعلى لتحسين السرة والأداء وقيمة أقل لتحسين الجودة.", + "EncoderPresetHelp": "اختر قيمة أعلى لتحسين السرة والأداء وقيمة أقل لتحسين الجودة.", "HardwareAccelerationWarning": "تمكين التسريع بعتاد الحاسوب قد يتسبب في عدم استقرار بعض أنواع الأنظمة. تأكد من أن نظام التشغيل الخاص بك محدث إلى آخر نسخة وأن سواقات الفيديو محدثة أيضاً. إذا واجهت أية صعوبات في تسغيل الفيديو بعد تمكين هذه الخاصية، فعليك إرجاع الإعداد إلى وضعية آلي.", "HeaderAccessSchedule": "جدول الدخولات", "HeaderAccessScheduleHelp": "إنشئ جدول دخولات لكي تتمكن من تحديد ساعات للدخول.", @@ -167,7 +167,7 @@ "HeaderConnectionFailure": "فشل في الاتصال", "HeaderContainerProfile": "عريضة الحاوية", "HeaderContainerProfileHelp": "عرائض الحاويات تشير إلى محدوديات جهاز ما عند تشغيل صيغ معينة. إن كان هناك أي محدودية مذكورة فستحال الوسيطة إلى التشغير البيني، حتى لو كانت الصيغة مضبوطة للعمل بتلقائية.", - "HeaderContinueWatching": "استئناف المشاهدة", + "HeaderContinueWatching": "استئناف", "HeaderCustomDlnaProfiles": "الحسابات المخصوصة", "HeaderDateIssued": "تاريخ الإصدار", "HeaderDefaultRecordingSettings": "إعدادات التسجيل الافتراضية", @@ -195,7 +195,7 @@ "HeaderGuideProviders": "مزودو الأدلة", "HeaderHttpHeaders": "رؤوس http", "HeaderIdentification": "التعريفة", - "HeaderIdentificationCriteriaHelp": "أدخل على الأقل معيار واحد للتعريف", + "HeaderIdentificationCriteriaHelp": "أدخل على الأقل معيار واحد للتعريف.", "HeaderIdentificationHeader": "رأس التعريفة", "HeaderImageOptions": "خيارات الصورة", "HeaderImageSettings": "إعدادات الصورة", @@ -220,7 +220,7 @@ "HeaderMovies": "الأفلام", "HeaderMusicVideos": "الفيديوهات الموسيقية", "HeaderMyMedia": "وسائطي", - "HeaderNewApiKey": "مفتاح api جديد", + "HeaderNewApiKey": "مفتاح API جديد", "HeaderNextUp": "التالي", "HeaderOtherItems": "عناصر أخرى", "HeaderParentalRatings": "التصنيف الأبوي", @@ -295,7 +295,7 @@ "HeaderXmlDocumentAttributes": "سمات مستند xml", "HeaderXmlSettings": "إعدادات xml", "HeaderYears": "السنوات", - "HeadersFolders": "مجلد:", + "HeadersFolders": "مجلدات", "ImportFavoriteChannelsHelp": "عند التفعيل، فقط القنوات التي علّمت في المفضلة على هذا المولف ستورد إلى النظام.", "ImportMissingEpisodesHelp": "عند التمكين، المعلومات الناقصة للحلقات ستورّد إلى قاعدة بيانات أمبي وستعرض داخل المواسم والمسلسلات. قد تتسبب هذه بأوقات أطول بكثير عند تمشيط المكنبات.", "LabelAbortedByServerShutdown": "(تم إهماله بسبب عملية إغلاق الخادم)", @@ -390,7 +390,7 @@ "LabelGroupMoviesIntoCollections": "تجميع الأفلام إلى مجاميع", "LabelGroupMoviesIntoCollectionsHelp": "عند استعراض قوائم الأفلام، فإن الأفلام التي تنتمي إلى مجموعة واحدة ستظهر كعنصر جامع.", "LabelH264Crf": "قيمة CRF لتشفير H264:", - "LabelH264EncodingPreset": "إعدادات تشفير H264:", + "LabelEncoderPreset": "إعدادات تشفير H264:", "LabelHardwareAccelerationType": "التسريع بعتاد الحاسب", "LabelHardwareAccelerationTypeHelp": "متاح في الأنظمة المدعومة فقط.", "LabelHttpsPort": "رقم منفذ https المحتلي:", @@ -587,7 +587,7 @@ "MediaInfoSampleRate": "معدًل الإعتيان", "MediaInfoSize": "حجم", "MediaInfoTimestamp": "البصمة الزمنية", - "MessageAlreadyInstalled": "هذا الإصدار تم تثبيته مسبقاً", + "MessageAlreadyInstalled": "هذا الإصدار تم تثبيته مسبقاً.", "MessageAreYouSureYouWishToRemoveMediaFolder": "هل أنت متأكد أنك تريد إزالة مجلد الوسائط هذا؟", "MessageConfirmDeleteGuideProvider": "هل أنت متأكد أنك ترغب في حذف مزود الدليل هذا؟", "MessageConfirmDeleteTunerDevice": "هل أنت متأكد أنك تريد حذف هذا المولف؟", @@ -595,22 +595,22 @@ "MessageConfirmRemoveMediaLocation": "هل أنت متأكد أنك تريد حذف هذا المكان؟", "MessageConfirmRestart": "هل أنت متأكد أنك تريد أن تعيد تشغيل خادم أمبي؟", "MessageConfirmRevokeApiKey": "هل أنت متأكد من أنك تريد أن ترفض المفتاح (api) هذا؟ سيتم قطع اتصال التطبيق عن خادم أمبي مباشرة.", - "MessageConfirmShutdown": "هل أنت متأكد أنك تريد أن تنهي تشغيل خادم أمبي؟", + "MessageConfirmShutdown": "هل أنت متأكد أنك تريد أن تنهي تشغيل الخادم؟", "MessageContactAdminToResetPassword": "الرجاء التواصل مع مدير النظام لإعادة أعداد كملة سرّك.", "MessageCreateAccountAt": "أنشئ حساب في {0}", "MessageDeleteTaskTrigger": "هل أنت متأكد أنك تريد حذف زناد المهمة؟", "MessageDirectoryPickerBSDInstruction": "من أجل BSD، يمكنك أن تضبط إعدادات التخزين دخال حساب FreeNAS Jail الخاص بك لكي يتمكن أمبي أن يتصل به.", "MessageDirectoryPickerInstruction": "يمكن إدخال مسارات الشبكة يدوياً في حال أن زر الشبكة يخفق في اكتشاف أجهزتك. على سبيل المثال، {0} أو {1}.", - "MessageDirectoryPickerLinuxInstruction": "من أجل أنظمة التشغيل التالية: Linux أو Arch Linux أو CentOS أو Debian أو Fedora أو OpenSuse أو Ubuntu، فيجب أن تمنح مستخدم أمبي النظامي صلاحية القراءة ليتمكن من الوصول إلى أماكن التخزين.", + "MessageDirectoryPickerLinuxInstruction": "من أجل أنظمة التشغيل التالية: Linux أو Arch Linux أو CentOS أو Debian أو Fedora أو openSUSE أو Ubuntu، يجب أن تمنح المستخدم النظامي صلاحية القراءة ليتمكن من الوصول إلى أماكن التخزين.", "MessageEnablingOptionLongerScans": "قد يؤدي تمكين هذا الخيار إلى إبطاء البحث في المكتبات بشكل ملحوظ.", - "MessageFileReadError": "حصل خطأ أثناء قراءة الملف", + "MessageFileReadError": "حصل خطأ أثناء قراءة الملف. الرجاء المحاولة مرة اخرى.", "MessageForgotPasswordFileCreated": "الملف التالي قد أنشيء على خادمك وهو يحتوي على التوجيهات لكيفية البدء:", "MessageForgotPasswordInNetworkRequired": "الرجاء المحاولة من خلال شبكة المنزل لبدء عملية إعادة إعداد كملة السر.", "MessageInstallPluginFromApp": "هذا الملحق يجب أن يثبت من داخل التطبيق الذي تريد استخدامه بداخله.", "MessageInvalidForgotPasswordPin": "لقد تم إدخال رمز شخصي غير صحيح أو منتهي الصلاحية. الرجاء المحاولة مرة أخرى.", "MessageInvalidUser": "اسم المستخدم أو كلمة السر غير صحيحة. الرجاء المحاولة مرة أخرى.", "MessageItemSaved": "تم حفظ العنصر.", - "MessageItemsAdded": "العناصر المضافة", + "MessageItemsAdded": "تم اضافة العناصر.", "MessageNoAvailablePlugins": "لا توجد أي ملحقات.", "MessageNoMovieSuggestionsAvailable": "لا يوجد حالياً اقتراحات افلام. إبداً بمشاهدة وتقييم الأفلام ثم عاود زيارة هذه الصفحة لمشاهدة المقترحات.", "MessageNoPluginsInstalled": "ليس عندك أي ملحقات مثبتة.", @@ -699,7 +699,6 @@ "OptionEnableAccessFromAllDevices": "تفعيل الدخول على كافة الأجهزة", "OptionEnableAccessToAllChannels": "تفعيل الدخول على كافة القنوات", "OptionEnableAccessToAllLibraries": "تمكين الدخول على كافة المكتبات", - "OptionEnableAutomaticServerUpdates": "تمكين التحديثات الآلية في الخادم", "OptionEnableExternalContentInSuggestions": "تمكين المحتوى الخارجي في المقترحات", "OptionEnableExternalContentInSuggestionsHelp": "السماح للعروض الإعلانية من الإنترنت وبرامج بث التلفزة الحي لتضمّن في المحتوى المقترح.", "OptionEnableForAllTuners": "تمكين كل أجهزة المولفات", @@ -919,13 +918,13 @@ "HeaderFavoriteEpisodes": "الحلقات المفضلة", "HeaderFavoriteArtists": "الفنانون المفضلون", "Shows": "الحلقات", - "Books": "كتب", - "ValueSpecialEpisodeName": "مميز - {0}", + "Books": "الكتب", + "ValueSpecialEpisodeName": "خاص - {0}", "HeaderFavoriteAlbums": "الألبومات المفضلة", "HeaderAlbumArtists": "فناني الألبومات", - "Genres": "أنواع الأفلام", + "Genres": "الأنواع", "Folders": "المجلدات", - "Favorites": "التفضيلات", + "Favorites": "المفضلة", "Collections": "مجموعات", "Categories": "التصنيفات", "CancelSeries": "الغاء المسلسل", @@ -947,18 +946,18 @@ "AuthProviderHelp": "حدد مقدم المصادقات ليتم استخدامه لمصادقة كلمة مرور هذا المستخدم.", "AroundTime": "حول", "AttributeNew": "جديد", - "AspectRatio": "نسبة العرض على الارتفاع", + "AspectRatio": "نسبة العرض الى الارتفاع", "Ascending": "تصاعدي", "AsManyAsPossible": "أكبر عدد ممكن", - "Artists": "الفنان", + "Artists": "الفنانين", "Art": "فن", "Anytime": "اي وقت", - "AnyLanguage": "اي لغة", + "AnyLanguage": "أي لغة", "AlwaysPlaySubtitlesHelp": "الترجمة التي تطابق تفضيلات اللغة سيتم تحميلها بغض النظر عن لغة الصوت.", "AlwaysPlaySubtitles": "شغل الترجمة دائماً", "AllowedRemoteAddressesHelp": "قائمة لعناوين IP أو إدخالات IP / قناع الشبكة مفصولة بفاصلة للشبكات التي سيتم السماح لها بالاتصال عن بعد. إذا تركت فارغة ، فسيتم السماح بجميع العناوين البعيدة.", "AllowOnTheFlySubtitleExtractionHelp": "يمكن استخراج الترجمات المدمجة في الفيديو وعرضها على المشاهد بنص عادي للمساعدة في منع تحويل الفيديو. ولكن في بعض الأنظمة ، قد يستغرق هذا وقتًا طويلًا ويتسبب في توقف تشغيل الفيديو أثناء عملية الاستخراج. قم بتعطيل هذا الأمر ليتم حرق ترجمات مضمّنة مع تحويل الفيديو عندما لا تكون معتمدة من قبل الجهاز العميل.", - "AllowOnTheFlySubtitleExtraction": "السماح بإستخراج الترجمه في الحال.", + "AllowOnTheFlySubtitleExtraction": "السماح بإستخراج الترجمه في الحال", "AllowMediaConversionHelp": "السماح او عدم السماح بالوصول لخاصية تحويل الوسائط.", "AllowMediaConversion": "السماح بتحويل الوسائظ", "AllLanguages": "كل اللغات", @@ -972,8 +971,79 @@ "AddToPlaylist": "أضف لقائمة", "AddToPlayQueue": "أضف لقائمة التشغيل", "AddToCollection": "أضف للمجموعة", - "Add": "أضف", + "Add": "إضافة", "Actor": "ممثل", "AccessRestrictedTryAgainLater": "الوصول مقيد حاليًا. الرجاء معاودة المحاولة في وقت لاحق.", - "Absolute": "مطلق" + "Absolute": "مطلق", + "Ended": "انتهى", + "EndsAtValue": "ينتهى عند {0}", + "Episodes": "الحلقات", + "ConfirmDeletion": "تأكيد الحذف", + "ConfirmDeleteItems": "سوف يتم حذف هذه العناصر من نظام الملفات ومن مكتبة الوسائط. هل ترغب فى الاستمرار؟", + "EveryNDays": "كل {0} يوم", + "ConfirmDeleteItem": "سوف يتم حذف هذا العنصر من نظام الملفات ومن مكتبة الوسائط. هل ترغب فى الاستمرار؟", + "DropShadow": "اسقاط ظل", + "LabelDropShadow": "اسقاط الظل:", + "EditSubtitles": "تعديل الترجمات", + "EditMetadata": "تعديل البيانات الوصفية", + "EditImages": "تعديل الصور", + "Edit": "تعديل", + "ManageRecording": "ادارة التسجيل", + "ManageLibrary": "ادارة المكتبة", + "MessageImageTypeNotSelected": "الرجاء اختيار نوع الصورة من القائمة المنسدلة.", + "MessageImageFileTypeAllowed": "ملفات JPEG و PNG مدعومون فقط.", + "MessageDownloadQueued": "تمت إضافة التحميل إلى قائمة الانتظار.", + "MessageConfirmRecordingCancellation": "الغاء التسجيل؟", + "MessageAreYouSureDeleteSubtitles": "هل انت متأكد انك تريد حذف ملف الترجمة هذا؟", + "Menu": "القائمة", + "MediaInfoStreamTypeSubtitle": "الترجمة", + "MediaInfoStreamTypeEmbeddedImage": "الصورة المضمنة", + "MediaInfoStreamTypeData": "البيانات", + "MediaInfoStreamTypeAudio": "الصوت", + "MediaInfoSoftware": "البرمجيات", + "MediaIsBeingConverted": "يتم تحويل الوسط الى صيغة متوافقة مع الحهاز الذي يشغل الوسط.", + "MediaInfoStreamTypeVideo": "فيديو", + "ContinueWatching": "اكمل المشاهدة", + "Horizontal": "عرضي", + "Home": "الصفحة الرئيسية", + "HideWatchedContentFromLatestMedia": "اخفاء المحتوى الذي تمت مشاهدته من احدث الوسائط", + "Hide": "اخفاء", + "Help": "المساعدة", + "HeaderVideoType": "نوع الفيديو", + "HeaderVideoQuality": "جودة الفيديو", + "HeaderSubtitleDownloads": "تحميلات الترجمة", + "HeaderSubtitleAppearance": "شكل الترجمة", + "HeaderStopRecording": "اوقف التسجيل", + "HeaderStartNow": "شغل الآن", + "HeaderSeriesStatus": "حالة المسلسل", + "HeaderSeriesOptions": "اعدادات المسلسل", + "HeaderSecondsValue": "{0} ثوانى", + "HeaderRestartingServer": "اعادة تشغيل الخادم", + "HeaderRecordingOptions": "اعدادات التسجيل", + "HeaderPlaybackError": "خطأ فى التشغيل", + "HeaderPlayOn": "شغل على", + "HeaderPhotoAlbums": "البومات الصور", + "HeaderOnNow": "الآن", + "HeaderNextVideoPlayingInValue": "سيتم تشغيل الفيديو القادم فى {0}", + "HeaderNextEpisodePlayingInValue": "سيتم تشغيل الحلقة القادمة فى {0}", + "HeaderNewDevices": "الاجهزة الجديدة", + "HeaderNavigation": "التنقل", + "HeaderMyMediaSmall": "وسائطى (العرض الصغير)", + "HeaderMyDevice": "جهازى", + "HeaderMusicQuality": "جودة الموسيقي", + "HeaderMetadataSettings": "اعدادات البيانات الوصفية", + "HeaderLiveTvTunerSetup": "اعداد موالف التلفاز المباشر", + "HeaderLibrarySettings": "اعدادات المكتبة", + "HeaderLibraryOrder": "ترتيب المكتبة", + "HeaderKodiMetadataHelp": "لتشغيل او اطفاء البيانات الوصفية بصيغة NFO، عدل احد المكتبات فى اعدادات المكتبات واوجد قسم حافظات البيانات الوصفية.", + "EnableNextVideoInfoOverlay": "عرض معلومات الفيديو القادم اثناء التشغيل", + "DatePlayed": "تاريخ التشغيل", + "DateAdded": "تاريخ الاضافة", + "CriticRating": "تقييم النقاد", + "ResumeAt": "اكمل من {0}", + "AskAdminToCreateLibrary": "أطلب من الأدمن إنشاء مكتبة.", + "Artist": "الفنان", + "AllowFfmpegThrottling": "إبطاء الترميزات", + "AlbumArtist": "المؤدي", + "Album": "الألبوم" } diff --git a/src/strings/bg-bg.json b/src/strings/bg-bg.json index c7ce361903..8357a9c8dd 100644 --- a/src/strings/bg-bg.json +++ b/src/strings/bg-bg.json @@ -10,7 +10,7 @@ "All": "Всички", "AllLibraries": "Всички библиотеки", "Art": "Картина", - "Artists": "Изпълнители", + "Artists": "Артисти", "AttributeNew": "Нови", "Audio": "Звук", "Auto": "Автоматично", @@ -86,23 +86,22 @@ "ChannelAccessHelp": "Изберете каналите, които да споделите с потребителя. Администраторите ще могат да редактират всички канали, използвайки управлението на метаданни.", "Collections": "Колекции", "ColorSpace": "Цветово пространство", - "CommunityRating": "Обществена ощенка", + "CommunityRating": "Рейтинг на общността", "Composer": "Съчинител", "ConfirmDeleteImage": "Изтриване на изображението?", - "ContinueWatching": "Продължаване на гледането", + "ContinueWatching": "Продължи гледането", "Continuing": "Продължаващо", "CriticRating": "Оценка на критиците", "DateAdded": "Дата на добавяне", "DatePlayed": "Дата на пускане", "DeathDateValue": "Починал/а на: {0}", "Default": "По подразбиране", - "Delete": "Изтриване", + "Delete": "Премахване", "DeleteMedia": "Изтриване на медията", "Desktop": "Работен плот", "DeviceAccessHelp": "Това се отнася само за устройства, които могат да бъдат различени и няма да попречи на достъп от мрежов четец. Филтрирането на потребителски устройства ще предотврати използването им докато не бъдат одобрени тук.", "Director": "Режисьор", - "DirectorValue": "Режисьор: {0}", - "DirectorsValue": "Режисьори: {0}", + "Directors": "Режисьори", "Disc": "Диск", "Dislike": "Нехаресване", "Display": "Показване", @@ -137,9 +136,8 @@ "FormatValue": "Формат: {0}", "Friday": "Петък", "Fullscreen": "Цял екран", - "GenreValue": "Жанр: {0}", + "Genre": "Жанр", "Genres": "Жанрове", - "GenresValue": "Жанрове: {0}", "GroupVersions": "Групиране на версиите", "GuestStar": "Гостуваща звезда", "Guide": "Справочник", @@ -305,9 +303,9 @@ "LabelCriticRating": "Оценка на критиците:", "LabelCurrentPassword": "Текуща парола:", "LabelCustomCertificatePath": "Път към потребителския сертификат:", - "LabelCustomCertificatePathHelp": "Път до файл с шифровъчен стандарт №12, съдържащ сертификат и частен ключ за поддръжка на протокол TLS на собствен домейн.", + "LabelCustomCertificatePathHelp": "Път до файл с шифровъчен стандарт №12 (PKCS #12), съдържащ сертификат и частен ключ за поддръжка на протокол TLS на собствен домейн.", "LabelCustomCss": "CSS по избор:", - "LabelCustomCssHelp": "Използвайте собствен CSS към уеб интерфейса.", + "LabelCustomCssHelp": "Добавете собствен стил към уеб-интерфейса.", "LabelCustomDeviceDisplayName": "Показвано име:", "LabelCustomRating": "Оценка по избор:", "LabelDashboardTheme": "Облик на сървърното табло:", @@ -435,7 +433,7 @@ "LabelStatus": "Състояние:", "LabelStopWhenPossible": "Спирай, когато е възможно:", "LabelSubtitlePlaybackMode": "Режим на субтитрите:", - "LabelSubtitles": "Субтитри:", + "LabelSubtitles": "Субтитри", "LabelSupportedMediaTypes": "Поддържани типове медия:", "LabelTag": "Етикет:", "LabelTextColor": "Цвят на текста:", @@ -565,7 +563,6 @@ "OptionEnableAccessFromAllDevices": "Позволяване на достъпа от всички устройства", "OptionEnableAccessToAllChannels": "Позволяване на достъпа до всички канали", "OptionEnableAccessToAllLibraries": "Позволяване на достъпа до всички библиотеки", - "OptionEnableAutomaticServerUpdates": "Разрешаване на автоматичните обновления", "OptionEnded": "Приключило", "OptionEveryday": "Всеки ден", "OptionExternallyDownloaded": "Външно сваляне", @@ -789,7 +786,7 @@ "AllowMediaConversion": "Разрешаване на медийни преобразувания", "AllLanguages": "Всички езици", "AllEpisodes": "Всички епизоди", - "AllComplexFormats": "Всички комплексни формати (ASS, SSA, VOBSUB, PGS, SUB/IDX, и т.н.)", + "AllComplexFormats": "Всички общи формати (ASS, SSA, VOBSUB, PGS, SUB/IDX, и др. )", "AllChannels": "Всички канали", "Alerts": "Известия", "AdditionalNotificationServices": "Разгледайте каталога с добавки за допълнителни услуги за известяване.", @@ -813,7 +810,7 @@ "MediaInfoLayout": "Подредба", "MusicVideo": "Музикален клип", "MediaInfoStreamTypeVideo": "Видео", - "LabelVideo": "Видео:", + "LabelVideo": "Видео", "HeaderVideoTypes": "Видове видеа", "HeaderVideoType": "Вид на видеото", "EnableExternalVideoPlayers": "Външни възпроизводители", @@ -833,5 +830,78 @@ "ButtonNetwork": "Мрежа", "ButtonFullscreen": "На цял екран", "ButtonDown": "Надолу", - "ButtonConnect": "Свързване" + "ButtonConnect": "Свързване", + "AllowOnTheFlySubtitleExtraction": "Позволява моментално извличане на поднадписи", + "AllowHWTranscodingHelp": "Позволява на тунера да прекодира моментално. Това може да помогне за редуциране на прекодирането от сървъра.", + "AddItemToCollectionHelp": "Добавяне към колекция чрез търсенето им и използване на дясно-щракване с мишката или контекстното меню.", + "Absolute": "Aбсолютен", + "LabelLanNetworks": "Локални мрежи:", + "LabelKodiMetadataSaveImagePathsHelp": "Това е препоръчително, ако наименованието на изображенията не са съобразени с изискванията на Kodi.", + "LabelKodiMetadataSaveImagePaths": "Записване на пътеките към изображенията в nfo файловете", + "LabelChannels": "Канали:", + "DropShadow": "Сянка", + "Raised": "Повишено", + "OptionResElement": "рес. елемент", + "ButtonChangeServer": "Смяна на сървър", + "ButtonAddImage": "Добавяне на изображение", + "BrowsePluginCatalogMessage": "За да видите наличните добавки, прегледайте каталога с добавките.", + "Box": "Кутия", + "AlwaysPlaySubtitlesHelp": "Поднадписите, съвпадащи с езика от настройките, ще се зареждат, независимо от езика на аудио то.", + "BookLibraryHelp": "Поддържат се звукови и текстови книги. Преглед на инструкция за наименоване {1} на книга {0}.", + "Blacklist": "Списък с блокирани", + "BirthLocation": "Месторождение", + "Banner": "Банер", + "AspectRatio": "Съотношение", + "AskAdminToCreateLibrary": "Помолете администратора за създаване на библиотека.", + "Ascending": "Възходящо", + "AsManyAsPossible": "Колкото е възможно повече", + "Artist": "Артист", + "AroundTime": "Към {0}", + "Anytime": "По всяко време", + "AnyLanguage": "Който и да е език", + "AlwaysPlaySubtitles": "Постоянно изпълнение", + "AllowRemoteAccessHelp": "Ако не е маркирано, всеки отдалечен достъп ще бъде блокиран.", + "AllowRemoteAccess": "Позволяване на отдалечен достъп до този Jellyfin сървър.", + "AllowFfmpegThrottling": "Подтискане на прекодирането", + "AllowMediaConversionHelp": "Даване или отнемане на права за функциите за конвертиране на медия.", + "AlbumArtist": "Изпълнител", + "Album": "Албум", + "ClientSettings": "Клиентски настройки", + "ChannelNumber": "Номер на канала", + "ChannelNameOnly": "Само {0} канал", + "CancelSeries": "Откажи сериите", + "CancelRecording": "Откажи записа", + "ButtonSplit": "Раздели", + "ButtonResetEasyPassword": "Нулиране на бързия ПИН код", + "ButtonRevoke": "Отмени", + "ButtonEditOtherUserPreferences": "Редакция на потребителския профил, изображение и лични предпочитания.", + "BoxRear": "Комплект (стар)", + "BoxSet": "Комплект", + "AuthProviderHelp": "Избор на доставчик на услуга за Автентификация, която ще се използва за автентификация на потребителската парола.", + "AllowedRemoteAddressesHelp": "Списък с IP адреси или IP/маска записи, разделени със запетая, които ще имат отдалечен достъп. Ако полето не е попълнено всички адреси ще имат отдалечен достъп.", + "BurnSubtitlesHelp": "Определя дали сървърът трябва да записва субтитри във видеоклиповете припрекодиране. Избягването на това значително ще подобри производителността. Изберете Auto, за да запишете формати, базирани на изображения (VOBSUB, PGS, SUB, IDX) и някои ASS или SSA субтитри.", + "AllowFfmpegThrottlingHelp": "Когато прекодирането или запазването на видео стигне достатъчно далеч напред от текущата позиция за възпроизвеждане, поставете на пауза процеса, така ще се изразходват по-малко ресурси. Това е най-полезно, когато се гледа, без да се търси често из видеото. Изключете това, ако имате проблеми с възпроизвеждането.", + "AllowOnTheFlySubtitleExtractionHelp": "Вградените субтитри могат да бъдат извлечени от видеоклиповете и прехвърлени към клиентите като обикновен текст, за да се предотврати транскодирането на видеото. В някои системи това може да отнеме много време и да спре възпроизвеждането на видео по време на процеса на извличане. Деактивирайте това, за да има вградени субтитри, записани с видео кодиране, когато те не се поддържат от клиентското устройство.", + "CinemaModeConfigurationHelp": "Режимът на кино носи театрално изживяване направо във вашата всекидневна с възможност за пускане на трейлъри и персонализирани интродукции преди основния филм.", + "ChangingMetadataImageSettingsNewContent": "Промените в настройките за изтегляне на метаданни или изображения ще се прилагат само за ново съдържание, добавено към вашата библиотека. За да приложите промените към съществуващите заглавия, ще трябва да обновите метаданните им ръчно.", + "DefaultMetadataLangaugeDescription": "Това са настройки по подразбиране и могат да се променят на база библиотека.", + "DefaultErrorMessage": "Възникна грешка при изпълнение на заявката. Моля опитайте по-късно.", + "CustomDlnaProfilesHelp": "Създаване на персонализиран профил за целево устройство или заменяне на системния профил.", + "CopyStreamURL": "Копиране URL на стрийма", + "CopyStreamURLError": "Възникна грешка при копиране на URL.", + "CopyStreamURLSuccess": "URL се копира успешно.", + "Connect": "Свързване", + "ConfirmEndPlayerSession": "Искате ли да изключите Jellyfin на {0}?", + "ConfirmDeletion": "Потвърждаване на изтриването", + "ConfirmDeleteItem": "Изтриването на елемента ще го премахне едновременно от файловата система и библиотеката. Сигурни ли сте, че искате да продължите?", + "ConfigureDateAdded": "Конфигурацията на добавянето на датата се определя в панела на Jellyfin сървъра в секцията за настройка на библиотека", + "ConfirmDeleteItems": "Изтриването на елементите ще ги премахне едновременно от файловата система и библиотеката. Сигурни ли сте, че искате да продължите?", + "ColorTransfer": "Предаване на цвета", + "ColorPrimaries": "Основни цветове", + "DeleteUserConfirmation": "Сигурнили сте че искате да премахнете този потребител?", + "DeleteUser": "Премахване на потребител", + "DeleteImageConfirmation": "Сигурнили сте че искате да премахнете това Изображение?", + "DeleteImage": "Премахване на Исображение", + "ButtonTogglePlaylist": "Списък с изпълнения", + "ButtonToggleContextMenu": "Повече" } diff --git a/src/strings/ca.json b/src/strings/ca.json index 711da8ae43..df1cdf28f6 100644 --- a/src/strings/ca.json +++ b/src/strings/ca.json @@ -7,7 +7,7 @@ "All": "Tot", "AllChannels": "Tots els canals", "AllEpisodes": "Tots els episodis", - "AlwaysPlaySubtitles": "Reprodueix sempre amb subtítols", + "AlwaysPlaySubtitles": "Reprodueix sempre", "AroundTime": "Cap a les {0}", "Artists": "Artistes", "AsManyAsPossible": "Tants com sigui possible", @@ -732,7 +732,7 @@ "XmlTvNewsCategoriesHelp": "Els programes amb aquestes categories es mostraran com a programes de notícies. Separa'n varis emprant '|'.", "XmlTvSportsCategoriesHelp": "Els programes amb aquestes categories es mostraran com a programes esportius. Separa'n varis emprant '|'.", "Books": "Llibres", - "Folders": "Directoris", + "Folders": "Carpetes", "Photos": "Fotos", "Shows": "Programes", "Songs": "Cançons", @@ -741,10 +741,82 @@ "Channels": "Canals", "Collections": "Col·leccions", "Favorites": "Preferits", - "HeaderAlbumArtists": "Artistes dels Àlbums", + "HeaderAlbumArtists": "Artistes del Àlbum", "HeaderFavoriteAlbums": "Àlbums Preferits", "HeaderFavoriteArtists": "Artistes Preferits", "HeaderFavoriteEpisodes": "Episodis Preferits", "HeaderFavoriteShows": "Programes Preferits", - "HeaderFavoriteSongs": "Cançons Preferides" + "HeaderFavoriteSongs": "Cançons Preferides", + "ChannelNumber": "Número de canal", + "Categories": "Categories", + "ButtonWebsite": "Lloc web", + "ButtonUp": "Amunt", + "ButtonUninstall": "Desinstal·lar", + "ButtonSplit": "Dividir", + "ButtonStart": "Començar", + "ButtonSelectView": "Selecciona la vista", + "ButtonScanAllLibraries": "Escanejar totes les biblioteques", + "ButtonRevoke": "Revocar", + "ButtonRepeat": "Repetir", + "ButtonRename": "Canviar el nom", + "ButtonNetwork": "Xarxa", + "ButtonInfo": "Informació", + "ButtonFullscreen": "Pantalla completa", + "ButtonDown": "A baix", + "ButtonConnect": "Connectar", + "ButtonAudioTracks": "Pistes d'àudio", + "ButtonAddImage": "Afegir imatge", + "Blacklist": "Llista negra", + "BirthPlaceValue": "Lloc de naixement: {0}", + "BirthLocation": "Lloc de naixement", + "BirthDateValue": "Nascut: {0}", + "Banner": "Banner", + "Auto": "Auto", + "AuthProviderHelp": "Seleccionar un proveïdor d'autenticació que s'utilitzarà per autenticar la contrasenya d'aquest usuari.", + "AskAdminToCreateLibrary": "Sol·liciteu a un administrador que crei una biblioteca.", + "Ascending": "Ascendent", + "Art": "Art", + "Anytime": "En qualsevol moment", + "AnyLanguage": "Qualsevol idioma", + "AlwaysPlaySubtitlesHelp": "Es carregaran els subtítols que coincideixin amb la preferència d’idioma independentment del llenguatge d’àudio.", + "AllowRemoteAccessHelp": "Si no es marca, totes les connexions remotes es bloquejaran.", + "AllowRemoteAccess": "Permet connexions remotes a aquest servidor de Jellyfin.", + "AllowOnTheFlySubtitleExtraction": "Permet extreure subtítols sobre la marxa", + "AllowMediaConversionHelp": "Concedir o denegar l’accés a la funció de mitjans de conversió.", + "AllowMediaConversion": "Permetre la conversió de mitjans", + "AllowHWTranscodingHelp": "Permet al sintonitzador transcodificar streams sobre la marxa. Això pot ajudar a reduir la transcodificació requerida pel servidor.", + "AllLibraries": "Totes les biblioteques", + "AllLanguages": "Tots els idiomes", + "AllComplexFormats": "Tots els formats complexos (ASS, SSA, VOBSUB, PGS, SUB / IDX, etc.)", + "Alerts": "Alertes", + "Aired": "Transmès", + "AirDate": "Data d'emissió", + "AdditionalNotificationServices": "Examineu el catàleg de complements per instal·lar serveis de notificació addicionals.", + "AddedOnValue": "Afegit {0}", + "AddItemToCollectionHelp": "Afegiu els elements a les col·leccions buscant-los i fent clic amb el botó dret o toqueu els menús per afegir-los a una col·lecció.", + "Actor": "Actor", + "Absolute": "Absolut", + "ClientSettings": "Configuració del client", + "CinemaModeConfigurationHelp": "El mode Cinema aporta l'experiència del teatre directament a la sala d'estar amb la possibilitat de jugar a tràilers i presentacions personalitzades abans de la funció principal.", + "ChannelNameOnly": "Número de canal", + "ChangingMetadataImageSettingsNewContent": "Els canvis als paràmetres de descàrrega de metadades o d'obra d'art només s'apliquen al contingut nou afegit a la biblioteca. Per aplicar els canvis als títols existents, haureu de refrescar les metadades manualment.", + "ButtonTogglePlaylist": "Llista de reproducció", + "ButtonToggleContextMenu": "més", + "ButtonOff": "Apagar", + "BurnSubtitlesHelp": "Determina si el servidor hauria de gravar-se en els subtítols en transcodificar vídeos. Evitar això millorarà molt el rendiment. Seleccioneu Automàtica per gravar formats basats en imatges (VOBSUB, PGS, SUB, IDX) i certs subtítols ASS o SSA.", + "Browse": "Navega", + "BoxRear": "Caixa (posterior)", + "BoxSet": "conjunt de caixes", + "Box": "Caixa", + "BookLibraryHelp": "Els àudio i llibres de text són compatibles. Reviseu la {0} guia de denominació de llibres {1}.", + "Backdrops": "Fons", + "Backdrop": "Fons", + "AutoBasedOnLanguageSetting": "Auto (basada en la configuració de l’idioma)", + "Artist": "Artista", + "AllowedRemoteAddressesHelp": "Llista d’adreces IP o d’entrades IP / netmasca separades per comes per a xarxes que podran connectar-se de forma remota. Si es deixa en blanc, es permetran totes les adreces remotes.", + "AllowFfmpegThrottlingHelp": "Quan un transcòdi o un remux estigui prou lluny de la posició de reproducció actual, feu una pausa en el procés perquè consumirà menys recursos. Això és més útil per mirar sense buscar sovint. Desactiveu-la si teniu problemes de reproducció.", + "AllowFfmpegThrottling": "Transcodes de l’acceleració", + "AllowOnTheFlySubtitleExtractionHelp": "Els subtítols incrustats es poden extreure de vídeos i entregar-los a clients en text senzill per tal d'evitar la transcodificació de vídeo. En alguns sistemes, això pot trigar molt i fer que la reproducció de vídeo s’aturi durant el procés d’extracció. Desactiveu-ho per tenir subtítols incrustats incrustats amb la transcodificació de vídeo quan no són compatibles amb el dispositiu client de forma nativa.", + "AlbumArtist": "Album artista", + "Album": "Album" } diff --git a/src/strings/cs.json b/src/strings/cs.json index b0827ca887..5e52da3f55 100644 --- a/src/strings/cs.json +++ b/src/strings/cs.json @@ -7,14 +7,14 @@ "AddToPlayQueue": "Přidat do fronty k přehrání", "AddToPlaylist": "Přidat do playlistu", "AddedOnValue": "Přidáno {0}", - "AdditionalNotificationServices": "Prohlédněte si katalog zásuvných modulů pro nainstalaci další oznámovací služby.", + "AdditionalNotificationServices": "Pro instalaci dalších oznamovacích služeb si prohlédněte katalog zásuvných modulů.", "Albums": "Alba", "All": "Vše", "AllChannels": "Všechny kanály", "AllEpisodes": "Všechny epizody", "AllLanguages": "Všechny jazyky", "AllowHWTranscodingHelp": "Povolit tuneru překódování v reálném čase. Může snížit zátěž překódovávání požadované Jellyfin serverem.", - "AlwaysPlaySubtitles": "Vždy zobrazit titulky", + "AlwaysPlaySubtitles": "Vždy zobrazovat", "AlwaysPlaySubtitlesHelp": "Titulky odpovídající jazykové předvolbě se načtou bez ohledu na jazyk audia.", "Anytime": "Kdykoliv", "AroundTime": "Okolo {0}", @@ -158,7 +158,7 @@ "Display": "Zobrazení", "DisplayMissingEpisodesWithinSeasons": "Zobrazit chybějící epizody", "DisplayMissingEpisodesWithinSeasonsHelp": "Toto musí být zapnuto pro knihovny TV v nastavení serveru.", - "DisplayModeHelp": "Zvolte typ obrazovky, na které používáte Jellyfin.", + "DisplayModeHelp": "Vyberte styl rozvržení, který chcete pro rozhraní.", "DoNotRecord": "Nenahrávat", "Down": "Dolů", "Download": "Stáhnout", @@ -227,9 +227,9 @@ "GuideProviderLogin": "Přihlášení", "GuideProviderSelectListings": "Výběr zobrazení", "H264CrfHelp": "Constant Rate faktor (CRF) je výchozím nastavení kvality pro kodér x264. Můžete nastavit hodnoty mezi 0 a 51, kde nižší hodnoty vedou lepší kvalitě (na úkor větší velikosti souborů). Rozumné hodnoty jsou mezi 18 a 28. Výchozí hodnota pro x264 je 23, který můžete použít jako výchozí bod.", - "H264EncodingPresetHelp": "Vyber hodnotu faster ke zvýšení výkonu, nebo slower ke zvýšení kvality.", + "EncoderPresetHelp": "Vyber hodnotu faster ke zvýšení výkonu, nebo slower ke zvýšení kvality.", "HDPrograms": "HD programy", - "HardwareAccelerationWarning": "Zapnutí hardwarové akcelerace může způsobit nestabilitu v některých prostředích. Ujistěte se, že vaše ovladače operačního systému a videa jsou plně aktuální. Máte-li potíže s přehráváním videa po zapnutí, budete muset změnit nastavení zpět na Auto.", + "HardwareAccelerationWarning": "Zapnutí hardwarové akcelerace může způsobit nestabilitu v některých prostředích. Ujistěte se, že váš operační systém a grafické ovladače jsou aktuální. Máte-li potíže s přehráváním videa po zapnutí této funkce, budete muset změnit nastavení zpět na Žádné.", "HeaderAccessSchedule": "Přístup k naplánované úloze", "HeaderAccessScheduleHelp": "Vytvořte plán přístupu pro limitování přístupu jen určitém čase.", "HeaderActiveDevices": "Aktivní zařízení", @@ -426,7 +426,7 @@ "Images": "Obrázky", "ImportFavoriteChannelsHelp": "Pokud je povoleno, jen kanály označené jako oblíbené budou importována na zařízení tuneru.", "ImportMissingEpisodesHelp": "Pokud je povoleno, budou informace o chybějících epizodách importovány do databáze Jellyfin a zobrazí se v sezónách seriálu. To může způsobit podstatně delší skenování knihovny.", - "InstallingPackage": "Instalace {0}", + "InstallingPackage": "Instalace {0} (Verze {1})", "InstantMix": "Okamžité míchání", "ItemCount": "{0} položek", "Items": "Položky", @@ -461,7 +461,7 @@ "LabelArtist": "Umělec", "LabelArtists": "Umělci:", "LabelArtistsHelp": "Odděl pomocí ;", - "LabelAudio": "Zvuk:", + "LabelAudio": "Zvuk", "LabelAudioLanguagePreference": "Preferovaný jazyk zvuku:", "LabelBindToLocalNetworkAddress": "Vázat na místní síťovou adresu:", "LabelBindToLocalNetworkAddressHelp": "Volitelné. Přepsat lokální IP adresu vazanou na http server. Pokud je ponecháno prázdné, server se sváže ke všem dostupným adresám (aplikace bude dostupná na všech síťových zařízení, které server nabízí). Změna této hodnoty vyžaduje restartování Jellyfin Serveru.", @@ -516,7 +516,7 @@ "LabelEmbedAlbumArtDidl": "Vložit alba do DIDL", "LabelEmbedAlbumArtDidlHelp": "Některá zařízení preferují tento způsob pro získání alba. Jiné mohou selhat pokud máte tuto volbu povolenu.", "LabelEnableAutomaticPortMap": "Povolit automatické mapování portů", - "LabelEnableAutomaticPortMapHelp": "Pokusí se automaticky namapovat veřejný port místního portu přes UPnP na vašem routeru. Nemusí fungovat u některých modelů routeru.", + "LabelEnableAutomaticPortMapHelp": "Pokusí se automaticky namapovat veřejný port místního portu přes UPnP na vašem routeru. Nemusí fungovat u některých modelů routeru. Změny se projeví až po restartování serveru.", "LabelEnableBlastAliveMessages": "Vytroubit zprávu do světa", "LabelEnableBlastAliveMessagesHelp": "Povolit v případě, že server není zjistitelný jinými UPnP zařízeními v síti.", "LabelEnableDlnaClientDiscoveryInterval": "Čas pro vyhledání klienta (sekund)", @@ -552,9 +552,9 @@ "LabelGroupMoviesIntoCollections": "Seskupit filmy do kolekcí", "LabelGroupMoviesIntoCollectionsHelp": "Při zobrazení seznamů filmu, budou filmy patřící do kolekce, zobrazeny jako jedna položka.", "LabelH264Crf": "H264 kódování CRF:", - "LabelH264EncodingPreset": "Přednastavení H264 kódování:", + "LabelEncoderPreset": "Přednastavení H264 kódování:", "LabelHardwareAccelerationType": "Hardwarová akcelerace:", - "LabelHardwareAccelerationTypeHelp": "Toto je experimentální funkce dostupná pouze v podporovaných systémech.", + "LabelHardwareAccelerationTypeHelp": "Hardwarová akcelerace vyžaduje další konfiguraci.", "LabelHomeScreenSectionValue": "Sekce domovské obrazovky {0}:", "LabelHttpsPort": "Lokální HTTPS port:", "LabelHttpsPortHelp": "Číslo portu TCP, ke kterému by se měl připojit HTTPS server Jellyfin.", @@ -709,7 +709,7 @@ "LabelStopping": "Zastavování", "LabelSubtitleFormatHelp": "Příklad: srt", "LabelSubtitlePlaybackMode": "Mód titulků:", - "LabelSubtitles": "Titulky:", + "LabelSubtitles": "Titulky", "LabelSupportedMediaTypes": "Podporované typy médií:", "LabelTagline": "Slogan:", "LabelTextBackgroundColor": "Barva pozadí textu:", @@ -862,14 +862,14 @@ "NoNextUpItemsMessage": "Nic nenalezeno. Začněte sledovat Vaše oblíbené seriály!", "NoPluginConfigurationMessage": "Tento zásuvný modul nemá žádné nastavení.", "NoSubtitleSearchResultsFound": "Žádné výsledky.", - "NoSubtitles": "Žádné titulky", + "NoSubtitles": "Žádné", "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í", "NumLocationsValue": "{0} složky", "Off": "Vypnuto", "OneChannel": "Jeden kanál", - "OnlyForcedSubtitles": "Pouze vynucené titulky", + "OnlyForcedSubtitles": "Pouze vynucené", "OnlyForcedSubtitlesHelp": "Jen vynucené titulky budou nahrány.", "OptionAdminUsers": "Administrátoři", "OptionAlbumArtist": "Umělec Alba", @@ -930,7 +930,6 @@ "OptionEnableAccessFromAllDevices": "Povolit přístup ze všech zařízení", "OptionEnableAccessToAllChannels": "Povolit přístup ze všech kanálů", "OptionEnableAccessToAllLibraries": "Povolit přístup ke všem knihovnám", - "OptionEnableAutomaticServerUpdates": "Povolit automatickou aktualizaci serveru", "OptionEnableExternalContentInSuggestions": "Aktivovat externí obsah v návrzích", "OptionEnableExternalContentInSuggestionsHelp": "Povolit zahrnutí internetových upoutávek a živých televizních programů do navrhovaného obsahu.", "OptionEnableForAllTuners": "Povolit pro všechna zařízení tunerů", @@ -1000,9 +999,9 @@ "OptionWeekly": "Týdenní", "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.", + "PackageInstallCancelled": "Instalace {0} (verze {1}) zrušena.", + "PackageInstallCompleted": "Instalace {0} (verze {1}) dokončena.", + "PackageInstallFailed": "Instalace {0} (verze {1}) selhala.", "ParentalRating": "Rodičovské hodnocení", "PasswordMatchError": "Heslo a potvrzení hesla musí souhlasit.", "PasswordResetComplete": "Heslo bylo obnoveno.", @@ -1023,7 +1022,7 @@ "PlayNext": "Přehrát další", "PlayNextEpisodeAutomatically": "Automaticky přehrávat další epizodu", "PlayOnAnotherDevice": "Přehrát na jiném zařízení", - "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.", + "PlaybackErrorNoCompatibleStream": "Tento klient není kompatibilní s médiem a server neodesílá kompatibilní formát médií.", "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": "Chcete-li toto video přehrát, vložte disk.", "Played": "Přehráno", @@ -1064,7 +1063,7 @@ "Repeat": "Opakovat", "RepeatAll": "Opakovat vše", "RepeatEpisodes": "Opakovaní epizod", - "RepeatMode": "Mód opakování", + "RepeatMode": "Režim opakování", "RepeatOne": "Opakovat jeden", "ReplaceAllMetadata": "Přepsat všechna metadata", "ReplaceExistingImages": "Nahradit existující obrázky", @@ -1206,7 +1205,7 @@ "ValueVideoCodec": "Video kodeky: {0}", "ViewAlbum": "Zobrazit album", "ViewArtist": "Zobrazit úmělce", - "Watched": "Shlédnuto", + "Watched": "Zhlédnuto", "Wednesday": "Středa", "WelcomeToProject": "Vítejte v Jellyfin!", "WizardCompleted": "To je vše, co nyní potřebujeme. Jellyfin začala shromažďovat informace o vaší knihovně médií. Podívejte se na některé z našich aplikací, a potom klepněte na tlačítko Dokončit pro zobrazení hlavního panelu.", @@ -1224,14 +1223,14 @@ "AirDate": "Datum vysílání", "Aired": "Vysíláno", "Alerts": "Upozornění", - "AllComplexFormats": "Všechny komplexní formáty (ASS, SSA, VOBSUB, PGS, SUB/IDX, atd.)", + "AllComplexFormats": "Všechny komplexní formáty (ASS, SSA, VOBSUB, PGS, SUB/IDX, atd.)", "AllLibraries": "Všechny knihovny", "AllowDeletionFromAll": "Povolit smazání médií ze všech knihoven", "AllowMediaConversion": "Povolit konverzi médií", "AllowMediaConversionHelp": "Povolit nebo zakázat přístup k funkci konverze médií.", "AllowOnTheFlySubtitleExtraction": "Povolit extrahování titulků za běhu", "AllowOnTheFlySubtitleExtractionHelp": "Vložené titulky mohou být extrahovány z videa a dodávány do aplikací ve formě prostého textu, aby se zabránilo překódování videa. V některých systémech to může trvat dlouho a způsobit zasekávání přehrávání videa. Při vypnutí funkce budou během překódování obsažené titulky vypáleny do obrazu, pokud je klientské zařízení nativně nepodporuje.", - "AllowRemoteAccess": "Povolit vzdálené připojení na server Jellyfin.", + "AllowRemoteAccess": "Povolit vzdálené připojení na tento Jellyfin server.", "AllowRemoteAccessHelp": "Pokud není zapnuto, všechna vzdálená připojení budou blokována.", "AllowSeasonalThemesHelp": "Pokud je povoleno, sezónní motivy občas přepíšou nastavení vašeho motivu.", "AllowedRemoteAddressesHelp": "Seznam IP adres nebo síťových masek oddělených čárkou pro sítě, ze kterých se lze vzdáleně připojit. Pokud necháte prázdné, všechny adresy budou povoleny.", @@ -1246,10 +1245,10 @@ "AutomaticallyConvertNewContentHelp": "Nový obsah přidaný do této složky bude automaticky zkonvertován.", "Banner": "Banner", "BestFit": "Nejvhodnější", - "Blacklist": "Blacklist", + "Blacklist": "Černá listina", "BobAndWeaveWithHelp": "Bob and weave (vyšší kvalita, ale pomalejší)", "Browse": "Procházet", - "BurnSubtitlesHelp": "Určuje, zda má server vypalovat titulky při převodu videa v závislosti na formátu titulků. Vynechání vypalování titulků zlepší výkon serveru. Chcete-li vypálit grafické formáty (VOBSUB, PGS, SUB / IDX atd.) a některé titulky ASS / SSA, vyberte možnost Auto.", + "BurnSubtitlesHelp": "Určuje, zda má server vypalovat titulky při překódování videa. Vynechání tohoto zlepší výkon serveru. Chcete-li vypálit grafické formáty (VOBSUB, PGS, SUB / IDX atd.) a některé titulky ASS nebo SSA, vyberte možnost Auto.", "ButtonInfo": "Info", "ButtonMenu": "Menu", "ButtonOk": "Ok", @@ -1277,8 +1276,7 @@ "DetectingDevices": "Hledání zařízení", "DirectPlayError": "Chyba přímého přehrávání", "DirectStreamHelp2": "Přímé streamování souboru používá velmi malý výkon bez ztráty kvality videa.", - "DirectorValue": "Režisér: {0}", - "DirectorsValue": "Režiséři: {0}", + "Directors": "Režiséři", "Disabled": "Vypnuto", "DisplayInMyMedia": "Zobrazit na domovské obrazovce", "DisplayInOtherHomeScreenSections": "Zobrazení v sekcích domovské obrazovky, jako jsou nejnovější média, a pokračování ve sledování", @@ -1298,8 +1296,7 @@ "Filters": "Filtry", "Folders": "Složky", "General": "Hlavní", - "GenreValue": "Žánr: {0}", - "GenresValue": "Žánry: {0}", + "Genre": "Žánr", "GroupBySeries": "Seskupit podle série", "HandledByProxy": "Zpracováno reverzním proxy", "HeaderAddLocalUser": "Přidat místního uživatele", @@ -1396,7 +1393,7 @@ "LabelUrl": "URL:", "LabelUserAgent": "User agent:", "LabelUserRemoteClientBitrateLimitHelp": "Přepíše výchozí globální hodnotu nastavenou v nastavení přehrávání serveru.", - "LabelVideo": "Video:", + "LabelVideo": "Video", "LabelVideoCodec": "Video kodek:", "LeaveBlankToNotSetAPassword": "Můžete ponechat prázdné pro nastavení bez hesla.", "LetterButtonAbbreviation": "A", @@ -1428,7 +1425,7 @@ "LabelUserLoginAttemptsBeforeLockout": "Neúspěšné pokusy o přihlášení před uzamčením uživatele:", "DashboardVersionNumber": "Verze: {0}", "DashboardServerName": "Server: {0}", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "MediaInfoStreamTypeEmbeddedImage": "Vložený obrázek", "MediaInfoStreamTypeSubtitle": "Titulky", "MediaIsBeingConverted": "Média se konvertují do formátu kompatibilního se zařízením, které médium přehrává.", @@ -1514,7 +1511,7 @@ "Vertical": "Svisle", "VideoRange": "Rozsah videa", "ViewPlaybackInfo": "Zobrazení informací o přehrávání", - "Whitelist": "Whitelist", + "Whitelist": "Bílá listina", "HeaderHome": "Domů", "DashboardOperatingSystem": "Operační systém: {0}", "DashboardArchitecture": "Architektura: {0}", @@ -1556,5 +1553,60 @@ "CopyStreamURL": "Kopírovat URL adresu streamu", "ButtonAddImage": "Přidat obrázek", "HeaderFavoritePeople": "Oblíbení lidé", - "OptionRandom": "Náhodně" + "OptionRandom": "Náhodně", + "SelectAdminUsername": "Vyberte uživatelské jméno pro účet správce.", + "HeaderNavigation": "Navigace", + "ButtonSplit": "Rozdělit", + "MessageConfirmAppExit": "Přejete si odejít?", + "CopyStreamURLError": "Při kopírování URL došlo k chybě.", + "LabelVideoResolution": "Rozlišení videa:", + "LabelStreamType": "Typ streamu:", + "EnableFastImageFadeInHelp": "Povolte rychlejší animaci pro načtené obrázky", + "EnableFastImageFadeIn": "Rychlé zmizení obrazu", + "LabelPlayerDimensions": "Zobrazené rozlišení:", + "LabelDroppedFrames": "Vynechané snímky:", + "LabelCorruptedFrames": "Poškozené snímky:", + "OptionForceRemoteSourceTranscoding": "Vynutit transkódování vzdálených zdrojů médií (jako např. živá TV)", + "NoCreatedLibraries": "Zdá se, že jste dosud nevytvořili žádnou knihovnu. {0}Chtěli byste nějakou vytvořit nyní?{1}", + "AskAdminToCreateLibrary": "Požádejte administrátora o vytvoření knihovny.", + "AllowFfmpegThrottlingHelp": "Když se překódování nebo remux dostane dostatečně daleko dopředu od aktuální pozice přehrávání, pozastaví se proces, aby spotřeboval méně zdrojů. To je nejužitečnější při sledování bez častého vyhledávání. Pokud máte problémy s přehráváním, vypněte tuto funkci.", + "AllowFfmpegThrottling": "Omezit překódování", + "BoxSet": "Sbírka", + "Track": "Stopa", + "Season": "Sezóna", + "ReleaseGroup": "Vydavatel", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferovat vloženou informaci o epizodě před názvem souboru", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Používat informaci o epizodě z vložených metadat, pokud jsou k dispozici.", + "Person": "Osoba", + "OtherArtist": "Ostatní interpreti", + "Movie": "Film", + "Episode": "Epizoda", + "ClientSettings": "Nastavení klienta", + "Artist": "Interpret", + "AlbumArtist": "Interpret alba", + "Album": "Album", + "OnApplicationStartup": "Při zapnutí aplikace", + "EveryXHours": "Každých {0} hodin", + "EveryHour": "Každou hodinu", + "EveryXMinutes": "Každých {0} minut", + "OnWakeFromSleep": "Při probuzení", + "DailyAt": "Denně v {0}", + "PersonRole": "jako {0}", + "ListPaging": "{0}-{1} ze {2}", + "WriteAccessRequired": "Jellyfin Server potřebuje oprávnění pro zápis v této složce. Zkontrolujte oprávnění a zkuste to znovu.", + "PathNotFound": "Cesta nebyla nalezena. Zkontrolujte, zda je platná a zkuste to znovu.", + "WeeklyAt": "V {0} v {1}", + "LastSeen": "Naposledy zobrazené {0}", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelLibraryPageSizeHelp": "Určuje počet položek k zobrazení na stránce knihovny. Nastavte na 0 pro vypnutí stránkování.", + "LabelLibraryPageSize": "Velikost stránky knihovny:", + "LabelDeinterlaceMethod": "Metoda odstranění prokládání:", + "DeinterlaceMethodHelp": "Vyberte metodu odstranění prokládání obrazu při překódování obsahu.", + "UnsupportedPlayback": "Jellyfin nemůže dešifrovat obsah chráněný technologií DRM, ale pokusí se zobrazit o veškerý obsah, včetně chráněných titulů. Některé soubory se mohou zdát úplně černé kvůli šifrování nebo jiným nepodporovaným funkcím, jako jsou například interaktivní funkce.", + "MessageUnauthorizedUser": "Momentálně nemáte oprávnění k přístupu na server. Další informace získáte od správce serveru.", + "Filter": "Filtr", + "New": "Nové", + "ButtonTogglePlaylist": "Playlist", + "ButtonToggleContextMenu": "Více" } diff --git a/src/strings/da.json b/src/strings/da.json index 4ddd00252e..5e7bbd2e11 100644 --- a/src/strings/da.json +++ b/src/strings/da.json @@ -12,11 +12,11 @@ "AllChannels": "Alle kanaler", "AllEpisodes": "Alle episoder", "AllLibraries": "Alle biblioteker", - "AllowHWTranscodingHelp": "Hvis aktiveret, omkoder tuneren streams on-the-fly. Dette kan hjælpe med at reducere omkodning der kræves af Jellyfin Server.", + "AllowHWTranscodingHelp": "Tillader tuneren at transkode streams \"on the fly\". Dette kan hjælpe med at reducere transkodningen, der kræves af serveren.", "AllowMediaConversion": "Tillad media konvertering", "AllowMediaConversionHelp": "Giv eller nægt adgang til Konvertér Media featuren.", "AllowOnTheFlySubtitleExtraction": "Tillad udtræk af undertekster on-the-fly", - "AllowOnTheFlySubtitleExtractionHelp": "Indeholdte undertekster kan trækkes ud af videoer og leveres til Jellyfin apps i ren tekst for at afhjælpe video kodning. På nogle systemer kan dette tage lang tid og forårsage at afspilning kan hænge mens den udtrækker. Slå dette fra, for at have undertekster brændt ind i video kodningen når det er supporteret på klient enheden.", + "AllowOnTheFlySubtitleExtractionHelp": "Indeholdte undertekster kan trækkes ud af videoer og leveres til klienter i ren tekst for at afhjælpe video omkodning. På nogle systemer kan dette tage lang tid og forårsage at afspilning kan hænge mens den udtrækker. Slå dette fra, for at have undertekster brændt ind i vha. video omkodningen når der ikke er indbygget understøttelse for ren tekst undertekster i klient enheden.", "AllowRemoteAccess": "Tillad fjernadgang til denne Jellyfin Server.", "AllowRemoteAccessHelp": "Hvis ikke markeret, vil alle fjernforbindelser blive blokeret.", "AllowedRemoteAddressesHelp": "Komma seperareret liste over IP adresser og netmasker der har ret til fjernadgang. Hvis blank er alle adresser tilladte.", @@ -29,7 +29,7 @@ "BirthDateValue": "Født: {0}", "BirthLocation": "Fødselslokation", "BirthPlaceValue": "Fødselssted: {0}", - "BookLibraryHelp": "Lyd- og tekstbøger er understøttet. Se {0}Jellyfins guide til navngivning af bøger{1}.", + "BookLibraryHelp": "Lyd- og tekstbøger er understøttet. Se {0}guiden til navngivning af bøger{1}.", "Browse": "Gennemse", "BrowsePluginCatalogMessage": "Gennemse vores plugin-katalog for at se tilgængelige plugins.", "ButtonAdd": "Tilføj", @@ -53,7 +53,7 @@ "ButtonEdit": "Rediger", "ButtonEditImages": "Rediger billeder", "ButtonEditOtherUserPreferences": "Rediger denne brugers profil, billede og personlige indstillinger.", - "ButtonForgotPassword": "Glemt adgangskode", + "ButtonForgotPassword": "Glemt Adgangskode", "ButtonFullscreen": "Fuld skærm", "ButtonGotIt": "Forstået", "ButtonHelp": "Hjælp", @@ -136,30 +136,30 @@ "DoNotRecord": "Optag ikke", "Download": "Hent", "DrmChannelsNotImported": "Kanaler med DRM importeres ikke.", - "EasyPasswordHelp": "Din pinkode bruges til offline adgang til understøttede Jellyfin apps, og kan også bruges til nemt login inden for eget netværk.", + "EasyPasswordHelp": "Din nemme pin-kode bruges til offline adgang på understøttede klienter og kan også bruges til nem login på netværket.", "Edit": "Rediger", "EditImages": "Rediger billeder", "EditSubtitles": "Rediger undertekster", - "EnableCinemaMode": "Aktiver biograftilstand", - "EnableColorCodedBackgrounds": "Aktiver farvekodet baggrunde", + "EnableCinemaMode": "Aktiver Biograftilstand", + "EnableColorCodedBackgrounds": "Aktiver Farvekodet baggrunde", "EnableHardwareEncoding": "Aktiver hardware indkoding", - "EnablePhotos": "Aktiver fotos", - "EnablePhotosHelp": "Fotos bliver opdaget og vist sammen med andre mediefiler.", + "EnablePhotos": "Vis fotoer", + "EnablePhotosHelp": "Billeder registreres og vises sammen med andre mediefiler.", "EnableStreamLooping": "Auto-gentag live streams", "EnableStreamLoopingHelp": "Aktiver dette hvis live streams kun indeholder få sekunders data og skal efterspørgsel hele tiden. Aktivering af dette uden det er nødvendigt kan forårsage problemer.", "Ended": "Færdig", "EndsAtValue": "Slutter {0}", - "ErrorAddingListingsToSchedulesDirect": "Der opstod en fejl under tilføjelse af opstilling til din Schedules Direct-konto. Schedules Direct tillader kun et begrænset antal opstillinger pr. konto. Du bliver muligvis nød til at logge på Schedules Direct-hjemmesiden og fjerne andre lister fra din konto for at fortsætte.", + "ErrorAddingListingsToSchedulesDirect": "Der opstod en fejl ved tilføjelse af lineup til din Schedules Direct-konto. Schedules Direct tillader kun et begrænset antal opstillinger pr. Konto. Det kan være nødvendigt at du logger ind på Schedules Direct-webstedet og fjerner andre lister fra din konto, før du fortsætter.", "ErrorAddingMediaPathToVirtualFolder": "Der opstod en fejl under tilføjelse af mediesti. Kontroller venligst at stien er gyldig og at Jellyfin Server-processen har adgang til denne lokation.", "ErrorAddingTunerDevice": "Der opstod en fejl under tilføjelse af tuner-enhed. Kontroller venligst at den er tilgængelig og prøv igen.", - "ErrorAddingXmlTvFile": "Der opstod en fejl under tilgang til XmlTV-filen. Kontroller venligst at filen findes og prøv igen.", - "ErrorGettingTvLineups": "Der opstod en fejl under download af tv-opstillinger. Kontroller venligst at dine informationer er korrekte og prøv igen.", + "ErrorAddingXmlTvFile": "Der opstod en fejl under tilgang til XMLTV-filen. Kontroller venligst at filen findes og prøv igen.", + "ErrorGettingTvLineups": "Der opstod en fejl under download af TV-opstillinger. Kontroller venligst at dine informationer er korrekte og prøv igen.", "ErrorMessageStartHourGreaterThanEnd": "Slut tid skal være større end start tid.", "ErrorPleaseSelectLineup": "Vælg venligst en opstilling og prøv igen. Hvis ingen opstillinger er tilgængelige, så kontroller venligst at dit brugernavn, adgangskode og postnummer er korrekt.", "ErrorSavingTvProvider": "Der opstod en fejl i forsøget på at gemme udbyder. Kontroller venligst at den er tilgængelig og prøv igen.", "EveryNDays": "Hver {0} dage", "ExitFullscreen": "Afslut fuldskærm", - "ExtractChapterImagesHelp": "Udvinding af kapitelbilleder lader Jellyfin apps vise grafiske menuer for scenevalg. Processen kan være langsom, cpu-intensiv og kræver muligvis adskillige gigabytes af lagerplads. Den køres når videoer opdages og desuden som en planlagt opgave, natligt. Den planlagte opgave kan konfigureres i området for planlagte opgaver. Det anbefales ikke at køre denne opgave under timer med spidsbelastning.", + "ExtractChapterImagesHelp": "Udtrækning af kapitelbilleder giver klienter mulighed for at vise grafiske scenevalgmenuer. Processen kan være langsom, ressourcekrævende og kan kræve flere gigabyte plads. Det kører, når videoer opdages, og også som en planlagt nat opgave. Skemaet kan konfigureres i det planlagte opgaverområde. Det anbefales ikke at køre denne opgave i de mest brugte timer.", "FFmpegSavePathNotFound": "Vi er ikke i stand til at finde FFmpeg via stien du har angivet. FFprobe er også påkrævet og skal findes i samme mappe. Disse komponenter er som regel pakket i den samme download. Kontroller venligst stien og prøv igen.", "FastForward": "Spol fremad", "Favorite": "Favorit", @@ -170,9 +170,9 @@ "FolderTypeBooks": "Bøger", "FolderTypeMovies": "Film", "FolderTypeMusic": "Musik", - "FolderTypeMusicVideos": "Musikvideoer", + "FolderTypeMusicVideos": "Musik Videoer", "FolderTypeTvShows": "TV", - "FolderTypeUnset": "Ikke valgt (blandet indhold)", + "FolderTypeUnset": "Blandet Indhold", "Friday": "Fredag", "Fullscreen": "Fuldskærm", "General": "Generel", @@ -181,9 +181,9 @@ "GuestStar": "Gæsteskuespiller", "GuideProviderSelectListings": "Vælg Udbyder", "H264CrfHelp": "Den Konstante Ratefaktor (CRF) er standardindstillingen for X264-koderen. Du kan sætte værdien i mellem 0 og 51, hvor de lavere værdier resulterer i bedre kvalitet (på bekostning af større filstørrelser). Fornuftige værdier er i mellem 18 og 28. Standarden for X264 er 23, så du kan bruge dette som udgangspunkt.", - "H264EncodingPresetHelp": "Vælg en hurtigere værdi for at forbedre ydeevne, eller en langsommere værdi for at forbedre kvalitet.", + "EncoderPresetHelp": "Vælg en hurtigere værdi for at forbedre ydeevne, eller en langsommere værdi for at forbedre kvalitet.", "HDPrograms": "HD-programmer", - "HardwareAccelerationWarning": "Aktivering af hardwareacceleration kan forårsage ustabilitet i nogle miljøer. Kontroller at dit operativsystem og videodriver er ajourført. Hvis du har problemer med at afspille video efter aktivering af dette, bliver du nød til at skifte tilbage til Auto.", + "HardwareAccelerationWarning": "Aktivering af hardwareacceleration kan forårsage ustabilitet i nogle miljøer. Kontroller at dit operativsystem og videodriver er opdateret. Hvis du har problemer med at afspille video efter aktivering af dette, bliver du nød til at skifte tilbage til Ingen.", "HeaderAccessSchedule": "Adgangsskema", "HeaderAccessScheduleHelp": "Skab et adgangsskema for at begrænse adgangen til bestemte tidsrum.", "HeaderActiveDevices": "Aktive enheder", @@ -197,9 +197,9 @@ "HeaderAdditionalParts": "Andre stier", "HeaderAlert": "Advarsel", "HeaderAllowMediaDeletionFrom": "Tillad Media Sletning Fra", - "HeaderApiKey": "API nøgle", - "HeaderApiKeys": "API nøgler", - "HeaderApiKeysHelp": "Eksterne applikationer skal have en API nøgle for at kunne kommunikere med Jellyfin. Nøgler udstedes ved at logge ind med en Jellyfin konto, eller ved manuelt at tildele applikationen en nøgle.", + "HeaderApiKey": "API Nøgle", + "HeaderApiKeys": "API Nøgler", + "HeaderApiKeysHelp": "Eksterne applikationer skal have en API-nøgle for at kunne kommunikere med Jellyfin. Nøgler udstedes ved at logge ind med en Jellyfin konto, eller ved manuelt at tildele applikationen en nøgle.", "HeaderAudioSettings": "Lydindstillinger", "HeaderAutomaticUpdates": "Automatiske opdateringer", "HeaderBlockItemsWithNoRating": "Klokér titler uden eller med ukendt bedømmelses information:", @@ -266,7 +266,7 @@ "HeaderItems": "Element", "HeaderKeepRecording": "Bevar Optagelse", "HeaderKeepSeries": "Bevar Serie", - "HeaderKodiMetadataHelp": "For at aktivere NFO metadata, rediger et bibliotek i Jellyfin biblioteks redigering og find metadata gemmer sektionen.", + "HeaderKodiMetadataHelp": "For at aktivere eller deaktivere NFO-metadata skal du redigere et bibliotek i Jellyfin-biblioteksopsætningen og finde afsnittet om metadata.", "HeaderLatestEpisodes": "Sidste episoder", "HeaderLatestMedia": "Seneste medier", "HeaderLatestMovies": "Seneste film", @@ -287,7 +287,7 @@ "HeaderMusicVideos": "Musikvideoer", "HeaderMyDevice": "Min Enhed", "HeaderMyMedia": "Mine medier", - "HeaderNewApiKey": "Ny API nøgle", + "HeaderNewApiKey": "Ny API Nøgle", "HeaderNewDevices": "Nye Enheder", "HeaderNextUp": "Næste", "HeaderOnNow": "Vises Nu", @@ -373,7 +373,7 @@ "Images": "Billeder", "ImportFavoriteChannelsHelp": "Hvis aktiveret, importeres der udelukkende kanaler der er markeret som favoritter på tuner-enheden.", "ImportMissingEpisodesHelp": "hvis aktiveret, vil information omkring manglende episoder bliver importeret ind i din Jellyfin-database og blive vist i sæsoner og serier. Dette medfører muligvis længere biblioteksscanninger.", - "InstallingPackage": "Installerer {0}", + "InstallingPackage": "Installerer {0} (version {1})", "InstantMix": "Instant Mix", "ItemCount": "{0} elementer", "Items": "emner", @@ -397,13 +397,13 @@ "LabelAll": "Alle", "LabelAllowHWTranscoding": "Tillad hardware-omkodning", "LabelAllowServerAutoRestart": "Tillad serveren at genstarte automatisk for at påføre opdateringer", - "LabelAllowServerAutoRestartHelp": "Serveren vil kun genstarte i inaktive perioder, når ingen brugere er aktive", + "LabelAllowServerAutoRestartHelp": "Serveren vil kun genstarte i inaktive perioder, når ingen brugere er aktive.", "LabelAllowedRemoteAddresses": "Fjernadgang IP adresse filter:", "LabelAllowedRemoteAddressesMode": "Fjernadgang IP adresse filter mode:", "LabelAppName": "App navn", - "LabelAppNameExample": "F. eks: Sickbeard, NzbDrone", + "LabelAppNameExample": "F. eks: Sickbeard, Sonarr", "LabelArtists": "Artister:", - "LabelArtistsHelp": "Angiv flere ved at sætte mellem dem ;", + "LabelArtistsHelp": "Angiv flere ved at sætte ;", "LabelAudioLanguagePreference": "Foretrukket lydsprog:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Genopfrisk automatisk metadata fra internettet:", "LabelBindToLocalNetworkAddress": "Bind til lokal netværksadresse:", @@ -411,9 +411,9 @@ "LabelBirthDate": "Fødselsdato:", "LabelBirthYear": "Fødselsår:", "LabelBlastMessageInterval": "Interval mellem 'i live' beskeder (sekunder)", - "LabelBlastMessageIntervalHelp": "Angiver intervallet i sekunder mellem serverens 'i live' beskeder.", + "LabelBlastMessageIntervalHelp": "Bestemmer varigheden i sekunder mellem eksplosive levende meddelelser.", "LabelCachePath": "Cachesti:", - "LabelCachePathHelp": "Angiv en brugerdefineret lokation for server cachefiler, så som billeder. Efterlad blankt for at benytte serverens standard.", + "LabelCachePathHelp": "Angiv en brugerdefineret placering for servercache-filer, såsom billeder. Lad være tom for at bruge serverens standard.", "LabelCancelled": "Annulleret", "LabelChannels": "Kanaler:", "LabelCollection": "Samling:", @@ -425,8 +425,8 @@ "LabelCustomCertificatePath": "Brugerdefineret SSL certifikat sti:", "LabelCustomCertificatePathHelp": "Sti til PKCS #12 fil indeholdende et certifikat og privat nøgle for at aktivere TLS understøttelse på et brugerdefineret domæne.", "LabelCustomCss": "Brugerdefineret CSS:", - "LabelCustomCssHelp": "Anvend din egen css til webinterfacet.", - "LabelCustomDeviceDisplayName": "Vist navn:", + "LabelCustomCssHelp": "Anvend din egen stil til webinterfacet.", + "LabelCustomDeviceDisplayName": "Visningsnavn:", "LabelCustomDeviceDisplayNameHelp": "Angiv en brugerdefineret navn. hvis der ikke angives et navn, bruges det navn enheden sender.", "LabelCustomRating": "Brugerdefineret bedømmelse:", "LabelDateAdded": "Dato for tilføjelse:", @@ -444,24 +444,24 @@ "LabelDisplayOrder": "Visningsorden:", "LabelDisplaySpecialsWithinSeasons": "Vis specialepisoder sammen med den sæson de blev sent i", "LabelDownMixAudioScale": "Forøg lydstyrke ved nedmiksning:", - "LabelDownMixAudioScaleHelp": "Forøg lydstyrken når der nedmikses. Sæt værdien til 1 for at beholde den originale lydstyrke.", + "LabelDownMixAudioScaleHelp": "Forøg lydstyrken når der nedmikses. Sæt værdien til en, for at beholde den originale lydstyrke.", "LabelDownloadLanguages": "Hent sprog:", - "LabelDropImageHere": "Smid billede her.", + "LabelDropImageHere": "Drop billede her, eller Tryk for at vælge.", "LabelEasyPinCode": "Pinkode:", "LabelEmbedAlbumArtDidl": "Indsæt album billede i DIDL", "LabelEmbedAlbumArtDidlHelp": "Nogle enheder foretrækker denne metode til overførsel af album billede. Andre kan fejle når dette er aktiveret.", "LabelEnableAutomaticPortMap": "Aktiver automatisk port mapping", - "LabelEnableAutomaticPortMapHelp": "Forsøg at mappe den offentlige port til den lokale port med uPnP. Dette virker ikke med alle routere.", + "LabelEnableAutomaticPortMapHelp": "Forsøg at mappe den offentlige port til den lokale port med uPnP. Dette virker ikke med alle routere. Ændringerne vil først træde i kræft et en server genstart.", "LabelEnableBlastAliveMessages": "Masseudsend 'i live' beskeder", "LabelEnableBlastAliveMessagesHelp": "Aktiver dette hvis UPnP enheder har problemer med forbindelsen til serveren.", "LabelEnableDlnaClientDiscoveryInterval": "Interval for klientsøgning (sekunder)", "LabelEnableDlnaClientDiscoveryIntervalHelp": "angiver intervallet i sekunder mellem Jellyfins SSDP søgninger.", "LabelEnableDlnaDebugLogging": "Aktiver debu logning af DLNA", - "LabelEnableDlnaDebugLoggingHelp": "Dette generer meget store logfiler, og er kun anbefalet at bruge til fejlfindingsformål.", + "LabelEnableDlnaDebugLoggingHelp": "Opret store logfiler og skal kun bruges efter behov til fejlfinding.", "LabelEnableDlnaPlayTo": "Aktiver DLNA \"Afspil Til\"", - "LabelEnableDlnaPlayToHelp": "Jellyfin kan finde enheder i dit netværk og tilbyde at kontrollere dem.", - "LabelEnableDlnaServer": "Aktiver DNLA server", - "LabelEnableDlnaServerHelp": "Tillader UPnP enheder i dit netværk at gennemse og afspille Jellyfins indhold.", + "LabelEnableDlnaPlayToHelp": "Find enheder i dit netværk og tilbyd at fjernstyre dem.", + "LabelEnableDlnaServer": "Aktiver DLNA server", + "LabelEnableDlnaServerHelp": "Tillader UPnP enheder i dit netværk at gennemse og afspille indhold.", "LabelEnableRealtimeMonitor": "Aktiver realtidsovervågning", "LabelEnableRealtimeMonitorHelp": "Ændringer vil blive behandlet øjeblikkeligt på understøttede filsystemer.", "LabelEnableSingleImageInDidlLimit": "Begræns til et enkelt indlejret billede", @@ -471,56 +471,56 @@ "LabelEvent": "Hændelse:", "LabelEveryXMinutes": "Hver:", "LabelExtractChaptersDuringLibraryScan": "Udtræk kapitelbilleder under biblioteksskanning", - "LabelExtractChaptersDuringLibraryScanHelp": "Aktiver dette for at udtrække kapitelbillleder mens videofiler bliver importeret under biblioteksskanningen. Hvi det ikke er aktiveret, bliver de udtrukket når den planlagte opgave kapitelbilleder kører, og lader den almindelige biblioteksskanning afslutte hurtigere.", + "LabelExtractChaptersDuringLibraryScanHelp": "Generere kapitelbillleder mens videofiler bliver importeret under biblioteksskanningen. Alternativt bliver de udtrukket når den planlagte opgave kapitelbilleder kører, hvilket tillader den almindelige biblioteksskanning at afslutte hurtigere.", "LabelFailed": "Fejlet", - "LabelFileOrUrl": "Fil eller url:", + "LabelFileOrUrl": "Fil eller URL:", "LabelFinish": "Afslut", "LabelForgotPasswordUsernameHelp": "Indtast dit brugernavn, hvis du kan huske det.", "LabelFriendlyName": "System venligt navn:", - "LabelServerNameHelp": "Dette navn bruges til at identificere serveren. Hvis det ikke udfyldes, bruges computerens navn.", + "LabelServerNameHelp": "Dette navn bruges til at identificere serveren. Som udgangspunkt anvendes computerens navn.", "LabelGroupMoviesIntoCollections": "Grupper film i samlinger", "LabelGroupMoviesIntoCollectionsHelp": "Film i samlinger vil blive vist som en samlet enhed i filmlister.", "LabelH264Crf": "H264-kodning CRF:", - "LabelH264EncodingPreset": "Forudindstillet H264-kodning:", + "LabelEncoderPreset": "Forudindstillet H264-kodning:", "LabelHardwareAccelerationType": "Hardwareacceleration:", - "LabelHardwareAccelerationTypeHelp": "Kun tilgængelig for understøttede systemer.", + "LabelHardwareAccelerationTypeHelp": "Hardwareacceleration kræver yderligere konfiguration.", "LabelHttpsPort": "Lokalt HTTPS portnummer:", - "LabelHttpsPortHelp": "Det portnummer Jellyfins https-server bruger.", - "LabelIconMaxHeight": "Max højde på ikoner:", - "LabelIconMaxHeightHelp": "Maksimumopløsningen på ikoner der bliver vist med upnp:icon", - "LabelIconMaxWidth": "Max bredde på ikoner:", - "LabelIconMaxWidthHelp": "Maksimumopløsningen på ikoner der bliver vist med upnp:icon", + "LabelHttpsPortHelp": "Det TCP-portnummer, som Jellyfins HTTPS-server skal benytte.", + "LabelIconMaxHeight": "Maximal højde af ikoner:", + "LabelIconMaxHeightHelp": "Maksimalopløsningen af ikoner, der bliver vist med upnp:icon.", + "LabelIconMaxWidth": "Maximal bredde på ikoner:", + "LabelIconMaxWidthHelp": "Maksimalopløsningen på ikoner der bliver vist med upnp:icon.", "LabelIdentificationFieldHelp": "En case-insensitive substring eller regex ekspression.", "LabelImageFetchersHelp": "Aktiver og ranger dine fortrukne billede-hentere i en prioriteret rækkefølge.", "LabelImageType": "Billedtype:", "LabelImportOnlyFavoriteChannels": "Begræns til kanaler der er markeret som favoritter", "LabelInNetworkSignInWithEasyPassword": "Tillad login inden for eget netværk med pinkode", - "LabelInNetworkSignInWithEasyPasswordHelp": "Aktiver dette for at loge ind i Jellyfin apps med din pinkode inden for dit eget netværk. Din almindelige adgangskode skal du så kun bruge når du ikke er hjemme. Hvis pinkoden er tom, kan du logge ind uden adgangskode inden for dit eget netværk.", + "LabelInNetworkSignInWithEasyPasswordHelp": "Brug den lette pinkode til at logge ind på klienter i dit lokale netværk. Din almindelige adgangskode er kun nødvendig hjemmefra. Hvis pinkoden efterlades tom, behøver du ikke en adgangskode på dit hjemmenetværk.", "LabelKeepUpTo": "Bevar op til:", "LabelKidsCategories": "Børnekategorier:", "LabelKodiMetadataDateFormat": "Format for udgivelsesdato:", - "LabelKodiMetadataDateFormatHelp": "Alle datoer i NFO-filer vil blive læst og skrevet med dette format.", - "LabelKodiMetadataEnableExtraThumbs": "kopier extrafanart til extrathumbs", + "LabelKodiMetadataDateFormatHelp": "Alle datoer i NFO-filer vil blive analyseret med dette format.", + "LabelKodiMetadataEnableExtraThumbs": "Kopier ekstra fanart til extrathumbs", "LabelKodiMetadataEnableExtraThumbsHelp": "Ved hentning af billeder, kan de gemmes i både extrafanart og extrathumbs. Dette giver maksimal Kodi skin kompatibilitet.", "LabelKodiMetadataEnablePathSubstitution": "Aktiver stisubstitution", "LabelKodiMetadataEnablePathSubstitutionHelp": "Aktiverer stisubstitution for billedstier med serverens stisubstitutionsindstillinger.", "LabelKodiMetadataSaveImagePaths": "Gem stier til billeder i Nfo-filer", "LabelKodiMetadataSaveImagePathsHelp": "Dette er anbefalet hvis du har billedfiler med navne der ikke lever op til Kodis retningslinjer.", - "LabelKodiMetadataUser": "Gem brugers set data til NFO'er for:", - "LabelKodiMetadataUserHelp": "Aktiver dette for at komme set data til NFO filer som andre programmer kan bruge.", + "LabelKodiMetadataUser": "Gem brugerdata til NFO-filer til:", + "LabelKodiMetadataUserHelp": "Gem overvågningsdata til NFO-filer til andre applikationer.", "LabelLanNetworks": "LAN netwærk:", "LabelLanguage": "Sprog:", "LabelLineup": "Opstilling:", - "LabelLocalHttpServerPortNumber": "Lokalt http portnummer:", - "LabelLocalHttpServerPortNumberHelp": "Det portnummer Jellyfins http-server bruger.", + "LabelLocalHttpServerPortNumber": "Lokalt HTTP-portnummer:", + "LabelLocalHttpServerPortNumberHelp": "Det TCP-portnummer, som Jellyfin's HTTP-server skal binde til.", "LabelLockItemToPreventChanges": "Lås for at undgå fremtidige ændringer", "LabelLoginDisclaimer": "Login ansvarsfraskrivelse:", - "LabelLoginDisclaimerHelp": "Dette bliver vist i bunden af loginsiden.", - "LabelManufacturer": "Producent", - "LabelManufacturerUrl": "Producent url", + "LabelLoginDisclaimerHelp": "En besked, som vises i bunden af loginsiden.", + "LabelManufacturer": "Producent:", + "LabelManufacturerUrl": "Producentens URL", "LabelMaxBackdropsPerItem": "Maksimum antal af bagtæpper per element:", "LabelMaxParentalRating": "Højst tilladte aldersgrænse:", - "LabelMaxResumePercentage": "Maks. fortsæt procentdel:", + "LabelMaxResumePercentage": "Maksimal fortsæt procentdel:", "LabelMaxResumePercentageHelp": "Medier anses som fuldt afspillet, hvis de stoppes efter denne tid.", "LabelMaxScreenshotsPerItem": "Maksimum antal af skærmbilleder per element:", "LabelMaxStreamingBitrate": "Maks. streaming kvalitet:", @@ -538,9 +538,9 @@ "LabelMethod": "Metode:", "LabelMinBackdropDownloadWidth": "Minimum baggrundsbillede bredde:", "LabelMinResumeDuration": "Min. fortsæt tidsrum (sekunder):", - "LabelMinResumeDurationHelp": "Medier med kortere afspilningstid en denne kan ikke fortsættes.", - "LabelMinResumePercentage": "Min. fortsæt procentdel:", - "LabelMinResumePercentageHelp": "Medier anses om ikke afspillet, hvis de stoppes inden denne tid.", + "LabelMinResumeDurationHelp": "Den korteste videolængde i sekunder, der gemmer afspilningsplacering og giver dig mulighed for at genoptage.", + "LabelMinResumePercentage": "Minimal fortsæt procentdel:", + "LabelMinResumePercentageHelp": "Medier anses som ikke afspillede, hvis de stoppes inden denne tid.", "LabelMinScreenshotDownloadWidth": "Minimum skærmbillede bredde:", "LabelModelDescription": "Modelbeskrivelse", "LabelModelName": "Modelnavn", @@ -548,10 +548,10 @@ "LabelMonitorUsers": "Overvåg aktivitet fra:", "LabelMovieCategories": "Filmkategorier:", "LabelMoviePrefix": "Film-præfiks:", - "LabelMoviePrefixHelp": "Angiv venligst her hvis der tilføjes et præfiks til filmtitler, så Jellyfin kan håndtere det korrekt.", + "LabelMoviePrefixHelp": "Angiv venligst her hvis der tilføjes et præfiks til filmtitler, så serveren kan håndtere det korrekt.", "LabelMovieRecordingPath": "Film afspilningssti (valgfri):", "LabelMusicStreamingTranscodingBitrate": "Bitrate for musiktranskodning:", - "LabelMusicStreamingTranscodingBitrateHelp": "Angiv en maksimal bitrate når der streames musik", + "LabelMusicStreamingTranscodingBitrateHelp": "Angiv en maksimal bitrate når der streames musik.", "LabelName": "Navn:", "LabelNewName": "Nyt navn:", "LabelNewPassword": "Ny kode:", @@ -590,10 +590,10 @@ "LabelProtocol": "Protokol:", "LabelProtocolInfo": "Protokolinformation:", "LabelProtocolInfoHelp": "Den værdi der bruges til svar på GetProtocolInfo-forespørgsler fra enheden.", - "LabelPublicHttpPort": "Offentligt http portnummer:", - "LabelPublicHttpPortHelp": "Det offentlige portnummer som bliver knyttet til det lokale http portnummer.", - "LabelPublicHttpsPort": "Offentligt https portnummer:", - "LabelPublicHttpsPortHelp": "Det offentlige portnummer som bliver knyttet til det lokale https portnummer.", + "LabelPublicHttpPort": "Offentligt HTTP-portnummer:", + "LabelPublicHttpPortHelp": "Det offentlige portnummer som bliver knyttet til det lokale HTTP-portnummer.", + "LabelPublicHttpsPort": "Offentligt HTTPS portnummer:", + "LabelPublicHttpsPortHelp": "Det offentlige portnummer som bliver knyttet til det lokale HTTPS portnummer.", "LabelReadHowYouCanContribute": "Lær hvordan du kan bidrage.", "LabelRecord": "Optag:", "LabelRecordingPath": "Standard afspilningssti:", @@ -614,7 +614,7 @@ "LabelSerialNumber": "Serienummer", "LabelSeriesRecordingPath": "Serier afspilningssti (valgfri):", "LabelServerHost": "Vært:", - "LabelServerHostHelp": "F. eks: 192.168.1.100 eller https://myserver.com", + "LabelServerHostHelp": "F. eks: 192.168.1.100:8096 eller https://myserver.com", "LabelSimultaneousConnectionLimit": "samtidige stream begrænsning:", "LabelSkipIfAudioTrackPresent": "Undlad hvis standardlydsporet er det samme sprog", "LabelSkipIfAudioTrackPresentHelp": "Angiv ikke dette for at sikre at alle videoer har undertekster, uanset hvilket sprog lydsporet anvender.", @@ -647,7 +647,7 @@ "LabelTranscodingTempPathHelp": "Definér en bugerdefineret sti til transkodede filer til klienter. Lad den stå tom for at bruge standardmappen i serverens datamappe.", "LabelTranscodingTemporaryFiles": "Midlertidige filer til omkodning:", "LabelTranscodingThreadCount": "Antal af omkodningstråde:", - "LabelTranscodingThreadCountHelp": "Vælg det maksimale antal af tråde der bruges under omkodning. Reduktion af antallet af tråde sænker cpu-forbrug, men resulterer muligvis i at konverteringer ikke foregår hurtigt nok til en jævn afspilning.", + "LabelTranscodingThreadCountHelp": "Vælg det maksimale antal af tråde der bruges under transcoding. Reduktion af antallet af tråde sænker CPU-forbrug, men resulterer muligvis i at konverteringer ikke foregår hurtigt nok til en jævn afspilning.", "LabelTriggerType": "Udløsertype:", "LabelTunerIpAddress": "IP-adresse for Tuner:", "LabelTunerType": "Tunertype:", @@ -707,37 +707,37 @@ "MessageConfirmRemoveMediaLocation": "Er du sikker på du ønsker at fjerne denne lokalisation?", "MessageConfirmRestart": "Er du sikker på du ønsker at genstarte Jellyfin?", "MessageConfirmRevokeApiKey": "Er du sikker på du ønsker at invalidere denne api nøgle? Applikationens forbindelse til Jellyfin vil blive afbrudt øjeblikkeligt.", - "MessageConfirmShutdown": "Er du sikker på du ønsker at lukke Jellyfin?", + "MessageConfirmShutdown": "Er du sikker på du ønsker at slukke for serveren?", "MessageContactAdminToResetPassword": "Kontakt venligst din systemadministrator for at nulstille din adgangskode.", "MessageCreateAccountAt": "Opret en konto hos {0}", "MessageDeleteTaskTrigger": "Er du sikker på du ønsker at slette denne task trigger?", "MessageDirectoryPickerBSDInstruction": "For BSD skal du muligvis konfigurere lager i dit FreeNAS Jail, før Jellyfin kan tilgå det.", "MessageDirectoryPickerInstruction": "Netværksstier kan indtastes manuelt i tilfælde af at netværksknappen ikke kan lokalisere dine enheder. Foreksempel, {0} eller {1}.", - "MessageDirectoryPickerLinuxInstruction": "For Linux på Arch Linux, CentOS, Debian, Fedora, OpenSuse eller Ubuntu skal du give Jellyfin-systembrugeren minimum læseadgang til dine lagerlokationer.", + "MessageDirectoryPickerLinuxInstruction": "For Linux på Arch Linux, CentOS, Debian, Fedora, openSUSE eller Ubuntu, skal du give servicebrugeren mindst læseadgang til dine lagerpladser.", "MessageDownloadQueued": "Download sat i kø.", "MessageEnablingOptionLongerScans": "Aktivering af denne indstilling kan resultere i væsentlig længere biblioteks skan.", "MessageFileReadError": "Der opstod en fejl i forsøget på at læse filen.", "MessageForgotPasswordFileCreated": "Den følgende fil er blevet oprettet på din server og indeholder instruktioner vedrørende hvordan du skal fortsætte:", "MessageForgotPasswordInNetworkRequired": "Prøv igen inde i dit hjemmenetværk for at igangsætte nulstilling af din adgangskode.", - "MessageInstallPluginFromApp": "Dette plugin skal være installeret inde i den app du ønsker at benytte det fra.", + "MessageInstallPluginFromApp": "Dette plugin skal installeres fra den app, du har til hensigt at bruge det i.", "MessageInvalidForgotPasswordPin": "En ugyldig eller udløbet pinkode blev indtastet. Prøv igen.", "MessageInvalidUser": "Ukendt brugernavn eller adgangskode. Prøv igen.", "MessageItemSaved": "Element gemt.", "MessageItemsAdded": "Emne tilføjet.", - "MessageLeaveEmptyToInherit": "Efterlad tom for at arve indstillinger fra en overliggende post eller den globale standardværdi.", + "MessageLeaveEmptyToInherit": "Lad være tom for at arve indstillinger fra et overordnet element eller den globale standardværdi.", "MessageNoAvailablePlugins": "Ingen tilgængelige plugins.", "MessageNoMovieSuggestionsAvailable": "Ingen filmforslag er tilgængelige. Begynd at se og vurder dine film, og kom tilbage for at se dine anbefalinger.", "MessageNoPluginsInstalled": "Du har ingen plugins installeret.", "MessageNoTrailersFound": "Ingen trailere fundet. Installer Trailer kanalen for at tilføje et bibliotek med trailere fra internettet.", "MessageNothingHere": "Her er ingenting.", - "MessagePasswordResetForUsers": "Adgangskoder blev fjernet for følgende brugere. For at logge ind, skal der benyttes en blank adgangskode.", + "MessagePasswordResetForUsers": "Følgende brugere har fået nulstillet deres adgangskoder. De kan nu logge på med de pinkoder, der blev brugt til at udføre nulstillingen.", "MessagePleaseEnsureInternetMetadata": "Sørg venligst for at hentning af metadata fra internettet er aktiveret.", "MessagePleaseWait": "Vent venligst. Dette kan tage et minut.", "MessagePluginConfigurationRequiresLocalAccess": "For at konfigurerer dette plugin log da venligst direkte ind på din lokale server.", "MessagePluginInstallDisclaimer": "Plugins fremstillet af medlemmer fra Jellyfin-fællesskabet er en alle tiders måde at forbedre din oplevelse af Jellyfin med yderligere features og fordele. Før installation, bedes du venligst være opmærksom på de effekter de kan have på din Jellyfin Server; så som lange scantider på biblioteker, yderligere baggrundsbehandling og forringet systemstabilitet.", "MessageReenableUser": "Se nedenfor om genaktivering", "MessageSettingsSaved": "Indstillinger er gemt.", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Følgende medielokationer bliver fjernet fra dit Jellyfin-bibliotek:", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Følgende medieplaceringer fjernes fra dit bibliotek:", "MessageUnableToConnectToServer": "Vi kan ikke forbinde til den valgte server på nuværende tidspunkt. Sikrer dig venligst at serveren kører og prøv igen.", "MessageUnsetContentHelp": "Indhold vil blive vist som almindelige mapper. For det bedste resultat benyt metadata manageren til at vælge indholdstypen i undermapper.", "MessageYouHaveVersionInstalled": "Du har version {0} installeret.", @@ -747,10 +747,10 @@ "MinutesBefore": "minutter før", "Monday": "Mandag", "MoreFromValue": "Mere fra {0}", - "MoreUsersCanBeAddedLater": "Flere brugere kan tilføjes senere i betjeningspanelet.", + "MoreUsersCanBeAddedLater": "Flere brugere kan tilføjes senere fra dashboardet.", "MoveLeft": "Flyt mod venstre", "MoveRight": "Flyt mod højre", - "MovieLibraryHelp": "Gennemse {0}Jellyfin film navngivningsguiden{1}.", + "MovieLibraryHelp": "Gennemse {0}film navngivningsguiden{1}.", "Movies": "Film", "Mute": "Afbryd lyd", "MySubtitles": "Mine Undertekster", @@ -782,7 +782,7 @@ "OptionAllowMediaPlaybackTranscodingHelp": "At begrænse adgang til omkodning kan forårsage afspilningsfejl i Jellyfin apps på grund af usupporterede medie formater.", "OptionAllowRemoteControlOthers": "Tillad fjernstyring af andre brugere", "OptionAllowRemoteSharedDevices": "Tillad fjernstyring af delte enheder", - "OptionAllowRemoteSharedDevicesHelp": "DLNA-enheder er delte indtil en bruger begynder at bruge den.", + "OptionAllowRemoteSharedDevicesHelp": "DLNA-enheder betragtes som delt, indtil en bruger begynder at kontrollere dem.", "OptionAllowSyncTranscoding": "Tillad medie hentning og synkronisering der kræver omkodning", "OptionAllowUserToManageServer": "Tillad denne bruger at administrere serveren", "OptionAllowVideoPlaybackRemuxing": "Tillad videoafspilning som kræver konvertering uden omkodning", @@ -811,13 +811,13 @@ "OptionDisableUserHelp": "Hvis deaktiveret vil serveren ikke tillade forbindelser fra denne bruger. Eksisterende forbindelser vil blive afbrudt øjeblikkeligt.", "OptionDislikes": "Ikke-Lide", "OptionDisplayFolderView": "Få vist en mappevisning til at se enkle mediemapper", - "OptionDisplayFolderViewHelp": "Hvis aktiveret, vil Jellyfin apps vise en Mappekategori ved siden af dine mediebiblioteker. Dette er brugbart, hvis du vil have vist enkle mappevisninger.", + "OptionDisplayFolderViewHelp": "Vis mapper sammen med dine andre mediebiblioteker. Dette kan være nyttigt, hvis du gerne vil have en almindelig mappevisning.", "OptionDownloadArtImage": "Billede", "OptionDownloadBackImage": "Bagside", "OptionDownloadBoxImage": "Boks", "OptionDownloadDiscImage": "Disk", "OptionDownloadImagesInAdvance": "Download billeder på forhånd", - "OptionDownloadImagesInAdvanceHelp": "Som standard downloades billeder kun når de anmodes af en Jellyfin app. Aktiver denne indstilling for at downloade alle billeder på forhånd, i mens nyt medie importeres. Dette resulterer muligvis i længere scanninger af bibliotek.", + "OptionDownloadImagesInAdvanceHelp": "Som standard downloades de fleste billeder kun, når de anmodes fra en Jellyfin-app. Aktivér denne mulighed for at downloade alle billeder på forhånd, da nye medier importeres. Dette kan forårsage betydeligt længere biblioteksscanninger.", "OptionDownloadPrimaryImage": "Primær", "OptionDownloadThumbImage": "Miniature", "OptionDvd": "DVD", @@ -825,9 +825,8 @@ "OptionEnableAccessFromAllDevices": "Tillad adgang fra alle enheder", "OptionEnableAccessToAllChannels": "Tillad adgang til alle kanaler", "OptionEnableAccessToAllLibraries": "Tillad adgang til alle biblioteker", - "OptionEnableAutomaticServerUpdates": "Aktiver automatiske serveropdateringer", "OptionEnableExternalContentInSuggestions": "Aktiver eksternt indhold i anbefalinger", - "OptionEnableExternalContentInSuggestionsHelp": "Tillad at internet-trailers og live-tv-programmer bliver inkluderet i det anbefalede indhold.", + "OptionEnableExternalContentInSuggestionsHelp": "Tillad at internet-trailers og live TV programmer bliver inkluderet i det anbefalede indhold.", "OptionEnableForAllTuners": "Aktiver for alle tuner-enheder", "OptionEnableM2tsMode": "Aktiver M2ts tilstand", "OptionEnableM2tsModeHelp": "Aktiver M2ts tilstand når der omkodes til mpegts.", @@ -845,8 +844,8 @@ "OptionHasThemeVideo": "Temavideo", "OptionHideUser": "Vis ikke denne bruger på loginsiden", "OptionHideUserFromLoginHelp": "Nyttigt for private kontoer eller skjulte administratorkontoer. Brugeren skal logge ind ved at skive sit brugernavn og adgangskode.", - "OptionHlsSegmentedSubtitles": "Hls segmented undertekster", - "OptionHomeVideos": "Hjemmevideoer og billeder", + "OptionHlsSegmentedSubtitles": "HLS segmenterede undertekster", + "OptionHomeVideos": "Billeder", "OptionIgnoreTranscodeByteRangeRequests": "Ignorer forespørgsler vedrørende transcode byte interval", "OptionIgnoreTranscodeByteRangeRequestsHelp": "Hvis aktiveret vil disse forespørgsler blive efterkommet, men byte range headeren ignoreret.", "OptionImdbRating": "IMDB bedømmelse", @@ -884,7 +883,7 @@ "OptionThursday": "Torsdag", "OptionTrackName": "Nummerets navn", "OptionTuesday": "Tirsdag", - "OptionTvdbRating": "Tvdb bedømmelse", + "OptionTvdbRating": "TVDB bedømmelse", "OptionUnairedEpisode": "Ikke sendte episoder", "OptionUnplayed": "Ikke afspillet", "OptionWakeFromSleep": "Vågner fra dvale", @@ -894,9 +893,9 @@ "OptionWeekly": "Ugentlig", "OriginalAirDateValue": "Originalt sendt: {0}", "Overview": "Overblik", - "PackageInstallCancelled": "{0} installation afbrudt.", - "PackageInstallCompleted": "{0} installation udført.", - "PackageInstallFailed": "{0} installationen mislykkedes.", + "PackageInstallCancelled": "{0} (version {1}) installation annulleret.", + "PackageInstallCompleted": "{0} (version {1}) installation udført.", + "PackageInstallFailed": "{0} (version {1}) installationen mislykkedes.", "ParentalRating": "Parental Rating", "PasswordMatchError": "Adgangskode og bekræft adgangskode skal være ens.", "PasswordResetComplete": "Adgangskoden er blevet nulstillet.", @@ -914,7 +913,7 @@ "Played": "Afspillet", "PleaseAddAtLeastOneFolder": "Tilføj venligst som minimum en enkelt mappe til dette bibliotek ved at klikke på Tilføj-knappen.", "PleaseConfirmPluginInstallation": "Klik venligst OK for at bekræfte at du har læst ovenstående og ønsker at fortsætte med installationen af plugin.", - "PleaseEnterNameOrId": "Indtast venligst et navn eller eksternt Id.", + "PleaseEnterNameOrId": "Indtast venligst et navn eller eksternt ID.", "PleaseRestartServerName": "Genstart venligst Jellyfin Server - {0}.", "PleaseSelectTwoItems": "Vælg venligst mindst to elementer.", "PluginInstalledMessage": "Plugin blev installeret med success. Jellyfin serveren skal genstartes for at aktivere det.", @@ -1026,7 +1025,7 @@ "TabProfiles": "Profiler", "TabRecordings": "Optagelser", "TabResponses": "Svar", - "TabResumeSettings": "Indstillinger for Genoptag", + "TabResumeSettings": "Genoptag", "TabScheduledTasks": "Planlagte opgaver", "TabSeries": "Serier", "TabSettings": "Indstillinger", @@ -1045,13 +1044,13 @@ "TitlePlayback": "Afspilning", "TrackCount": "{0} numre", "Tuesday": "Tirsdag", - "TvLibraryHelp": "Gennemse {0}Jellyfin TV navngivningsguiden{1}.", + "TvLibraryHelp": "Gennemgå {0} TV-navneguiden {1}.", "UninstallPluginConfirmation": "Er du sikker på du vil afinstallere {0}?", "UninstallPluginHeader": "Afinstaller plugin", "Unmute": "Genoptag lyd", "Unrated": "Ingen bedømmelse", - "UserAgentHelp": "Angiv en brugerdefineret user-agent http header, hvis nødvendigt.", - "UserProfilesIntro": "Jellyfin har indbygget understøttelse af brugerprofiler. Dette giver hver bruger sine egne indstillinger for visning, afspilningsstatus og forældrekontrol.", + "UserAgentHelp": "Angiv en brugerdefineret bruger-agent HTTP-header.", + "UserProfilesIntro": "Jellyfin inkluderer support til brugerprofiler med granuleret displayindstillinger, afspilningstilstand og forældrekontrol.", "ValueAlbumCount": "{0} album", "ValueAudioCodec": "Lyd codec: {0}", "ValueConditions": "Forhold: {0}", @@ -1073,17 +1072,17 @@ "ViewPlaybackInfo": "Vis afspilnings information", "Wednesday": "Onsdag", "WelcomeToProject": "Velkommen til Jellyfin!", - "WizardCompleted": "Det er alt vi behøver for nu. Jellyfin er begyndt at indsamle information omkring dit mediebibliotek. Tjek nogle af vores apps og klik derefter på Færdig for at se Server betjeningspanelet.", + "WizardCompleted": "Det er alt, hvad vi har brug for nu. Jellyfin er begyndt at indsamle information om dit mediebibliotek. Se nogle af vores apps, og klik derefter på Udfør for at se Dashboard.", "Writer": "Forfatter", - "XmlDocumentAttributeListHelp": "Disse attributter bliver tilføjet til rodelementet i alle XML svar.", + "XmlDocumentAttributeListHelp": "Disse attributter anvendes til rodelementet i hvert XML-svar.", "XmlTvKidsCategoriesHelp": "Programmer med disse kategorier bliver vist som programmer for børn. Adskil flere med '|'.", "XmlTvMovieCategoriesHelp": "Programmer med disse kategorier bliver vist som film. Adskil flere med '|'.", "XmlTvNewsCategoriesHelp": "Programmer med disse kategorier bliver vist som nyhedsprogrammer. Adskil flere med '|'.", - "XmlTvPathHelp": "En sti til en xml tv-fil. Jellyfin læser denne fil og kontrollerer periodisk for opdateringer. Du er ansvarlig for at oprette og opdatere filen.", + "XmlTvPathHelp": "En sti til en XMLTV fil. Jellyfin læser denne fil og kontrollerer periodisk for opdateringer. Du er ansvarlig for at oprette og opdatere filen.", "XmlTvSportsCategoriesHelp": "Programmer med disse kategorier bliver vist som sportsprogrammer. Adskil flere med '|'.", "Yesterday": "I går", "AirDate": "Luftdata", - "Albums": "Album", + "Albums": "Albums", "Artists": "Kunstnere", "Books": "Bøger", "Collections": "Samlinger", @@ -1093,15 +1092,15 @@ "Absolute": "Absolut", "AccessRestrictedTryAgainLater": "Adgang er begrænset. Prøv igen senere.", "Aired": "Blev sendt", - "AllComplexFormats": "Alle komplekse formater (ASS, SSA, VOBSUB, PGS, SUB/IDX osv.)", + "AllComplexFormats": "Alle Komplekse Formater (ASS, SSA, VOBSUB, PGS, SUB,IDX osv.)", "AllLanguages": "Alle sprog", - "AlwaysPlaySubtitles": "Afspil altid undertekster", + "AlwaysPlaySubtitles": "Afspil Altid", "AlwaysPlaySubtitlesHelp": "Undertekster, der matcher dine sprogindstillinger, vil altid blive indlæst uanset lydsprog.", "HeaderLiveTV": "Live-TV", "Shows": "Serier", "Songs": "Sange", "AndroidUnlockRestoreHelp": "For at gendanne dit tidligere køb skal du sørge for, at du er logget ind på enheden med den samme Google- eller Amazon-konto, som oprindeligt gjorde købet. Sørg for, at app store er aktiveret og ikke begrænset af forældrekontrol, og sørg for, at du har en aktiv internetforbindelse. Du skal kun gøre dette én gang for at gendanne dit tidligere køb.", - "AnyLanguage": "Ethvert sprog", + "AnyLanguage": "Hvilken som helst sprog", "Art": "Kunst", "Ascending": "Stigende", "AudioBitDepthNotSupported": "Lyd bit dybde ikke understøttet", @@ -1118,11 +1117,11 @@ "AutomaticallySyncNewContentHelp": "Nyt indhold tilføjet til denne mappe vil automatisk blive downloadet til enheden.", "Backdrop": "Baggrund", "Backdrops": "Baggrunde", - "Banner": "Bannere", + "Banner": "Banner", "Blacklist": "Blackliste", "Box": "Boks", "BoxRear": "Boks (bagside)", - "BurnSubtitlesHelp": "Bestemmer om serveren skal brænde underteksterne ind i videoen når den konverterer baseret på undertekstformatet. Det vil øge serverens ydeevne ikke at brænde underteksterne i filen. Vælg Automatisk for at brænde billedbaserede formater (VOBSUB, PGS, SUB/IDX, osv) og nogle ASS/SSA undertekster.", + "BurnSubtitlesHelp": "Bestemmer om serveren skal brænde undertekster, når der afspilles transcoding videoer. Undgå dette vil forbedre ydelsen meget. Vælg Auto for at brænde billedbaserede formater (VOBSUB, PGS, SUB, IDX) og bestemte ASS- eller SSA-undertekster.", "ButtonFilter": "Filter", "ButtonGuide": "Vejledning", "ButtonInfo": "Information", @@ -1167,8 +1166,7 @@ "DirectStreamHelp1": "Medie filen er kompatibel med enheden i forhold til opløsning og medie type (H.264,AC3, etc.), men er i en ikke kompatibel fil container (mkv, avi, wmv, etc). Videoen vil blive genpakket live før den streames til enheden.", "DirectStreamHelp2": "Direkte Streaming af en fil bruger meget lidt processor kraft uden nogen tab af video kvalitet.", "DirectStreaming": "Direkte streaming", - "DirectorValue": "Instruktør: {0}", - "DirectorsValue": "Instruktører: {0}", + "Directors": "Instruktører", "Disc": "Disk", "Dislike": "Kan ikke lide", "Display": "Visning", @@ -1176,14 +1174,14 @@ "DisplayInOtherHomeScreenSections": "Visning på hjemmeskærm sektioner som seneste medier og se videre", "DisplayMissingEpisodesWithinSeasons": "Vis manglende afsnit inde i sæsoner", "DisplayMissingEpisodesWithinSeasonsHelp": "Dette skal også være aktiveret for TV biblioteker i serverens indstillinger.", - "DisplayModeHelp": "Vælg skærmtypen du kører Jellyfin på.", + "DisplayModeHelp": "Vælg det ønskede tema for grænsefladen.", "Down": "Ned", "DownloadItemLimitHelp": "Valgfri. Sæt en begrænsning på antallet af ting der vil blive hentet.", "Downloaded": "Hentet", "DownloadingDots": "Henter...", "Downloads": "Hentninger", "DownloadsValue": "{0} hentninger", - "DropShadow": "Drop skygge", + "DropShadow": "Drop Skygge", "DvrFeatureDescription": "Tidsindstil individuelle TV optagelser, serie optagelser, og mere med Jellyfin DVR.", "EditMetadata": "Redigér metadata", "EnableBackdrops": "Baggrundsbilleder", @@ -1203,13 +1201,12 @@ "ErrorAddingJellyfinConnectAccount1": "Der skete en fejl ved tilføjelsen af Jellyfin Connect kontoen. Har du lavet en Jellyfin konto? Registrer dig på {0}.", "ErrorAddingJellyfinConnectAccount2": "Hvis du stadig har et problem, så send venligst en email til {0} fra den email adresse tilknyttet Jellyfin kontoen.", "ErrorDeletingItem": "Der skete en fejl ved sletningen af mediet fra Jellyfin Server. Tjek venligst at Jellyfin Server har skrive adgang til mediemappen og prøv igen.", - "ExtraLarge": "Ekstra stor", + "ExtraLarge": "Ekstra Stor", "Extras": "Bonusmateriale", "Features": "Funktioner", "Filters": "Filtre", "FormatValue": "Format: {0}", - "GenreValue": "Genre: {0}", - "GenresValue": "Genrer: {0}", + "Genre": "Genre", "GroupBySeries": "Gruppér efter serie", "Guide": "Vejledning", "GuideProviderLogin": "Log Ind", @@ -1271,20 +1268,20 @@ "Label3DFormat": "3D format:", "LabelAlbum": "Album:", "LabelArtist": "Kunstner", - "LabelAudio": "Lyd:", + "LabelAudio": "Lyd", "LabelBitrateMbps": "Bitrate (Mbps):", - "LabelBlockContentWithTags": "Blokér filer med mærkerne:", + "LabelBlockContentWithTags": "Blokér filer med etiketter:", "LabelBurnSubtitles": "Brænd undertekster:", "LabelCache": "Cache:", "LabelCertificatePassword": "Adgangskode til certifikat:", - "LabelCertificatePasswordHelp": "Hvis dit certifikat kræver en adgangskode, skriv det benligst her.", + "LabelCertificatePasswordHelp": "Hvis dit certifikat kræver en adgangskode, skriv det venligst her.", "LabelConvertTo": "Konvertér til:", "LabelDashboardTheme": "Server dashboard tema:", "LabelDateTimeLocale": "Dato og tid område:", "LabelDefaultScreen": "Standard skærm:", "LabelDisplayLanguage": "Visningssprog:", "LabelDisplayLanguageHelp": "Oversættelse af Jellyfin er et vedvarende projekt.", - "LabelDisplayMode": "Visningsmodus:", + "LabelDisplayMode": "Visningstilstand:", "LabelDropShadow": "Drop skygge:", "LabelDynamicExternalId": "{0} ID:", "LabelEmail": "Email:", @@ -1300,7 +1297,7 @@ "LabelMaxBitrate": "Maks bitrate:", "LabelMaxChromecastBitrate": "Chromecast streaming kvalitet:", "LabelMetadata": "Metadata:", - "LabelModelUrl": "Model link", + "LabelModelUrl": "Model URL", "LabelPreferredSubtitleLanguage": "Foretrukket undertekst sprog:", "LabelProfileCodecs": "Codecs:", "LabelProfileContainer": "Beholder:", @@ -1316,7 +1313,7 @@ "LabelSortOrder": "Sorteringsorden:", "LabelSoundEffects": "Lydeffekter:", "LabelStatus": "Status:", - "LabelSubtitles": "Undertekster:", + "LabelSubtitles": "Undertekster", "LabelSyncNoTargetsHelp": "Det ser ud til at du ikke har nogen apps der understøtter offline hentning.", "LabelTVHomeScreen": "TV modus hjemmeskærm:", "LabelTag": "Mærke:", @@ -1330,7 +1327,7 @@ "LabelUrl": "Link:", "LabelVersion": "Version:", "LabelVersionNumber": "Version {0}", - "LabelVideo": "Video:", + "LabelVideo": "Video", "LabelVideoCodec": "Video codec:", "LabelWindowBackgroundColor": "Tekst baggrundsfarve:", "LabelXDlnaCap": "X-DLNA begrænsning:", @@ -1381,7 +1378,7 @@ "Off": "Fra", "OnlyForcedSubtitles": "Kun tvungne undertekster", "OnlyForcedSubtitlesHelp": "Kun undertekster markeret som tvungne vil blive indlæst.", - "OnlyImageFormats": "Kun billedformater (VOBSUB, PGS, SUB, etc)", + "OnlyImageFormats": "Kun billedformater (VOBSUB, PGS, SUB)", "Option2Player": "2+", "Option3D": "3D", "Option3Player": "3+", @@ -1423,7 +1420,7 @@ "PlayCount": "Afspilninger", "PlayNext": "Afspil næste", "PlayNextEpisodeAutomatically": "Afspil næste afsnit automatisk", - "PlaybackErrorNoCompatibleStream": "Ingen kompatible streams er tilgængelige. Prøv venligst igen senere eller kontakt din system administrator for detaljer.", + "PlaybackErrorNoCompatibleStream": "Denne klient er ikke kompatibel med medierne, og serveren sender ikke et kompatibelt medieformat.", "PlaybackErrorNotAllowed": "Du har ikke adgang til at afspille dette indhold. Kontakt venligst system administratoren for detaljer.", "PlaybackErrorPlaceHolder": "Indlæs venligst disken for at afspille denne video.", "PlaybackSettings": "Afspilningsindstillinger", @@ -1439,7 +1436,7 @@ "RefFramesNotSupported": "Antal af video reference billeder ikke understøttet", "RefreshMetadata": "Genopfrisk metadata", "RepeatAll": "Gentag alle", - "RepeatMode": "Gentagelsesmode", + "RepeatMode": "Gentagelses tilstand", "RepeatOne": "Gentag én", "RestartPleaseWaitMessage": "Vent venligst mens Jellyfin Server lukker og genstarter. Dette kan tage et minut eller to.", "RunAtStartup": "Kør ved opstart", @@ -1447,7 +1444,7 @@ "Schedule": "Tidsplan", "Screenshot": "Skærmbillede", "SecondaryAudioNotSupported": "Lydspor skift ikke understøttet", - "SeriesDisplayOrderHelp": "Sortér afsnit efter sende dato, dvd rækkefølge eller obsolut nummering.", + "SeriesDisplayOrderHelp": "Sortér episoder efter luftdato, DVD-orden eller absolut nummerering.", "ShowTitle": "Vis titel", "ShowYear": "Vis år", "Small": "Lille", @@ -1535,5 +1532,116 @@ "LabelServerName": "Server navn:", "LabelUserLoginAttemptsBeforeLockout": "Fejlede loginforsøg før bruger lukkes ude:", "HeaderRestartingServer": "Genstarter Server", - "ButtonAddImage": "Tilføj billede" + "ButtonAddImage": "Tilføj billede", + "AllowFfmpegThrottlingHelp": "Når en omkodning eller remux kommer langt nok foran den nuværende afspildings position, pauses processen så der bruges færre resurser. Dette er mest brugbart når man ikke springer i filmen. Slå dette fra hvis du har problemer med playback.", + "AllowFfmpegThrottling": "Begræns Omkodning", + "AlbumArtist": "Album Artist", + "Album": "Album", + "EveryHour": "Hver time", + "EveryXMinutes": "Hvert {0} minut", + "OnWakeFromSleep": "Ved vækning fra dvale", + "WeeklyAt": "{0}s ved {1}", + "DailyAt": "Dagligt kl. {0}", + "LastSeen": "Sidst set {0}", + "PersonRole": "som {0}", + "ListPaging": "{0}-{1} af {2}", + "WriteAccessRequired": "Jellyfin Server kræver skriveadgang til denne mappe. Sørg for skriveadgang, og prøv igen.", + "PathNotFound": "Stien blev ikke fundet. Sørg for, at stien er gyldig, og prøv igen.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Spor", + "TabNetworking": "Netværk", + "SubtitleOffset": "Undertekst Offset", + "SelectAdminUsername": "Vælg et brugernavn til administrator kontoen.", + "Season": "Sæson", + "ReleaseGroup": "Release Group", + "Premiere": "Premiere", + "PreferEmbeddedEpisodeInfosOverFileNames": "Foretrækker integreret episode information frem for filnavne", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Dette bruger episode informationen fra de integrerede metadata, hvis den er tilgængelig.", + "PlaybackData": "Afspilningsdata", + "Person": "Person", + "PasswordResetProviderHelp": "Vælg en leverandør af nulstil adgangskode, der skal bruges, når denne bruger anmoder om en nulstilling af adgangskode", + "OtherArtist": "Anden kunstner", + "OptionThumbCard": "Thumb card", + "OptionThumb": "Thumb", + "OptionRandom": "Tilfældig", + "OptionPosterCard": "Plakatkort", + "OptionPoster": "Plakat", + "OptionLoginAttemptsBeforeLockoutHelp": "En værdi på nul betyder at arve standard for tre forsøg for normale brugere og fem for administratorer. Indstilling af dette til -1 vil deaktivere funktionen.", + "OptionLoginAttemptsBeforeLockout": "Bestemmer, hvor mange forkerte loginforsøg, der kan gøres, før lockout finder sted.", + "OptionList": "Liste", + "OptionForceRemoteSourceTranscoding": "Tving transcoding af eksterne mediekilder (som LiveTV)", + "NoCreatedLibraries": "Det ser ud til, at du ikke har oprettet nogen biblioteker endnu. {0} Vil du oprette en nu? {1}", + "MusicVideo": "Musik Video", + "MusicLibraryHelp": "Gennemgå {0} guide til navngivning af musik {1}.", + "MusicArtist": "Musik Artist", + "MusicAlbum": "Musik Album", + "Movie": "Film", + "MoreMediaInfo": "Medieinfo", + "MessageNoServersAvailable": "Der er ikke fundet nogen servere ved hjælp af den automatiske serveropdagelse.", + "MessageNoCollectionsAvailable": "Samlinger tillader dig at nyde personlige grupperinger af Film, Serier og Albums. Klik på + knappen for at skabe en samling.", + "MessageConfirmAppExit": "Vil du afslutte?", + "MediaInfoStreamTypeSubtitle": "Undertekst", + "MediaInfoStreamTypeEmbeddedImage": "Indlejret billede", + "MediaInfoStreamTypeAudio": "Lyd", + "LaunchWebAppOnStartupHelp": "Åben web klienten i den standard web browser når serveren starter første gang. Dette vil ikke ske når restart server funktionen benyttes.", + "LaunchWebAppOnStartup": "Åben webinterfacet når serveren startes", + "LabelWeb": "Web:", + "LabelVideoResolution": "Videoopløsning:", + "LabelVideoBitrate": "Video bitrate:", + "DashboardArchitecture": "Arkitektur: {0}", + "DashboardOperatingSystem": "Styresystem: {0}", + "DashboardServerName": "Server: {0}", + "DashboardVersionNumber": "Version: {0}", + "LabelTranscodingProgress": "Transcoding fremskridt:", + "LabelTranscodingFramerate": "Transcoding framerate:", + "LabelTranscodes": "Transcodes:", + "LabelTranscodePath": "Transcode sti:", + "LabelStreamType": "Stream type:", + "LabelSonyAggregationFlags": "Sony aggregering flag:", + "LabelSize": "Størrelse:", + "EnableFastImageFadeInHelp": "Aktivér hurtigere fade-in-animation til indlæste billeder", + "EnableFastImageFadeIn": "Hurtigt billede indtoning", + "LabelPleaseRestart": "Ændringer vil træde i kraft efter web klienten er blevet genindlæst manuelt.", + "LabelPlayMethod": "Afspilnings metode:", + "LabelPlayerDimensions": "Afspillerdimensioner:", + "LabelPlayer": "Afspiller:", + "LabelPasswordResetProvider": "Udbyder til nulstilling as kodeord:", + "LabelLibraryPageSizeHelp": "Indstiller mængden af genstande, der skal vises på en bibliotekside. Indstil til 0 for at deaktivere.", + "LabelLibraryPageSize": "Biblioteks størrelse:", + "LabelFolder": "Mappe:", + "LabelBaseUrl": "Base URL:", + "LabelBaseUrlHelp": "Du kan tilføje en speciel undermappe her for, at have adgang til serveren fra en mere unik URL.", + "LabelDroppedFrames": "Tabte frames:", + "LabelDeinterlaceMethod": "Konventerings metode:", + "LabelCorruptedFrames": "Korrupte frames:", + "LabelBitrate": "Bitrate:", + "LabelAuthProvider": "Autentificeringsudbyder:", + "LabelAudioSampleRate": "Lydeksempelfrekvens:", + "LabelAudioCodec": "Lyd codec:", + "LabelAudioChannels": "Lyd kanaler:", + "LabelAudioBitrate": "Lyd bitrate:", + "LabelAudioBitDepth": "Lyd bitdybde:", + "HeaderFavoritePeople": "Foretrukne Personer", + "HeaderFavoriteBooks": "Foretrukne Bøger", + "FetchingData": "Henter yderligere data", + "Episode": "Afsnit", + "DeinterlaceMethodHelp": "Vælg hvilken konverteringsmulighed der skal bruges til transkodning af indhold.", + "CopyStreamURLError": "Der skete en fejl med at kopiere URL'en.", + "CopyStreamURLSuccess": "URL blev kopieret.", + "CopyStreamURL": "Kopiér stream URL", + "ClientSettings": "Klient Indstillinger", + "ButtonSplit": "Opdel", + "BoxSet": "Box Set", + "AuthProviderHelp": "Vælg en godkendelsesudbyder til at godkende denne brugers adgangskode.", + "AskAdminToCreateLibrary": "Spørg en administrator om at oprette et bibliotek.", + "Artist": "Artist", + "EveryXHours": "Hver {0} time", + "OnApplicationStartup": "Ved programstart", + "UnsupportedPlayback": "Jellyfin kan ikke dekryptere indhold, der er beskyttet af DRM, men alt indhold vil blive forsøgt afspillet uanset, inklusive beskyttede titler. Nogle filer kan eventuelt vises med sort skærm på grund af kryptering eller andre funktioner, der ikke understøttes, såsom interaktive titler.", + "MessageUnauthorizedUser": "Du har ikke tilladelse til at tilgå serveren på dette tidspunkt. Kontakt din serveradministrator for mere information.", + "Filter": "Filtrer", + "New": "Nye", + "ButtonTogglePlaylist": "Spilleliste", + "ButtonToggleContextMenu": "Mere" } diff --git a/src/strings/de.json b/src/strings/de.json index 034cf04d55..0c333860a3 100644 --- a/src/strings/de.json +++ b/src/strings/de.json @@ -1,5 +1,5 @@ { - "Absolute": "Gesamt", + "Absolute": "Absolut", "AccessRestrictedTryAgainLater": "Der Zugriff ist derzeit eingeschränkt. Bitte versuche es später erneut.", "Actor": "Darsteller(in)", "Add": "Hinzufügen", @@ -10,14 +10,14 @@ "AddToPlaylist": "Zur Wiedergabeliste hinzufügen", "AddUser": "Benutzer anlegen", "AddUserByManually": "Lege einen lokalen User durch manuelle Eingabe der User-Informationen an.", - "AddedOnValue": "Hinzugefügt {0}", - "AdditionalNotificationServices": "Schau im Pluginkatalog, um weitere Benachrichtigungsdienste zu installieren.", + "AddedOnValue": "{0} hinzugefügt", + "AdditionalNotificationServices": "Durchsuche den Pluginkatalog, um weitere Benachrichtigungsdienste zu installieren.", "AirDate": "Erstausstrahlung", "Aired": "Ausgestrahlt", "Albums": "Alben", "All": "Alle", "AllChannels": "Alle Kanäle", - "AllComplexFormats": "Alle komplexen Formate (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Alle komplexen Formate (ASS, SSA, VOBSUB, PGS, SUB/IDX, ...)", "AllEpisodes": "Alle Folgen", "AllLanguages": "Alle Sprachen", "AllLibraries": "Alle Bibliotheken", @@ -26,13 +26,13 @@ "AllowMediaConversion": "Erlaube Medienkonvertierung", "AllowMediaConversionHelp": "Erlaube oder unterbinde Zugriff auf die Medienkonvertierung.", "AllowOnTheFlySubtitleExtraction": "Erlaube Untertitelextraktion \"on-the-fly\"", - "AllowOnTheFlySubtitleExtractionHelp": "Eingebettete Untertitel können aus Videos extrahiert und in Textformat an Clients gesendet werden um Transkodieren zu vermeiden. Auf manchen Systemen kann dieser Vorgang eine lange Zeit in Anspruch nehmen und die Videowiedergabe zum Halten bringen während der Extraktion. Deaktiviere diese Option um eingebettete Untertitel während der Videotranskodierung einbrennen zu lassen, wenn sie nicht nativ vom Client unterstützt werden.", + "AllowOnTheFlySubtitleExtractionHelp": "Eingebettete Untertitel können aus Videos extrahiert und in Reintext an Clients gesendet werden, um eine Videotranskodierung zu vermeiden. Auf manchen Systemen kann dieser Vorgang eine lange Zeit in Anspruch nehmen und deswegen währenddessen die Videowiedergabe stoppen. Deaktiviere diese Option, um eingebettete Untertitel während des Videotranskodierens einbrennen zu lassen, wenn sie nicht nativ vom Client unterstützt werden.", "AllowRemoteAccess": "Erlaube externe Verbindungen zu diesem Jellyfin Server.", "AllowRemoteAccessHelp": "Wenn deaktiviert werden alle externen Verbindungen blockiert.", "AllowSeasonalThemes": "Erlaube automatische Jahreszeitenmotive", "AllowSeasonalThemesHelp": "Wenn aktiviert, werden Jahreszeitenmotive von Zeit zu Zeit deine Motiveinstellungen überschreiben.", "AllowedRemoteAddressesHelp": "Kommagetrennte Liste von IP Adressen oder IP/Netzmasken für Netzwerke, für die externe Verbindungen erlaubt sind. Wenn leer, sind alle Adressen erlaubt.", - "AlwaysPlaySubtitles": "Untertitel immer einblenden", + "AlwaysPlaySubtitles": "Immer anzeigen", "AlwaysPlaySubtitlesHelp": "Untertitel die den Spracheinstellungen entsprechen werden unabhängig von der Tonspursprache geladen.", "AnyLanguage": "Jede Sprache", "Anytime": "Jederzeit", @@ -60,7 +60,7 @@ "BoxRear": "Box (Rückseite)", "Browse": "Blättern", "BrowsePluginCatalogMessage": "Durchsuche unsere Bibliothek, um alle verfügbaren Plugins anzuzeigen.", - "BurnSubtitlesHelp": "Legt fest, ob der Server die Untertitel basierend auf deren Format während der Videokonvertierung einbrennen soll. 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.", + "BurnSubtitlesHelp": "Legt fest, ob der Server die Untertitel während der Videotranskodierung einbrennen soll. Deaktivieren verbessert die Serverperformance immens. Wähle Auto, um bildbasierte Formate (z.B. VOBSUB, PGS, SUB, IDX, ...) sowie bestimmte ASS- oder SSA-Untertitel einbrennen zu lassen.", "ButtonAdd": "Hinzufügen", "ButtonAddMediaLibrary": "Füge Medienbibliothek hinzu", "ButtonAddScheduledTaskTrigger": "Auslöser hinzufügen", @@ -175,8 +175,7 @@ "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}", + "Directors": "Regisseure", "Disabled": "Abgeschaltet", "Disc": "Disk", "Disconnect": "Verbindung trennen", @@ -186,7 +185,7 @@ "DisplayInOtherHomeScreenSections": "Zeige auf dem Homescreen Bereiche wie 'Neueste Medien' oder 'Weiterschauen'", "DisplayMissingEpisodesWithinSeasons": "Zeige fehlende Episoden innerhalb von Staffeln", "DisplayMissingEpisodesWithinSeasonsHelp": "Dies muss auch für Serienbibliotheken in den Servereinstellungen aktiviert sein.", - "DisplayModeHelp": "Bitte wähle den Typ des Bildschirms auf dem Du Jellyfin verwendest.", + "DisplayModeHelp": "Wähle das Layout welches du für die Oberfläche verwenden möchtest.", "DoNotRecord": "Nicht aufnehmen", "Down": "Runter", "DownloadsValue": "{0} Downloads", @@ -257,10 +256,10 @@ "GuideProviderLogin": "Anmelden", "GuideProviderSelectListings": "Wähle Listen", "H264CrfHelp": "Der Constant Rate Factor (CRF) bezeichnet die Einstellung für die Standardqualität des x264 Encoders. Setze einen Wert zwischen 0 und 51. Ein niedriger Wert resultiert in besserer Qualität (auf Kosten einer größeren Datei). Gängige Werte sind 18-28. Der Standard für x264 ist 23 und empfohlen als Startpunkt.", - "H264EncodingPresetHelp": "Wähle einen schnelleren Wert um die Performance zu verbessern oder einen langsameren Wert um die Qualität zu verbessern.", + "EncoderPresetHelp": "Wähle einen schnelleren Wert um die Performance zu verbessern oder einen langsameren Wert um die Qualität zu verbessern.", "HDPrograms": "HD Programme", "HandledByProxy": "Verwaltet vom Reverse Proxy", - "HardwareAccelerationWarning": "Das Aktivieren der Hardwarebeschleunigung kann auf einigen Systemen zu Instabilität führen. Stellen Sie sicher, dass Ihr Betriebssystem sowie Ihre Grafikkarten-Treiber auf dem aktuellsten Stand sind. Wenn Sie nach der Aktivierung Probleme mit der Wiedergabe von Videos haben, müssen Sie diese Einstellung zurück auf \"Auto\" stellen.", + "HardwareAccelerationWarning": "Das Aktivieren der Hardwarebeschleunigung kann auf einigen Systemen zu Instabilität führen. Stellen Sie sicher, dass Ihr Betriebssystem sowie Ihre Grafikkarten-Treiber auf dem aktuellsten Stand sind. Wenn Sie nach der Aktivierung Probleme mit der Wiedergabe von Videos haben, müssen Sie diese Einstellung zurück auf \"Keine\" stellen.", "HeaderAccessSchedule": "Zugangsplan", "HeaderAccessScheduleHelp": "Erstelle einen Zugangsplan, um den Zugriff auf bestimmte Zeiten zu limitieren.", "HeaderActiveDevices": "Aktive Geräte", @@ -304,7 +303,7 @@ "HeaderContainerProfile": "Containerprofil", "HeaderContainerProfileHelp": "Containerprofile weisen auf Beschränkungen einen Gerätes beim Abspielen bestimmter Formate hin. Wenn eine Beschränkung zutrifft, dann werden Medien transcodiert, auch wenn das Format für die Direktwiedergabe konfiguriert ist.", "HeaderContinueListening": "Weiterhören", - "HeaderContinueWatching": "Weiterschauen", + "HeaderContinueWatching": "Fortsetzen", "HeaderCustomDlnaProfiles": "Benutzerdefinierte Profile", "HeaderDateIssued": "Datum gesetzt", "HeaderDefaultRecordingSettings": "Standard Aufnahmeeinstellungen", @@ -470,7 +469,7 @@ "Images": "Bilder", "ImportFavoriteChannelsHelp": "Wenn aktiviert, werden nur auf dem Tuner favorisierte Kanäle importiert.", "ImportMissingEpisodesHelp": "Wenn aktiviert, werden Informationen über fehlende Episoden in Deine Jellyfin Datenbank importiert und innerhalb von Staffeln angezeigt. Dies kann zu deutlich längeren Bibliothek Scans führen.", - "InstallingPackage": "Installiere {0}", + "InstallingPackage": "Installiere {0} (Version {1})", "InstantMix": "Schnellmix", "ItemCount": "{0} Einträge", "Items": "Einträge", @@ -560,7 +559,7 @@ "LabelEmbedAlbumArtDidl": "Integrierte Alben-Cover in Didl", "LabelEmbedAlbumArtDidlHelp": "Einige Geräte bevorzugen diese Methode um Album Art darstellen zu können. Andere wiederum können evtl. nichts abspielen, wenn diese Funktion aktiviert ist.", "LabelEnableAutomaticPortMap": "Aktiviere das automatische Port-Mapping", - "LabelEnableAutomaticPortMapHelp": "Versuche automatisch den öffentlichen Port dem lokalen Port mit Hilfe von UPnP zuzuordnen. Dies kann mit einigen Router-Modellen nicht funktionieren.", + "LabelEnableAutomaticPortMapHelp": "Versuche automatisch den öffentlichen Port dem lokalen Port mit Hilfe von UPnP zuzuordnen. Dies kann mit einigen Router-Modellen nicht funktionieren. Die Änderungen werden erst nach einem Neustart des Server aktiv.", "LabelEnableBlastAliveMessages": "Erzeuge Alive Meldungen", "LabelEnableBlastAliveMessagesHelp": "Aktiviere dies, wenn der Server nicht zuverlässig von anderen UPnP Geräten in ihrem Netzwerk erkannt wird.", "LabelEnableDlnaClientDiscoveryInterval": "Client-Entdeckungs Intervall (Sekunden)", @@ -591,9 +590,9 @@ "LabelServerNameHelp": "Dieser Name wird benutzt um den Server zu identifizieren, normalerweise wird der Server-/Computername verwendet.", "LabelGroupMoviesIntoCollections": "Gruppiere Filme in Collections", "LabelGroupMoviesIntoCollectionsHelp": "Wenn Filmlisten angezeigt werden, dann werden Filme, die zu einer Collection gehören, als ein gruppiertes Element angezeigt.", - "LabelH264EncodingPreset": "H264 Encoding Voreinstellung:", + "LabelEncoderPreset": "H264 Encoding Voreinstellung:", "LabelHardwareAccelerationType": "Hardware Beschleunigung:", - "LabelHardwareAccelerationTypeHelp": "Dies ist eine experimentelle Funktion und nur auf unterstützten Systemen verfügbar.", + "LabelHardwareAccelerationTypeHelp": "Hardwarebeschleunigung benötigt zusätzliche Konfiguration.", "LabelHomeNetworkQuality": "Heimnetzwerkqualität:", "LabelHomeScreenSectionValue": "Startseitenbereich {0}:", "LabelHttpsPort": "Lokale HTTPS-Portnummer:", @@ -636,7 +635,7 @@ "LabelMaxChromecastBitrate": "Max Chromcast Datenrate:", "LabelMaxParentalRating": "Höchste erlaubte elterlich Bewertung:", "LabelMaxResumePercentage": "Maximale Prozent für Wiederaufnahme:", - "LabelMaxResumePercentageHelp": "Titel werden als \"vollständig gesehen\" eingetragen, wenn sie nach dieser Zeit gestoppt werden", + "LabelMaxResumePercentageHelp": "Titel werden als \"vollständig gesehen\" markiert, wenn sie nach dieser Zeitmarke gestoppt werden.", "LabelMaxScreenshotsPerItem": "Maximale Anzahl von Screenshots pro Element:", "LabelMaxStreamingBitrate": "Maximale Streaming-Qualität:", "LabelMaxStreamingBitrateHelp": "Wähle die maximale Bitrate während des streamens.", @@ -654,9 +653,9 @@ "LabelMethod": "Methode:", "LabelMinBackdropDownloadWidth": "Minimale Breite für zu herunterladende Hintergründe:", "LabelMinResumeDuration": "Minimale Dauer für Wiederaufnahme:", - "LabelMinResumeDurationHelp": "Die kürzeste Videolänge in Sekunden, die den Wiedergabeplatz speichert und dich fortsetzen lässt", + "LabelMinResumeDurationHelp": "Die Videolänge in Sekunden, ab der die Wiedergabeposition gespeichert wird und dich fortsetzen lässt.", "LabelMinResumePercentage": "Minimale Prozent für Wiederaufnahme:", - "LabelMinResumePercentageHelp": "Titel werden als \"Ungesehen\" eingetragen, wenn sie vor dieser Zeit gestoppt werden", + "LabelMinResumePercentageHelp": "Titel werden als \"Ungesehen\" eingetragen, wenn sie vor dieser Zeit gestoppt werden.", "LabelMinScreenshotDownloadWidth": "Minimale Breite für zu herunterladende Screenshot:", "LabelModelDescription": "Modellbeschreibung", "LabelModelName": "Modellname", @@ -759,7 +758,7 @@ "LabelSubtitleDownloaders": "Untertitel Downloader:", "LabelSubtitleFormatHelp": "Beispiel: srt", "LabelSubtitlePlaybackMode": "Untertitelmodus:", - "LabelSubtitles": "Untertitel:", + "LabelSubtitles": "Untertitel", "LabelSupportedMediaTypes": "Unterstüzte Medientypen:", "LabelTVHomeScreen": "TV-Mode Startseite:", "LabelTextBackgroundColor": "Hintergrundfarbe des Textes:", @@ -909,15 +908,15 @@ "NoNextUpItemsMessage": "Es wurde nichts gefunden. Schau dir deine Shows an!", "NoPluginConfigurationMessage": "Dieses Plugin hat keine konfigurierbaren Einstellungen.", "NoSubtitleSearchResultsFound": "Keine Ergebnisse gefunden.", - "NoSubtitles": "Keine Untertitel", + "NoSubtitles": "Keine", "NoSubtitlesHelp": "Untertitel werden standardmäßig nicht geladen. Sie können aber während der Wiedergabe manuell aktiviert werden.", "None": "Keines", "NumLocationsValue": "{0} Verzeichnisse", "Off": "Aus", "OneChannel": "Ein Kanal", - "OnlyForcedSubtitles": "Nur erzwungene Untertitel", + "OnlyForcedSubtitles": "Nur Erzwungene", "OnlyForcedSubtitlesHelp": "Nur Untertitel, die als erzwungen markiert wurden, werden geladen.", - "OnlyImageFormats": "Nur Bildformate (VOBSUB, PGS, SUB, etc.)", + "OnlyImageFormats": "Nur Bildformate (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Administratoren", "OptionAlbumArtist": "Album-Interpret", "OptionAllUsers": "Alle Benutzer", @@ -974,7 +973,6 @@ "OptionEnableAccessFromAllDevices": "Erlaube Zugriff von allen Geräten", "OptionEnableAccessToAllChannels": "Erlaube Zugriff auf alle Kanäle", "OptionEnableAccessToAllLibraries": "Erlaube Zugriff auf alle Bibliotheken", - "OptionEnableAutomaticServerUpdates": "Aktiviere automatische Server Updates", "OptionEnableExternalContentInSuggestions": "Aktiviere externe Inhalte in Empfehlungen", "OptionEnableExternalContentInSuggestionsHelp": "Erlaube Internet Trailer und Live TV Sendungen in Empfehlungen.", "OptionEnableForAllTuners": "Aktiviere für alle Tuner", @@ -1002,7 +1000,7 @@ "OptionLikes": "Mag ich", "OptionMissingEpisode": "Fehlende Episoden", "OptionMonday": "Montag", - "OptionNew": "Neu...", + "OptionNew": "Neu…", "OptionNone": "Keines", "OptionOnAppStartup": "Bei Anwendungsstart", "OptionOnInterval": "Nach einem Intervall", @@ -1038,9 +1036,9 @@ "OptionWeekly": "Wöchentlich", "OriginalAirDateValue": "Erstausstrahlung: {0}", "Overview": "Übersicht", - "PackageInstallCancelled": "{0} Installation abgebrochen.", - "PackageInstallCompleted": "{0} Installation abgeschlossen.", - "PackageInstallFailed": "{0} Installation fehlgeschlagen.", + "PackageInstallCancelled": "{0} (Version {1}) Installation abgebrochen.", + "PackageInstallCompleted": "{0} (Version {1}) Installation abgeschlossen.", + "PackageInstallFailed": "{0} (Version {1}) Installation fehlgeschlagen.", "ParentalRating": "Altersfreigabe", "PasswordMatchError": "Die Passwörter müssen übereinstimmen.", "PasswordResetComplete": "Das Passwort wurde zurückgesetzt.", @@ -1070,6 +1068,8 @@ "PluginInstalledMessage": "Das Plugin wurde erfolgreich installiert. Der Jellyfin-Server muss neu gestartet werden, um die Änderungen zu übernehmen.", "PreferEmbeddedTitlesOverFileNames": "Bevorzuge eingebettete Titel vor Dateinamen", "PreferEmbeddedTitlesOverFileNamesHelp": "Das bestimmt den Standard Displaytitel wenn keine lokale oder Internetmetadaten verfügbar sind.", + "PreferEmbeddedEpisodeInfosOverFileNames": "Bevorzuge eingebettete Episodeninformationen vor Dateinamen", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Bevorzugt die in den Metadaten eingebetteten Episodeninformationen.", "PreferredNotRequired": "Bevorzugt, aber nicht benötigt", "Premieres": "Premieren", "Previous": "Vorheriges", @@ -1097,7 +1097,7 @@ "RefreshMetadata": "Aktualisiere Metadaten", "RefreshQueued": "Aktualisierung eingereiht.", "ReleaseDate": "Veröffentlichungsdatum", - "RememberMe": "Erinnere mich", + "RememberMe": "Angemeldet bleiben", "RemoveFromCollection": "Aus Sammlung entfernen", "RemoveFromPlaylist": "Von Wiedergabeliste entfernen", "Repeat": "Wiederholen", @@ -1143,8 +1143,8 @@ "Share": "Teilen", "ShowAdvancedSettings": "Zeige erweiterte Einstellungen", "ShowIndicatorsFor": "Zeige Indikatoren für:", - "ShowTitle": "Zeige Titel", - "ShowYear": "Zeige Jahr", + "ShowTitle": "Titel anzeigen", + "ShowYear": "Jahr anzeigen", "Shows": "Serien", "Shuffle": "Zufallswiedergabe", "SimultaneousConnectionLimitHelp": "Die maximale Anzahl der parallel erlaubten Streams. 0 für kein Limit.", @@ -1275,7 +1275,7 @@ "Audio": "Audio", "Auto": "Auto", "Banner": "Banner", - "Blacklist": "Blacklist", + "Blacklist": "Sperrliste", "ButtonDownload": "Download", "ButtonFilter": "Filter", "ButtonHome": "Startseite", @@ -1292,9 +1292,8 @@ "Extras": "Extras", "FolderTypeTvShows": "TV Serien", "FormatValue": "Format: {0}", - "GenreValue": "Genre: {0}", + "Genre": "Genre", "Genres": "Genres", - "GenresValue": "Genres: {0}", "HeaderAdmin": "Admin", "HeaderApp": "App", "HeaderGenres": "Genres", @@ -1306,7 +1305,7 @@ "Home": "Startseite", "Horizontal": "Horizontal", "LabelAlbum": "Album:", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelCache": "Cache:", "LabelFormat": "Format:", "LabelH264Crf": "H264 Encodierungs-CRF:", @@ -1315,7 +1314,7 @@ "LabelProfileCodecs": "Codecs:", "LabelProfileContainer": "Container:", "LabelSkin": "Textur:", - "Art": "Kunst", + "Art": "Coverkunst", "Name": "Name", "Songs": "Songs", "ValueSpecialEpisodeName": "Extra - {0}", @@ -1325,8 +1324,8 @@ "LabelTypeText": "Text", "LabelVersion": "Version:", "LabelVersionNumber": "Version {0}", - "LabelVideo": "Video:", - "LeaveBlankToNotSetAPassword": "Optional - frei lassen um kein Passwort zu setzen", + "LabelVideo": "Video", + "LeaveBlankToNotSetAPassword": "Du kannst dieses Feld frei lassen um kein Passwort zu setzen.", "LinksValue": "Links: {0}", "MessageImageFileTypeAllowed": "Nur JPEG- und PNG-Dateien werden unterstützt.", "MessageImageTypeNotSelected": "Bitte wähle einen Bildtyp aus dem Drop-Down Menü aus.", @@ -1401,8 +1400,8 @@ "Thumb": "Miniaturansicht", "TitleSupport": "Hilfe", "Whitelist": "Erlaubt", - "AuthProviderHelp": "Auswählen eines Authentifizierungsanbieter, der zur Authentifizierung des Passworts dieses Benutzes verwendet werden soll.", - "Features": "Features", + "AuthProviderHelp": "Authentifizierungsanbieter auswählen, der zur Authentifizierung des Benutzerpassworts verwendet werden soll.", + "Features": "Funktionen", "HeaderFavoriteBooks": "Lieblingsbücher", "HeaderFavoriteMovies": "Lieblingsfilme", "HeaderFavoriteShows": "Lieblingsserien", @@ -1418,7 +1417,7 @@ "LabelUserLoginAttemptsBeforeLockout": "Fehlgeschlagene Anmeldeversuche, bevor der Benutzer gesperrt wird:", "DashboardVersionNumber": "Version: {0}", "DashboardServerName": "Server: {0}", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "MediaInfoSoftware": "Software", "MediaInfoStreamTypeAudio": "Audio", "MediaInfoStreamTypeData": "Daten", @@ -1451,7 +1450,7 @@ "LabelFolder": "Ordner:", "LabelPasswordResetProvider": "Anbieter zum Zurücksetzen des Passwortes:", "LabelPlayMethod": "Spielmethode:", - "DashboardOperatingSystem": "Betriebssystem: {O}", + "DashboardOperatingSystem": "Betriebssystem: {0}", "DashboardArchitecture": "Architektur: {0}", "LabelVideoCodec": "Videocodec:", "LaunchWebAppOnStartup": "Das Webinterface öffnen, wenn der Server startet", @@ -1460,7 +1459,7 @@ "MusicAlbum": "Musikalbum", "MoreMediaInfo": "Medieninformation", "MessageNoServersAvailable": "Die automatische Serversuche konnte keinen Server finden.", - "LabelPlayer": "Player:", + "LabelPlayer": "Schauspieler:", "MediaInfoCodecTag": "Codec Tag", "SubtitleOffset": "Untertitelvorlauf", "PlaybackData": "Wiedergabeinformationen", @@ -1475,5 +1474,60 @@ "OptionRandom": "Zufällig", "TabNetworking": "Netzwerk", "VideoRange": "Videobereich", - "ButtonSplit": "Teilen" + "ButtonSplit": "Teilen", + "SelectAdminUsername": "Bitte einen Benutzernamen für das Administrator-Konto auswählen.", + "HeaderNavigation": "Navigation", + "CopyStreamURLError": "Beim Kopieren der URL ist ein Fehler aufgetreten.", + "MessageConfirmAppExit": "Wirklich verlassen?", + "LabelVideoResolution": "Videoauflösung:", + "LabelStreamType": "Streamtyp:", + "EnableFastImageFadeInHelp": "Aktiviere schnellere Einblendeanimation für geladene Bilder", + "EnableFastImageFadeIn": "Schnelle Bildeinblendung", + "LabelPlayerDimensions": "Playerabmessungen:", + "LabelDroppedFrames": "Verlorene Frames:", + "LabelCorruptedFrames": "Fehlerhafte Frames:", + "OptionForceRemoteSourceTranscoding": "Transkodieren von externen Medienquellen erzwingen (z.B. LiveTV)", + "AskAdminToCreateLibrary": "Bitten Sie einen Administrator, eine Bibliothek zu erstellen.", + "NoCreatedLibraries": "Sieht so aus als hättest du bis jetzt keine Bibliothek erstellt. {0}Möchtest du jetzt eine Bibliothek erstellen?{1}", + "AllowFfmpegThrottling": "Transkodierung drosseln", + "PlaybackErrorNoCompatibleStream": "Dieser Client ist nicht mit den Medien kompatibel und der Server sendet kein kompatibles Medienformat.", + "AllowFfmpegThrottlingHelp": "Wenn eine Transkodierung oder ein Remux weit genug über die aktuelle Abspielposition fortgeschritten ist, pausiere sie sodass weniger Ressourcen verbraucht werden. Dies ist am nützlichsten, wenn wenig geskippt wird. Bei Wiedergabeproblemen sollte diese Option deaktiviert werden.", + "ClientSettings": "Client Einstellungen", + "OnApplicationStartup": "Beim Starten der Applikation", + "EveryXHours": "Alle {0} Stunden", + "EveryHour": "Jede Stunde", + "EveryXMinutes": "Alle {0} Minuten", + "OnWakeFromSleep": "Beim Aufwachen aus \"Energie sparen\"", + "WeeklyAt": "{0} um {1}", + "DailyAt": "Täglich um {0}", + "LastSeen": "Zuletzt gesehen {0}", + "PersonRole": "als {0}", + "ListPaging": "{0}-{1} von {2}", + "WriteAccessRequired": "Jellyfin Server benötigt Schreibrechte auf diesem Ordner. Bitte prüfe die Schreibrechte und versuche es erneut.", + "PathNotFound": "Der Pfad konnte nicht gefunden werden. Bitte versichere dich dass der Pfad korrekt ist und versuche es erneut.", + "Track": "Track", + "Season": "Staffel", + "ReleaseGroup": "Veröffentlichungs-Gruppe", + "Person": "Person", + "OtherArtist": "Andere Künstler", + "Movie": "Film", + "Episode": "Episode", + "Artist": "Künstler", + "AlbumArtist": "Album Künstler", + "Album": "Album", + "BoxSet": "Box Set", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelLibraryPageSizeHelp": "Setzt die Anzahl der auf einer Seite angezeigten Objekte. Setze auf 0, um alle Elemente auf einer Seite anzuzeigen.", + "LabelLibraryPageSize": "Bibliothek Seiten Größe:", + "DeinterlaceMethodHelp": "Wähle die Deinterlacing-Methode zum Transkodieren von Inhalten im Zeilensprungverfahren (Interlace).", + "LabelDeinterlaceMethod": "Deinterlacing-Methode:", + "UnsupportedPlayback": "Jellyfin kann keine DRM-geschützten Inhalte entschlüsseln, aber es wird versucht, alle Inhalte unabhängig davon zu entschlüsseln, einschließlich geschützter Titel. Einige Dateien können aufgrund der Verschlüsselung oder anderer nicht unterstützter Funktionen, wie z.B. interaktive Titel, komplett schwarz erscheinen.", + "Filter": "Filter", + "New": "Neu", + "MessageUnauthorizedUser": "Sie sind im Moment nicht berechtigt, auf den Server zuzugreifen. Bitte kontaktieren Sie Ihren Server-Administrator für weitere Informationen.", + "HeaderFavoritePlaylists": "Lieblings-Wiedergabeliste", + "ButtonTogglePlaylist": "Wiedergabeliste", + "ButtonToggleContextMenu": "Mehr", + "ApiKeysCaption": "Liste der aktuell aktivierten API-Schlüssel" } diff --git a/src/strings/el.json b/src/strings/el.json index e189620c64..4804928364 100644 --- a/src/strings/el.json +++ b/src/strings/el.json @@ -10,7 +10,7 @@ "AdditionalNotificationServices": "Περιηγηθείτε στον κατάλογο plugin για να εγκαταστήσετε πρόσθετες υπηρεσίες ειδοποίησης.", "AirDate": "Ημερομηνία προβολής", "Aired": "Προβλήθηκε", - "Albums": "Άλμπουμ", + "Albums": "Άλμπουμς", "All": "Όλα", "AllChannels": "Όλα τα κανάλια", "AllComplexFormats": "Όλες οι σύνθετες μορφές (ASS, SSA, VOBSUB, PGS, SUB / IDX κ.λπ.)", @@ -19,7 +19,7 @@ "AllLibraries": "Όλες οι βιβλιοθήκες", "AllowRemoteAccess": "Να επιτρέπονται οι απομακρυσμένες συνδέσεις σε αυτόν το διακομιστή Jellyfin.", "AllowRemoteAccessHelp": "Εάν δεν επιλεχθεί, όλες οι απομακρυσμένες συνδέσεις θα αποκλειστούν.", - "AlwaysPlaySubtitles": "Πάντα αναπαραγωγή Υποτίτλων", + "AlwaysPlaySubtitles": "Παίξτε πάντα", "AlwaysPlaySubtitlesHelp": "Οι υπότιτλοι που ταιριάζουν με τις προτιμήσεις γλώσσας θα φορτωθούν ανεξάρτητα από τη γλώσσα του ήχου.", "AnyLanguage": "Οποιαδήποτε γλώσσα", "Anytime": "Οποτεδήποτε", @@ -28,7 +28,7 @@ "Artists": "Καλλιτέχνες", "AsManyAsPossible": "Οσο το δυνατον περισσοτερα", "Ascending": "Αύξουσα", - "AspectRatio": "Αρχικός λόγος διαστάσεων", + "AspectRatio": "Αναλογία απεικόνισης", "AttributeNew": "Νέο", "Audio": "Ήχος", "Auto": "Αυτόματο", @@ -166,8 +166,7 @@ "DirectStreamHelp2": "Η άμεση ροή ενός αρχείου χρησιμοποιεί ελάχιστη ισχύ επεξεργασίας χωρίς απώλεια της ποιότητας του βίντεο.", "DirectStreaming": "Απευθείας Αναμετάδοση", "Director": "Σκηνοθέτης", - "DirectorValue": "Σκηνοθέτης: {0}", - "DirectorsValue": "Σκηνοθέτες: {0}", + "Directors": "Σκηνοθέτες", "Disabled": "Απενεργοποιημένο", "Disc": "Δίσκος", "Disconnect": "Αποσύνδεση", @@ -233,9 +232,8 @@ "Friday": "Παρασκευή", "Fullscreen": "ΠΛΗΡΗΣ ΟΘΟΝΗ", "General": "Γενικά", - "GenreValue": "Είδος: {0}", + "Genre": "Είδος", "Genres": "Είδη", - "GenresValue": "Είδη: {0}", "GroupBySeries": "Ομαδοποίηση κατά σειρά", "GroupVersions": "Ομαδικές εκδόσεις", "GuestStar": "Φιλική Συμμετοχή", @@ -452,7 +450,7 @@ "LabelAppNameExample": "Παράδειγμα: Sickbeard, NzbDrone", "LabelArtists": "Καλλιτέχνες:", "LabelArtistsHelp": "Ξεχωρίστε πολλαπλά χρησιμοποιώντας;", - "LabelAudio": "Ήχος:", + "LabelAudio": "Ήχος", "LabelAudioLanguagePreference": "Προτιμώμενη γλώσσα ήχου:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Αυτόματη ανανέωση μεταδεδομένων από το internet:", "LabelBirthDate": "Ημερομηνία Γενεθλίων:", @@ -666,7 +664,7 @@ "LabelStopWhenPossible": "Διακοπή όταν είναι δυνατόν:", "LabelSubtitleFormatHelp": "Παράδειγμα: srt", "LabelSubtitlePlaybackMode": "Λειτουργία υποτίτλων:", - "LabelSubtitles": "Υπότιτλοι:", + "LabelSubtitles": "Υπότιτλοι", "LabelSupportedMediaTypes": "Υποστηριζόμενοι τύποι μέσων:", "LabelTVHomeScreen": "Αρχική οθόνη λειτουργίας τηλεόρασης:", "LabelTag": "Ετικέτα:", @@ -696,7 +694,7 @@ "LabelVersion": "Έκδοση:", "LabelVersionInstalled": "{0} εγκαταστήθηκε", "LabelVersionNumber": "Έκδοση {0}", - "LabelVideo": "Βίντεο:", + "LabelVideo": "Βίντεο", "LabelXDlnaCapHelp": "Καθορίζει το περιεχόμενο του στοιχείου X_DLNACAP στο urn:schemas-dlna-org:device-1-0 namespace.", "LabelXDlnaDocHelp": "Καθορίζει το περιεχόμενο του στοιχείου X_DLNACAP στο urn:schemas-dlna-org:device-1-0 namespace.", "LabelYear": "Έτος:", @@ -868,7 +866,6 @@ "OptionEnableAccessFromAllDevices": "Πρόσβαση από όλες τις συσκευές", "OptionEnableAccessToAllChannels": "Ενεργοποιήστε την πρόσβαση σε όλα τα κανάλια", "OptionEnableAccessToAllLibraries": "Πρόσβαση σε όλες τις Βιβλιοθήκες", - "OptionEnableAutomaticServerUpdates": "Ενεργοποίηση αυτόματων ενημερώσεων διακομιστή", "OptionEnableExternalContentInSuggestionsHelp": "Να επιτρέπεται η συμπερίληψη internet trailers και προγράμματα live tv στο προτεινόμενο περιεχόμενο.", "OptionEnableM2tsMode": "Ενεργοποίηση λειτουργίας M2ts", "OptionEnded": "Τέλος", @@ -1196,7 +1193,7 @@ "HeaderFavoriteEpisodes": "Αγαπημένα Επεισόδια", "HeaderFavoriteShows": "Αγαπημένες Σειρές", "AllowMediaConversion": "Να επιτρέπονται οι μετατροπές μέσων", - "H264EncodingPresetHelp": "Επιλέξτε γρηγορότερη επιλογή για να βελτιώσετε την επίδοση, ή πιο αργή για να βελτιώσετε την ποιότητα.", + "EncoderPresetHelp": "Επιλέξτε γρηγορότερη επιλογή για να βελτιώσετε την επίδοση, ή πιο αργή για να βελτιώσετε την ποιότητα.", "ErrorAddingXmlTvFile": "Υπήρξε σφάλμα κατά την πρόσβαση του αρχείου XmlTV. Βεβαιωθείτε ότι το αρχείο υπάρχει και ξαναπροσπαθήστε.", "ErrorAddingTunerDevice": "Υπήρξε σφάλμα κατά την προσθήκη του δέκτη. Βεβαιωθείτε ότι είναι προσβάσιμη και ξαναπροσπαθήστε.", "EnableStreamLoopingHelp": "Ενεργοποιήστε το αν τα live stream περιέχουν μόνο λίγα δευτερόλεπτα δεδομένων και πρέπει να ζητούνται συνεχώς. Η ενεργοποίηση αυτής της επιλογής όταν δεν είναι απαραίτητη μπορεί να προκαλέσει προβλήματα.", @@ -1227,6 +1224,14 @@ "LabelServerName": "Όνομα Διακομιστή:", "ButtonAddImage": "Προσθήκη Εικόνας", "BoxRear": "Κουτί(πίσω)", - "BookLibraryHelp": "Ήχος και βιβλία υποστηρίζονται.Ελέγξτε τον {0}ονομαστικό οδηγό βιβλίων{1}.", - "AuthProviderHelp": "Επιλέξτε ένα Πάροχο Επαλήθευσης για να επαληθεύσετε το κωδικό αυτού του χρήστη." + "BookLibraryHelp": "Υποστήριξη ήχου και βιβλίων κειμένου. Εξετάστε τον {0}οδηγό ονομάτων βιβλίου{1}.", + "AuthProviderHelp": "Επιλέξτε ένα Πάροχο Επαλήθευσης για να επαληθεύσετε το κωδικό αυτού του χρήστη.", + "AllowFfmpegThrottling": "Επιτάχυνση Διακωδικοποιησής", + "AlbumArtist": "Άλμπουμ Καλλιτέχνη", + "Album": "Άλμπουμ", + "BoxSet": "Σετ Κουτιού", + "AskAdminToCreateLibrary": "Ζητήστε από έναν διαχειριστή να δημιουργήσει μια βιβλιοθήκη.", + "Artist": "Καλλιτέχνης", + "AllowedRemoteAddressesHelp": "Λίστα διαχωρισμένων διευθύνσεων IP ή καταχωρίσεων IP / netmask για δίκτυα που θα επιτρέπεται η σύνδεση εξ αποστάσεως. Εάν αφεθεί κενό, όλες οι απομακρυσμένες διευθύνσεις θα επιτρέπονται.", + "AllowFfmpegThrottlingHelp": "Όταν ένας διακωδικοποιητής ή remux φτάσει αρκετά μπροστά από την τρέχουσα θέση αναπαραγωγής, διακόψτε τη διαδικασία ώστε να καταναλώσει λιγότερους πόρους. Αυτό είναι πιο χρήσιμο όταν παρακολουθείτε χωρίς να αναζητάτε συχνά. Απενεργοποιήστε το εάν αντιμετωπίζετε προβλήματα αναπαραγωγής." } diff --git a/src/strings/en-gb.json b/src/strings/en-gb.json index 62658cb087..b111dfa24a 100644 --- a/src/strings/en-gb.json +++ b/src/strings/en-gb.json @@ -75,15 +75,15 @@ "AllowRemoteAccess": "Allow remote connections to this Jellyfin Server.", "AllowRemoteAccessHelp": "If unchecked, all remote connections will be blocked.", "AllowedRemoteAddressesHelp": "Comma separated list of IP addresses or IP/netmask entries for networks that will be allowed to connect remotely. If left blank, all remote addresses will be allowed.", - "AlwaysPlaySubtitles": "Always play subtitles", + "AlwaysPlaySubtitles": "Always Play", "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnyLanguage": "Any language", + "AnyLanguage": "Any Language", "Anytime": "Anytime", "AroundTime": "Around {0}", "Art": "Art", "AsManyAsPossible": "As many as possible", "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", + "AspectRatio": "Aspect Ratio", "AttributeNew": "New", "Audio": "Audio", "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password.", @@ -100,7 +100,7 @@ "Box": "Box", "BoxRear": "Box (rear)", "Browse": "Browse", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitle format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB/IDX, etc) and certain ASS/SSA subtitles.", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when transcoding videos. Avoiding this will greatly improve performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB, IDX) and certain ASS or SSA subtitles.", "ButtonAdd": "Add", "ButtonAddMediaLibrary": "Add Media Library", "ButtonAddScheduledTaskTrigger": "Add Trigger", @@ -223,8 +223,7 @@ "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}", + "Directors": "Directors", "Disabled": "Disabled", "Disc": "Disc", "Disconnect": "Disconnect", @@ -234,7 +233,7 @@ "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 the server configuration.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", + "DisplayModeHelp": "Select the layout style you want for the interface.", "DoNotRecord": "Do not record", "Down": "Down", "Download": "Download", @@ -299,8 +298,7 @@ "Friday": "Friday", "Fullscreen": "Full screen", "General": "General", - "GenreValue": "Genre: {0}", - "GenresValue": "Genres: {0}", + "Genre": "Genre", "GroupBySeries": "Group by series", "GroupVersions": "Group versions", "GuestStar": "Guest star", @@ -308,9 +306,9 @@ "GuideProviderLogin": "Login", "GuideProviderSelectListings": "Select Listings", "H264CrfHelp": "The Constant Rate Factor (CRF) is the default quality setting for the x264 encoder. You can set the values between 0 and 51, where lower values would result in better quality (at the expense of higher file sizes). Sane values are between 18 and 28. The default for x264 is 23, so you can use this as a starting point.", - "H264EncodingPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.", + "EncoderPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.", "HandledByProxy": "Handled by reverse proxy", - "HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to Auto.", + "HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to None.", "HeaderAccessSchedule": "Access Schedule", "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.", "HeaderActiveDevices": "Active Devices", @@ -387,6 +385,7 @@ "HeaderFavoriteArtists": "Favourite Artists", "HeaderFavoriteSongs": "Favourite Songs", "HeaderFavoriteVideos": "Favourite Videos", + "HeaderFavoritePlaylists": "Favourite Playlists", "HeaderFeatureAccess": "Feature Access", "HeaderFeatures": "Features", "HeaderFetchImages": "Fetch Images:", @@ -529,6 +528,8 @@ "Smart": "Smart", "SimultaneousConnectionLimitHelp": "The maximum number of allowed simultaneous streams. Enter 0 for no limit.", "Shuffle": "Shuffle", + "New": "New", + "Filter": "Filter", "ShowYear": "Show year", "ShowIndicatorsFor": "Show indicators for:", "ShowAdvancedSettings": "Show advanced settings", @@ -565,7 +566,7 @@ "ReplaceExistingImages": "Replace existing images", "ReplaceAllMetadata": "Replace all metadata", "RepeatOne": "Repeat one", - "RepeatMode": "Repeat mode", + "RepeatMode": "Repeat Mode", "RepeatEpisodes": "Repeat episodes", "RepeatAll": "Repeat all", "Repeat": "Repeat", @@ -619,9 +620,9 @@ "PasswordResetComplete": "The password has been reset.", "PasswordMatchError": "Password and password confirmation must match.", "ParentalRating": "Parental rating", - "PackageInstallFailed": "{0} installation failed.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallCancelled": "{0} installation cancelled.", + "PackageInstallFailed": "{0} (version {1}) installation failed.", + "PackageInstallCompleted": "{0} (version {1}) installation completed.", + "PackageInstallCancelled": "{0} (version {1}) installation cancelled.", "OriginalAirDateValue": "Original air date: {0}", "OptionWeekly": "Weekly", "OptionWeekends": "Weekends", @@ -692,12 +693,12 @@ "OptionAlbumArtist": "Album Artist", "OptionAlbum": "Album", "Option3D": "3D", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB, etc)", + "OnlyImageFormats": "Only Image Formats (VOBSUB, PGS, SUB)", "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", "Normal": "Normal", "None": "None", "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", - "NoSubtitles": "No subtitles", + "NoSubtitles": "None", "NoPluginConfigurationMessage": "This plugin has no settings to configure.", "NoNextUpItemsMessage": "None found. Start watching your shows!", "No": "No", @@ -808,7 +809,7 @@ "LabelTag": "Tag:", "LabelTVHomeScreen": "TV mode home screen:", "LabelSupportedMediaTypes": "Supported Media Types:", - "LabelSubtitles": "Subtitles:", + "LabelSubtitles": "Subtitles", "LabelSubtitlePlaybackMode": "Subtitle mode:", "LabelSubtitleFormatHelp": "Example: srt", "LabelSubtitleDownloaders": "Subtitle downloaders:", @@ -836,6 +837,8 @@ "LabelSecureConnectionsMode": "Secure connection mode:", "LabelSeasonNumber": "Season number:", "LabelScreensaver": "Screensaver:", + "EnableFastImageFadeIn": "Fast image fade-in", + "EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images", "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.", "LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.", "LabelRuntimeMinutes": "Run time (minutes):", @@ -871,7 +874,7 @@ "MessageConfirmProfileDeletion": "Are you sure you wish to delete this profile?", "LaunchWebAppOnStartup": "Launch the web interface when starting the server", "LabelYourFirstName": "Your first name:", - "OnlyForcedSubtitles": "Only forced subtitles", + "OnlyForcedSubtitles": "Only Forced", "Off": "Off", "NumLocationsValue": "{0} folders", "Name": "Name", @@ -1024,13 +1027,13 @@ "LabelKidsCategories": "Children's categories:", "LabelInNetworkSignInWithEasyPasswordHelp": "Use the easy pin code to sign in to clients within your local network. Your regular password will only be needed away from home. If the pin code is left blank, you won't need a password within your home network.", "LabelInNetworkSignInWithEasyPassword": "Enable in-network sign in with my easy pin code", - "LabelHardwareAccelerationTypeHelp": "This is an experimental feature only available on supported systems.", + "LabelHardwareAccelerationTypeHelp": "Hardware acceleration requires additional configuration.", "LabelEnableHardwareDecodingFor": "Enable hardware decoding for:", "LabelEnableDlnaServerHelp": "Allows UPnP devices on your network to browse and play content.", "LabelEnableDlnaDebugLoggingHelp": "Create large log files and should only be used as needed for troubleshooting purposes.", "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determines the duration in seconds between SSDP searches performed by Jellyfin.", - "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models.", - "InstallingPackage": "Installing {0}", + "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models. Changes will not apply until after a server restart.", + "InstallingPackage": "Installing {0} (version {1})", "ImportMissingEpisodesHelp": "If enabled, information about missing episodes will be imported into your Jellyfin database and displayed within seasons and series. This may cause significantly longer library scans.", "HeaderSubtitleAppearance": "Subtitle Appearance", "LabelProtocol": "Protocol:", @@ -1105,7 +1108,7 @@ "LabelHomeScreenSectionValue": "Home screen section {0}:", "LabelHomeNetworkQuality": "Home network quality:", "LabelHardwareAccelerationType": "Hardware acceleration:", - "LabelH264EncodingPreset": "H264 encoding preset:", + "LabelEncoderPreset": "H264 and H265 encoding preset:", "LabelH264Crf": "H264 encoding CRF:", "LabelGroupMoviesIntoCollectionsHelp": "When displaying movie lists, movies belonging to a collection will be displayed as one grouped item.", "LabelGroupMoviesIntoCollections": "Group movies into collections", @@ -1167,7 +1170,7 @@ "LabelAudioChannels": "Audio channels:", "LabelAudioBitrate": "Audio bitrate:", "LabelAudioBitDepth": "Audio bit depth:", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelArtistsHelp": "Separate multiple using ;", "LabelArtists": "Artists:", "LabelAppName": "App name", @@ -1303,7 +1306,6 @@ "OptionEnableM2tsModeHelp": "Enable m2ts mode when encoding to mpegts.", "OptionEnableM2tsMode": "Enable M2ts mode", "OptionEnableExternalContentInSuggestions": "Enable external content in suggestions", - "OptionEnableAutomaticServerUpdates": "Enable automatic server updates", "OptionEnableAccessToAllLibraries": "Enable access to all libraries", "OptionEnableAccessToAllChannels": "Enable access to all channels", "OptionEnableAccessFromAllDevices": "Enable access from all devices", @@ -1337,7 +1339,7 @@ "MediaInfoSoftware": "Software", "ValueOneSeries": "1 series", "MediaInfoBitrate": "Bitrate", - "LabelVideo": "Video:", + "LabelVideo": "Video", "LabelPrevious": "Previous", "LabelPostProcessorArgumentsHelp": "Use {path} as the path to the recording file.", "LabelKodiMetadataEnableExtraThumbs": "Copy extrafanart to extrathumbs field", @@ -1461,5 +1463,55 @@ "ButtonAddImage": "Add Image", "OptionRandom": "Random", "SelectAdminUsername": "Please select a username for the admin account.", - "ButtonSplit": "Split" + "ButtonSplit": "Split", + "HeaderNavigation": "Navigation", + "OptionForceRemoteSourceTranscoding": "Force transcoding of remote media sources (like LiveTV)", + "MessageConfirmAppExit": "Do you want to exit?", + "LabelVideoResolution": "Video resolution:", + "LabelStreamType": "Stream type:", + "LabelPlayerDimensions": "Player dimensions:", + "LabelDroppedFrames": "Dropped frames:", + "LabelCorruptedFrames": "Corrupted frames:", + "CopyStreamURLError": "There was an error copying the URL.", + "NoCreatedLibraries": "Seems like you haven't created any libraries yet. {0}Would you like to create one now?{1}", + "AskAdminToCreateLibrary": "Ask an administrator to create a library.", + "PlaybackErrorNoCompatibleStream": "This client isn't compatible with the media and the server isn't sending a compatible media format.", + "AllowFfmpegThrottlingHelp": "When a transcode or remux gets far enough ahead from the current playback position, pause the process so it will consume less resources. This is most useful when watching without seeking often. Turn this off if you experience playback issues.", + "AllowFfmpegThrottling": "Throttle Transcodes", + "OnApplicationStartup": "On application startup", + "EveryXHours": "Every {0} hours", + "EveryHour": "Every hour", + "EveryXMinutes": "Every {0} minutes", + "OnWakeFromSleep": "On wake from sleep", + "WeeklyAt": "{0}s at {1}", + "DailyAt": "Daily at {0}", + "LastSeen": "Last seen {0}", + "PersonRole": "as {0}", + "ListPaging": "{0}-{1} of {2}", + "WriteAccessRequired": "Jellyfin Server requires write access to this folder. Please ensure write access and try again.", + "PathNotFound": "The path could not be found. Please ensure the path is valid and try again.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Track", + "Season": "Season", + "ReleaseGroup": "Release Group", + "PreferEmbeddedEpisodeInfosOverFileNames": "Prefer embedded episode information over filenames", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.", + "Person": "Person", + "OtherArtist": "Other Artist", + "Movie": "Movie", + "LabelLibraryPageSizeHelp": "Sets the amount of items to show on a library page. Set to 0 in order to disable paging.", + "LabelLibraryPageSize": "Library page size:", + "LabelDeinterlaceMethod": "Deinterlacing method:", + "Episode": "Episode", + "DeinterlaceMethodHelp": "Select the deinterlacing method to use when transcoding interlaced content.", + "ClientSettings": "Client Settings", + "BoxSet": "Box Set", + "Artist": "Artist", + "AlbumArtist": "Album Artist", + "Album": "Album", + "UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles.", + "MessageUnauthorizedUser": "You are not authorized to access the server at this time. Please contact your server administrator for more information.", + "ButtonTogglePlaylist": "Playlist", + "ButtonToggleContextMenu": "More" } diff --git a/src/strings/en-us.json b/src/strings/en-us.json index 9c48b3edfb..2f75f2d1c7 100644 --- a/src/strings/en-us.json +++ b/src/strings/en-us.json @@ -11,11 +11,13 @@ "AdditionalNotificationServices": "Browse the plugin catalog to install additional notification services.", "AirDate": "Air date", "Aired": "Aired", + "Album": "Album", + "AlbumArtist": "Album Artist", "Albums": "Albums", "Alerts": "Alerts", "All": "All", "AllChannels": "All channels", - "AllComplexFormats": "All complex formats (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "All Complex Formats (ASS, SSA, VOBSUB, PGS, SUB, IDX, …)", "AllEpisodes": "All episodes", "AllLanguages": "All languages", "AllLibraries": "All libraries", @@ -23,20 +25,24 @@ "AllowMediaConversion": "Allow media conversion", "AllowMediaConversionHelp": "Grant or deny access to the convert media feature.", "AllowOnTheFlySubtitleExtraction": "Allow subtitle extraction on the fly", - "AllowOnTheFlySubtitleExtractionHelp": "Embedded subtitles can be extracted from videos and delivered to clients in plain text in order to help prevent video transcoding. On some systems this can take a long time and cause video playback to stall during the extraction process. Disable this to have embedded subtitles burned in with video transcoding when they are not natively supported by the client device.", + "AllowOnTheFlySubtitleExtractionHelp": "Embedded subtitles can be extracted from videos and delivered to clients in plain text, in order to help prevent video transcoding. On some systems this can take a long time and cause video playback to stall during the extraction process. Disable this to have embedded subtitles burned in with video transcoding when they are not natively supported by the client device.", + "AllowFfmpegThrottling": "Throttle Transcodes", + "AllowFfmpegThrottlingHelp": "When a transcode or remux gets far enough ahead from the current playback position, pause the process so it will consume less resources. This is most useful when watching without seeking often. Turn this off if you experience playback issues.", "AllowRemoteAccess": "Allow remote connections to this Jellyfin Server.", "AllowRemoteAccessHelp": "If unchecked, all remote connections will be blocked.", "AllowedRemoteAddressesHelp": "Comma separated list of IP addresses or IP/netmask entries for networks that will be allowed to connect remotely. If left blank, all remote addresses will be allowed.", - "AlwaysPlaySubtitles": "Always play subtitles", + "AlwaysPlaySubtitles": "Always Play", "AlwaysPlaySubtitlesHelp": "Subtitles matching the language preference will be loaded regardless of the audio language.", - "AnyLanguage": "Any language", + "AnyLanguage": "Any Language", "Anytime": "Anytime", "AroundTime": "Around {0}", "Art": "Art", + "Artist": "Artist", "Artists": "Artists", "AsManyAsPossible": "As many as possible", "Ascending": "Ascending", - "AspectRatio": "Aspect ratio", + "AskAdminToCreateLibrary": "Ask an administrator to create a library.", + "AspectRatio": "Aspect Ratio", "AttributeNew": "New", "Audio": "Audio", "AuthProviderHelp": "Select an Authentication Provider to be used to authenticate this user's password.", @@ -52,10 +58,11 @@ "BookLibraryHelp": "Audio and text books are supported. Review the {0}book naming guide{1}.", "Books": "Books", "Box": "Box", + "BoxSet": "Box Set", "BoxRear": "Box (rear)", "Browse": "Browse", "BrowsePluginCatalogMessage": "Browse our plugin catalog to view available plugins.", - "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when converting video depending on the subtitle format. Avoiding burning in subtitles will improve server performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB/IDX, etc) and certain ASS/SSA subtitles.", + "BurnSubtitlesHelp": "Determines if the server should burn in subtitles when transcoding videos. Avoiding this will greatly improve performance. Select Auto to burn image based formats (VOBSUB, PGS, SUB, IDX, …) and certain ASS or SSA subtitles.", "ButtonAdd": "Add", "ButtonAddImage": "Add Image", "ButtonAddMediaLibrary": "Add Media Library", @@ -130,6 +137,8 @@ "ButtonSplit": "Split", "ButtonSubmit": "Submit", "ButtonSubtitles": "Subtitles", + "ButtonToggleContextMenu": "More", + "ButtonTogglePlaylist": "Playlist", "ButtonTrailer": "Trailer", "ButtonUninstall": "Uninstall", "ButtonUp": "Up", @@ -144,6 +153,7 @@ "ChannelNumber": "Channel number", "Channels": "Channels", "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.", + "ClientSettings": "Client Settings", "Collections": "Collections", "ColorPrimaries": "Color primaries", "ColorSpace": "Color space", @@ -161,6 +171,7 @@ "Continuing": "Continuing", "CopyStreamURL": "Copy Stream URL", "CopyStreamURLSuccess": "URL copied successfully.", + "CopyStreamURLError": "There was an error copying the URL.", "CriticRating": "Critic rating", "CustomDlnaProfilesHelp": "Create a custom profile to target a new device or override a system profile.", "DateAdded": "Date added", @@ -170,6 +181,7 @@ "DefaultErrorMessage": "There was an error processing the request. Please try again later.", "DefaultMetadataLangaugeDescription": "These are your defaults and can be customized on a per-library basis.", "DefaultSubtitlesHelp": "Subtitles are loaded based on the default and forced flags in the embedded metadata. Language preferences are considered when multiple options are available.", + "DeinterlaceMethodHelp": "Select the deinterlacing method to use when transcoding interlaced content.", "Delete": "Delete", "DeleteDeviceConfirmation": "Are you sure you wish to delete this device? It will reappear the next time a user signs in with it.", "DeleteImage": "Delete Image", @@ -187,8 +199,7 @@ "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}", + "Directors": "Directors", "Disabled": "Disabled", "Disc": "Disc", "Disconnect": "Disconnect", @@ -198,7 +209,7 @@ "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 the server configuration.", - "DisplayModeHelp": "Select the type of screen you're running Jellyfin on.", + "DisplayModeHelp": "Select the layout style you want for the interface.", "DoNotRecord": "Do not record", "Down": "Down", "Download": "Download", @@ -230,6 +241,7 @@ "EnableThemeVideosHelp": "Play theme videos in the background while browsing the library.", "Ended": "Ended", "EndsAtValue": "Ends at {0}", + "Episode": "Episode", "Episodes": "Episodes", "ErrorAddingListingsToSchedulesDirect": "There was an error adding the lineup to your Schedules Direct account. Schedules Direct only allows a limited number of lineups per account. You may need to log into the Schedules Direct website and remove others listings from your account before proceeding.", "ErrorAddingMediaPathToVirtualFolder": "There was an error adding the media path. Please ensure the path is valid and the Jellyfin Server process has access to that location.", @@ -267,9 +279,8 @@ "Friday": "Friday", "Fullscreen": "Full screen", "General": "General", - "GenreValue": "Genre: {0}", + "Genre": "Genre", "Genres": "Genres", - "GenresValue": "Genres: {0}", "GroupBySeries": "Group by series", "GroupVersions": "Group versions", "GuestStar": "Guest star", @@ -277,10 +288,10 @@ "GuideProviderLogin": "Login", "GuideProviderSelectListings": "Select Listings", "H264CrfHelp": "The Constant Rate Factor (CRF) is the default quality setting for the x264 encoder. You can set the values between 0 and 51, where lower values would result in better quality (at the expense of higher file sizes). Sane values are between 18 and 28. The default for x264 is 23, so you can use this as a starting point.", - "H264EncodingPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.", + "EncoderPresetHelp": "Choose a faster value to improve performance, or a slower value to improve quality.", "HDPrograms": "HD programs", "HandledByProxy": "Handled by reverse proxy", - "HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to Auto.", + "HardwareAccelerationWarning": "Enabling hardware acceleration may cause instability in some environments. Ensure that your operating system and video drivers are fully up to date. If you have difficulty playing video after enabling this, you'll need to change the setting back to None.", "HeaderAccessSchedule": "Access Schedule", "HeaderAccessScheduleHelp": "Create an access schedule to limit access to certain hours.", "HeaderActiveDevices": "Active Devices", @@ -300,6 +311,7 @@ "HeaderApiKey": "API Key", "HeaderApiKeys": "API Keys", "HeaderApiKeysHelp": "External applications are required to have an API key in order to communicate with Jellyfin Server. Keys are issued by logging in with a Jellyfin account, or by manually granting the application a key.", + "ApiKeysCaption": "List of the currently enabled API keys", "HeaderApp": "App", "HeaderAppearsOn": "Appears On", "HeaderAudioBooks": "Audio Books", @@ -359,6 +371,7 @@ "HeaderFavoriteArtists": "Favorite Artists", "HeaderFavoriteSongs": "Favorite Songs", "HeaderFavoriteVideos": "Favorite Videos", + "HeaderFavoritePlaylists": "Favorite Playlists", "HeaderFeatureAccess": "Feature Access", "HeaderFeatures": "Features", "HeaderFetchImages": "Fetch Images:", @@ -408,6 +421,7 @@ "HeaderMyDevice": "My Device", "HeaderMyMedia": "My Media", "HeaderMyMediaSmall": "My Media (small)", + "HeaderNavigation": "Navigation", "HeaderNewApiKey": "New API Key", "HeaderNewDevices": "New Devices", "HeaderNextEpisodePlayingInValue": "Next Episode Playing in {0}", @@ -512,7 +526,7 @@ "Images": "Images", "ImportFavoriteChannelsHelp": "If enabled, only channels that are marked as favorite on the tuner device will be imported.", "ImportMissingEpisodesHelp": "If enabled, information about missing episodes will be imported into your Jellyfin database and displayed within seasons and series. This may cause significantly longer library scans.", - "InstallingPackage": "Installing {0}", + "InstallingPackage": "Installing {0} (version {1})", "InstantMix": "Instant mix", "ItemCount": "{0} items", "Items": "Items", @@ -545,7 +559,7 @@ "LabelAppNameExample": "Example: Sickbeard, Sonarr", "LabelArtists": "Artists:", "LabelArtistsHelp": "Separate multiple using ;", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelAudioBitDepth": "Audio bit depth:", "LabelAudioBitrate": "Audio bitrate:", "LabelAudioChannels": "Audio channels:", @@ -573,6 +587,7 @@ "LabelCollection": "Collection:", "LabelCommunityRating": "Community rating:", "LabelContentType": "Content type:", + "LabelCorruptedFrames": "Corrupted frames:", "LabelCountry": "Country:", "LabelCriticRating": "Critic rating:", "LabelCurrentPassword": "Current password:", @@ -593,6 +608,7 @@ "LabelDefaultScreen": "Default screen:", "LabelDefaultUser": "Default user:", "LabelDefaultUserHelp": "Determines which user library should be displayed on connected devices. This can be overridden for each device using profiles.", + "LabelDeinterlaceMethod": "Deinterlacing method:", "LabelDeviceDescription": "Device description", "LabelDidlMode": "DIDL mode:", "LabelDiscNumber": "Disc number:", @@ -607,13 +623,14 @@ "LabelDownMixAudioScaleHelp": "Boost audio when downmixing. A value of one will preserve the original volume.", "LabelDownloadLanguages": "Download languages:", "LabelDropImageHere": "Drop image here, or click to browse.", + "LabelDroppedFrames": "Dropped frames:", "LabelDropShadow": "Drop shadow:", "LabelDynamicExternalId": "{0} Id:", "LabelEasyPinCode": "Easy pin code:", "LabelEmbedAlbumArtDidl": "Embed album art in Didl", "LabelEmbedAlbumArtDidlHelp": "Some devices prefer this method for obtaining album art. Others may fail to play with this option enabled.", "LabelEnableAutomaticPortMap": "Enable automatic port mapping", - "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models.", + "LabelEnableAutomaticPortMapHelp": "Attempt to automatically map the public port to the local port via UPnP. This may not work with some router models. Changes will not apply until after a server restart.", "LabelEnableBlastAliveMessages": "Blast alive messages", "LabelEnableBlastAliveMessagesHelp": "Enable this if the server is not detected reliably by other UPnP devices on your network.", "LabelEnableDlnaClientDiscoveryInterval": "Client discovery interval (seconds)", @@ -649,9 +666,9 @@ "LabelGroupMoviesIntoCollections": "Group movies into collections", "LabelGroupMoviesIntoCollectionsHelp": "When displaying movie lists, movies belonging to a collection will be displayed as one grouped item.", "LabelH264Crf": "H264 encoding CRF:", - "LabelH264EncodingPreset": "H264 encoding preset:", + "LabelEncoderPreset": "H264 and H265 encoding preset:", "LabelHardwareAccelerationType": "Hardware acceleration:", - "LabelHardwareAccelerationTypeHelp": "This is an experimental feature only available on supported systems.", + "LabelHardwareAccelerationTypeHelp": "Hardware acceleration requires additional configuration.", "LabelHomeNetworkQuality": "Home network quality:", "LabelHomeScreenSectionValue": "Home screen section {0}:", "LabelHttpsPort": "Local HTTPS port number:", @@ -681,6 +698,8 @@ "LabelKodiMetadataUserHelp": "Save watch data to NFO files for other applications to utilize.", "LabelLanNetworks": "LAN networks:", "LabelLanguage": "Language:", + "LabelLibraryPageSize": "Library page size:", + "LabelLibraryPageSizeHelp": "Sets the amount of items to show on a library page. Set to 0 in order to disable paging.", "LabelLineup": "Lineup:", "LabelLocalHttpServerPortNumber": "Local HTTP port number:", "LabelLocalHttpServerPortNumberHelp": "The TCP port number that Jellyfin's HTTP server should bind to.", @@ -755,6 +774,7 @@ "LabelPlaceOfBirth": "Place of birth:", "LabelPlayDefaultAudioTrack": "Play default audio track regardless of language", "LabelPlayer": "Player:", + "LabelPlayerDimensions": "Player dimensions:", "LabelPlaylist": "Playlist:", "LabelPlayMethod": "Play method:", "LabelPleaseRestart": "Changes will take effect after manually reloading the web client.", @@ -792,6 +812,8 @@ "LabelSaveLocalMetadataHelp": "Saving artwork into media folders will put them in a place where they can be easily edited.", "LabelScheduledTaskLastRan": "Last ran {0}, taking {1}.", "LabelScreensaver": "Screensaver:", + "EnableFastImageFadeIn": "Fast image fade-in", + "EnableFastImageFadeInHelp": "Enable faster fade-in animation for loaded images", "LabelSeasonNumber": "Season number:", "LabelSecureConnectionsMode": "Secure connection mode:", "LabelSelectFolderGroups": "Automatically group content from the following folders into views such as Movies, Music and TV:", @@ -826,10 +848,11 @@ "LabelStatus": "Status:", "LabelStopWhenPossible": "Stop when possible:", "LabelStopping": "Stopping", + "LabelStreamType": "Stream type:", "LabelSubtitleDownloaders": "Subtitle downloaders:", "LabelSubtitleFormatHelp": "Example: srt", "LabelSubtitlePlaybackMode": "Subtitle mode:", - "LabelSubtitles": "Subtitles:", + "LabelSubtitles": "Subtitles", "LabelSupportedMediaTypes": "Supported Media Types:", "LabelTVHomeScreen": "TV mode home screen:", "LabelTag": "Tag:", @@ -875,9 +898,10 @@ "DashboardServerName": "Server: {0}", "DashboardOperatingSystem": "Operating System: {0}", "DashboardArchitecture": "Architecture: {0}", - "LabelVideo": "Video:", + "LabelVideo": "Video", "LabelVideoBitrate": "Video bitrate:", "LabelVideoCodec": "Video codec:", + "LabelVideoResolution": "Video resolution:", "LabelWeb": "Web:", "LabelXDlnaCap": "X-DLNA cap:", "LabelXDlnaCapHelp": "Determines the content of the X_DLNACAP element in the urn:schemas-dlna-org:device-1-0 namespace.", @@ -945,6 +969,7 @@ "MessageAlreadyInstalled": "This version is already installed.", "MessageAreYouSureDeleteSubtitles": "Are you sure you wish to delete this subtitle file?", "MessageAreYouSureYouWishToRemoveMediaFolder": "Are you sure you wish to remove this media folder?", + "MessageConfirmAppExit": "Do you want to exit?", "MessageConfirmDeleteGuideProvider": "Are you sure you wish to delete this guide provider?", "MessageConfirmDeleteTunerDevice": "Are you sure you wish to delete this device?", "MessageConfirmProfileDeletion": "Are you sure you wish to delete this profile?", @@ -969,6 +994,7 @@ "MessageInstallPluginFromApp": "This plugin must be installed from within the app you intend to use it in.", "MessageInvalidForgotPasswordPin": "An invalid or expired pin code was entered. Please try again.", "MessageInvalidUser": "Invalid username or password. Please try again.", + "MessageUnauthorizedUser": "You are not authorized to access the server at this time. Please contact your server administrator for more information.", "MessageItemSaved": "Item saved.", "MessageItemsAdded": "Items added.", "MessageLeaveEmptyToInherit": "Leave empty to inherit settings from a parent item or the global default value.", @@ -1004,6 +1030,7 @@ "MoveLeft": "Move left", "MoveRight": "Move right", "MovieLibraryHelp": "Review the {0}movie naming guide{1}.", + "Movie": "Movie", "Movies": "Movies", "MusicAlbum": "Music Album", "MusicArtist": "Music Artist", @@ -1022,26 +1049,28 @@ "Next": "Next", "NextUp": "Next Up", "No": "No", + "NoCreatedLibraries": "Seems like you haven't created any libraries yet. {0}Would you like to create one now?{1}", "NoNewDevicesFound": "No new devices found. To add a new tuner, close this dialog and enter the device information manually.", "NoNextUpItemsMessage": "None found. Start watching your shows!", "NoPluginConfigurationMessage": "This plugin has no settings to configure.", "NoSubtitleSearchResultsFound": "No results found.", - "NoSubtitles": "No subtitles", + "NoSubtitles": "None", "NoSubtitlesHelp": "Subtitles will not be loaded by default. They can still be turned on manually during playback.", "None": "None", "Normal": "Normal", "NumLocationsValue": "{0} folders", "Off": "Off", "OneChannel": "One channel", - "OnlyForcedSubtitles": "Only forced subtitles", + "OnlyForcedSubtitles": "Only Forced", "OnlyForcedSubtitlesHelp": "Only subtitles marked as forced will be loaded.", - "OnlyImageFormats": "Only image formats (VOBSUB, PGS, SUB, etc)", + "OnlyImageFormats": "Only Image Formats (VOBSUB, PGS, SUB)", "Option3D": "3D", "OptionAdminUsers": "Administrators", "OptionAlbum": "Album", "OptionAlbumArtist": "Album Artist", "OptionAllUsers": "All users", "OptionAllowAudioPlaybackTranscoding": "Allow audio playback that requires transcoding", + "OptionForceRemoteSourceTranscoding": "Force transcoding of remote media sources (like LiveTV)", "OptionAllowBrowsingLiveTv": "Allow Live TV access", "OptionAllowContentDownloading": "Allow media downloading and syncing", "OptionAllowLinkSharing": "Allow social media sharing", @@ -1103,7 +1132,6 @@ "OptionEnableAccessFromAllDevices": "Enable access from all devices", "OptionEnableAccessToAllChannels": "Enable access to all channels", "OptionEnableAccessToAllLibraries": "Enable access to all libraries", - "OptionEnableAutomaticServerUpdates": "Enable automatic server updates", "OptionEnableExternalContentInSuggestions": "Enable external content in suggestions", "OptionEnableExternalContentInSuggestionsHelp": "Allow internet trailers and live TV programs to be included within suggested content.", "OptionEnableForAllTuners": "Enable for all tuner devices", @@ -1139,7 +1167,7 @@ "OptionMissingEpisode": "Missing Episodes", "OptionMonday": "Monday", "OptionNameSort": "Name", - "OptionNew": "New...", + "OptionNew": "New…", "OptionNone": "None", "OptionOnAppStartup": "On application startup", "OptionOnInterval": "On an interval", @@ -1189,10 +1217,11 @@ "OptionWeekends": "Weekends", "OptionWeekly": "Weekly", "OriginalAirDateValue": "Original air date: {0}", + "OtherArtist": "Other Artist", "Overview": "Overview", - "PackageInstallCancelled": "{0} installation cancelled.", - "PackageInstallCompleted": "{0} installation completed.", - "PackageInstallFailed": "{0} installation failed.", + "PackageInstallCancelled": "{0} (version {1}) installation cancelled.", + "PackageInstallCompleted": "{0} (version {1}) installation completed.", + "PackageInstallFailed": "{0} (version {1}) installation failed.", "ParentalRating": "Parental rating", "PasswordMatchError": "Password and password confirmation must match.", "PasswordResetComplete": "The password has been reset.", @@ -1202,6 +1231,7 @@ "PasswordSaved": "Password saved.", "People": "People", "PerfectMatch": "Perfect match", + "Person": "Person", "Photos": "Photos", "PictureInPicture": "Picture in picture", "PinCodeResetComplete": "The pin code has been reset.", @@ -1214,6 +1244,7 @@ "PlayFromBeginning": "Play from beginning", "PlayNext": "Play next", "PlayNextEpisodeAutomatically": "Play next episode automatically", + "PlaybackErrorNoCompatibleStream": "This client isn't compatible with the media and the server isn't sending a compatible media format.", "Played": "Played", "Playlists": "Playlists", "PleaseAddAtLeastOneFolder": "Please add at least one folder to this library by clicking the Add button.", @@ -1224,6 +1255,8 @@ "PluginInstalledMessage": "The plugin has been successfully installed. Jellyfin Server will need to be restarted for changes to take effect.", "PreferEmbeddedTitlesOverFileNames": "Prefer embedded titles over filenames", "PreferEmbeddedTitlesOverFileNamesHelp": "This determines the default display title when no internet metadata or local metadata is available.", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "This uses the episode information from the embedded metadata if available.", + "PreferEmbeddedEpisodeInfosOverFileNames": "Prefer embedded episode information over filenames", "PreferredNotRequired": "Preferred, but not required", "Premiere": "Premiere", "Premieres": "Premieres", @@ -1252,13 +1285,14 @@ "RefreshMetadata": "Refresh metadata", "RefreshQueued": "Refresh queued.", "ReleaseDate": "Release date", + "ReleaseGroup": "Release Group", "RememberMe": "Remember me", "RemoveFromCollection": "Remove from collection", "RemoveFromPlaylist": "Remove from playlist", "Repeat": "Repeat", "RepeatAll": "Repeat all", "RepeatEpisodes": "Repeat episodes", - "RepeatMode": "Repeat mode", + "RepeatMode": "Repeat Mode", "RepeatOne": "Repeat one", "ReplaceAllMetadata": "Replace all metadata", "ReplaceExistingImages": "Replace existing images", @@ -1282,6 +1316,7 @@ "SearchForMissingMetadata": "Search for missing metadata", "SearchForSubtitles": "Search for Subtitles", "SearchResults": "Search Results", + "Season": "Season", "SelectAdminUsername": "Please select a username for the admin account.", "SendMessage": "Send message", "Series": "Series", @@ -1304,6 +1339,8 @@ "ShowYear": "Show year", "Shows": "Shows", "Shuffle": "Shuffle", + "New": "New", + "Filter": "Filter", "SimultaneousConnectionLimitHelp": "The maximum number of allowed simultaneous streams. Enter 0 for no limit.", "SkipEpisodesAlreadyInMyLibrary": "Don't record episodes that are already in my library", "SkipEpisodesAlreadyInMyLibraryHelp": "Episodes will be compared using season and episode numbers, when available.", @@ -1397,6 +1434,7 @@ "TitleHardwareAcceleration": "Hardware Acceleration", "TitleHostingSettings": "Hosting Settings", "TitlePlayback": "Playback", + "Track": "Track", "TrackCount": "{0} tracks", "Trailers": "Trailers", "Transcoding": "Transcoding", @@ -1452,6 +1490,21 @@ "XmlTvNewsCategoriesHelp": "Programs with these categories will be displayed as news programs. Separate multiple with '|'.", "XmlTvPathHelp": "A path to a XMLTV file. Jellyfin will read this file and periodically check it for updates. You are responsible for creating and updating the file.", "XmlTvSportsCategoriesHelp": "Programs with these categories will be displayed as sports programs. Separate multiple with '|'.", + "Yadif": "YADIF", + "YadifBob": "YADIF Bob", "Yes": "Yes", - "Yesterday": "Yesterday" + "Yesterday": "Yesterday", + "PathNotFound": "The path could not be found. Please ensure the path is valid and try again.", + "WriteAccessRequired": "Jellyfin Server requires write access to this folder. Please ensure write access and try again.", + "ListPaging": "{0}-{1} of {2}", + "PersonRole": "as {0}", + "LastSeen": "Last seen {0}", + "DailyAt": "Daily at {0}", + "WeeklyAt": "{0}s at {1}", + "OnWakeFromSleep": "On wake from sleep", + "EveryXMinutes": "Every {0} minutes", + "EveryHour": "Every hour", + "EveryXHours": "Every {0} hours", + "OnApplicationStartup": "On application startup", + "UnsupportedPlayback": "Jellyfin cannot decrypt content protected by DRM but all content will be attempted regardless, including protected titles. Some files may appear completely black due to encryption or other unsupported features, such as interactive titles." } diff --git a/src/strings/eo.json b/src/strings/eo.json new file mode 100644 index 0000000000..3151c9e434 --- /dev/null +++ b/src/strings/eo.json @@ -0,0 +1,5 @@ +{ + "AddToCollection": "Aldoni al kolekto", + "Actor": "Aktoro", + "Absolute": "Absoluto" +} diff --git a/src/strings/es-ar.json b/src/strings/es-ar.json index 2b99b91242..69c571a57a 100644 --- a/src/strings/es-ar.json +++ b/src/strings/es-ar.json @@ -37,9 +37,9 @@ "Favorites": "Favoritos", "Folders": "Carpetas", "Genres": "Géneros", - "HeaderAlbumArtists": "Artistas de álbumes", - "HeaderContinueWatching": "Continuar viendo", - "HeaderNextUp": "Continuar Viendo", + "HeaderAlbumArtists": "Artistas de álbum", + "HeaderContinueWatching": "Seguir viendo", + "HeaderNextUp": "A Continuación", "Movies": "Películas", "Photos": "Fotos", "Playlists": "Listas de reproducción", @@ -61,17 +61,17 @@ "Alerts": "Alertas", "All": "Todo", "AllChannels": "Todos los canales", - "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AllEpisodes": "Todos los capítulos", "AllLanguages": "Todos los idiomas", "AllLibraries": "Todas las bibliotecas", "AllowMediaConversion": "Permitir conversión de medios", "AllowMediaConversionHelp": "Permitir o denegar acceso a la opción de convertir medios.", "AllowOnTheFlySubtitleExtraction": "Permitir extracción de subtítulos al vuelo", - "AllowOnTheFlySubtitleExtractionHelp": "Los subtítulos incrustados pueden ser extraídos de videos y entregados a apps de Jellyfin en texto plano para ayudar a prevenir la transcodificación de video. En algunos sistemas esto puede llevar un largo tiempo y causar demoras en la reproducción durante el proceso de extracción. Desactivar esta opción para quemar los subtítulos incrustados en la transcodificación de video cuando no son soportados nativamente por el dispositivo cliente.", + "AllowOnTheFlySubtitleExtractionHelp": "Los subtítulos incrustados pueden extraerse de los videos y entregarse a los reproductores en texto plano para ayudar a evitar la transcodificación de video. En algunos sistemas, esto puede tardar mucho tiempo y provocar que la reproducción de video se detenga durante el proceso de extracción. Deshabilite esta opción para que los subtítulos incrustados se graben con transcodificación de video cuando no estén soportados de forma nativa por el dispositivo cliente.", "AllowRemoteAccess": "Permitir conexiones remotas a este Servidor Jellyfin.", "AllowRemoteAccessHelp": "Si no está tildado, todas las conexiones remotas serán bloqueadas.", - "AlwaysPlaySubtitles": "Siempre reproducir subtítulos", + "AlwaysPlaySubtitles": "Siempre mostrar subtítulos", "AnyLanguage": "Cualquier idioma", "Anytime": "Cualquier fecha", "Ascending": "Ascendente", @@ -81,7 +81,7 @@ "AutoBasedOnLanguageSetting": "Auto (basado en configuración de idioma)", "AutomaticallyConvertNewContent": "Convertir contenido nuevo automáticamente", "Backdrop": "Fondo", - "AllowHWTranscodingHelp": "Si se activa, se permitirá al sintonizador transcodificar streams al vuelo. Esto podría ayudar a reducir la transcodificación requerida por el servidor Jellyfin.", + "AllowHWTranscodingHelp": "Permite que el sintonizador transcodifique las transmisiones sobre la marcha. Esto puede ayudar a reducir la transcodificación requerida por el servidor.", "AllowedRemoteAddressesHelp": "Lista separada por comas de direcciones IP o IP/máscara-de-red para redes a las que se les permitirá conectarse de forma remota. Si se deja vacía, todas las direcciones remotas serán permitidas.", "AlwaysPlaySubtitlesHelp": "Los subtítulos que concuerden con la preferencia de idioma se cargarán independientemente del idioma del audio.", "AndroidUnlockRestoreHelp": "Para recuperar tu compra anterior, por favor asegurate que iniciaste sesión en el dispositivo con la misma cuenta de Google (o Amazon) que hizo la compra originalmente. Asegurate de que la tienda de aplicaciones esté habilitada y no posea control parental alguno, y que tiene una conexión a Internet activa. Solo tendrás que hacer esto una sola vez para recuperar tu compra anterior.", @@ -102,12 +102,12 @@ "BirthPlaceValue": "Lugar de nacimiento: {0}", "Blacklist": "Lista negra", "BobAndWeaveWithHelp": "Bob and weave (mayor calidad, pero más lento)", - "BookLibraryHelp": "Libros de audio y de texto son soportados. Revise la {0}guía de nombrado de libros de Jellyfin{1}.", + "BookLibraryHelp": "Los libros de texto y audio libros son soportados. Revise la {0}Guía para Nomenclatura de Libros{1}.", "Box": "Caja", "BoxRear": "Caja (lado opuesto)", "Browse": "Explorar", "BrowsePluginCatalogMessage": "Explore nuestro catálogo de complementos para ver los complementos disponibles.", - "BurnSubtitlesHelp": "Determine si el servidor debería incrustar los subtítulos cuando convierte los videos dependiendo del formato de subtítulo. Evitar incrustar subtitulos mejorará el rendimiento del servidor. Seleccione Auto para incrustar formatos basados en imagen (por ejemplo, VOBSUB, PGS, SUB/IDX, etc.), como así también ciertos subtítulos ASS/SSA", + "BurnSubtitlesHelp": "Determina si el servidor debe grabar subtítulos al transcodificar videos. Evitar esto mejorará altamente el rendimiento del servidor. Seleccione Auto para grabar formatos basados en imágenes (VOBSUB, PGS, SUB/IDX) y ciertos subtítulos ASS o SSA.", "ButtonAccept": "Aceptar", "ButtonAdd": "Agregar", "ButtonAddMediaLibrary": "Agregar biblioteca de medios", @@ -308,12 +308,11 @@ "DeviceLastUsedByUserName": "Usado ultima vez por {0}", "DirectPlayError": "Error en la reproducción directa", "DirectPlaying": "Reproducción directa", - "DirectStreamHelp1": "El medio es compatible con el dispositivo respecto a la resolución y el tipo de medio (H.264, AC3, etc.), pero esta en un contenedor incompatible (.mkv, .avi, .wmv, etc.). El video va a ser re-empaquetado en el momento que sea transmitido al dispositivo.", + "DirectStreamHelp1": "El medio es compatible con el dispositivo en cuanto a la resolución y tipo de medio (H.264, AC3, etc.), pero está en un contenedor de archivo incompatible (mkv, avi, wmv, etc.). El video sera reempaquetado en el acto antes de transmitirlo al dispositivo.", "DirectStreamHelp2": "Transmitir directamente un archivo usa muy poco procesamiento, esto sin perdida en la calidad de video.", "DirectStreaming": "Transmisión en directo", "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directores: {0}", + "Directors": "Directores", "Disabled": "Deshabilitado", "Disc": "Disco", "Disconnect": "Desconectar", @@ -321,8 +320,8 @@ "DisplayInMyMedia": "Mostrar en pantalla principal", "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla principal, como últimos medios y continuar viendo", "DisplayMissingEpisodesWithinSeasons": "Mostrar episodios faltantes entre temporadas", - "DisplayMissingEpisodesWithinSeasonsHelp": "Esto debe ser habilitado en las bibilotecas de TV, en la configuracion del servidor de Jellyfin.", - "DisplayModeHelp": "Selecciona el tipo de pantalla en el cual estas usando Jellyfin.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe estar habilitado para las bibliotecas de TV en la configuración del servidor.", + "DisplayModeHelp": "Seleccione el estilo de diseño que desea en la Interfaz.", "DoNotRecord": "No grabar", "Down": "Abajo", "Download": "Descargar", @@ -336,49 +335,49 @@ "DropShadow": "Sombra paralela", "DvrFeatureDescription": "Agendar grabaciones individuales de TV en vivo, grabaciones de series y mucho mas con Jellyfin DVR.", "DvrSubscriptionRequired": "Jellyfin DVR requiere una suscripción a Jellyfin Premiere.", - "EasyPasswordHelp": "Tu numero de PIN fácil puede ser usado por las aplicaciones de Jellyfin soportadas, también pueden ser utilizadas para acceder fácilmente al ingresar dentro de tu red.", + "EasyPasswordHelp": "Su código PIN fácil se utiliza para el acceso sin conexión en los clientes compatibles y también puede utilizarse para acceder fácilmente cuando se está en la misma red.", "Edit": "Editar", "EditImages": "Editar imagenes", "EditMetadata": "Editar metadata", "EditSubtitles": "Editar subtitulos", - "EnableBackdrops": "Habilitar fondo", - "EnableBackdropsHelp": "Si esta habilitado, los fondos van a ser mostrados en segundo plano de algunas paginas mientras estas en la biblioteca.", - "EnableCinemaMode": "Habilitar modo Cine", - "EnableColorCodedBackgrounds": "Habilitar colores en el fondo del codigo", - "AuthProviderHelp": "Selecciona un Proveedor de Autenticación para autenticar la contraseña de este usuario", + "EnableBackdrops": "Imágenes de fondo", + "EnableBackdropsHelp": "Muestra imágenes de fondo en el fondo de algunas páginas mientras se navega por la biblioteca.", + "EnableCinemaMode": "Modo cine", + "EnableColorCodedBackgrounds": "Habilitar colores en el fondo del código", + "AuthProviderHelp": "Seleccione un proveedor de autenticación que se utilizará para autenticar la contraseña de este usuario.", "CriticRating": "Calificación de la crítica", "DefaultSubtitlesHelp": "Los subtítulos se cargan en base a los indicadores por defecto y los indicadores forzados en los metadatos embebidos. Las preferencias de idioma son consideradas cuando existe más de una opción.", "Dislike": "No me gusta", "EnableDebugLoggingHelp": "El registro de depuración debería activarse solo a fin de solucionar problemas. El incremento en el acceso al sistema de archivos podría prevenir que el servidor entre en modo de suspensión en algunos entornos.", "EnableDisplayMirroring": "Habilitar duplicación de la pantalla", - "EnableExternalVideoPlayers": "Habilitar reproductores de vídeo externos", + "EnableExternalVideoPlayers": "Habilitar reproductores de video externos", "EnableExternalVideoPlayersHelp": "Se mostrará un menú de reproductor externo al iniciar la reproducción de video", - "EnableNextVideoInfoOverlay": "Habilitar vista de información del siguiente vídeo durante la reproducción", + "EnableNextVideoInfoOverlay": "Mostrar la información del siguiente video durante la reproducción", "EnableNextVideoInfoOverlayHelp": "Al finalizar un video, mostrar información sobre el siguiente vídeo en la lista de reproducción", - "EnablePhotos": "Habilitar fotos", - "EnablePhotosHelp": "Las fotos serán detectadas y se mostrarán junto a otros archivos de medios", + "EnablePhotos": "Mostrar fotografías", + "EnablePhotosHelp": "Las imágenes serán detectadas y mostradas junto con otros archivos multimedia.", "EnableStreamLooping": "Repetir automáticamente transmisiones en vivo", "EnableStreamLoopingHelp": "Habilita esto sí las transmisiones en vivo sólo contienen unos cuantos segundos y es necesario solicitarlos continuamente. Habilitar esto cuando no es necesario puede causar problemas.", - "EnableThemeSongs": "Habilitar canciones tema", - "EnableThemeSongsHelp": "Al habilitarse, las canciones tema se reproducirán de fondo cuando navegas por la biblioteca.", - "EnableThemeVideos": "Habilitar videos de tema", - "EnableThemeVideosHelp": "Al habilitarse, los videos de tema se reproducirán de fondo mientras navegues por la biblioteca.", + "EnableThemeSongs": "Canciones temáticas", + "EnableThemeSongsHelp": "Reproducir canciones temáticas en el fondo mientras se navega por la biblioteca.", + "EnableThemeVideos": "Videos temáticos", + "EnableThemeVideosHelp": "Al habilitarse, los vídeos de tema se reproducirán de fondo mientras navegues por la biblioteca.", "Ended": "Finalizado", "EndsAtValue": "Termina en {0}", "Episodes": "Episodios", "ErrorAddingListingsToSchedulesDirect": "Ocurrió un error al añadir el alineamiento a tu cuenta de Schedules Direct. Schedules Direct solo permite una cantidad limitada de alineamientos por cuenta. Quizás necesites ingresar al sitio de Schedules Direct y eliminar otros alineamientos de tu cuenta antes de continuar.", "ErrorAddingMediaPathToVirtualFolder": "Ocurrió un error al agregar la ruta de medios. Por favor, asegurate que la ruta es válida y que el proceso que sirve Jellyfin tiene acceso a esa ubicación.", "ErrorAddingTunerDevice": "Ocurrió un error al añadir el dispositivo sintonizador. Por favor asegurate que está disponible e intenta de nuevo.", - "ErrorAddingXmlTvFile": "Ocurrió un error al acceder al archivo de XmlTV. Por favor asegurate de que el archivo existe e intenta de nuevo.", + "ErrorAddingXmlTvFile": "Ocurrió un error al acceder al archivo de XmlTV. Por favor asegúrate de que el archivo existe e intenta de nuevo.", "ErrorDeletingItem": "Ocurrió un error al eliminar el ítem del servidor Jellyfin. Por favor verifica que el servidor Jellyfin tiene permiso de escritura a la carpeta de medios e intenta de nuevo.", - "ErrorGettingTvLineups": "Ocurrió un error al descargar los alineamientos de TV. Por favor asegúrate que tu información es correcta e intenta de nuevo.", + "ErrorGettingTvLineups": "Ocurrió un error al descargar la guía de programación de TV. Por favor asegúrate que tu información es correcta e intenta de nuevo.", "ErrorMessageStartHourGreaterThanEnd": "La hora de fin tiene que ser mayor que la de inicio.", "ErrorPleaseSelectLineup": "Por favor selecciona un alineamiento e intenta de nuevo. Si no existen alineamientos disponibles, asegúrate de que tu nombre de usuario, contraseña y código postal son correctos.", "ErrorSavingTvProvider": "Ocurrió un error al guardar el proveedor de TV. Por favor asegúrate de que está disponible e intenta de nuevo.", "EveryNDays": "Cada {0} días", "ExitFullscreen": "Salir de pantalla completa", "ExtraLarge": "Extra grande", - "ExtractChapterImagesHelp": "Extraer imágenes de los capítulos permitirá a las aplicaciones de Jellyfin mostrar menúes gráficos de selección de escena. El proceso puede ser lento, ocupar mucho tiempo de cpu y puede ocupar varios gigabytes de almacenamiento. El proceso corre cuando los videos son descubiertos, y también como un proceso periódico por la noche. El horario del proceso periódico se puede configurar en el área de procesos periódicos. No se recomienda correr este proceso durante horas de alto uso.", + "ExtractChapterImagesHelp": "Extraer imágenes de los capítulos permitirá a las aplicaciones de Jellyfin mostrar menús gráficos de selección de escena. El proceso puede ser lento, ocupar mucho tiempo de cpu y puede ocupar varios gigabytes de almacenamiento. El proceso corre cuando los vídeos son descubiertos, y también como un proceso periódico por la noche. El horario del proceso periódico se puede configurar en el área de procesos periódicos. No se recomienda correr este proceso durante horas de alto uso.", "Extras": "Extras", "FFmpegSavePathNotFound": "No pudimos localizar FFmpeg usando la ruta que has ingresado. FFprobe también es necesario y debe existir en la misma carpeta. Éstos componentes normalmente están incluidos en la misma descarga. Por favor, revisa la ruta e intenta de nuevo.", "FastForward": "Avanzar Rápido", @@ -392,14 +391,13 @@ "FolderTypeBooks": "Libros", "FolderTypeMovies": "Películas", "FolderTypeMusic": "Música", - "FolderTypeMusicVideos": "Videos Musicales", - "FolderTypeUnset": "Sin especificar (Contenido Mixto)", + "FolderTypeMusicVideos": "Vídeos Musicales", + "FolderTypeUnset": "Contenido Mixto", "FormatValue": "Formato: {0}", "Friday": "Viernes", "Fullscreen": "Pantalla Completa", "General": "General", - "GenreValue": "Género: {0}", - "GenresValue": "Géneros: {0}", + "Genre": "Género", "GroupBySeries": "Agrupar por Serie", "GroupVersions": "Agrupar versiones", "GuestStar": "Estrella invitada", @@ -411,5 +409,96 @@ "HeaderFavoriteEpisodes": "Episodios favoritos", "HeaderFavoriteArtists": "Artistas favoritos", "HeaderFavoriteAlbums": "Álbumes favoritos", - "Shows": "Series" + "Shows": "Series", + "CopyStreamURLError": "Hubo un error copiando la URL.", + "CopyStreamURLSuccess": "URL copiada con éxito.", + "CopyStreamURL": "Copiar la URL de la transmisión", + "ButtonSplit": "Dividir", + "ButtonAddImage": "Agregar imagen", + "AskAdminToCreateLibrary": "Preguntar al administrador para crear una biblioteca.", + "AllowFfmpegThrottlingHelp": "Cuando una transcodificación o conversión avanza demasiado con respecto a la posición actual de la reproducción, se pausara el proceso para consumir menos recursos. esto es mas útil cuando no se hacen búsquedas de tiempo a menudo. Desactive esta opción si experimenta problemas en la reproducción.", + "AllowFfmpegThrottling": "Transcodificación Throttle", + "HeaderCancelRecording": "Cancelar Grabación", + "HeaderBranding": "Marca", + "HeaderBooks": "Libros", + "HeaderBlockItemsWithNoRating": "Bloquear elementos con rating de información vacía o no reconocible:", + "HeaderAutomaticUpdates": "Actualizaciones Automáticas", + "HeaderAudioSettings": "Configuración del Audio", + "HeaderAudioBooks": "Audiolibros", + "HeaderAppearsOn": "Aparece en", + "HeaderApp": "Aplicación", + "HeaderApiKeysHelp": "Las aplicaciones externas requieren una llave API para poder comunicarse con el servidor Jellyfin. Las llaves se emiten iniciando sesión con una cuenta Jellyfin u otorgando manualmente una clave a la aplicación.", + "HeaderApiKeys": "Llaves API", + "HeaderApiKey": "Contraseña API", + "HeaderAllowMediaDeletionFrom": "Permitir el borrado de medios desde", + "HeaderAlert": "Alerta", + "HeaderAlbums": "Albumes", + "HeaderAdmin": "Admin", + "HeaderAdditionalParts": "Partes adicionales", + "HeaderAddUpdateImage": "Agregar/Actualizar imagen", + "HeaderAddToPlaylist": "Agregar a la lista de reproducción", + "HeaderAddToCollection": "Agregar a la Colección", + "HeaderAddScheduledTaskTrigger": "Agregar disparador", + "HeaderActivity": "Actividad", + "HeaderActiveRecordings": "Grabaciones activas", + "HeaderActiveDevices": "Dispositivos activos", + "HeaderAccessScheduleHelp": "Crear un calendario de acceso, para limitar el acceso en determinadas horas.", + "HeaderAccessSchedule": "Acceder al Calendario", + "HardwareAccelerationWarning": "Habilitar la aceleración de hardware puede causar inestabilidad en algunos entornos. Asegúrese de que su sistema operativo y los controladores de vídeo estén completamente actualizados. Si tiene dificultades para reproducir el vídeo después de habilitarlo, deberá volver a cambiar la configuración a \"Nada\".", + "HandledByProxy": "Manejado por un proxy reverso", + "HDPrograms": "Programas en HD", + "EncoderPresetHelp": "Elige un valor más rápido para mejorar el desempeño, o elige un valor más lento para mejorar la calidad.", + "FetchingData": "Obteniendo información adicional", + "Episode": "Episodio", + "Yesterday": "Ayer", + "ClientSettings": "Configuración de cliente", + "BoxSet": "Colección", + "Artist": "Artista", + "AlbumArtist": "Artista del Album", + "Album": "Album", + "HeaderDateIssued": "Fecha de Emisión", + "HeaderCustomDlnaProfiles": "Perfiles personalizados", + "HeaderContinueListening": "Seguir escuchando", + "HeaderContainerProfileHelp": "Los perfiles de contenedor indican las limitaciones de un dispositivo cuando se reproducen formatos específicos. Si se aplica una limitación, los medios se transcodificarán, incluso si el formato está configurado para reproducción directa.", + "HeaderContainerProfile": "Perfil de contenedor", + "HeaderConnectionFailure": "Conexión fallida", + "HeaderConnectToServer": "Conectar al servidor", + "HeaderConfirmRevokeApiKey": "Revocar llave de API", + "HeaderConfirmProfileDeletion": "Confirmar borrado de perfil", + "HeaderConfirmPluginInstallation": "Confirmar instalación del complemento", + "HeaderConfigureRemoteAccess": "Configurar acceso remoto", + "HeaderCodecProfileHelp": "Los perfiles de códec indican las limitaciones de un dispositivo cuando se reproducen códecs específicos. Si se aplica una limitación, los medios se transcodificarán, incluso si el códec está configurado para reproducción directa.", + "HeaderCodecProfile": "Perfil del códec", + "HeaderChapterImages": "Imágenes del capitulo", + "HeaderChannels": "Canales", + "HeaderChannelAccess": "Acceso al canal", + "HeaderCastCrew": "Reparto", + "HeaderCastAndCrew": "Reparto", + "HeaderCancelSeries": "Cancelar serie", + "H264CrfHelp": "El Factor de velocidad constante (CRF) es la configuración de calidad predeterminada para el codificador x264. Puede establecer los valores entre 0 y 51, donde valores más bajos resultarían en una mejor calidad (a expensas de tamaños de archivo más altos). Los valores correctos están entre 18 y 28. El valor predeterminado para x264 es 23, por lo que puede usar esto como punto de partida.", + "DeinterlaceMethodHelp": "Seleccione el método de desentrelazado que se usará al transcodificar contenido entrelazado.", + "HeaderFavoriteVideos": "Videos favoritos", + "HeaderFavoritePeople": "Gente favorita", + "HeaderFavoriteMovies": "Películas Favoritas", + "HeaderFavoriteBooks": "Libros favoritos", + "HeaderExternalIds": "IDs externos:", + "HeaderError": "Error", + "HeaderEpisodes": "Episodios", + "HeaderEnabledFields": "Campos habilitados", + "HeaderEditImages": "Editar imágenes", + "HeaderEasyPinCode": "Pin sencillo", + "HeaderDownloadSync": "Descargar y sincronizar", + "HeaderDisplay": "Pantalla", + "HeaderDirectPlayProfile": "Perfil Direct Play", + "HeaderDevices": "Dispositivos", + "HeaderDeviceAccess": "Acceso al dispositivo", + "HeaderDeveloperInfo": "Información para desarrolladores", + "HeaderDetectMyDevices": "Detectar mis dispositivos", + "HeaderDeleteTaskTrigger": "Elminar disparador de acciones", + "HeaderDeleteProvider": "Eliminar proveedor", + "HeaderDeleteItems": "Eliminar ítems", + "HeaderDeleteItem": "Eliminar ítem", + "HeaderDeleteDevice": "Eliminar dispositivo", + "HeaderDefaultRecordingSettings": "Ajustes de grabación por defecto", + "UnsupportedPlayback": "Jellyfin no puede descifrar contenido protegido por DRM pero a pesar de esto lo intentará con todo el contenido, incluyendo títulos protegidos. Algunos archivos pueden aparecer completamente en negro por estar cifrados o por otras características no soportadas, como títulos interactivos." } diff --git a/src/strings/es-mx.json b/src/strings/es-mx.json index 26b6643ffe..fcf5643816 100644 --- a/src/strings/es-mx.json +++ b/src/strings/es-mx.json @@ -15,7 +15,7 @@ "Alerts": "Alertas", "All": "Todo", "AllChannels": "Todos los canales", - "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AllEpisodes": "Todos los episodios", "AllLanguages": "Todos los idiomas", "AllLibraries": "Todas las bibliotecas", @@ -55,7 +55,7 @@ "BoxRear": "Reverso de caja", "Browse": "Navegar", "BrowsePluginCatalogMessage": "Explorar el catalogo de complementos para ver los complementos disponibles.", - "BurnSubtitlesHelp": "Determina si el servidor debe grabar subtítulos al convertir videos dependiendo del formato de los subtítulos. Evitar la grabación de subtítulos mejorará el rendimiento del servidor. Seleccione Auto para grabar formatos basados en imágenes (VOBSUB, PGS, SUB/IDX, etc.) y ciertos subtítulos ASS/SSA.", + "BurnSubtitlesHelp": "Determina si el servidor debe grabar subtítulos al transcodificar videos. Evitar esto mejorará altamente el rendimiento del servidor. Seleccione Auto para grabar formatos basados en imágenes (VOBSUB, PGS, SUB/IDX) y ciertos subtítulos ASS o SSA.", "ButtonAdd": "Agregar", "ButtonAddMediaLibrary": "Agregar Biblioteca de Medios", "ButtonAddScheduledTaskTrigger": "Agregar Disparador", @@ -158,7 +158,7 @@ "CustomDlnaProfilesHelp": "Crear un perfil personalizado para un nuevo dispositivo o reemplazar un perfil del sistema.", "DateAdded": "Fecha de adición", "DatePlayed": "Fecha de reproducción", - "DeathDateValue": "Fallcimiento: {0}", + "DeathDateValue": "Terminación: {0}", "Default": "Por defecto", "DefaultErrorMessage": "Ha ocurrido un error al procesar la solicitud. Por favor inténtelo de nuevo mas tarde.", "DefaultMetadataLangaugeDescription": "Estas son sus configuraciones por defecto y puedes ser personalizadas independientemente en cada biblioteca.", @@ -179,7 +179,7 @@ "DirectStreamHelp1": "El medio es compatible con el dispositivo en cuanto a la resolución y tipo de medio (H.264, AC3, etc.), pero está en un contenedor de archivo incompatible (mkv, avi, wmv, etc.). El video sera reempaquetado en el acto 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", - "DirectorsValue": "Directores: {0}", + "Directors": "Directores", "Disabled": "Desactivado", "Disc": "DIsco", "Disconnect": "Desconectar", @@ -189,14 +189,14 @@ "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio como Recientes o Continua Viendo", "DisplayMissingEpisodesWithinSeasons": "Mostrar episodios faltantes en las temporadas", "DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe estar habilitado para las bibliotecas de TV en la configuración del servidor.", - "DisplayModeHelp": "Seleccione el tipo de pantalla en la que se encuentra ejecutando Jellyfin.", + "DisplayModeHelp": "Seleccione el estilo de diseño que desea en la Interfaz.", "DoNotRecord": "No grabar", "Down": "Abajo", "Download": "Descargar", "DownloadsValue": "{0} descargas", "DrmChannelsNotImported": "Los canales con DRM no serán importados.", - "DropShadow": "Mostrar sombra", - "EasyPasswordHelp": "Su código PIN fácil se utiliza para el acceso sin conexión en los clientes compatibles y también puede utilizarse para acceder fácilmente cuando se está en la misma red.", + "DropShadow": "Sombra paralela", + "EasyPasswordHelp": "El código PIN fácil se utiliza para el acceso sin conexión en los clientes soportados y también puede utilizarse para acceder fácilmente cuando se está en la misma red.", "Edit": "Editar", "EditImages": "Editar imágenes", "EditMetadata": "Editar metadatos", @@ -204,7 +204,7 @@ "EnableBackdrops": "Imágenes de fondo", "EnableBackdropsHelp": "Muestra imágenes de fondo en el fondo de algunas páginas mientras se navega por la biblioteca.", "EnableCinemaMode": "Modo cine", - "EnableColorCodedBackgrounds": "Fondos con código de color", + "EnableColorCodedBackgrounds": "Fondos de color codificado", "EnableDisplayMirroring": "Duplicado de pantalla", "EnableExternalVideoPlayers": "Reproductores de video externos", "EnableExternalVideoPlayersHelp": "Un menú de reproductor externo se mostrara cuando inicie la reproducción de un video.", @@ -225,7 +225,7 @@ "ErrorAddingListingsToSchedulesDirect": "Hubo un error agregando la programación de su cuenta de Schedules Direct. Schedules Direct solo permite un numero limitado de programaciones por cuenta. Tal vez necesite acceder al sitio web de Schedules Direct y eliminar otras programaciones de su cuenta antes de continuar.", "ErrorAddingMediaPathToVirtualFolder": "Hubo un error agregando la ruta de medios. Por favor asegúrese de que la ruta es valida y que el proceso del Servidor Jellyfin tenga acceso a ese destino.", "ErrorAddingTunerDevice": "Hubo un error al agregar el dispositivo sintonizador. Por favor asegúrese de que este disponible e intente de nuevo.", - "ErrorAddingXmlTvFile": "Hubo un error accediendo al archivo XmlTV. Por favor asegúrese de que el archivo existe e intente de nuevo.", + "ErrorAddingXmlTvFile": "Hubo un error accediendo al archivo XMLTV. Por favor asegúrese de que el archivo existe e intente de nuevo.", "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.", "ErrorGettingTvLineups": "Hubo un error al descargar la programación de TV. Por favor, asegúrese de que su información este correcta e inténtelo de nuevo.", "ErrorMessageStartHourGreaterThanEnd": "El horario de fin debe ser mayor al de comienzo.", @@ -255,9 +255,8 @@ "FormatValue": "Formato: {0}", "Friday": "Viernes", "Fullscreen": "Pantalla Completa", - "GenreValue": "Genero: {0}", + "Genre": "Genero", "Genres": "Géneros", - "GenresValue": "Géneros: {0}", "GroupBySeries": "Agrupar por series", "GroupVersions": "Agrupar versiones", "GuestStar": "Estrella invitada", @@ -265,10 +264,10 @@ "GuideProviderLogin": "Iniciar Sesión", "GuideProviderSelectListings": "Elegir Listados", "H264CrfHelp": "El \"Factor de Transferencia Constante\" o \"Constant Rate Factor\" (CFR) es la configuración por defecto para el codificador x264. Puede poner valores entre 0 y 51, donde los valores mas bajos dan como resultado mejor calidad (a expensas de archivos mas grandes). Los valores comunes son entre 18 y 28. El valor por defecto para x264 es 23, puede usar este valor como punto de referencia.", - "H264EncodingPresetHelp": "Elija un valor mas rápido para mejorar el rendimiento, o uno mas lento para mejorar la calidad.", + "EncoderPresetHelp": "Elija un valor mas rápido para mejorar el rendimiento, o uno mas lento para mejorar la calidad.", "HDPrograms": "Programas en HD", "HandledByProxy": "Manejado por un proxy inverso", - "HardwareAccelerationWarning": "Habilitar la aceleración por hardware podría causar inestabilidad en algunos entornos, Asegúrese de que su sistema operativo y controladores de video están actualizados. Si tiene dificultades reproduciendo vides después de habilitar esto, necesita cambiar las configuraciones de nuevo a Auto.", + "HardwareAccelerationWarning": "Habilitar la aceleración por hardware podría causar inestabilidad en algunos entornos. Asegúrese de que su sistema operativo y controladores de video están actualizados. Si tiene dificultades reproduciendo vides después de habilitar esto, necesita volver a cambiar la configuración a NO.", "HeaderAccessSchedule": "Acceder Programación", "HeaderAccessScheduleHelp": "Crear programación de acceso para limitar el acceso a ciertos horarios.", "HeaderActiveDevices": "Dispositivos Activos", @@ -479,12 +478,12 @@ "Hide": "Ocultar", "HideWatchedContentFromLatestMedia": "Ocultar contenido ya visto de Agregadas Recientemente", "Home": "Inicio", - "HttpsRequiresCert": "Para habilitar las conexiones seguras, es necesario proporcionar un certificado SSL de confianza, como el de \"Lets Encrypt\". Por favor proporcione un certificado, o desactive las conexiones seguras.", + "HttpsRequiresCert": "Para habilitar las conexiones seguras, es necesario proporcionar un certificado SSL de confianza, como el de \"Let's Encrypt\". Por favor proporcione un certificado, o desactive las conexiones seguras.", "Identify": "Identificar", "Images": "Imágenes", "ImportFavoriteChannelsHelp": "Si se habilita, solo los canales marcados como favoritos en el dispositivo sintonizador serán importados.", "ImportMissingEpisodesHelp": "Si se habilita, se importara a su base de datos de Jellyfin información sobre episodios faltantes y se mostrara dentro de las temporadas y series. Esto podría ocasionar escaneos de biblioteca significativamente mas largos.", - "InstallingPackage": "Instalando {0}", + "InstallingPackage": "Instalando {0} (versión {1})", "InstantMix": "Mix instantáneo", "ItemCount": "{0} ítems", "Items": "Ítems", @@ -514,7 +513,7 @@ "LabelAllowedRemoteAddresses": "Filtrar IP remota:", "LabelAllowedRemoteAddressesMode": "Modo de filtrado de IP remota:", "LabelAppName": "Nombre del App", - "LabelAppNameExample": "Ejemplo: Sickbeard, NzbDrone", + "LabelAppNameExample": "Ejemplo: Sickbeard, Sonarr", "LabelArtists": "Artistas:", "LabelArtistsHelp": "Separar múltiples empleando ;", "LabelAudioLanguagePreference": "Idioma preferido de audio:", @@ -540,7 +539,7 @@ "LabelCountry": "País:", "LabelCriticRating": "Calificación de la crítica:", "LabelCurrentPassword": "Contraseña actual:", - "LabelCustomCertificatePath": "Ruta personalizada del certificado ssl:", + "LabelCustomCertificatePath": "Ruta personalizada del certificado SSL:", "LabelCustomCertificatePathHelp": "Trayectoria a un archivo PKCS #12 que contiene el certificado y la llave privada para habilitar soporte a TLS en un dominio personalizado.", "LabelCustomCss": "CSS personalizado:", "LabelCustomCssHelp": "Aplicar tu propio estilo personalizado a la interfaz web.", @@ -576,7 +575,7 @@ "LabelEmbedAlbumArtDidl": "Incrustar arte del álbum en DIDL", "LabelEmbedAlbumArtDidlHelp": "Algunos dispositivos prefieren este método para obtener arte del álbum. Otros podrían fallar al reproducir con esta opción habilitada.", "LabelEnableAutomaticPortMap": "Habilitar mapeo automático de puertos", - "LabelEnableAutomaticPortMapHelp": "Intentar mapear automáticamente el puerto público con el puerto local via UPnP. Esto podría no funcionar con algunos modelos de ruteadores.", + "LabelEnableAutomaticPortMapHelp": "Intentar mapear automáticamente el puerto público con el puerto local vía UPnP. Esto podría no funcionar con algunos modelos de ruteadores.", "LabelEnableBlastAliveMessages": "Bombardeo de mensajes de vida", "LabelEnableBlastAliveMessagesHelp": "Habilite esto si el servidor no es detectado de manera confiable por otros dispositivos UPnP en su red.", "LabelEnableDlnaClientDiscoveryInterval": "Intervalo de Detección de Clientes (segundos)", @@ -609,9 +608,9 @@ "LabelGroupMoviesIntoCollections": "Agrupar películas en colecciones", "LabelGroupMoviesIntoCollectionsHelp": "Cuando se muestran listados de películas, las películas que pertenecen a una colección serán mostradas agrupadas en un solo ítem.", "LabelH264Crf": "CRF de codificación H264:", - "LabelH264EncodingPreset": "Codificación H264 predefinido:", + "LabelEncoderPreset": "Codificación H264 predefinido:", "LabelHardwareAccelerationType": "Aceleración por Hardware:", - "LabelHardwareAccelerationTypeHelp": "Esta es una característica experimental que solo está disponible en los sistemas soportados.", + "LabelHardwareAccelerationTypeHelp": "Aceleración por Hardware requiere configuración adicional.", "LabelHomeNetworkQuality": "Calidad en Red Local:", "LabelHomeScreenSectionValue": "Pagina de inicio sección {0}:", "LabelHttpsPort": "Número de puerto local HTTPS:", @@ -648,13 +647,13 @@ "LabelLoginDisclaimer": "Aviso legal:", "LabelLoginDisclaimerHelp": "Un mensaje que se mostrará en la parte inferior de la página de inicio de sesión.", "LabelLogs": "Bitácoras:", - "LabelManufacturer": "Fabricante", + "LabelManufacturer": "Fabricante:", "LabelManufacturerUrl": "URL del fabricante", "LabelMatchType": "Tipo de Coincidencia:", "LabelMaxBackdropsPerItem": "Número máximo de imágenes de fondo por ítem:", "LabelMaxChromecastBitrate": "Tasa maxima de bits para El Chromecast:", "LabelMaxParentalRating": "Máxima clasificación parental permitida:", - "LabelMaxResumePercentage": "Porcentaje máximo de reanudación:", + "LabelMaxResumePercentage": "Porcentaje máximo para la reanudación:", "LabelMaxResumePercentageHelp": "Los medios se consideran totalmente reproducidos si se detienen después de este tiempo.", "LabelMaxScreenshotsPerItem": "Número máximo de capturas de pantalla por ítem:", "LabelMaxStreamingBitrate": "Calidad máxima de transmisión:", @@ -687,7 +686,7 @@ "LabelMoviePrefixHelp": "Si un prefijo es aplicado al título de las películas, introdúzcalo aquí para que el servidor pueda manejarlo correctamente.", "LabelMovieRecordingPath": "Ruta para grabaciones de Películas (opcional):", "LabelMusicStreamingTranscodingBitrate": "Tasa de transcodificación de música:", - "LabelMusicStreamingTranscodingBitrateHelp": "Especifique la tasa de bits máxima al transferir musica en tiempo real", + "LabelMusicStreamingTranscodingBitrateHelp": "Especifique la tasa de bits máxima al transmitir música.", "LabelName": "Nombre:", "LabelNewName": "Nuevo nombre:", "LabelNewPassword": "Nueva contraseña:", @@ -759,7 +758,7 @@ "LabelServerHost": "Servidor:", "LabelServerHostHelp": "192.168.1.100:8096 o https://miservidor.com", "LabelSimultaneousConnectionLimit": "Limite de transmisiones simultaneas:", - "LabelSkin": "Piel:", + "LabelSkin": "Apariencia:", "LabelSkipBackLength": "Longitud de salto hacia atrás:", "LabelSkipForwardLength": "Longitud de salto hacia adelante:", "LabelSkipIfAudioTrackPresent": "Omitir si la pista de audio por defecto coincide con el lenguaje de descarga", @@ -782,7 +781,7 @@ "LabelSubtitleDownloaders": "Recolectores de Subtitulos:", "LabelSubtitleFormatHelp": "Ejemplo: srt", "LabelSubtitlePlaybackMode": "Modo de subtítulo:", - "LabelSubtitles": "Subtítulos:", + "LabelSubtitles": "Subtítulos", "LabelSupportedMediaTypes": "Tipos de Medios Soportados:", "LabelTVHomeScreen": "Modo de pantalla de TV:", "LabelTag": "Etiqueta:", @@ -822,7 +821,7 @@ "LabelVersionNumber": "Versión {0}", "LabelXDlnaCap": "X-DLNA cap:", "LabelXDlnaCapHelp": "Determina el contenido del elemento X_DLNACAP en el namespace urn:schemas-dlna-org:device-1-0.", - "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaDoc": "Documento X-DLNA:", "LabelXDlnaDocHelp": "Determina el contenido del elemento X_DLNADOC en el namespace urn:schemas-dlna-org:device-1-0.", "LabelYear": "Año:", "LabelYourFirstName": "Su nombre:", @@ -889,7 +888,7 @@ "MessageDeleteTaskTrigger": "¿Está seguro de querer eliminar este disparador de tarea?", "MessageDirectoryPickerBSDInstruction": "Para BSD, quizás necesite configurar el almacenamiento dentro de su \"FreeNAS Jail\" de manera que permita a Jellyfin accesarlo.", "MessageDirectoryPickerInstruction": "Las rutas de red pueden ser introducidas manualmente en caso de que el botón de Red no pueda localizar sus dispositivos. Por ejemplo, {0} or {1}.", - "MessageDirectoryPickerLinuxInstruction": "Para Linux en Arch Linux, CentOS, Debian, Fedora, OpenSuse o Ubuntu, debe conceder al usuario del servicio al menos permisos de lectura a sus ubicaciones de almacenamiento.", + "MessageDirectoryPickerLinuxInstruction": "Para Linux en Arch Linux, CentOS, Debian, Fedora, openSUSE, o Ubuntu. Debe conceder al usuario del servicio al menos permisos de lectura a sus ubicaciones de almacenamiento.", "MessageDownloadQueued": "Descargar cola.", "MessageEnablingOptionLongerScans": "Habilitar esta opción podría resultar en escaneos de bibliotecas significativamente mas largos.", "MessageFileReadError": "Hubo un error al leer el archivo. Por favor intente de nuevo.", @@ -947,15 +946,15 @@ "NoNextUpItemsMessage": "No se encontró nada. ¡Comienza a ver tus programas!", "NoPluginConfigurationMessage": "El complemento no tiene configuraciones disponibles.", "NoSubtitleSearchResultsFound": "No se encontraron resultados.", - "NoSubtitles": "Sin Subtitulos", + "NoSubtitles": "Nada", "NoSubtitlesHelp": "Los subtítulos no serán cargados por defecto. Pero pueden ser activados manualmente durante la reproducción.", "None": "Ninguno", "NumLocationsValue": "{0} carpetas", "Off": "Apagar", "OneChannel": "Un canal", - "OnlyForcedSubtitles": "Únicamente subtítulos forzados", + "OnlyForcedSubtitles": "Únicamente forzados", "OnlyForcedSubtitlesHelp": "Se cargarán únicamente subtítulos marcados como forzados.", - "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB, etc.)", + "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Administradores", "OptionAlbum": "Álbum", "OptionAlbumArtist": "Artista del Álbum", @@ -1004,12 +1003,12 @@ "OptionDisplayFolderView": "Mostrar una vista de carpetas para mostrar carpetas de medios simples", "OptionDisplayFolderViewHelp": "Muestra las carpetas junto con sus otras bibliotecas multimedia. Esto puede ser útil si desea tener una vista de carpeta sencilla.", "OptionDownloadArtImage": "Arte", - "OptionDownloadBackImage": "Reverso", - "OptionDownloadBannerImage": "Cartél", + "OptionDownloadBackImage": "Atras", + "OptionDownloadBannerImage": "Banner", "OptionDownloadBoxImage": "Caja", "OptionDownloadDiscImage": "DIsco", "OptionDownloadImagesInAdvance": "Descargar las imágenes desde el inicio", - "OptionDownloadImagesInAdvanceHelp": "Por defecto, la mayoría de las imágenes son descargadas solo cuando son solicitadas por alguna aplicación Jellyfin. Habilite esta opción para descargar todas las imágenes desde por adelantado, conforme se vayan agregando mas medios. Esto podría causar escaneos de bibliotecas mas largos.", + "OptionDownloadImagesInAdvanceHelp": "Por defecto, la mayoría de las imágenes son descargadas solo cuando son solicitadas por una aplicacion Jellyfin. Habilite esta opción para descargar todas las imágenes por adelantado, a medida que se agregen mas medios. Esto podría causar escaneos de bibliotecas significativamente largos.", "OptionDownloadMenuImage": "Menú", "OptionDownloadPrimaryImage": "Principal", "OptionDownloadThumbImage": "Miniatura", @@ -1018,7 +1017,6 @@ "OptionEnableAccessFromAllDevices": "Habilitar acceso desde todos los dispositivos", "OptionEnableAccessToAllChannels": "Habilitar acceso a todos los canales", "OptionEnableAccessToAllLibraries": "Habilitar el acceso a todas las bibliotecas", - "OptionEnableAutomaticServerUpdates": "Habilitar actualizaciones automáticas del servidor", "OptionEnableExternalContentInSuggestions": "Habilitar contenido externo en las sugerencias", "OptionEnableExternalContentInSuggestionsHelp": "Permitir que los trailers de Internet y los programas de televisión en vivo se incluyan en el contenido sugerido.", "OptionEnableForAllTuners": "Habilitar para todos los dispositivos sintonizadores", @@ -1069,7 +1067,7 @@ "OptionReportByteRangeSeekingWhenTranscodingHelp": "Esto es requerido para algunos dispositivos que no pueden hacer búsquedas por tiempo muy bien.", "OptionRequirePerfectSubtitleMatch": "Solo descargar subtitulos que corresponden perfectamente para mis archivos de video", "OptionRequirePerfectSubtitleMatchHelp": "Solicitar una coincidencia perfecta filtrara los subtitulos para incluir solo aquellos que han sido verificados exactamente con su archivo de video. Desmarcar esta opción incrementara las probabilidades de que los subtitulos sean descargados, a la vez que incrementara las posibilidades de obtener subtitulos mal sincronizados o con texto incorrecto.", - "OptionResElement": "Elemento res", + "OptionResElement": "Elemento Res", "OptionResumable": "Reanudable", "OptionRuntime": "Duración", "OptionSaturday": "Sábado", @@ -1081,7 +1079,7 @@ "OptionThursday": "Jueves", "OptionTrackName": "Nombre de la Pista", "OptionTuesday": "Martes", - "OptionTvdbRating": "Calificación de Tvdb", + "OptionTvdbRating": "Calificación de TVDB", "OptionUnairedEpisode": "Episodios no Emitidos", "OptionUnplayed": "No reproducido", "OptionWakeFromSleep": "Al Despertar", @@ -1091,9 +1089,9 @@ "OptionWeekly": "Semanal", "OriginalAirDateValue": "Fecha de emisión original: {0}", "Overview": "Sinopsis", - "PackageInstallCancelled": "{0} instalación cancelada.", - "PackageInstallCompleted": "{0} instalación completada.", - "PackageInstallFailed": "{0} instalación fallida.", + "PackageInstallCancelled": "{0} (versión {1}) instalación cancelada.", + "PackageInstallCompleted": "{0} (version {1}) instalación completada.", + "PackageInstallFailed": "{0} (versión {1}) instalación fallida.", "ParentalRating": "Clasificación Parental", "PasswordMatchError": "La Contraseña y la confirmación de la contraseña deben coincidir.", "PasswordResetComplete": "La contraseña ha sido restablecida.", @@ -1117,7 +1115,7 @@ "Playlists": "Listas de reproducción", "PleaseAddAtLeastOneFolder": "Por favor agregue al menos una carpeta a esta biblioteca dando clic al botón de Agregar.", "PleaseConfirmPluginInstallation": "Por favor haga clic en OK para confirmar que ha leido lo que se encuentra arriba y que desea proceder con la instalación del complemento.", - "PleaseEnterNameOrId": "Por favor introduzca un nombre o id externo.", + "PleaseEnterNameOrId": "Por favor introduzca un nombre o ID externo.", "PleaseRestartServerName": "Por favor reinicie el Servidor Jellyfin - {0}.", "PleaseSelectTwoItems": "Por favor selecciona al menos dos ítems.", "PluginInstalledMessage": "El complemento ha sido instalado exitosamente. El Servidor Jellyfin necesitará reiniciarse para que los cambios surtan efecto.", @@ -1133,7 +1131,7 @@ "Programs": "Programas", "Quality": "Calidad", "QueueAllFromHere": "Encolar todos desde aquí", - "Raised": "Elevacion", + "Raised": "Elevación", "Rate": "Calificación", "RecentlyWatched": "Visto recientemente", "RecommendationBecauseYouLike": "Porque te gustó {0}", @@ -1157,7 +1155,7 @@ "Repeat": "Repetir", "RepeatAll": "Repetir todas", "RepeatEpisodes": "Repetir episodios", - "RepeatMode": "Modo de repeticion", + "RepeatMode": "Modo de repetición", "RepeatOne": "Repetir uno", "ReplaceAllMetadata": "Remplazar todos los metadatos", "ReplaceExistingImages": "Reemplazar imágenes existentes", @@ -1183,7 +1181,7 @@ "SearchResults": "Resultados de la búsqueda", "SendMessage": "Enviar mensaje", "SeriesCancelled": "Serie cancelada.", - "SeriesDisplayOrderHelp": "Ordenar los episodios por fecha transmisión, orden del dvd o por su numeración absoluta.", + "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", @@ -1197,7 +1195,7 @@ "Share": "Compartir", "ShowAdvancedSettings": "Mostrar configuraciones avanzadas", "ShowIndicatorsFor": "Mostrar indicadores para:", - "ShowTitle": "Mostrar titulo", + "ShowTitle": "Mostrar título", "ShowYear": "Mostrar año", "Shows": "Programas", "Shuffle": "Aleatorio", @@ -1336,9 +1334,9 @@ "Writer": "Escritor", "XmlDocumentAttributeListHelp": "Estos atributos se aplican al elemento raíz de cada respuesta XML.", "XmlTvKidsCategoriesHelp": "Los programas con estas categorías serán mostrados como programas infantiles. Separe varios con un \"|\".", - "XmlTvMovieCategoriesHelp": "Los programas con estas categorías serán mostrado como películas. Separe varios con un \"|\".", - "XmlTvNewsCategoriesHelp": "Los programas con estas categorías serán mostrado como programas noticiosos. Separe varios con un \"|\".", - "XmlTvPathHelp": "Una ruta a un archivo XML de TV. Jellyfin leerá este archivo y lo revisará periódicamente en busca de actualizaciones. Usted es responsable de crear y actualizar el fichero.", + "XmlTvMovieCategoriesHelp": "Los programas con estas categorías serán mostrados como películas. Separe varios con un \"|\".", + "XmlTvNewsCategoriesHelp": "Los programas con estas categorías serán mostrados como programas noticiosos. Separe varios con un \"|\".", + "XmlTvPathHelp": "Ruta al archivo XMLTV. Jellyfin leerá este archivo y lo revisará periódicamente en busca de actualizaciones. Usted es responsable de crear y actualizar el archivo.", "XmlTvSportsCategoriesHelp": "Los programas con estas categorías serán mostrados como programas deportivos. Separe varios con un \"|\".", "Yes": "Sí", "Yesterday": "Ayer", @@ -1351,11 +1349,10 @@ "ButtonTrailer": "Trailer", "AuthProviderHelp": "Seleccione un proveedor de autenticación que se utilizará para autenticar la contraseña de este usuario.", "Director": "Director", - "DirectorValue": "Director: {0}", "Extras": "Extras", "General": "General", "HeaderAdmin": "Administrador", - "HeaderApp": "App", + "HeaderApp": "Aplicación", "HeaderError": "Error", "HeaderFavoriteMovies": "Peliculas favoritas", "HeaderFavoriteShows": "Programas favoritos", @@ -1368,7 +1365,7 @@ "HeaderRestartingServer": "Reiniciando servidor", "HeaderVideos": "Videos", "Horizontal": "Horizontal", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelAuthProvider": "Proveedor de autenticación:", "LabelDynamicExternalId": "{0} Id:", "LabelPasswordResetProvider": "Proveedor de restablecimiento de contraseña:", @@ -1381,8 +1378,8 @@ "DashboardServerName": "Servidor: {0}", "DashboardOperatingSystem": "Sistema operativo: {0}", "DashboardArchitecture": "Arquitectura: {0}", - "LabelVideo": "Video:", - "LabelWeb": "Web: ", + "LabelVideo": "Video", + "LabelWeb": "Web:", "LaunchWebAppOnStartup": "Iniciar la interfaz web al iniciar el servidor", "LaunchWebAppOnStartupHelp": "Abre el cliente web en su navegador web predeterminado cuando se inicia el servidor. Esto no ocurrirá cuando se utilice la función de reinicio del servidor.", "LeaveBlankToNotSetAPassword": "Puede dejar este campo en blanco para no establecer ninguna contraseña.", @@ -1403,7 +1400,7 @@ "No": "No", "Normal": "Normal", "Option3D": "3D", - "OptionBanner": "Banner", + "OptionBanner": "Baner", "OptionBluray": "Blu-ray", "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)", "OptionDownloadLogoImage": "Logo", @@ -1455,5 +1452,64 @@ "LabelVideoBitrate": "Velocidad de bits:", "LabelTranscodingProgress": "Progreso de la transcodificación:", "LabelTranscodingFramerate": "Velocidad de cuadros de la transcodificación:", - "LabelSize": "Tamaño:" + "LabelSize": "Tamaño:", + "SelectAdminUsername": "Por favor seleccione un nombre de usuario para la cuenta de administrador.", + "EnableFastImageFadeInHelp": "Habilita la animación de desvanecido rápido para las imágenes cargadas", + "LabelDroppedFrames": "Cuadros saltados:", + "CopyStreamURLError": "Hubo un error copiando la URL.", + "ButtonSplit": "Dividir", + "WeeklyAt": "{0}s a las {1}", + "OnApplicationStartup": "Cuando se inicia la aplicación", + "EveryXHours": "Cada {0} horas", + "EveryHour": "Cada hora", + "EveryXMinutes": "Cada {0} minutos", + "OnWakeFromSleep": "Activarse del Modo Suspensión", + "DailyAt": "Diariamente a las {0}", + "LastSeen": "Ultima vez visto {0}", + "PersonRole": "como {0}", + "ListPaging": "{0}-{1} de {2}", + "WriteAccessRequired": "El servidor Jellyfin requiere permiso de escritura en esta carpeta. Por favor brinde acceso de escritura e intente de nuevo.", + "PathNotFound": "No se pudo encontrar la ruta. Por favor asegúrese de que la ruta es valida e intente de nuevo.", + "Track": "Pista", + "Season": "Temporada", + "ReleaseGroup": "Grupo de salida", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferir información embebida en el episodio sobre los nombres de archivo", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Esto utiliza la información del episodio desde metadatos embebidos si esta disponible.", + "PlaybackErrorNoCompatibleStream": "Este cliente no es compatible con los medios y el servidor no está enviando un formato de medios compatible.", + "Person": "Persona", + "OtherArtist": "Otro artista", + "OptionRandom": "Aleatorio", + "OptionForceRemoteSourceTranscoding": "Forzar transcodificación para fuentes remotas (como TV en Vivo)", + "NoCreatedLibraries": "Parece que no has creado ninguna biblioteca todavía. {0}Quisieras crear una ahora?{1}", + "Movie": "Película", + "MessageConfirmAppExit": "Deseas salir?", + "LabelVideoResolution": "Resolución de video:", + "LabelStreamType": "Tipo de transmisión:", + "EnableFastImageFadeIn": "Desvanecido de imagen rápido", + "LabelPlayerDimensions": "Dimensiones del reproductor:", + "LabelCorruptedFrames": "Cuadros corruptos:", + "HeaderNavigation": "Navegación", + "HeaderFavoritePeople": "Personas favoritas", + "Episode": "Episodio", + "ClientSettings": "Configuración de cliente", + "BoxSet": "Box Set", + "AskAdminToCreateLibrary": "Preguntar al administrador para crear una biblioteca.", + "Artist": "Artista", + "AllowFfmpegThrottlingHelp": "Cuando una transcodificación o remux se encuentra muy por delante de la posición de reproducción, pausar el proceso para consumir menos recursos. Esto es mas practico cuando se esta viendo sin buscar constantemente. Deshabilitar esta opción si experimentas problemas de reproducción.", + "AllowFfmpegThrottling": "Aceleración de Transcoders", + "AlbumArtist": "Álbum de artista", + "Album": "Álbum", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelDeinterlaceMethod": "Metodo de Desentrelazado:", + "DeinterlaceMethodHelp": "Seleccione el método de desentrelazado que se usará al codificar el contenido entrelazado.", + "Filter": "Filtro", + "New": "Nuevo", + "MessageUnauthorizedUser": "No estás autorizado para acceder al servidor en este momento. Por favor contacta con el administrador del servidor para mas información.", + "LabelLibraryPageSizeHelp": "Establecer el número de elementos a mostrar en la página biblioteca. Establezca 0 para deshabilitar paginado.", + "LabelLibraryPageSize": "Tamaño de la página Biblioteca:", + "HeaderFavoritePlaylists": "Listas de reproducción favoritas", + "ButtonTogglePlaylist": "Lista de reproducción", + "ButtonToggleContextMenu": "Más", + "UnsupportedPlayback": "Jellyfin no puede desencriptar contenido protegido por DRM aún así será intentado, incluyendo títulos protegidos. Algunos archivos pueden aparecer completamente en negro debido al encriptado o características no soportadas, como títulos alternativos." } diff --git a/src/strings/es.json b/src/strings/es.json index bb25fa5c4c..1ce4425797 100644 --- a/src/strings/es.json +++ b/src/strings/es.json @@ -1,16 +1,16 @@ { "AccessRestrictedTryAgainLater": "El acceso está restringido actualmente. Por favor, inténtalo más tarde.", "Add": "Añadir", - "AddItemToCollectionHelp": "Agregue elementos a las colecciones buscando en ellos y utilizando sus menús con el botón derecho del ratón o pulsando en los menús para agregarlos a una colección.", + "AddItemToCollectionHelp": "Agregue elementos a las colecciones buscándolos y haciendo clic con el botón derecho o tocando los menús para agregarlos a una colección.", "AddToCollection": "Añadir a la colección", "AddToPlaylist": "Añadir a la lista de reproducción", "AddedOnValue": "Añadido {0}", - "AdditionalNotificationServices": "Visite el catálogo de complementos para instalar servicios de notificación adicionales.", + "AdditionalNotificationServices": "Visite el catálogo de extensiones para instalar servicios de notificación adicionales.", "Albums": "Álbumes", "Alerts": "Alertas", "All": "Todo", "AllChannels": "Todos los canales", - "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Todos los formatos complejos (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AllEpisodes": "Todos los episodios", "AllLanguages": "Todos los idiomas", "AllLibraries": "Todas las bibliotecas", @@ -22,7 +22,7 @@ "AllowRemoteAccess": "Permitir conexiones remotas a este servidor Jellyfin.", "AllowRemoteAccessHelp": "Si no está activado, todas las conexiones remotas serán bloqueadas.", "AllowedRemoteAddressesHelp": "Lista separada por comas de direcciones IP o entradas de IP / máscara de red para redes a las que se les permitirá conectarse de forma remota. Si se deja en blanco, se permitirán todas las direcciones remotas.", - "AlwaysPlaySubtitles": "Mostrar subtítulos siempre", + "AlwaysPlaySubtitles": "Siempre mostrar subtítulos", "AlwaysPlaySubtitlesHelp": "Los subtítulos que concuerden con la preferencia de idioma se cargarán independientemente del idioma de audio.", "Art": "Arte", "Artists": "Artistas", @@ -40,7 +40,7 @@ "Box": "Caja", "BoxRear": "Caja (trasera)", "Browse": "Explorar", - "BrowsePluginCatalogMessage": "Navegar el catalogo de complementos para ver los complementos disponibles.", + "BrowsePluginCatalogMessage": "Explore el catálogo de extensiones para ver las extensiones disponibles.", "ButtonAdd": "Añadir", "ButtonAddMediaLibrary": "Añadir biblioteca de medios", "ButtonAddScheduledTaskTrigger": "Agregar Activador", @@ -95,7 +95,7 @@ "ButtonRestart": "Reiniciar", "ButtonResume": "Continuar", "ButtonRevoke": "Revocar", - "ButtonSave": "Grabar", + "ButtonSave": "Guardar", "ButtonScanAllLibraries": "Escanear todas las bibliotecas", "ButtonSearch": "Buscar", "ButtonSelectDirectory": "Seleccionar directorio", @@ -120,7 +120,7 @@ "CancelRecording": "Cancelar grabación", "CancelSeries": "Cancelar series", "Categories": "Categorías", - "ChannelAccessHelp": "Seleccione los canales para compartir con este usuario. Los administradores podrán editar todos los canales mediante el gestor de metadatos.", + "ChannelAccessHelp": "Seleccione los canales para compartir con este usuario. Los administradores podrán editar todos los canales mediante el editor de etiquetas.", "ChannelNameOnly": "Canal {0} solo", "ChannelNumber": "Número de canal", "Channels": "Canales", @@ -139,8 +139,8 @@ "DeathDateValue": "Murió: {0}", "Default": "Por defecto", "DefaultErrorMessage": "Ha habido un error procesando la solicitud. Por favor inténtalo más tarde.", - "DefaultMetadataLangaugeDescription": "Estos son tus ajustes y se pueden personalizar para cada librería.", - "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.", + "DefaultMetadataLangaugeDescription": "Estos son tus ajustes y se pueden personalizar para cada biblioteca.", + "DefaultSubtitlesHelp": "Los subtítulos que se utilizarán dependerán de como estén etiquetadas las pistas de los archivos (si \"por defecto\" o \"forzado\"). Los ajustes de idioma se tienen en cuenta cuando hay varias opciones disponibles.", "Delete": "Borrar", "DeleteDeviceConfirmation": "¿Estás seguro de que quieres borrar este dispositivo? Volverá a aparecer la próxima vez que un usuario inicie sesión en él.", "DeleteImage": "Borrar imagen", @@ -157,7 +157,7 @@ "Disc": "Disco", "Disconnect": "Desconectar", "Dislike": "No me gusta", - "DisplayModeHelp": "Seleccione el tipo de pantalla que está ejecutando Jellyfin.", + "DisplayModeHelp": "Seleccione el estilo de diseño que desea en la Interfaz.", "DoNotRecord": "No grabar", "Down": "Abajo", "Download": "Descargar", @@ -183,7 +183,7 @@ "ErrorAddingListingsToSchedulesDirect": "Ha habido un error añadiendo la alineación a tu cuenta de Schedules Direct. Schedules Direct solo permite un determinado número de alineaciones por cuenta. Necesitarás iniciar sesión en la web de Schedules Direct y quitar otras listas de tu cuenta antes de proceder.", "ErrorAddingMediaPathToVirtualFolder": "Ha habido un error añadiendo la ruta de los medios. Por favor, asegúrate de que la ruta es válida y que el proceso del servidor Jellyfin tiene acceso a esa ubicación.", "ErrorAddingTunerDevice": "Ha habido un error añadiendo el dispositivo sintonizador. Por favor, asegúrate de que es accesible e inténtalo otra vez.", - "ErrorAddingXmlTvFile": "Ha habido un error accediendo al archivo XMLTV. Por favor, asegúrate de que existe e inténtalo de nuevo.", + "ErrorAddingXmlTvFile": "Ha sucedido un error accediendo al archivo XML. Por favor, asegúrate que el archivo existe e inténtalo de nuevo.", "ErrorGettingTvLineups": "Ha habido un error descargando la programación de TV. Por favor, asegúrese que la información es correcta e inténtalo de nuevo.", "ErrorMessageStartHourGreaterThanEnd": "La hora de finalización tiene que ser mayor que la de inicio.", "ErrorPleaseSelectLineup": "Por favor selecciona una alineación e inténtalo otra vez. Si no hay alineaciones disponibles, revisa que tu nombre de usuario, contraseña y código postal son correctos.", @@ -215,10 +215,10 @@ "Guide": "Guía", "GuideProviderSelectListings": "Seleccionar listados", "H264CrfHelp": "El factor de velocidad constante (CRF) es el ajuste de calidad predeterminado para el codificador x264. Puede establecer los valores entre 0 y 51, donde valores más bajos resultarían en una mejor calidad (a expensas de tamaños de archivo más altos). Los valores sanos están entre 18 y 28. El valor predeterminado para x264 es 23, por lo que puede utilizar esto como punto de partida.", - "H264EncodingPresetHelp": "Elija un valor más rápido para mejorar el rendimiento o un valor más lento para mejorar la calidad.", + "EncoderPresetHelp": "Elija un valor más rápido para mejorar el rendimiento o un valor más lento para mejorar la calidad.", "HDPrograms": "Programas en HD", "HandledByProxy": "Gestionado por proxy inverso", - "HardwareAccelerationWarning": "Activar la aceleración por hardware puede producir inestabilidades en algunos ambientes. Asegúrate de que tu sistema operativo y tus controladores de vídeo están actualizados. Si tienes dificultades para reproducir los vídeos después de activar esto, tendrás que volver a poner este ajuste en Auto.", + "HardwareAccelerationWarning": "Activar la aceleración por hardware puede producir inestabilidades en algunos entornos. Asegúrate de que tu sistema operativo y tus controladores de vídeo están actualizados. Si tienes dificultades para reproducir los vídeos después de activar esto, tendrás que volver a poner este ajuste en None.", "HeaderAccessSchedule": "Horario de acceso", "HeaderAccessScheduleHelp": "Crea un horario de acceso para limitar el acceso a determinadas horas.", "HeaderActiveDevices": "Dispositivos activos", @@ -304,13 +304,13 @@ "HeaderItems": "Elementos", "HeaderKeepRecording": "Mantener grabación", "HeaderKeepSeries": "Mantener series", - "HeaderKodiMetadataHelp": "Para habilitar o deshabilitar metadatos NFO, edite una biblioteca en la configuración de la biblioteca Jellyfin y localice la sección de metadatos.", + "HeaderKodiMetadataHelp": "Puedes activar o desactivar las etiquetas en formato NFO abriendo la configuración de una biblioteca y revisando los ajustes en la sección de etiquetas.", "HeaderLatestEpisodes": "Últimos episodios", "HeaderLatestMedia": "Últimos medios", "HeaderLatestMovies": "Últimas películas", "HeaderLatestMusic": "Última música", "HeaderLatestRecordings": "Últimas grabaciones", - "HeaderLibraries": "Blibliotecas", + "HeaderLibraries": "Bibliotecas", "HeaderLibraryAccess": "Acceso a la biblioteca", "HeaderLibraryFolders": "Carpetas de la biblioteca", "HeaderLibraryOrder": "Orden de la biblioteca", @@ -322,7 +322,7 @@ "HeaderMedia": "Medios", "HeaderMediaFolders": "Carpetas de medios", "HeaderMediaInfo": "Información multimedia", - "HeaderMetadataSettings": "Ajustes de metadatos", + "HeaderMetadataSettings": "Ajustes de etiquetas", "HeaderMoreLikeThis": "Más como este", "HeaderMovies": "Películas", "HeaderMusicVideos": "Vídeos musicales", @@ -349,7 +349,7 @@ "HeaderPlaybackError": "Error de reproducción", "HeaderPleaseSignIn": "Por favor, inicie sesión", "HeaderPluginInstallation": "Instalación del complemento", - "HeaderPreferredMetadataLanguage": "Idioma preferido para los metadatos", + "HeaderPreferredMetadataLanguage": "Idioma preferido para las etiquetas", "HeaderProfile": "Perfil", "HeaderProfileInformation": "Información del perfil", "HeaderProfileServerSettingsHelp": "Estos valores controlan como el servidor Jellyfin se presenta al dispositivo.", @@ -369,8 +369,8 @@ "HeaderSeasons": "Temporadas", "HeaderSecondsValue": "{0} segundos", "HeaderSelectCertificatePath": "Elige la ruta del certificado", - "HeaderSelectMetadataPath": "Seleccione la ruta para Metadatos", - "HeaderSelectMetadataPathHelp": "Busque o escriba la ruta donde desea almacenar los metadatos. La carpeta debe tener permiso de escritura.", + "HeaderSelectMetadataPath": "Seleccione la ruta para las etiquetas", + "HeaderSelectMetadataPathHelp": "Busque o escriba la ruta donde almacenar las etiquetas. La carpeta debe tener permiso de escritura.", "HeaderSelectPath": "Elige ruta", "HeaderSelectServer": "Selecionar servidor", "HeaderSelectServerCachePath": "Seleccione la ruta para el caché del servidor", @@ -420,12 +420,12 @@ "Help": "Ayuda", "Hide": "Ocultar", "HideWatchedContentFromLatestMedia": "Esconder medios vistos de los medios más recientes", - "HttpsRequiresCert": "Para habilitar las conexiones seguras, deberás proporcionar un certificado SSL de confianza, como los de Let's Encrypt. Por favor, proporciona un certificado o deshabilita las conexiones seguras.", + "HttpsRequiresCert": "Para activar la conexión segura, necesitas un certificado SSL de confianza, como Let's Encrypt. De lo contrario, desactive las conexiones seguras.", "Identify": "Identificar", "Images": "Imágenes", "ImportFavoriteChannelsHelp": "Si está activado, sólo los canales guardados como favoritos en el sintonizador se importarán.", "ImportMissingEpisodesHelp": "Si está activada, la información sobre los episodios que faltan se importará en su base de datos Jellyfin y se mostrará en temporadas y series. Esto puede causar exploraciones de bibliotecas significativamente más largas.", - "InstallingPackage": "Instalando {0}", + "InstallingPackage": "Instalando {0} (versión {1})", "InstantMix": "Mix instantáneo", "ItemCount": "Elementos {0}", "Items": "Elemento", @@ -459,7 +459,7 @@ "LabelArtists": "Artistas:", "LabelArtistsHelp": "Separar múltiples artistas usando ;", "LabelAudioLanguagePreference": "Idioma de audio preferido:", - "LabelAutomaticallyRefreshInternetMetadataEvery": "Actualizar los metadatos automáticamente de internet:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Actualizar las etiquetas automáticamente desde Internet:", "LabelBindToLocalNetworkAddress": "Vincular a la dirección de red local:", "LabelBindToLocalNetworkAddressHelp": "Opcional. Anule la dirección IP local para enlazar el servidor HTTP. Si se deja vacío, el servidor se enlazará a todas las direcciones disponibles. Para cambiar este valor, debe reiniciar el servidor Jellyfin.", "LabelBirthDate": "Fecha de nacimiento:", @@ -489,7 +489,7 @@ "LabelCustomRating": "Valoración pesonalizada:", "LabelDateAdded": "Fecha de añadido:", "LabelDateAddedBehavior": "Comportamiento de la fecha añadida para contenido nuevo:", - "LabelDateAddedBehaviorHelp": "Si un valor de metadato está disponible su usará siempre antes que ninguna de esas opciones.", + "LabelDateAddedBehaviorHelp": "Si el elemento tiene etiquetas que contengan información sobre la fecha de creación, independientemente de lo seleccionado aquí, se utilizarán para ordenar el contenido.", "LabelDay": "Día:", "LabelDeathDate": "Fecha de muerte:", "LabelDefaultUser": "Usuario por defecto:", @@ -511,7 +511,7 @@ "LabelEmbedAlbumArtDidl": "Incorporar la carátula del álbum en didl", "LabelEmbedAlbumArtDidlHelp": "Algunos dispositivos prefieren este método para obtener la carátula del álbum. Otros pueden fallar al reproducir con esta opción habilitada.", "LabelEnableAutomaticPortMap": "Habilitar asignación de puertos automático", - "LabelEnableAutomaticPortMapHelp": "UPnP permite la configuración del router para acceso externo de forma fácil y automática. Esto puede no funcionar en algunos modelos de routers.", + "LabelEnableAutomaticPortMapHelp": "UPnP permite la configuración del router para acceso externo de forma fácil y automática. Esto puede no funcionar en algunos modelos de routers. Los cambios no se aplicarán hasta que el servidor sea reiniciado.", "LabelEnableBlastAliveMessages": "Explotar mensajes en vivo", "LabelEnableBlastAliveMessagesHelp": "Active aquí si el servidor no es detectado correctamente por otros dispositivos UPnP en su red.", "LabelEnableDlnaClientDiscoveryInterval": "Intervalo de detección de cliente (segundos)", @@ -544,9 +544,9 @@ "LabelGroupMoviesIntoCollections": "Agrupar películas en colecciones", "LabelGroupMoviesIntoCollectionsHelp": "Cuando se muestran las listas de películas, las películas pertenecientes a una colección se mostrarán como un elemento agrupado.", "LabelH264Crf": "H264 que codifica CRF:", - "LabelH264EncodingPreset": "Configuración de codificación H264:", + "LabelEncoderPreset": "Configuración de codificación H264:", "LabelHardwareAccelerationType": "Aceleración por hardware:", - "LabelHardwareAccelerationTypeHelp": "Esto es una función experimental disponible sólo en los sistemas soportados.", + "LabelHardwareAccelerationTypeHelp": "La aceleración por hardware requiere configuración adicional.", "LabelHomeScreenSectionValue": "Sección de la pantalla de inicio {0}:", "LabelHttpsPort": "Puerto local HTTPS:", "LabelHttpsPortHelp": "Puerto TCP al que el servidor HTTPS de Jellyfin debe de ser enlazado.", @@ -595,15 +595,15 @@ "LabelMaxStreamingBitrateHelp": "Especifica la tasa de bits máxima de la transmisión.", "LabelMessageText": "Mensaje de texto:", "LabelMessageTitle": "Título del mensaje:", - "LabelMetadata": "Metadatos:", + "LabelMetadata": "Etiquetas:", "LabelMetadataDownloadLanguage": "Idioma preferido de visualizado:", - "LabelMetadataDownloadersHelp": "Activa y ordena tus descargadores de metadatos por prioridad. Los que tengan menor prioridad se sólo se utilizarán para llenar la información faltante.", - "LabelMetadataPath": "Ruta de los metadatos:", - "LabelMetadataPathHelp": "Especifica una ruta para los pósteres y metadatos.", - "LabelMetadataReaders": "Lectores de metadatos:", - "LabelMetadataReadersHelp": "Ordena tus fuentes de metadatos locales por prioridad. Se leerá el primer archivo encontrado.", - "LabelMetadataSavers": "Almacenadores de metadatos:", - "LabelMetadataSaversHelp": "Elige el formato de archivo para guardar tus metadatos.", + "LabelMetadataDownloadersHelp": "Activa y ordena estos proveedores de etiquetas por prioridad. Los que tengan menor prioridad sólo se utilizarán para completar la información que falte.", + "LabelMetadataPath": "Ruta de las etiquetas:", + "LabelMetadataPathHelp": "Especifica una ruta para las imágenes y las etiquetas.", + "LabelMetadataReaders": "Lectores de etiquetas:", + "LabelMetadataReadersHelp": "Ordena los proveedores de etiquetas locales por prioridad. Se leerá el primer archivo encontrado.", + "LabelMetadataSavers": "Formato de etiquetas:", + "LabelMetadataSaversHelp": "Elige el formato de archivo para guardar las etiquetas.", "LabelMethod": "Método:", "LabelMinBackdropDownloadWidth": "Anchura mínima de descarga de imágenes de fondo:", "LabelMinResumeDuration": "Duración mínima de reanudación:", @@ -676,8 +676,8 @@ "LabelRemoteClientBitrateLimit": "Límite de la transmisión de tasa de bits por internet (Mbps):", "LabelRemoteClientBitrateLimitHelp": "Un límite opcional de tasa de bits para todos los dispositivos fuera de la red. Esto es útil para evitar que los dispositivos soliciten una tasa de bits más alta que la que su conexión a Internet puede manejar. Esto puede ocasionar una mayor carga de la CPU en su servidor para transcodificar vídeos sobre la marcha a una tasa de bits más baja.", "LabelRuntimeMinutes": "Tiempo de ejecución (minutos):", - "LabelSaveLocalMetadata": "Guardar imágenes y metadatos en las carpetas de medios", - "LabelSaveLocalMetadataHelp": "Guardar imágenes y metadatos directamente en las carpetas de medios, permitirá colocarlas en un lugar donde se pueden editar fácilmente.", + "LabelSaveLocalMetadata": "Guardar imágenes y etiquetas en las carpetas de medios", + "LabelSaveLocalMetadataHelp": "Guardar imágenes y etiquetas directamente en las carpetas en las que estén los elementos hará que se puedan editar más fácilmente.", "LabelScheduledTaskLastRan": "Última ejecución {0}, tardando {1}.", "LabelScreensaver": "Salvapantallas:", "LabelSeasonNumber": "Número de temporada:", @@ -729,7 +729,7 @@ "LabelTunerIpAddress": "IP del sintonizador:", "LabelTunerType": "Tipo de sintonizador:", "LabelType": "Tipo:", - "LabelTypeMetadataDownloaders": "{0} descargadores de metadatos:", + "LabelTypeMetadataDownloaders": "Proveedores de etiquetas para {0}:", "LabelTypeText": "Texto", "LabelUseNotificationServices": "Usar los siguientes servicios:", "LabelUser": "Usuario:", @@ -754,7 +754,7 @@ "LanNetworksHelp": "Lista de direcciones IP separadas por comas o entradas de dirección IP / máscara de red para redes que se considerarán en la red local al imponer restricciones de ancho de banda. Si se establece, todas las demás direcciones IP se considerarán en la red externa y estarán sujetas a las restricciones de ancho de banda externo. Si se deja en blanco, solo se considera que la subred del servidor está en la red local.", "Large": "Grande", "LatestFromLibrary": "Reciente en {0}", - "LibraryAccessHelp": "Seleccione las bibliotecas a compartir con este usuario. Los administradores podrán editar todas las carpetas usando el gestor de metadatos.", + "LibraryAccessHelp": "Seleccione las bibliotecas a compartir con este usuario. Los administradores podrán editar todas las carpetas usando el gestor de etiquetas.", "Like": "Me gusta", "Live": "Directo", "LiveBroadcasts": "Emisiones en vivo", @@ -818,25 +818,25 @@ "MessageItemSaved": "Elemento grabado.", "MessageItemsAdded": "Ítems añadidos.", "MessageLeaveEmptyToInherit": "Dejar en blanco para heredar la configuración del elemento padre, o el valor global por defecto.", - "MessageNoAvailablePlugins": "No hay complementos disponibles.", + "MessageNoAvailablePlugins": "No hay extensiones disponibles.", "MessageNoMovieSuggestionsAvailable": "No hay sugerencias de películas disponibles. Comience ver y calificar sus películas y vuelva para ver las recomendaciones.", - "MessageNoPluginsInstalled": "No tiene complementos instalados.", + "MessageNoPluginsInstalled": "No hay extensiones instaladas.", "MessageNoTrailersFound": "No se han encontrado tráilers. Instala el canal de tráilers para mejorar su experiencia añadiendo una biblioteca de tráilers por internet.", "MessageNothingHere": "Nada aquí.", "MessagePasswordResetForUsers": "Se ha restablecido las contraseñas a los siguientes usuarios. Ahora pueden iniciar sesión con los códigos PIN que usaron para el restablecimiento.", - "MessagePleaseEnsureInternetMetadata": "Por favor, asegúrese que la descarga de metadatos de internet está habilitada.", + "MessagePleaseEnsureInternetMetadata": "Asegúrate de que la descarga de etiquetas desde internet está activada.", "MessagePleaseWait": "Por favor, espere.", "MessagePluginConfigurationRequiresLocalAccess": "Para configurar este complemento inicia sesión en tu servidor local directamente.", - "MessagePluginInstallDisclaimer": "Los complementos creados por los miembros de la comunidad de Jellyfin son una buena forma de mejorar tu experiencia Jellyfin con características adicionales y otros beneficios. Antes de instalarlos considera los efectos que pueden tener en tu servidor Jellyfin, como escaneos de la biblioteca más largos, procesado en segundo plano adicional y una reducción de la estabilidad del sistema.", + "MessagePluginInstallDisclaimer": "Las extensiones creadas por los miembros de la comunidad de Jellyfin son una buena forma de mejorar tu experiencia con características adicionales y otros beneficios. Antes de instalarlos considera los efectos que pueden tener en tu servidor Jellyfin, como escaneos de la biblioteca más largos, procesado en segundo plano adicional y una reducción de la estabilidad del sistema.", "MessageReenableUser": "Mira abajo para reactivarlo", "MessageSettingsSaved": "Ajustes guardados.", "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Se eliminarán las siguientes ubicaciones de medios de tu biblioteca:", "MessageUnableToConnectToServer": "No podemos conectar con el servidor seleccionado ahora mismo. Por favor, asegúrate de que esta funcionando e inténtalo otra vez.", "MessageUnsetContentHelp": "El contenido se mostrará como carpetas planas. Para tener mejores resultados utiliza el gestor de metadatos para establecer los tipos de contenidos de las sub-carpetas.", "MessageYouHaveVersionInstalled": "Actualmente tienes la versión {0} instalada.", - "Metadata": "Metadatos", - "MetadataManager": "Administrador de metadatos", - "MetadataSettingChangeHelp": "El cambio de la configuración de metadatos afectará al nuevo contenido que se añada en el futuro. Para actualizar el contenido existente, abra la pantalla de detalles y haga clic en el botón Actualizar o realice actualizaciones masivas utilizando el administrador de metadatos.", + "Metadata": "Etiquetas", + "MetadataManager": "Administrador de etiquetas", + "MetadataSettingChangeHelp": "Este cambio afectará al nuevo contenido que se añada en el futuro. Para actualizar el contenido existente abra la pantalla de detalles y haga clic en el botón \"Actualizar\". También se pueden actualizar todas las etiquetas a la vez utilizando el administrador de etiquetas.", "MinutesAfter": "minutos después", "MinutesBefore": "minutos antes", "Mobile": "Móvil", @@ -869,7 +869,7 @@ "OneChannel": "Un canal", "OnlyForcedSubtitles": "Solo subtítulos forzados", "OnlyForcedSubtitlesHelp": "Solo se cargarán los subtítulos marcados como forzados.", - "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB, etc.)", + "OnlyImageFormats": "Solo formatos de imagen (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Administradores", "OptionAlbum": "Álbum", "OptionAlbumArtist": "Artista de álbum", @@ -928,7 +928,6 @@ "OptionEnableAccessFromAllDevices": "Habilitar acceso desde todos los equipos", "OptionEnableAccessToAllChannels": "Habilitar acceso a todos los canales", "OptionEnableAccessToAllLibraries": "Habilitar acceso a todas las bibliotecas", - "OptionEnableAutomaticServerUpdates": "Activar actualizaciones automáticas del servidor", "OptionEnableExternalContentInSuggestions": "Habilitar contenido externo en sugerencias", "OptionEnableExternalContentInSuggestionsHelp": "Permite incluir los tráilers de Internet y los programas de TV en vivo en el contenido sugerido.", "OptionEnableForAllTuners": "Activar para todos los dispositivos sintonizadores", @@ -958,7 +957,7 @@ "OptionMissingEpisode": "Episodios que faltan", "OptionMonday": "Lunes", "OptionNameSort": "Nombre", - "OptionNew": "Nuevo...", + "OptionNew": "Nuevo…", "OptionNone": "Nada", "OptionOnAppStartup": "Al iniciar la aplicación", "OptionOnInterval": "En un intervalo", @@ -982,14 +981,14 @@ "OptionResumable": "Se puede continuar", "OptionRuntime": "Tiempo", "OptionSaturday": "Sábado", - "OptionSaveMetadataAsHidden": "Guardar los metadatos e imágenes como archivos ocultos", - "OptionSaveMetadataAsHiddenHelp": "Cambiar esto se aplicará a los nuevos metadatos guardados en el futuro. Los archivos de metadatos existentes se actualizarán la próxima vez que sean guardados por el servidor Jellyfin.", + "OptionSaveMetadataAsHidden": "Guardar las etiquetas e imágenes como archivos ocultos", + "OptionSaveMetadataAsHiddenHelp": "La configuración se aplicará a las nuevas etiquetas que se creen. Las etiquetas existentes se actualizarán la próxima vez que sean guardadas por Jellyfin.", "OptionSpecialEpisode": "Especiales", "OptionSunday": "Domingo", "OptionThursday": "Jueves", "OptionTrackName": "Nombre de pista", "OptionTuesday": "Martes", - "OptionTvdbRating": "Puntuación TVDB", + "OptionTvdbRating": "Valoración TVDB", "OptionUnairedEpisode": "Episodios no emitidos", "OptionUnplayed": "No reproducido", "OptionWakeFromSleep": "Despertar", @@ -999,10 +998,10 @@ "OptionWeekly": "Semanal", "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": "Calificación de los padres", + "PackageInstallCancelled": "{0} (versión {1}) instalación cancelada.", + "PackageInstallCompleted": "{0} (versión {1}) instalación completada.", + "PackageInstallFailed": "{0} (versión {1}) instalación fallida.", + "ParentalRating": "Clasificación parental", "PasswordMatchError": "La contraseña y la confirmación de la contraseña deben de ser iguales.", "PasswordResetComplete": "La contraseña se ha restablecido.", "PasswordResetConfirmation": "¿Esta seguro de que desea restablecer la contraseña?", @@ -1025,7 +1024,7 @@ "PleaseSelectTwoItems": "Seleccione al menos dos elementos.", "PluginInstalledMessage": "El complemento se ha instalado correctamente. El servidor Jellyfin deberá reiniciarse para que los cambios surjan efecto.", "PreferEmbeddedTitlesOverFileNames": "Preferir títulos incrustados sobre los nombres de archivo", - "PreferEmbeddedTitlesOverFileNamesHelp": "Esto determina el título por defecto cuando no hay ningún metadato de internet o local.", + "PreferEmbeddedTitlesOverFileNamesHelp": "Esto determina el título que se utilizará cuando un elemento no tenga etiquetas ni estas se hayan podido descargar de Internet.", "PreferredNotRequired": "Preferido, pero no requerido", "Premieres": "Estrenos", "Previous": "Anterior", @@ -1048,7 +1047,7 @@ "RecordingScheduled": "Grabación programada.", "Recordings": "Grabaciones", "Refresh": "Refrescar", - "RefreshMetadata": "Actualizar metadatos", + "RefreshMetadata": "Actualizar etiquetas", "RefreshQueued": "Actualización programada.", "ReleaseDate": "Fecha de lanzamiento", "RememberMe": "Recuérdame", @@ -1059,7 +1058,7 @@ "RepeatEpisodes": "Repetir episodios", "RepeatMode": "Modo de repetición", "RepeatOne": "Repetir uno", - "ReplaceAllMetadata": "Reemplazar todos los metadatos", + "ReplaceAllMetadata": "Reemplazar todas las etiquetas", "ReplaceExistingImages": "Reemplazar imágenes existentes", "RequiredForAllRemoteConnections": "Requerido para todas las conexiones remotas", "ResumeAt": "Continuar desde {0}", @@ -1075,8 +1074,8 @@ "Screenshot": "Captura de pantalla", "Screenshots": "Capturas de pantalla", "Search": "Buscar", - "SearchForCollectionInternetMetadata": "Buscar en internet ilustraciones y metadatos", - "SearchForMissingMetadata": "Buscar metadatos faltantes", + "SearchForCollectionInternetMetadata": "Buscar en internet imágenes y etiquetas", + "SearchForMissingMetadata": "Buscar etiquetas que falten", "SearchForSubtitles": "Búsqueda de subtítulos", "SearchResults": "Resultados de la búsqueda", "SendMessage": "Enviar mensaje", @@ -1094,10 +1093,10 @@ "Share": "Compartir", "ShowAdvancedSettings": "Mostrar opciones avanzadas", "ShowIndicatorsFor": "Mostrar indicaciones para:", - "Shows": "Series", + "Shows": "Mostrar", "Shuffle": "Mezclar", "SimultaneousConnectionLimitHelp": "Número máximo de transmisiones simultáneas permitidas. Pon 0 para no tener límite.", - "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya están en mi librería", + "SkipEpisodesAlreadyInMyLibrary": "No grabar episodios que ya están en mi biblioteca", "SkipEpisodesAlreadyInMyLibraryHelp": "Los episodios serán comparados usando el número de temporada y de episodio, cuando estén disponibles.", "Small": "Pequeño", "Smart": "Inteligente", @@ -1135,12 +1134,12 @@ "TabLatest": "Novedades", "TabLibrary": "Biblioteca", "TabLiveTV": "Televisión en directo", - "TabMetadata": "Metadatos", + "TabMetadata": "Etiquetas", "TabMovies": "Películas", "TabMusic": "Música", "TabMusicVideos": "Videos musicales", - "TabMyPlugins": "Mis complementos", - "TabNetworks": "redes", + "TabMyPlugins": "Mis extensiones", + "TabNetworks": "Cadenas", "TabNfoSettings": "Ajustes de NFO", "TabNotifications": "Notificaciones", "TabOther": "Otros", @@ -1217,9 +1216,9 @@ "XmlDocumentAttributeListHelp": "Estos atributos se aplican al elemento raíz de cada respuesta XML.", "XmlTvKidsCategoriesHelp": "Los programas con estas categorías se mostrarán como programas para niños. Separe el múltiplo con '|'.", "XmlTvMovieCategoriesHelp": "Los programas con estas categorías se mostrarán como películas. Separe el múltiplo con '|'.", - "XmlTvNewsCategoriesHelp": "Los programas con estas categorías se mostrarán como programas de noticias. Separe el múltiplo con '|'.", - "XmlTvPathHelp": "Ruta al archivo XML de TV. Jellyfin leerá este archivo y comprobará periódicamente si hay actualizaciones. Usted es responsable de crear y actualizar el archivo.", - "XmlTvSportsCategoriesHelp": "Los programas con estas categorías se mostrarán como programas deportivos. Separe el múltiplo con '|'.", + "XmlTvNewsCategoriesHelp": "Los programas con estas categorías se mostrarán como programas de noticias. Puede poner múltiples categorías separándolas con '|'.", + "XmlTvPathHelp": "Ruta al archivo XML TV. Jellyfin leerá este archivo y comprobará periódicamente si hay actualizaciones. Usted es responsable de crear y actualizar el archivo.", + "XmlTvSportsCategoriesHelp": "Los programas con estas categorías se mostrarán como programas deportivos. Puede poner múltiples categorías separándolas con '|'.", "Yes": "Sí", "Yesterday": "Ayer", "Absolute": "Absoluto", @@ -1235,9 +1234,9 @@ "Auto": "Automático", "AutoBasedOnLanguageSetting": "Automático (basado en la configuración de idioma)", "Banner": "Pancarta", - "BurnSubtitlesHelp": "Determina si el servidor debería incrustar los subtítulos al convertir el vídeo dependiendo del formato de los subtítulos. Evitar incrustar los subtítulos mejorará el rendimiento del servidor. Selecciona Auto para incrustar subtítulos basados en imágenes (VOBSUB, PGS, SUB/IDX, etc.) y algunos subtítulos de tipo ASS/SSA.", + "BurnSubtitlesHelp": "Determina si el servidor debe grabar los subtítulos en el vídeo al transcodificar. Desactivar esta opción puede mejorar el rendimiento. Seleccione 'Auto' para grabar formatos basados en imágenes (VOBSUB, PGS, SUB/IDX) y ciertos subtítulos ASS o SSA.", "ButtonInfo": "Información", - "ChangingMetadataImageSettingsNewContent": "Los cambios a la configuración de descarga de metadatos o arte sólo se aplicará al nuevo contenido añadido a la biblioteca. Para aplicar los cambios a los títulos existentes, necesitarás actualizar los metadatos manualmente.", + "ChangingMetadataImageSettingsNewContent": "Los cambios a la configuración de descarga de etiquetas e imágenes sólo se aplicará al nuevo contenido que se añada a la biblioteca. Para aplicar los cambios a los elementos existentes necesitarás actualizar las etiquetas manualmente.", "ColorPrimaries": "Colores primarios", "ColorSpace": "Espacio de color", "ColorTransfer": "Transferencia de color", @@ -1249,16 +1248,15 @@ "Descending": "Descendiente", "DirectStreamHelp1": "El tipo de archivo (H.264, AC3, etc.) y la resolución son compatibles con el dispositivo, pero no el contenedor (mkv, avi, wmv, etc.). El vídeo será re-empaquetado al vuelo antes de transmitirlo al dispositivo.", "DirectStreamHelp2": "La transmisión directa del archivo usa muy poco procesamiento sin ninguna pérdida de calidad en el vídeo.", - "Director": "Director", - "DirectorValue": "Director: {0}", - "DirectorsValue": "Directores: {0}", + "Director": "Dirección de", + "Directors": "Directores", "Display": "Mostrar", "DisplayInMyMedia": "Mostrar en la pantalla de inicio", "DisplayInOtherHomeScreenSections": "Mostrar en las secciones de la pantalla de inicio al igual que \"últimos\" y \"continuar viendo\"", "DisplayMissingEpisodesWithinSeasons": "Mostrar episodios ausentes en las temporadas", "DisplayMissingEpisodesWithinSeasonsHelp": "Esto también debe ser habilitado para la biblioteca de TV en la configuración del servidor.", - "DropShadow": "Sombra", - "EditMetadata": "Editar metadatos", + "DropShadow": "Eliminar sombra", + "EditMetadata": "Editar etiquetas", "EnableBackdrops": "Imágenes de fondo", "EnableBackdropsHelp": "Mostrar imágenes de fondo en algunas páginas mientras se explora la biblioteca.", "EnableColorCodedBackgrounds": "Fondos con código de colores", @@ -1273,8 +1271,7 @@ "Filters": "Filtros", "Folders": "Carpetas", "General": "General", - "GenreValue": "Género: {0}", - "GenresValue": "Géneros: {0}", + "Genre": "Género", "GroupBySeries": "Agrupar por series", "GuideProviderLogin": "Credenciales", "HeaderAlbumArtists": "Artistas del álbum", @@ -1291,7 +1288,7 @@ "HeaderVideoType": "Tipo de vídeo", "Home": "Inicio", "Horizontal": "Horizontal", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelBurnSubtitles": "Incrustar subtítulos:", "LabelDashboardTheme": "Tema para la interfaz del servidor:", "LabelDateTimeLocale": "Fecha y hora local:", @@ -1309,10 +1306,10 @@ "LabelSortBy": "Ordenar por:", "LabelSortOrder": "Orden:", "LabelSoundEffects": "Efectos de sonido:", - "LabelSubtitles": "Subtítulos:", + "LabelSubtitles": "Subtítulos", "LabelTVHomeScreen": "Modo televisión en pantalla de inicio:", "LabelVersion": "Versión:", - "LabelVideo": "Vídeo:", + "LabelVideo": "Vídeo", "LabelXDlnaCap": "X-DNLA cap:", "LabelXDlnaDoc": "X-DLNA doc:", "LearnHowYouCanContribute": "Descubre cómo puedes contribuir.", @@ -1368,7 +1365,7 @@ "DashboardServerName": "Servidor: {0}", "DashboardOperatingSystem": "Sistema operativo: {0}", "DashboardArchitecture": "Arquitectura: {0}", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "LaunchWebAppOnStartup": "Iniciar la aplicación web al iniciar el servidor", "LaunchWebAppOnStartupHelp": "Abrir el cliente web en el navegador por defecto al iniciar el servidor. Esto no ocurrirá al utilizar la función de reinicio del servidor.", "MediaInfoSoftware": "Software", @@ -1402,13 +1399,13 @@ "PlayCount": "Reproducciones", "Premiere": "Estreno", "Raised": "Elevación", - "RefreshDialogHelp": "Los metadatos se actualizan basados en las configuraciones y los servicios de internet habilitados en el panel del servidor Jellyfin.", + "RefreshDialogHelp": "Las etiquetas se actualizan basándose en las configuraciones y los servicios de internet activados desde el panel de control de Jellyfin.", "RestartPleaseWaitMessage": "Por favor, espera mientras el servidor Jellyfin se reinicia. Esto puede tardar un minuto o dos.", "RunAtStartup": "Ejecutar al iniciar", "Series": "Series", "SeriesDisplayOrderHelp": "Ordena los episodios por fecha de emisión, orden de DVD o número absoluto.", - "ShowTitle": "Título del show", - "ShowYear": "Año del show", + "ShowTitle": "Mostrar título", + "ShowYear": "Mostrar año", "SmallCaps": "Letras minúsculas", "Smaller": "Más pequeño", "Sort": "Ordenar", @@ -1419,7 +1416,7 @@ "TV": "Televisión", "TabInfo": "Info", "TabLogs": "Registros", - "TabPlugins": "Complementos", + "TabPlugins": "Extensiones", "TabSeries": "Series", "TabTrailers": "Tráilers", "TagsValue": "Etiquetas: {0}", @@ -1458,6 +1455,64 @@ "MusicLibraryHelp": "Revisar la {0}guía de nombres de música{1}.", "FetchingData": "Obteniendo datos adicionales", "ButtonAddImage": "Añadir imagen", - "HeaderFavoritePeople": "Personas favoritas", - "OptionRandom": "Aleatorio" + "HeaderFavoritePeople": "Gente favorita", + "OptionRandom": "Aleatorio", + "SelectAdminUsername": "Por favor seleccione un nombre de usuario para la cuenta administrador.", + "ButtonSplit": "Dividir", + "HeaderNavigation": "Navegación", + "MessageConfirmAppExit": "¿Quieres salir?", + "EnableFastImageFadeInHelp": "Las imágenes que hayan terminado de cargarse mostrarán una pequeña animación", + "EnableFastImageFadeIn": "Cargar las imágenes suavemente", + "CopyStreamURLError": "Ha habido un error copiando la dirección.", + "AllowFfmpegThrottlingHelp": "Cuando una transcodificación o un remux se adelanta lo suficiente desde la posición de reproducción actual, pause el proceso para que consuma menos recursos. Esto es más útil cuando se reproduce de forma linear, sin saltar de posición de reproducción a menudo. Desactívelo si experimenta problemas de reproducción.", + "PlaybackErrorNoCompatibleStream": "Este contenido no es compatible con este dispositivo y no se puede reproducir: No se puede obtener del servidor en un formato compatible.", + "OptionForceRemoteSourceTranscoding": "Forzar la transcodificación para fuentes remotas de medios (como LiveTV)", + "NoCreatedLibraries": "Parece que aún no se han creado librearías. {0}¿Quiere crear una ahora?{1}", + "LabelVideoResolution": "Resolución de video:", + "LabelStreamType": "Tipo de stream:", + "LabelPlayerDimensions": "Dimensiones del reproductor:", + "LabelDroppedFrames": "Frames perdidos:", + "LabelCorruptedFrames": "Frames corruptos:", + "AskAdminToCreateLibrary": "Solo un administrador puede crear librerías.", + "AllowFfmpegThrottling": "Acelerar transcodificación", + "ClientSettings": "Ajustes de cliente", + "PreferEmbeddedEpisodeInfosOverFileNames": "Priorizar la información embebida sobre los nombres de archivos", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Usar la información de episodio de los metadatos embebidos si está disponible.", + "PathNotFound": "No se encontró la ruta especificada. Asegúrate de que existe e inténtalo de nuevo.", + "WriteAccessRequired": "Jellyfin requiere de permisos de escritura en esta carpeta. Asegúrate de que existe este permiso e inténtalo de nuevo.", + "ListPaging": "{0}-{1} de {2}", + "PersonRole": "como {0}", + "LastSeen": "Última vez {0}", + "DailyAt": "Diariamente a las {0}", + "WeeklyAt": "Los {0}s a las {1}", + "OnWakeFromSleep": "Al reanudar el servidor", + "EveryXMinutes": "Cada {0} minutos", + "EveryHour": "Cada hora", + "EveryXHours": "Cada {0} horas", + "OnApplicationStartup": "Al iniciarse el servidor", + "Track": "Pista", + "Season": "Temporada", + "ReleaseGroup": "Grupo de salida", + "Person": "Persona", + "OtherArtist": "Otro artista", + "Movie": "Película", + "Episode": "Episodio", + "BoxSet": "Box Set", + "Artist": "Artista", + "AlbumArtist": "Artista del álbum", + "Album": "Álbum", + "LabelDeinterlaceMethod": "Metodo de desentrelazar:", + "DeinterlaceMethodHelp": "Seleccione el método de desentrelazar para el transcodificar de contenido entrelazado.", + "LabelLibraryPageSize": "Tamaño de la página de la biblioteca:", + "LabelLibraryPageSizeHelp": "Establece la cantidad de artículos a mostrar en una página de la biblioteca. Ponlo en 0 para desactivar la paginación.", + "UnsupportedPlayback": "No es posible desencriptar contenido protegido mediante DRM; sin embargo se intentará su reproducción. Algunos archivos pueden aparecer completamente negros debido a encriptación u otras características no soportadas, como títulos interactivos.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "MessageUnauthorizedUser": "No tiene autorización para acceder al servidor en este momento. Póngase en contacto con el administrador del servidor para obtener más información.", + "ButtonTogglePlaylist": "Lista de reproducción", + "ButtonToggleContextMenu": "Más", + "Filter": "Filtro", + "New": "Nuevo", + "HeaderFavoritePlaylists": "Lista reproducción favorita", + "ApiKeysCaption": "Lista de las claves API actuales" } diff --git a/src/strings/es_DO.json b/src/strings/es_DO.json new file mode 100644 index 0000000000..7c42778a1c --- /dev/null +++ b/src/strings/es_DO.json @@ -0,0 +1,16 @@ +{ + "Add": "Añadir", + "Actor": "Actor", + "AccessRestrictedTryAgainLater": "El acceso está restringido actualmente. Inténtelo de nuevo más tarde.", + "Absolute": "Absoluto", + "HeaderAlbumArtists": "Artistas del Álbum", + "HeaderContinueWatching": "Continuar Viendo", + "Genres": "Géneros", + "Folders": "Carpetas", + "Favorites": "Favoritos", + "Collections": "Colecciones", + "Books": "Libros", + "Albums": "Álbumes", + "Artists": "Artistas", + "Channels": "Canales" +} diff --git a/src/strings/fa.json b/src/strings/fa.json index 7b7393c6b9..76f8ec4e2b 100644 --- a/src/strings/fa.json +++ b/src/strings/fa.json @@ -1,8 +1,8 @@ { "All": "همه", - "AllowMediaConversion": "اجازه تبدیل رسانه ها", - "AllowMediaConversionHelp": "دادن یا ندادن دسترسی به ویژگی تبدیل رسانه ها", - "AllowRemoteAccess": "اجازه دادن اتصال از راه دور به سرور Jellyfin", + "AllowMediaConversion": "اجازه تبدیل رسانه‌ها", + "AllowMediaConversionHelp": "دادن یا ندادن دسترسی به ویژگی تبدیل رسانه‌ها.", + "AllowRemoteAccess": "اجازه بدهید اتصال‌های از راه دور به این سرور Jellyfin متصل شوند.", "AllowRemoteAccessHelp": "اگرانتخاب نشود، تمامی اتصال های از راه دور بلوکه می شوند.", "Browse": "مرور کردن", "ButtonAddUser": "افزودن کاربر", @@ -19,11 +19,11 @@ "ButtonSort": "مرتب سازی", "DeleteMedia": "حذف رسانه", "Disabled": "غیرفعال شده", - "FolderTypeBooks": "کتاب ها", - "FolderTypeMovies": "سینمایی ها", - "FolderTypeMusic": "موسیقی", - "FolderTypeMusicVideos": "موزیک ویدئوها", - "FolderTypeTvShows": "سریال تلویزیونی", + "FolderTypeBooks": "کتاب‌ها", + "FolderTypeMovies": "فیلم‌ها", + "FolderTypeMusic": "موسیقی‌ها", + "FolderTypeMusicVideos": "موزیک ویدیوها", + "FolderTypeTvShows": "سریال‌های تلویزیونی", "HeaderAddUser": "اضافه کردن کاربر", "HeaderContinueWatching": "ادامه تماشا", "HeaderCustomDlnaProfiles": "پروفایل های سفارشی", @@ -33,9 +33,9 @@ "HeaderFilters": "فیلتر ها", "HeaderImageOptions": "گزینه های تصویر", "HeaderInstantMix": "درهم کردن فوری", - "HeaderKodiMetadataHelp": "برای فعال یا غیرفعال سازی متاداده های Nfo ، یک کتابخانه را در صفحه تنظیم کتابخانه Jellyfin ویرایش کرده و قسمت سرورهای متاداده را مسیردهی کنید.", + "HeaderKodiMetadataHelp": "برای فعال یا غیرفعال سازی ابرداده‌های Nfo ، یک کتابخانه را در صفحه تنظیم کتابخانه Jellyfin ویرایش کرده و قسمت سرورهای ابرداده را مسیردهی کنید.", "HeaderLatestEpisodes": "آخرین قسمت ها", - "HeaderNextUp": "بعدی", + "HeaderNextUp": "قسمت بعدی", "HeaderPaths": "مسیرها", "HeaderPlayAll": "پخش همه", "HeaderPreferredMetadataLanguage": "زبان مدنظر اطلاعات محتوی", @@ -45,15 +45,15 @@ "HeaderTypeImageFetchers": "{0} هماهنگ کننده تصویر", "HeaderUsers": "کاربران", "LabelAudioLanguagePreference": "اولویت زبان صدا:", - "LabelContentType": "نوع محتوی", - "LabelCountry": "کشور", + "LabelContentType": "نوع محتوا:", + "LabelCountry": "کشور:", "LabelCurrentPassword": "رمز فعلی:", - "LabelCustomCertificatePath": "مسیر اختصصای گواهینامه SSL:", + "LabelCustomCertificatePath": "مسیر اختصاصی گواهینامه SSL:", "LabelCustomCertificatePathHelp": "پچ به فایل PKCS #12 حاوی یک گواهینامه و کلید خصوصی است تا پشتیبانی از TLS را در یک دامنه شخصی فعال کند.", "LabelDisplayMissingEpisodesWithinSeasons": "نمایش قسمت های ناموجود در بین فصل ها", "LabelFinish": "پایان", - "LabelLanguage": "زبان", - "LabelMaxParentalRating": "حداکثر درجه سنی مجاز والدین", + "LabelLanguage": "زبان:", + "LabelMaxParentalRating": "حداکثر امتیاز سنی مجاز والدین:", "LabelNewPassword": "رمز جدید:", "LabelNewPasswordConfirm": "تایید رمز جدید:", "LabelNext": "بعدی", @@ -64,7 +64,7 @@ "LabelSecureConnectionsMode": "حالت اتصال ایمن:", "LabelSelectUsers": "انتخاب کاربران:", "LabelTimeLimitHours": "محدودیت زمان (ساعت):", - "LabelTypeMetadataDownloaders": "{0} دانلود کننده ی متاداده:", + "LabelTypeMetadataDownloaders": "{0} دانلود کننده فراداده:", "LabelYourFirstName": "اسم کوچک شما:", "LabelYoureDone": "به پایان رسید!", "LibraryAccessHelp": "انتخاب پوشه های رسانه برای اشتراک گذاری با این کاربر. مدیر سیستم میتواند با استفاده از مدیریت متاداده همه ی پوشه ها را ویرایش کند.", @@ -95,9 +95,9 @@ "TabArtists": "هنرمندان", "TabEpisodes": "قسمت ها", "TabGenres": "ژانرها", - "TabLatest": "آخرین", - "TabMetadata": "اطلاعات محتوی", - "TabMusicVideos": "موزیک ویدیو ها", + "TabLatest": "جدیدترین‌ها", + "TabMetadata": "فراداده", + "TabMusicVideos": "موزیک ویدیوها", "TabNetworks": "شبکه ها", "TabNotifications": "اعلان ها", "TabPassword": "رمز عبور", @@ -106,38 +106,601 @@ "TabProfiles": "پروفایل ها", "TabShows": "سریال ها", "TabSongs": "آهنگ ها", - "TabSuggestions": "پیشنهادات", + "TabSuggestions": "پیشنهادها", "TabUpcoming": "بزودی", "TellUsAboutYourself": "در مورد خودتان به ما بگویید", - "ThisWizardWillGuideYou": "این ویزارد برای انجام تنظیمات به شما کمک می کند. برای شروع، لطفا زبان مورد نظر خود را انتخاب فرمایید", + "ThisWizardWillGuideYou": "این عمل برای انجام تنظیمات به شما کمک می‌کند. برای شروع، لطفا زبان مورد نظر خود را انتخاب کنید.", "UserProfilesIntro": "Jellyfin دارای پشتیبانی داخلی از پروفایل کاربران می باشد. با فعال سازی هر کاربر، او می تواند تنظیمات ، وضعیت پخش و کنترل والدین خاص خودش را داشته باشد.", "WelcomeToProject": "به Jellyfin خوش آمدید!", - "WizardCompleted": "همه چیزی که فعلا می خواهیم همین است.جمع آوری اطلاعات کتابخانه های شما هم اکنون توسط Jellyfin آغاز شده است. اپلیکیشن های ما را امتحان کنید و سپس بر روی پایان کلیک کنید تا پیشخوان سرور را مشاهده نمایید.", - "Albums": "آلبوم ها", + "WizardCompleted": "همه چیزی که فعلا می‌خواهیم همین است. جمع آوری اطلاعات کتابخانه‌های شما هم اکنون توسط Jellyfin آغاز شده است. اپلیکیشن‌های ما را امتحان کنید و سپس بر روی پایان کلیک کنید تا پیشخوان سرور را مشاهده نمایید.", + "Albums": "آلبوم‌ها", "Artists": "هنرمندان", - "Books": "کتاب ها", - "Channels": "کانال ها", - "Collections": "کلکسیون ها", - "Favorites": "مورد علاقه ها", - "Folders": "پوشه ها", + "Books": "کتاب‌ها", + "Channels": "کانال‌ها", + "Collections": "مجموعه‌ها", + "Favorites": "مورد علاقه‌ها", + "Folders": "پوشه‌ها", "Genres": "ژانرها", "HeaderAlbumArtists": "هنرمندان آلبوم", - "HeaderFavoriteShows": "سریال های مورد علاقه", - "HeaderFavoriteEpisodes": "قسمت های مورد علاقه", - "HeaderFavoriteAlbums": "آلبوم های مورد علاقه", + "HeaderFavoriteShows": "سریال‌های مورد علاقه", + "HeaderFavoriteEpisodes": "قسمت‌های مورد علاقه", + "HeaderFavoriteAlbums": "آلبوم‌های مورد علاقه", "HeaderFavoriteArtists": "هنرمندان مورد علاقه", - "HeaderFavoriteSongs": "آهنگ های مورد علاقه", - "HeaderLiveTV": "پخش زنده تلویزیون", - "Movies": "فیلم های سینمایی", - "Photos": "عکس ها", - "Playlists": "لیست های پخش", - "Shows": "سریال ها", - "Songs": "آهنگ ها", - "Sync": "همگامسازی", - "ValueSpecialEpisodeName": "ویژه- {0}", - "AllEpisodes": "تمام قسمت ها", - "AllLanguages": "تمام زبان ها", - "AllLibraries": "تمام کتابخانه ها", - "AllowHWTranscodingHelp": "اگر فعال شود, اجازه میدهید تبدیل ( کم و زیاد کردن کیفیت ) درلحظه و توسط کارت دریافت سیگنال صورت گیرد. این کمک میکند به اینکه سرور جلیفین کمتر عمل تبدیل را انجام دهد.", - "AllowOnTheFlySubtitleExtraction": "اجازه میدهد در لحظه زیرنویس بازشود" + "HeaderFavoriteSongs": "آهنگ‌های مورد علاقه", + "HeaderLiveTV": "پخش زنده", + "Movies": "فیلم‌ها", + "Photos": "عکس‌ها", + "Playlists": "لیست‌های پخش", + "Shows": "سریال‌ها", + "Songs": "موسیقی‌ها", + "Sync": "همگام‌سازی", + "ValueSpecialEpisodeName": "ویژه - {0}", + "AllEpisodes": "تمام قسمت‌ها", + "AllLanguages": "تمام زبان‌ها", + "AllLibraries": "تمام کتابخانه‌ها", + "AllowHWTranscodingHelp": "اگر فعال شود, اجازه می‌دهید تبدیل کیفیت در لحظه انجام شود. این ممکن است به کاهش کدگذاری لازم برای Jellyfin منجر بشود.", + "AllowOnTheFlySubtitleExtraction": "اجازه می‌دهد در لحظه زیرنویس بازشود", + "Add": "افزودن", + "Actor": "بازیگر", + "AccessRestrictedTryAgainLater": "دسترسی در حال حاضر محدود شده است. لطفا دوباره تلاش کنید.", + "ButtonShuffle": "مخلوط کردن", + "ButtonSettings": "تنظیمات", + "ButtonSend": "ارسال", + "ButtonSelectView": "انتخاب نما", + "ButtonSelectServer": "انتخاب سرور", + "ButtonSearch": "جستجو", + "ButtonScanAllLibraries": "اسکن تمام کتابخانه‌ها", + "ButtonRevoke": "ابطال", + "ButtonResume": "ادامه", + "ButtonRestart": "راه اندازی مجدد", + "ButtonResetEasyPassword": "بازنشانی کد پین آسان", + "ButtonRepeat": "تکرار", + "ButtonRename": "تغییر نام", + "ButtonRemove": "حذف", + "ButtonRefreshGuideData": "به‌روز‌رسانی داده‌ی راهنما", + "ButtonRefresh": "به‌روز‌رسانی", + "ButtonProfile": "نمایه", + "ButtonNextTrack": "ترانه پسین", + "ButtonPreviousTrack": "ترانه پیشین", + "ButtonPause": "مکث", + "ButtonParentalControl": "رتبه بندی والدین", + "ButtonOpen": "باز", + "ButtonOff": "خاموش", + "ButtonNetwork": "شبکه", + "ButtonMore": "بیشتر", + "ButtonManualLogin": "ورود دستی", + "ButtonLibraryAccess": "دسترسی به کتابخانه", + "ButtonLearnMore": "بیشتر بدانید", + "ButtonInfo": "اطلاعات", + "ButtonHome": "خانه", + "ButtonHelp": "کمک", + "ButtonGuide": "راهنما", + "ButtonGotIt": "متوجه شدم", + "ButtonFullscreen": "تمام صفحه", + "ButtonForgotPassword": "فراموشی گذرواژه", + "ButtonEditImages": "ویرایش عکس‌ها", + "ButtonEdit": "ویرایش", + "ButtonDownload": "بارگیری", + "ButtonDown": "پایین", + "ButtonDelete": "حذف", + "ButtonConnect": "اتصال", + "ButtonChangeServer": "تغییر سرور", + "ButtonBack": "بازگشت", + "ButtonArrowUp": "بالا", + "ButtonArrowRight": "راست", + "ButtonArrowLeft": "چپ", + "ButtonArrowDown": "پایین", + "ButtonAddServer": "افزودن سرور", + "ButtonAddScheduledTaskTrigger": "افزودن راه انداز", + "ButtonAddMediaLibrary": "افزودن کتابخانه رسانه", + "ButtonAddImage": "افزودن تصویر", + "ButtonAdd": "افزودن", + "BoxRear": "جعبه (پشت)", + "Box": "جعبه", + "Blacklist": "لیست سیاه", + "BirthPlaceValue": "محل تولد: {0}", + "BirthLocation": "محل تولد", + "BirthDateValue": "متولد: {0}", + "Banner": "سرصفحه", + "Backdrops": "پس زمینه‌ها", + "Backdrop": "پس زمینه", + "AutoBasedOnLanguageSetting": "خودکار (بر اساس تنظیمات زبانی)", + "Auto": "خودکار", + "Audio": "صدا", + "AttributeNew": "جدید", + "AspectRatio": "نسبت ابعاد", + "AskAdminToCreateLibrary": "از کاربر مدیر بخواهید که یک کتابخانه ایجاد کند.", + "Ascending": "بالا رونده", + "AsManyAsPossible": "تا حدی که ممکن است", + "AroundTime": "حدود {0}", + "Anytime": "هر زمانی", + "AnyLanguage": "هر زبانی", + "AlwaysPlaySubtitles": "همیشه پخش کن", + "AllowFfmpegThrottling": "گلوگاه تبدیل کیفیت", + "AllChannels": "همه کانال‌ها", + "Alerts": "هشدارها", + "Aired": "پخش شده", + "AirDate": "تاریخ پخش", + "AddedOnValue": "{0} افزوده شد", + "AddToPlaylist": "افزودن به لیست پخش", + "AddToPlayQueue": "افزودن به صف پخش", + "AddToCollection": "افزودن به مجموعه", + "ExitFullscreen": "خروج از تمام صفحه", + "EveryNDays": "هر {0} روز", + "ErrorMessageStartHourGreaterThanEnd": "زمان پایان باید پس از زمان شروع باشد.", + "Episodes": "قسمت‌ها", + "EndsAtValue": "تمام شده در {0}", + "Ended": "تمام شده", + "EnableThemeVideos": "تم فیلم‌ها", + "EnableThemeSongs": "آهنگ‌های تم", + "EnableStreamLooping": "چرخش خودکار پخش‌های زنده", + "EnablePhotos": "نمایش عکس‌ها", + "EnableNextVideoInfoOverlay": "نمایش اطلاعات ودیوی بعدی حین پخش ویدیو", + "EnableHardwareEncoding": "فعال سازی رمزگذاری سخت افزاری", + "EnableExternalVideoPlayersHelp": "یک منوی پخش کننده ویدیوی خارجی، زمانی که شروع به پخش ویدیو می‌شود نمایش داده خواهد شد.", + "EnableExternalVideoPlayers": "پخش کننده ویدیوی خارجی", + "EnableDisplayMirroring": "نمایش آینه", + "EnableCinemaMode": "حالت سینما", + "EnableBackdrops": "پشت‌زمینه‌ها", + "EditSubtitles": "ویرایش زیرنویس‌ها", + "EditMetadata": "ویرایش فراداده", + "EditImages": "ویرایش عکس‌ها", + "Edit": "ویرایش", + "DropShadow": "سایه پشت زمینه", + "DrmChannelsNotImported": "کانال‌ها با DRM وارد نخواند شد.", + "DownloadsValue": "{0} بارگیری‌ها", + "Download": "بارگیری", + "Down": "پایین", + "DoNotRecord": "ضبط نکن", + "DisplayModeHelp": "سبک رابط کاربری مورد نظر خود را انتخاب کنید.", + "DisplayMissingEpisodesWithinSeasons": "قسمت‌های ناموجود در فصل‌ها را نمایش بده", + "DisplayInMyMedia": "نمایش در صفحه‌ی خانه", + "Display": "نمایش", + "Dislike": "دوست نداشتن", + "Disconnect": "قطع اتصال", + "Disc": "دیسک", + "Directors": "کارگردانان", + "Director": "کارگردان", + "DirectStreaming": "پخش مستقیم", + "DirectStreamHelp2": "پخش مستقیم فایل از قدرت پردازش بسیار کمی بدون از دست دادن کیفیت ویدیو استفاده می‌کند.", + "DirectPlaying": "پخش مستقیم", + "DetectingDevices": "در حال تشخیص دستگاه‌ها", + "Descending": "پایین رونده", + "Depressed": "پژمرده", + "DeleteUserConfirmation": "آیا اطمینان دارید که می‌خواهید این کاربر را حذف کنید؟", + "DeleteUser": "حذف کاربر", + "DeleteImageConfirmation": "آیا اطمینان دارید که می‌خواهید این تصویر را حذف کنید؟", + "DeleteImage": "حذف تصویر", + "DeleteDeviceConfirmation": "آیا از حذف این دستگاه اطمینان دارید؟ هنگامی که یک کاربر دوباره با آن دستگاه وارد شود، دوباره نمایش داده می‌شود.", + "Delete": "حذف", + "DefaultMetadataLangaugeDescription": "این موارد پیشفرض‌های شماست و می‌توانید برای هر کتابخانه آن را شخصی سازی کنید.", + "DefaultErrorMessage": "خطایی در پردازش درخواست رخ داد. لطفا اندکی بعد دوباره تلاش کنید.", + "Default": "پیشفرض", + "DeathDateValue": "تلف شد: {0}", + "DatePlayed": "تاریخ پخش شده", + "DateAdded": "تاریخ اضافه شده", + "CriticRating": "امتیاز منتقدان", + "CopyStreamURLError": "در کپی کردن آدرس خطایی رخ داد.", + "CopyStreamURLSuccess": "آدرس با موفقیت کپی شد.", + "CopyStreamURL": "کپی آدرس پخش", + "Continuing": "ادامه", + "ContinueWatching": "ادامه تماشا", + "Connect": "اتصال", + "ConfirmEndPlayerSession": "آیا می‌خواهید Jellyfin را روی {0} خاموش کنید؟", + "ConfirmDeletion": "تایید حذف", + "ConfirmDeleteImage": "حذف تصویر؟", + "Composer": "آهنگساز", + "CommunityRating": "امتیاز عمومی", + "ColorTransfer": "انتقال رنگ", + "ColorSpace": "فضای رنگی", + "ColorPrimaries": "مقدمات رنگی", + "ClientSettings": "تنظیمات مشتری", + "ChannelNumber": "شماره کانال", + "ChannelNameOnly": "تنها کانال {0}", + "Categories": "دسته‌بندی‌ها", + "CancelSeries": "لغو سریال‌ها", + "CancelRecording": "لغو ضبط", + "ButtonWebsite": "وبسایت", + "ButtonViewWebsite": "بازدید وبسایت", + "ButtonUp": "بالا", + "ButtonUninstall": "حذف نصب", + "ButtonTrailer": "تریلر", + "ButtonSubtitles": "زیرنویس‌ها", + "ButtonSubmit": "تایید", + "ButtonSplit": "جدا کردن", + "ButtonStop": "توقف", + "ButtonStart": "شروع", + "ButtonSignIn": "ورود", + "ButtonShutdown": "خاموش", + "ButtonSelectDirectory": "انتخاب مسیر", + "ButtonEditOtherUserPreferences": "نمایه، تصویر و ترجیحات شخصی این کاربر را ویرایش کنید.", + "BrowsePluginCatalogMessage": "برای مرور کردن افزونه‌های موجود، به فروشگاه افزونه‌های ما سر بزنید.", + "AuthProviderHelp": "ارائه دهنده تأیید اعتبار را انتخاب کنید تا برای تأیید اعتبار گذرواژه این کاربر استفاده شود.", + "HeaderRecordingPostProcessing": "در حال ضبط پس پردازش", + "HeaderRecordingOptions": "گزینه‌های ضبط", + "HeaderRecentlyPlayed": "به تازگی پخش شده", + "HeaderProfileInformation": "اطلاعات نمایه", + "HeaderProfile": "نمایه", + "HeaderPluginInstallation": "نصب افزونه", + "HeaderPleaseSignIn": "لطفا وارد شوید", + "HeaderPlaybackError": "خطای پخش", + "HeaderPlayback": "پخش رسانه", + "HeaderPlayOn": "پخش در", + "HeaderPinCodeReset": "بازنشانی پین کد", + "HeaderPhotoAlbums": "آلبوم‌های عکس", + "HeaderPeople": "افراد", + "HeaderPendingInvitations": "دعوت‌های در انتظار", + "HeaderPasswordReset": "بازنشانی گذرواژه", + "HeaderPassword": "گذرواژه", + "HeaderParentalRatings": "رتبه بندی والدین", + "HeaderOtherItems": "آیتم‌های دیگر", + "HeaderOnNow": "هم اکنون", + "HeaderNextVideoPlayingInValue": "پخش ویدیوی بعد در {0}", + "HeaderNextEpisodePlayingInValue": "پخش قسمت بعدی در {0}", + "HeaderNewDevices": "دستگاه جدید", + "HeaderNewApiKey": "کلید API جدید", + "HeaderMyMediaSmall": "رسانه‌ی من (کوچک)", + "HeaderMyMedia": "رسانه‌ی من", + "HeaderMyDevice": "دستگاه‌های من", + "HeaderMusicVideos": "موزیک ویدیوها", + "HeaderMusicQuality": "کیفیت آهنگ", + "HeaderMovies": "فیلم‌ها", + "HeaderMoreLikeThis": "موارد مشابه با این", + "HeaderMetadataSettings": "تنظیمات ابرداده", + "HeaderMediaInfo": "اطلاعات رسانه", + "HeaderMediaFolders": "پوشه‌های رسانه", + "HeaderMedia": "رسانه", + "HeaderLoginFailure": "ورود ناموفق", + "HeaderLiveTvTunerSetup": "تنظیم تلویزیون زنده", + "HeaderLiveTv": "تلویزیون زنده", + "HeaderLibrarySettings": "تنظیمات کتابخانه", + "HeaderLibraryOrder": "ترتیت کتابخانه", + "HeaderLibraryFolders": "پوشه‌های کتابخانه", + "HeaderLibraryAccess": "دسترسی به کتابخانه", + "HeaderLibraries": "کتابخانه‌ها", + "HeaderLatestRecordings": "جدیدترین‌ ضبط‌ها", + "HeaderLatestMusic": "جدیدترین‌ آهنگ‌ها", + "HeaderLatestMovies": "جدیدترین‌ فیلم‌ها", + "HeaderLatestMedia": "جدیدترین‌ رسانه‌ها", + "HeaderKeepSeries": "سریال ادامه دهید", + "HeaderKeepRecording": "ضبط را ادامه دهید", + "HeaderItems": "آیتم‌ها", + "HeaderInstall": "نصب", + "HeaderImageSettings": "تنظیمات عکس", + "HeaderIdentifyItemHelp": "یک یا بیشتر مورد برای جستجو وارد کنید. موارد را حذف کنید تا نتیجه جستجو را افزایش دهید.", + "HeaderIdentificationHeader": "سرفصل تعیین هویت", + "HeaderIdentificationCriteriaHelp": "حداقل یک مورد تعیین هویت وارد کنید.", + "HeaderIdentification": "تعیین هویت", + "HeaderHttpHeaders": "سرفصل‌های HTTP", + "HeaderHome": "خانه", + "HeaderGuideProviders": "ارائه دهنده داده راهنمای تلویزیونی", + "HeaderGenres": "ژانرها", + "HeaderFrequentlyPlayed": "اغلب پخش شده", + "HeaderForgotPassword": "فراموشی گذرواژه", + "HeaderForKids": "برای کودکان", + "HeaderFetchImages": "دریافت عکس‌ها:", + "HeaderFeatures": "برجسته‌ها", + "HeaderFeatureAccess": "دسترسی‌های برجسته", + "HeaderFavoriteVideos": "ویدیو‌های مورد علاقه", + "HeaderFavoritePeople": "افراد مورد علاقه", + "HeaderFavoriteMovies": "فیلم‌های مورد علاقه", + "HeaderFavoriteBooks": "کتاب‌های مورد علاقه", + "HeaderExternalIds": "ID های خارجی:", + "HeaderError": "خطا", + "HeaderEpisodes": "قسمت‌ها", + "HeaderEnabledFieldsHelp": "یک فیلد را برای جلوگیری از تغییر در داده‌ی آن علامت بزنید تا قفل بشود.", + "HeaderEnabledFields": "فیلد‌های فعال شده", + "HeaderEditImages": "ویرایش عکس‌ها", + "HeaderDownloadSync": "بارگیری و همگام‌سازی", + "HeaderDisplay": "نمایش", + "HeaderDirectPlayProfileHelp": "نمایه‌ی پخش مستقیم را اضافه کنید تا مشخص کنید با چه فرمی دستگاه می‌تواند محلی برخورد کند.", + "HeaderDirectPlayProfile": "نمایه‌ی پخش مستقیم", + "HeaderDevices": "دستگاه‌ها", + "HeaderDeveloperInfo": "اطلاعات توسعه دهنده", + "HeaderDetectMyDevices": "تشخیص دستگاه‌های من", + "HeaderDeleteTaskTrigger": "حذف راه انداز وظیفه", + "HeaderDeleteProvider": "حذف ارائه‌دهنده", + "HeaderDeleteItems": "حذف آیتم‌ها", + "HeaderDeleteItem": "حذف آیتم", + "HeaderDeleteDevice": "حذف دستگاه", + "HeaderDefaultRecordingSettings": "تنظمیات پیش‌فرض ضبط", + "HeaderDateIssued": "تاریخ صدور", + "HeaderCodecProfileHelp": "نمایه‌های کدک محدودیت‌های یک دستگاه را هنگام پخش کدک‌های خاص نشان می‌دهد. اگر محدودیتی اعمال شود، رسانه‌ها کد گذاری می‌شوند ، حتی اگر کدک برای پخش مستقیم پیکربندی شده باشد.", + "HeaderCodecProfile": "نمایه کدک", + "HeaderChapterImages": "عکس‌های سکانس", + "HeaderChannels": "کانال‌ها", + "HeaderChannelAccess": "دسترسی به کانال", + "HeaderCastCrew": "بازیگران و کارکنان", + "HeaderCastAndCrew": "بازیگران و کارکنان", + "HeaderCancelSeries": "لغو سریال", + "HeaderCancelRecording": "لغو ضبط", + "HeaderBooks": "کتاب‌ها", + "HeaderBlockItemsWithNoRating": "موارد مسدود شده با نقص یا عدم وجود اطلاعات امتیاز:", + "LabelSkipIfAudioTrackPresentHelp": "این گزینه را عدم انتخاب کنید تا اطمینان حاصل کنید که همه ویدیوها فارغ از زبان صوت، زیرنویس دارند.", + "LabelSkipIfAudioTrackPresent": "اگر صدای پیش‌فرض با زبان دانلودی یکسان است پرش کن", + "LabelSkipForwardLength": "میزان رفتن به جلو:", + "LabelSkipBackLength": "میزان بازگشت به عقب:", + "LabelSkin": "پوسته:", + "LabelSize": "سایز:", + "LabelSimultaneousConnectionLimit": "محدودیت پخش همزمان:", + "LabelServerName": "نام سرور:", + "LabelServerHostHelp": "192.168.1.100:8096 یا https://myserver.com", + "LabelServerHost": "میزبان:", + "LabelSerialNumber": "شماره سریال", + "LabelSendNotificationToUsers": "ارسال اعلان به:", + "LabelSelectVersionToInstall": "نسخه مورد نظر برای نصب را انتخاب کنید:", + "LabelVersionInstalled": "{0} نصب شده است", + "EncoderPresetHelp": "یک مقدار سریع‌تر انتخاب کنید تا کارایی بهبود پیدا کند یا یک مقدار کُندتر انتخاب کنید تا کیفیت بهبود پیدا کند.", + "ShowYear": "نمایش سال", + "ShowTitle": "نمایش عنوان", + "ButtonAudioTracks": "آهنگ‌ها", + "AlbumArtist": "هنرمند آلبوم", + "Album": "آلبوم", + "HeaderAddScheduledTaskTrigger": "افزودن فعال‌ساز", + "HeaderActivity": "فعالیت‌ها", + "HeaderActiveRecordings": "ضبط‌های فعال", + "HeaderActiveDevices": "دستگاه‌های فعال", + "HeaderAccessScheduleHelp": "یک زمان‌بندی دسترسی ایجاد کنید تا دسترسی به ساعاتی مشخص محدود شود.", + "HeaderAccessSchedule": "زمان‌بندی دسترسی", + "HandledByProxy": "توسط reverse proxy مدیریت می‌شود", + "HDPrograms": "برنامه‌های HD", + "Filters": "صافی‌ها", + "FileReadError": "خطایی هنگام خواندن فایل رخ داد.", + "FileReadCancelled": "خواندن فایل لغو شد.", + "FileNotFound": "فایل پیدا نشد.", + "File": "فایل", + "FetchingData": "در حال دریافت داده‌های اضافی", + "Features": "برجسته‌ها", + "Favorite": "مورد علاقه", + "FastForward": "سریع جلو", + "Extras": "موارد اضافی", + "ExtraLarge": "فوق العاده بزرگ", + "BoxSet": "جعبه ست", + "Art": "هنر", + "Artist": "هنرمند", + "AllComplexFormats": "تمام فرمت‌های پیچیده (ASS, SSA, VOBSUB, PGS, SUB, IDX)", + "GuideProviderLogin": "ورود", + "Guide": "راهنما", + "GuestStar": "ستاره‌ی مهمان", + "GroupVersions": "نسخه‌های گروه", + "GroupBySeries": "گروه بندی بر اساس سریال‌ها", + "Genre": "ژانر", + "General": "عمومی", + "Fullscreen": "تمام صفحه", + "Friday": "جمعه", + "FormatValue": "قالب‌ها: {0}", + "FolderTypeUnset": "محتواهای مخلوط", + "TabMyPlugins": "افزونه‌های من", + "TabMusic": "موسیقی‌ها", + "TabMovies": "فیلم‌ها", + "TabLogs": "واقعه نگار‌ها", + "TabLiveTV": "تلویزیون زنده", + "LatestFromLibrary": "جدیدترین‌های {0}", + "Large": "بزرگ", + "LabelffmpegPath": "مسیر FFmpeg:", + "LabelZipCode": "کدپستی:", + "LabelYear": "سال:", + "LabelWeb": "وب:", + "LabelVideoResolution": "کیفیت ویدیو:", + "LabelVideo": "ویدیو", + "DashboardArchitecture": "معماری: {0}", + "DashboardOperatingSystem": "سیستم عامل: {0}", + "DashboardServerName": "سرور: {0}", + "DashboardVersionNumber": "نسخه: {0}", + "LabelVersion": "نسخه:", + "LabelValue": "مقدار:", + "LabelVaapiDevice": "دستگاه VA API:", + "LabelUsername": "نام کاربری:", + "LabelUserLibrary": "کتابخانه کاربر:", + "LabelUserAgent": "عامل کاربر:", + "LabelUser": "کاربر:", + "LabelUseNotificationServices": "استفاده از سرویس‌های زیر:", + "LabelTypeText": "متن", + "LabelType": "نوع:", + "LabelKodiMetadataEnablePathSubstitution": "فعال سازی تعویض مسیر", + "LabelKodiMetadataDateFormatHelp": "تمام تاریخ‌های موجود در فایل‌های NFO با استفاده از این قالب تجزیه می‌شوند.", + "LabelKodiMetadataDateFormat": "قالب تاریخ انتشار:", + "LabelKidsCategories": "دسته‌بندی‌های کودکان:", + "OnApplicationStartup": "هنگام شروع برنامه", + "EveryXHours": "هر {0} ساعت", + "EveryHour": "هر ساعت", + "EveryXMinutes": "هر {0} دقیقه", + "OnWakeFromSleep": "هنگام بیداری از خواب", + "WeeklyAt": "{0} در {1}", + "DailyAt": "روزانه در {0}", + "LastSeen": "آخرین بازدید {0}", + "PersonRole": "در نقش {0}", + "ListPaging": "{0}-{1} از {2}", + "Yesterday": "دیروز", + "Yes": "بلی", + "YadifBob": "Yadif Bob", + "Yadif": "Yadif", + "ValueConditions": "شرایط: {0}", + "ValueCodec": "کدک: {0}", + "ValueAudioCodec": "کدک صدا: {0}", + "ValueAlbumCount": "{0} آلبوم", + "Upload": "آپلود", + "Up": "بالا", + "Unrated": "بدون امتیاز", + "Unplayed": "پخش نشده", + "Unmute": "صدادار", + "UninstallPluginHeader": "حذف نصب افزونه", + "UninstallPluginConfirmation": "آیا اطمینان دارید که می‌خواهید {0} را حذف نصب کنید؟", + "Uniform": "یکپارچه", + "Tuesday": "سه‌شنبه", + "Transcoding": "کدگذاری", + "Trailers": "تریلرها", + "Track": "آهنگ", + "TrackCount": "{0} آهنگ", + "TitlePlayback": "پخش", + "TitleHostingSettings": "تنظیمات میزبانی", + "TitleHardwareAcceleration": "تسریع کننده سخت افزاری", + "Thursday": "پنج‌شنبه", + "Thumb": "بندانگشتی", + "ThemeVideos": "تم ویدیوها", + "ThemeSongs": "آهنگ‌های تم", + "TagsValue": "برچسب‌ها: {0}", + "Tags": "برچسب‌ها", + "TabUsers": "کاربران", + "Absolute": "کامل", + "Writer": "نویسنده", + "Whitelist": "لیست سفید", + "Wednesday": "چهارشنبه‌ها", + "Watched": "مشاهده شده", + "ViewPlaybackInfo": "مشاهده اطلاعات پخش", + "ViewArtist": "مشاهده هنرمند", + "ViewAlbum": "مشاهده آلبوم", + "VideoRange": "محدوده ویدیو", + "Vertical": "عمودی", + "ValueVideoCodec": "کدک ویدیو: {0}", + "ValueTimeLimitSingleHour": "محدودیت زمانی: 1 ساعت", + "ValueTimeLimitMultiHour": "محدودیت زمانی: {0} ساعت", + "ValueSongCount": "{0} آهنگ", + "ValueSeriesCount": "{0} سریال", + "ValueSeconds": "{0} ثانیه", + "ValueOneSong": "1 آهنگ", + "ValueOneSeries": "1 سریال", + "ValueOneMusicVideo": "1 موزیک ویدیو", + "ValueOneMovie": "1 فیلم", + "ValueOneEpisode": "1 قسمت", + "ValueOneAlbum": "1 آلبوم", + "ValueMusicVideoCount": "{0} موزیک ویدیو", + "ValueMovieCount": "{0} فیلم", + "ValueMinutes": "{0} دقیقه", + "ValueEpisodeCount": "{0} قسمت", + "ValueDiscNumber": "دیسک {0}", + "LabelImportOnlyFavoriteChannels": "محدود کردن کانال‌هایی که به عنوان مورد علاقه انتخاب شده‌اند", + "LabelDateAdded": "تاریخ اضافه شده:", + "LabelDashboardTheme": "تم داشبورد سرور:", + "LabelCustomRating": "امتیازدهی سفارشی:", + "LabelCustomDeviceDisplayName": "نام نمایشی:", + "LabelCustomCssHelp": "ظاهر سفارشی مورد نظر خود را در رابط وب اعمال کنید.", + "LabelCustomCss": "CSS سفارشی:", + "LabelCriticRating": "امتیاز منتقدان:", + "LabelCorruptedFrames": "فریم‌های خراب شده:", + "LabelImageType": "نوع عکس:", + "LabelIconMaxWidth": "حداکثر عرض آیکن:", + "LabelIconMaxHeight": "حداکثر ارتفاع آیکن:", + "LabelHttpsPort": "شماره پورت HTTPS محلی:", + "LabelHomeNetworkQuality": "کیفیت شبکه خانگی:", + "LabelHardwareAccelerationTypeHelp": "تسریع کننده سخت افزاری نیاز به پیکربندی اضافی دارد.", + "LabelSupportedMediaTypes": "نوع‌ رسانه‌های پشتیبانی شده:", + "LabelSubtitles": "زیرنویس‌ها", + "LabelSubtitlePlaybackMode": "حالت زیرنویس:", + "LabelSubtitleFormatHelp": "مثال: srt", + "LabelSubtitleDownloaders": "دانلود کننده زیرنویس:", + "LabelStreamType": "نوع پخش:", + "LabelStopping": "در حال توقف", + "LabelStopWhenPossible": "هنگامی که ممکن است متوقف شود:", + "LabelStatus": "وضعیت:", + "LabelStartWhenPossible": "هنگامی که ممکن است شروع شود:", + "LabelSportsCategories": "دسته‌بندی‌های ورزشی:", + "LabelSpecialSeasonsDisplayName": "نام نمایشی فصل مخصوص:", + "LabelSource": "منبع:", + "LabelSoundEffects": "جلوه‌های صدا:", + "LabelSortTitle": "مرتب‌سازی عنوان:", + "LabelSortOrder": "ترتیب مرتب‌سازی:", + "LabelSortBy": "مرتب‌سازی بر اساس:", + "LabelSonyAggregationFlags": "پرچم‌های جمع‌آوری سونی:", + "LabelSkipIfGraphicalSubsPresent": "صرف نظر کردن اگر ویدیو پیش از این زیرنویس چسبیده در خود دارد", + "EnableColorCodedBackgrounds": "پشت‌ زمینه‌های کدگذاری شده رنگی", + "DisplayMissingEpisodesWithinSeasonsHelp": "این مورد همچنین باید برای کتابخانه های تلویزیون در پیکربندی سرور فعال شود.", + "DisplayInOtherHomeScreenSections": "در بخش‌های صفحه اصلی مانند آخرین رسانه‌ها و ادامه تماشا نمایش بده", + "Desktop": "دسکتاپ", + "CustomDlnaProfilesHelp": "برای هدف قرار دادن یک دستگاه جدید یا سرپوش گذاشتن روی نمایه سیستم ، یک نمایه سفارشی ایجاد کنید.", + "ConfirmDeleteItems": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که می‌خواهید ادامه دهید؟", + "ConfirmDeleteItem": "حذف این مورد، آن را هم از فایل سیستمی و هم از کتابخانه رسانه شما حذف می کند. آیا اطمینان دارید که می‌خواهید ادامه دهید؟", + "AlwaysPlaySubtitlesHelp": "زیرنویس‌های متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.", + "AllowedRemoteAddressesHelp": "لیستی از آدرس های IP یا ورودی‌های IP/‌netmask برای شبکه هایی که به آنها امکان ارتباط از راه دور داده می‌شود ، با کاما از هم جدا شدند. در صورت خالی ماندن ، تمام آدرسهای راه دور مجاز خواهند بود.", + "AllowOnTheFlySubtitleExtractionHelp": "زیرنویس های جاسازی شده را می‌توان از فیلم‌ها استخراج کرد و به منظور جلوگیری از کدگذاری فیلم ، به صورت متن ساده به بازدید کننده ارسال کرد. در بعضی از سیستم‌ها این می‌تواند مدت زیادی طول بکشد و باعث شود پخش فیلم در طول فرآیند استخراج متوقف شود. این گزینه را غیرفعال کنید تا زیرنویس‌های جاسازی شده با استفاده از رمزگذاری ویدیو در حالی که به طور محلی توسط دستگاه بازدیدکننده پشتیبانی نمی‌شوند ارسال شود.", + "AdditionalNotificationServices": "برای نصب سرویس‌های اعلان اضافی، در فروشگاه افزونه‌ها جستجو کنید.", + "OptionThumbCard": "کارت بندانگشتی", + "OptionThumb": "بندانگشتی", + "OptionThursday": "پنجشنبه", + "OptionSunday": "یکشنبه", + "OptionSubstring": "زیررشته", + "OptionSpecialEpisode": "ویژه‌ها", + "OptionSaveMetadataAsHidden": "ذخیره فراداده‌ها و عکس‌ها به عنوان فایل‌های پنهان", + "OptionSaturday": "شنبه", + "OptionRuntime": "زمان اجرا", + "OptionResumable": "قابل از سرگیری", + "OptionResElement": "عنصر res", + "OptionReleaseDate": "تاریخ انتشار", + "OptionRegex": "عبارت منظم", + "OptionRandom": "تصادفی", + "OptionProtocolHttp": "HTTP", + "OptionProtocolHls": "پخش مستقیم HTTP", + "OptionProfileVideoAudio": "صوتی تصویری", + "OptionProfilePhoto": "عکس", + "OptionProfileAudio": "صدا", + "OptionPremiereDate": "تاریخ پخش", + "OptionPosterCard": "کارتِ پوستر", + "OptionPoster": "پوستر", + "OptionPlayCount": "تعداد پخش", + "OptionPlainVideoItems": "نمایش همه فیلم‌ها به عنوان موارد ویدیویی ساده", + "OptionPlainStorageFolders": "نمایش همه پوشه‌ها به عنوان پوشه‌های ذخیره سازی ساده", + "OptionParentalRating": "رتبه بندی والدین", + "OptionOnInterval": "در یک فاصله", + "BookLibraryHelp": "کتاب‌های صوتی و متنی پشتیبانی می‌شوند. {0}راهنمای نامگذاری کتاب{1} را مرور کنید.", + "TabInfo": "اطلاعات", + "TabGuide": "راهنما", + "TabFavorites": "مورد علاقه‌ها", + "TabDisplay": "نمایش", + "TabDirectPlay": "پخش مستقیم", + "TabDevices": "دستگاه‌ها", + "TabDashboard": "داشبورد", + "TabCollections": "مجموعه‌ها", + "TabCodecs": "کدک‌ها", + "TabChannels": "کانال‌ها", + "TabCatalog": "فهرست", + "TV": "تلویزیون", + "Sunday": "یکشنبه", + "TabTranscoding": "کدگذاری", + "TabTrailers": "تریلرها", + "Suggestions": "پیشنهادها", + "Subtitles": "زیرنویس‌ها", + "Studios": "استودیو‌ها", + "StopRecording": "توقف ضبط", + "Sports": "ورزش‌ها", + "SortName": "مرتب سازی نام", + "SortChannelsBy": "مرتب سازی کانال‌ها بر اساس:", + "SortByValue": "مرتب شده بر اساس {0}", + "Sort": "مرتب سازی", + "Smart": "باهوش", + "Smaller": "کوچکتر", + "Small": "کوچک", + "ButtonTogglePlaylist": "لیست پخش", + "ButtonToggleContextMenu": "بیشتر", + "TheseSettingsAffectSubtitlesOnThisDevice": "این تنظیمات روی زیرنویس‌ها در این دستگاه تأثیر می‌گذارد", + "TabStreaming": "در حال پخش", + "TabSettings": "تنظیمات", + "TabServer": "سرور", + "TabSeries": "سریال‌ها", + "TabScheduledTasks": "وظایف زمان بندی شده", + "TabResumeSettings": "ادامه", + "TabResponses": "پاسخ‌ها", + "TabRecordings": "ضبط‌ها", + "TabPlugins": "افزونه‌ها", + "TabPlaylists": "لیست‌های پخش", + "TabPlayback": "پخش", + "TabParentalControl": "رتبه بندی والدین", + "TabOther": "سایر", + "TabNfoSettings": "تنظیمات NFO", + "TabNetworking": "شبکه سازی", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "این تنظیمات همچنین در مورد هر پخش Chromecast که توسط این دستگاه شروع شده است اعمال می شود.", + "SmartSubtitlesHelp": "زیرنویس‌های متناسب با توجه به اولویت زبان بدون در نظر گرفتن زبان صوتی ویدیو پخش می شوند.", + "SkipEpisodesAlreadyInMyLibrary": "قسمت‌هایی که هم اکنون در کتابخانه من موجود است را ضبط نکن", + "SimultaneousConnectionLimitHelp": "حداکثر تعداد پخش‌های مجاز همزمان. ۰ را برای بدون محدودیت وارد کنید.", + "MessagePluginConfigurationRequiresLocalAccess": "برای پیکربندی این افزونه، لطفاً مستقیماً به سرور محلی خود وارد شوید.", + "MessagePleaseWait": "لطفا صبر کنید. این ممکن است چند دقیقه طول بکشد.", + "MessageNoServersAvailable": "هیچ سروری با استفاده از کشف خودکار سرور یافت نشد.", + "MessageNoPluginsInstalled": "هیچ افزونه‌ی نصب نشده است.", + "MessageNoMovieSuggestionsAvailable": "هیچ پیشنهادی برای فیلم در دسترس نیست. شروع به تماشای و رتبه بندی فیلم‌های خود بکنید ، و سپس دوباره به دیدن پیشنهاد‌های خود بیایید.", + "MessageNoAvailablePlugins": "افزونه‌ای موجود نیست.", + "MessageItemsAdded": "آیتم‌ها اضافه شدند.", + "MessageItemSaved": "آیتم ذخیره شد.", + "MessageUnauthorizedUser": "در حال حاضر مجاز به دسترسی به سرور نیستید. لطفا برای اطلاعات بیشتر با مدیر سرور خود تماس بگیرید.", + "MessageInvalidUser": "نام کاربری یا گذرواژه نامعتبر است. لطفا دوباره تلاش کنید.", + "MessageInvalidForgotPasswordPin": "کد پین نامعتبر یا منقضی شده وارد شد. لطفا دوباره تلاش کنید.", + "MessageInstallPluginFromApp": "این افزونه باید از داخل برنامه‌ای که قصد استفاده از آن را دارید نصب شود." } diff --git a/src/strings/fi.json b/src/strings/fi.json index 10e1a95a72..1c7147a50b 100644 --- a/src/strings/fi.json +++ b/src/strings/fi.json @@ -4,7 +4,7 @@ "ButtonAddUser": "Lisää Käyttäjä", "ButtonCancel": "Peruuta", "ButtonDeleteImage": "Poista Kuva", - "ButtonResetPassword": "Uusi Salasana", + "ButtonResetPassword": "Nollaa salasana", "ButtonSave": "Tallenna", "ButtonSignOut": "Sign out", "Delete": "Poista", @@ -15,41 +15,41 @@ "FileNotFound": "Tiedostoa ei löydy.", "FileReadCancelled": "Tiedoston luku on peruutettu.", "FileReadError": "Virhe tiedoston luvun aikana.", - "FolderTypeTvShows": "TV", + "FolderTypeTvShows": "TV-sarjat", "HeaderCreatePassword": "Luo Salasana:", "HeaderParentalRating": "Parental Rating", - "HeaderSeries": "Series:", + "HeaderSeries": "Sarjat", "HeaderYear": "Year:", "LabelAudioLanguagePreference": "Äänen ensisijainen kieli:", "LabelConfigureSettings": "Muuta asetuksia", "LabelCountry": "Maa:", "LabelCurrentPassword": "Tämän hetkinen salsana:", - "LabelDisplayMissingEpisodesWithinSeasons": "Näytä puuttuvat jaksot tuotantokausissa", + "LabelDisplayMissingEpisodesWithinSeasons": "Näytä puuttuvat jaksot kausien sisällä", "LabelDownloadInternetMetadata": "Lataa kuvamateriaali ja metadata internetistä", "LabelFinish": "Valmis", "LabelFolderType": "Kansion tyyppi:", "LabelLanguage": "Kieli:", - "LabelMaxParentalRating": "Suurin sallittu vanhempien arvostelu:", + "LabelMaxParentalRating": "Suurin sallittu ikäraja:", "LabelNewPassword": "Uusi salasana:", "LabelNewPasswordConfirm": "Uuden salasanan varmistus:", "LabelNext": "Seuraava", "LabelPrevious": "Edellinen", - "LabelSaveLocalMetadata": "Tallenna kuvamateriaali ja metadata media kansioihin.", + "LabelSaveLocalMetadata": "Tallenna kuvamateriaali mediakansioihin", "LabelSaveLocalMetadataHelp": "Kuvamateriaalin ja metadatan tallentaminen suoraan kansioihin missä niitä on helppo muuttaa.", "LabelSubtitleLanguagePreference": "Tekstityksien ensisijainen kieli:", "LabelUnairedMissingEpisodesWithinSeasons": "Näytä julkaisemattomat jaksot tuotantokausissa", - "LabelYourFirstName": "Sinun ensimmäinen nimi:", - "LabelYoureDone": "Olet valmis!", - "LibraryAccessHelp": "Valitse media kansiot jotka haluat jakaa tämän käyttäjän kanssa. Järjestelmänvalvoja pystyy muokkaamaan kaikkia kansioita käyttäen metadata hallintaa.", - "MaxParentalRatingHelp": "Suuremman arvosanan takia, sisältö tulla piilottamaan käyttäjältä.", - "MoreUsersCanBeAddedLater": "Käyttäjiä voi lisätä lisää myöhemmin Dashboardista", + "LabelYourFirstName": "Etunimesi:", + "LabelYoureDone": "Valmista!", + "LibraryAccessHelp": "Valitse kirjastot, jotka haluat jakaa tämän käyttäjän kanssa. Järjestelmänvalvoja pystyy muokkaamaan kaikkia kansioita käyttäen metadatan hallintatyökalua.", + "MaxParentalRatingHelp": "Suuremman luokituksen sisältö piilotetaan käyttäjältä.", + "MoreUsersCanBeAddedLater": "Käyttäjiä voidaan lisätä myöhemmin lisää päänäkymästä.", "NoPluginsInstalledMessage": "Sinulla ei ole mitään lisäosia asennettuna.", "OptionRelease": "Virallinen Julkaisu", - "ParentalRating": "Parental Rating", + "ParentalRating": "Ikäraja", "Password": "Salasana", - "PasswordMatchError": "Salasana ja salasanan vahvistuksen pitää olla samat.", - "PasswordResetComplete": "Salasana on palauttettu.", - "PasswordResetConfirmation": "Oletko varma, että haluat palauttaa salasanan?", + "PasswordMatchError": "Salasanan ja salasanan vahvistuksen on oltava samat.", + "PasswordResetComplete": "Salasana on nollattu.", + "PasswordResetConfirmation": "Haluatko varmasti nollata salasanan?", "PasswordSaved": "Salasana tallennettu.", "Save": "Tallenna", "SettingsSaved": "Asetukset tallennettu.", @@ -59,7 +59,7 @@ "TabProfile": "Profiili", "TabProfiles": "Profiilit", "TellUsAboutYourself": "Kerro meille itsestäsi", - "ThisWizardWillGuideYou": "Tämä työkalu auttaa sinua asennus prosessin aikana. loittaaksesi valitse kieli.", + "ThisWizardWillGuideYou": "Tämä työkalu auttaa sinua asennusprosessin aikana. Valitse kieli aloittaaksesi.", "UninstallPluginConfirmation": "Oletko varma, että haluat poistaa {0}?", "UninstallPluginHeader": "Poista Lisäosa", "Users": "Käyttäjät", @@ -88,10 +88,10 @@ "AddGuideProviderHelp": "Lisää lähde ohjelmaoppaalle.", "AddItemToCollectionHelp": "Lisää nimikkeitä etsimällä niitä ja käyttämällä hiiren oikeaa nappia tai valikkoa lisätäksesi ne kokoelmaan.", "Aired": "Esityspäivä", - "AllowHWTranscodingHelp": "Jos sallittu, salli virittimen muuntaa bittivirtaa lennossa. Tämä voi vähentää tarvetta muunnokseen Jellyfin palvelimella.", + "AllowHWTranscodingHelp": "Salli virittimen muuntaa bittivirtaa lennossa. Tämä voi vähentää muunnoksen tarvetta Jellyfin-palvelimella.", "AllowMediaConversion": "Salli median muunto", "AllowMediaConversionHelp": "Salli tai kiellä pääsy median muunnostoimintoon.", - "AllowOnTheFlySubtitleExtractionHelp": "Sulautetut tekstitykset voi erottaa videoista ja toimittaa Jellyfin ohjelmalle tekstinä, jotta videoita ei tarvitse uudelleenkoodata. Joissain järjestelmissä tämä voi viedä paljon aikaa ja aiheuttaa videotoiston pysähtymisen purun ajaksi. Poista tämä liittääksesi tekstiyksen videokuvaankon asiakaslaite ei tue tekstiyksiä.", + "AllowOnTheFlySubtitleExtractionHelp": "Sisäiset tekstitykset voidaan lähettää päätelaitteille ilmitekstinä, jotta videota ei tarvitsisi uudelleenkoodata. Joissain järjestelmissä tämä voi viedä paljon aikaa ja aiheuttaa toiston pysähtymisen purun ajaksi. Poista tämä käytöstä polttaaksesi tekstiykset suoraan videoon, mikäli päätelaite ei tue tekstityksiä.", "AllowRemoteAccess": "Salli etäyhteydet tähän Jellyfin palvelimeen.", "AllowRemoteAccessHelp": "Jos merkki puuttuu, kaikki ulkopuoliset yhteydet estetään.", "AllowSeasonalThemes": "Salli automaattiset vuodenaikateemat", @@ -101,7 +101,7 @@ "AlwaysPlaySubtitlesHelp": "Oletuskieliasetusta vastaava tekstitys otetaan käyttöön ääniraidan kielestä huolimatta.", "AnamorphicVideoNotSupported": "Anamorfinen video ei ole tuettu", "AndroidUnlockRestoreHelp": "Palauttaaksesi aikaisemman ostoksesi, varmista, että olet kirjautuneena samalla Google (tai Amazon) tunnuksella, jolla teit alkuperäisen oston. Varmista, että sovelluskauppa on päällä eikä sitä ole rajoitettu vanhempien lukolla. Varmista myös, että sinulla on toimiva internet -yhteys. Sinun tarvitsee tehdä taämä vain kerran.", - "AnyLanguage": "Mikä tahansa kieli", + "AnyLanguage": "Mikä tahansa", "Anytime": "Milloin tahansa", "AroundTime": "Noin {0}", "Art": "Taide", @@ -112,16 +112,16 @@ "AttributeNew": "Uusi", "Audio": "Ääni", "AuthProviderHelp": "Valitse todentamispalvelu, jota käytetään tämän käyttäjän salasanan todentamisessa.", - "Auto": "Automaattinen", + "Auto": "Auto", "AutoBasedOnLanguageSetting": "Automaattinen (perustuu kieliasetukseen)", "Backdrop": "Tausta", "Backdrops": "Taustat", - "Banner": "Juliste", + "Banner": "Lippu", "BirthDateValue": "Syntynyt: {0}", "BirthLocation": "Syntymäpaikka", "BirthPlaceValue": "Syntymäpaikka: {0}", "Blacklist": "Kieltolista", - "BookLibraryHelp": "Ääni- ja tekstimuotoiset kirjat on tuettuja. Katso {0}Jellyfin Kirjojen nimeämisopas{1}.", + "BookLibraryHelp": "Ääni- ja tekstimuotoiset kirjat on tuettuja. Katso {0}kirjojen nimeämisopas{1}.", "Books": "Kirjat", "Box": "Laatikko", "BoxRear": "Laatikko (takaa)", @@ -145,9 +145,9 @@ "ButtonEdit": "Muokkaa", "ButtonEditImages": "Muokkaa kuvia", "ButtonEditOtherUserPreferences": "Muokkaa tämän käyttäjän profiilia, kuvaa ja henkilökohtaisia asetuksia.", - "ButtonFilter": "Suodin", - "ButtonForgotPassword": "Unohdin salasanani", - "ButtonFullscreen": "Täysi kuvaruutu", + "ButtonFilter": "Suodata", + "ButtonForgotPassword": "Unohtuiko salasana", + "ButtonFullscreen": "Kokonäyttötila", "ButtonGotIt": "Selvä", "ButtonGuide": "Opas", "ButtonHelp": "Apua", @@ -163,8 +163,8 @@ "ButtonNextTrack": "Seuraava raita", "ButtonOff": "Pois päältä", "ButtonOk": "Ok", - "ButtonOpen": "Avoin", - "BurnSubtitlesHelp": "Määrittää jos palvelimen pitäisi upottaa tekstitykset suoraan videotiedostoon muuntamisvaiheessa tekstitysformaatista riippuen. Upottamisen välttäminen parantaa palvelimen suorituskykyä. Valitse Automaattinen upottaaksesi sekä kuvapohjaiset- (esim. VOBSUB, PGS, SUB/IDX, jne.) että ASS/SSA tekstitysmuodot", + "ButtonOpen": "Avaa", + "BurnSubtitlesHelp": "Määrittää mikäli palvelimen pitäisi polttaa tekstitykset suoraan videoon muunnoksen aikana riippuen tekstitysten formaatista. Tekstitysten polttamisen välttäminen parantaa palvelimen suorituskykyä. Valitse Automaattinen polttaaksesi sekä kuva- (esim. VOBSUB, PGS, SUB/IDX, jne.) että tekstipohjaiset (ASS/SSA) formaatit.", "ButtonParentalControl": "Lapsilukko", "ButtonPause": "Tauko", "ButtonPlay": "Toista", @@ -236,12 +236,11 @@ "DetectingDevices": "Tunnistetaan laitteita", "DeviceAccessHelp": "Tämä pätee ainoastaan laitteisiin, jotka voidaan tunnistaa uniikkina ja ei estä selainpääsyä. Uusien laitteiden suodattaminen estää niiden käyttämisen ennen hyväksyntää täältä.", "DirectPlaying": "Suoraan toistaminen", - "DirectStreamHelp1": "Tämä media on yhteensopiva laitteen kanssa katsoen resoluutiota ja mediatyyppiä (H.264, AC3, jne.), mutta se ei ole yhteensopivassa tiedostosäiliössä (.mkv, .avi, .wmv, etc.). Tämä video uudelleenpakataan lennossa ennen laitteeseen toistoa.", + "DirectStreamHelp1": "Tämä media on yhteensopiva laitteen kanssa katsoen resoluutiota ja mediatyyppiä (H.264, AC3, jne.), mutta se ei ole yhteensopivassa tiedostosäiliössä (mkv, avi, wmv, jne.). Tämä video uudelleenpakataan lennossa ennen laitteeseen lähetystä.", "DirectStreamHelp2": "Tiedoston suoraan toistaminen käyttää erittäin vähän prosessorin resursseja ilman laadun heikentämistä.", "DirectStreaming": "Suora suoratoisto", "Director": "Ohjaaja", - "DirectorValue": "Ohjaaja: {0}", - "DirectorsValue": "Ohjaajat: {0}", + "Directors": "Ohjaajat", "Disabled": "Pois päältä kytkettynä", "Disc": "Levy", "Disconnect": "Katkaise yhteys", @@ -249,15 +248,15 @@ "DisplayInMyMedia": "Näytä kotinäytöllä", "DisplayInOtherHomeScreenSections": "Näytä kotinäytöllä osastoja kuten viimeisin media ja jatka katselua", "DisplayMissingEpisodesWithinSeasons": "Näytä puuttuvat jaksot tuotantokausissa", - "DisplayMissingEpisodesWithinSeasonsHelp": "Tämän pitää aktivoida TV-kirjastoille myös Jellyfin-palvelimen asennusvaiheessa.", - "DisplayModeHelp": "Valitse näyttölaitteen tyyppi jolla pyörität Jellyfiniä.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Tämän pitää aktivoida TV-kirjastoille myös palvelimen asetuksissa.", + "DisplayModeHelp": "Valitse ulkonäkö, jonka haluat käyttöliittymälle.", "DoNotRecord": "Älä tallenna", "Down": "Alas", "Download": "Lataa", "DownloadsValue": "{0} latausta", "DrmChannelsNotImported": "Kanavia joissa on tekijänoikeusesto-ohjelmia, ei ladata.", - "DropShadow": "Tiputa varjo", - "EasyPasswordHelp": "Sinun helppoa PIN-koodia käytetään offline-käytössä tuetuissa Jellyfin-sovelluksissa, ja voidaan myös nopeuttaa verkkoon kirjautumista.", + "DropShadow": "Varjostus", + "EasyPasswordHelp": "Helppoa PIN-koodiasi käytetään offline-käyttöä tukevissa sovelluksissa, ja sitä voidaan myös käyttää verkossa kirjautumiseen.", "Edit": "Muokkaa", "EditImages": "Muokkaa kuvia", "EditMetadata": "Muokkaa metadataa", @@ -268,16 +267,989 @@ "ButtonAddImage": "Lisää kuva", "Movies": "Elokuvat", "HeaderNextUp": "Seuraavaksi", - "HeaderLiveTV": "Netti-TV", + "HeaderLiveTV": "Live-TV", "HeaderFavoriteSongs": "Lempikappaleet", "HeaderFavoriteShows": "Lempisarjat", "HeaderFavoriteEpisodes": "Lempijaksot", "HeaderFavoriteArtists": "Lempiartistit", "HeaderFavoriteAlbums": "Lempialbumit", - "HeaderContinueWatching": "Jatka Katsomista", - "HeaderAlbumArtists": "Albumiartistit", - "Genres": "Genret", + "HeaderContinueWatching": "Jatka katsomista", + "HeaderAlbumArtists": "Albumin esittäjä", + "Genres": "Tyylilajit", "Folders": "Kansiot", "Favorites": "Suosikit", - "Display": "Näytä" + "Display": "Näytä", + "Photos": "Kuvat", + "Playlists": "Soittolistat", + "ValueSpecialEpisodeName": "Erikois - {0}", + "Sync": "Synkronoi", + "Songs": "Kappaleet", + "Shows": "Sarjat", + "CopyStreamURLSuccess": "Osoite kopioitu onnistuneesti.", + "DeathDateValue": "Kuoli: {}", + "CustomDlnaProfilesHelp": "Luo uusi profiili kohdistaaksesi uuteen laitteeseen tai ohittaaksesi järjestelmäprofiilin.", + "EnableBackdrops": "Taustat", + "ErrorAddingMediaPathToVirtualFolder": "Media-polkua lisätessä ilmeni ongelma. Varmista, että polku on kirjoitettu oikein ja Jellyfin Palvelimella pääsy sijaintiin.", + "Episodes": "Jaksot", + "EndsAtValue": "Päättyy {0}", + "Ended": "Päättynyt", + "EnableThemeSongsHelp": "Soita tunnussäveliä taustalla selatessasi kirjastoa.", + "EnableThemeSongs": "Tunnuslaulut", + "EnableStreamLoopingHelp": "Laita tämä päälle, jos suoratoistot sisältävät vain muutaman sekuntin verran dataa jota tarvitsee pyytää jatkuvasti. Tämän päälle laittaminen ilman toiminnon tarvetta voi aiheuttaa ongelmia.", + "EnablePhotosHelp": "Kuvat tunnistetaan ja näytetään muiden media-tiedostojen ohessa.", + "EnablePhotos": "Näytä valokuvat", + "EnableNextVideoInfoOverlay": "Näytä seuraavan videon tiedot toiston aikana", + "EnableHardwareEncoding": "Salli rauta-tason muunnoksen kiihdytys", + "EnableExternalVideoPlayers": "Ulkoiset videosoittimet", + "EnableDisplayMirroring": "Näytön peilaus", + "EnableColorCodedBackgrounds": "Väri-koodatut taustat", + "EnableCinemaMode": "Teatteri-tila", + "EnableBackdropsHelp": "Näytä taustat tietyillä sivuilla selatessasi kirjastoa.", + "EnableExternalVideoPlayersHelp": "Videota soitettaessa näytetään erillinen valikko.", + "Depressed": "Painettu", + "CopyStreamURLError": "Osoitteen kopioidessa tapahtui virhe.", + "ButtonSplit": "jaa", + "AskAdminToCreateLibrary": "Pyydä järjestelmän ylläpitäjää luomaan kirjasto.", + "EnableStreamLooping": "Looppaa suoralähetykset", + "EnableNextVideoInfoOverlayHelp": "Näytä videon lopussa tietoja seuraavasta videosta soittolistalla.", + "ClientSettings": "Pääte-asetukset", + "AllowFfmpegThrottlingHelp": "Kun uudelleenkoodaus tai remux ehtii tarpeeksi toiston edelle, keskeytä laskenta jotta laskentaresursseja kuluu vähemmän. Tämä on hyödyllistä jos katselet hyppimättä eri kohtiin. Älä käytä jos toiston kanssa ilmenee ongelmia.", + "AllowFfmpegThrottling": "Rajoita uudelleenkoodaus", + "ErrorDeletingItem": "Tiedostoa poistaessa Jellyfin Palvelimelta ilmeni virhe. Varmista, että Jellyfin Palvelimella on kirjoitusoikeudet mediakansioon ja kokeile uudestaan.", + "ErrorAddingXmlTvFile": "XMLTV-tiedostoa käyttäessä tapahtui virhe. Varmista, että tiedosto on olemassa ja kokeile uudestaan.", + "ErrorAddingTunerDevice": "Viritintä lisätessä ilmeni ongelma. Varmista, että se on kytketty oikein ja kokeile uudestaan.", + "EnableThemeVideosHelp": "Soita tunnusvideoita taustalla, selatessasi kirjastoa.", + "EnableThemeVideos": "Tunnusvideot", + "AlbumArtist": "Albumin Artisti", + "Album": "Albumi", + "Played": "Toistetut", + "PlayFromBeginning": "Toista alusta", + "PlayNext": "Toista seuraava", + "Play": "Toista", + "PinCodeResetConfirmation": "Haluatko varmasti nollata PIN-koodin?", + "People": "Ihmiset", + "PasswordResetHeader": "Nollaa salasana", + "OriginalAirDateValue": "Alkuperäinen esityspäivä: {0}", + "OptionWeekly": "Viikottainen", + "OptionWeekends": "Viikonloput", + "OptionWeekdays": "Arkipäivät", + "OptionTvdbRating": "TVDB luokitus", + "OptionTrackName": "Raidan nimi", + "OptionThumbCard": "Pienoiskuvakortti", + "OptionThumb": "Pienoiskuva", + "OptionSubstring": "Substring", + "OptionSpecialEpisode": "Erikoisjaksot", + "OptionSaveMetadataAsHidden": "Tallenna metadata ja kuvat piilotettuina tiedostoina", + "OptionRuntime": "Kesto", + "OptionResumable": "Jatkettavissa oleva", + "OptionResElement": "res element", + "OptionReleaseDate": "Julkaisupäivä", + "OptionRegex": "Regex", + "OptionRandom": "Satunnainen", + "OptionProtocolHttp": "HTTP", + "OptionProtocolHls": "HTTP Suoratoisto", + "OptionProfileVideoAudio": "Video Audio", + "OptionProfileVideo": "Video", + "OptionProfilePhoto": "Kuva", + "OptionProfileAudio": "Audio", + "OptionPremiereDate": "Ensi-iltapäivä", + "OptionPosterCard": "Julistekortti", + "OptionPoster": "Juliste", + "OptionPlayCount": "Toistokerrat", + "OptionPlayed": "Toistettu", + "OptionOnAppStartup": "Käynnistyksen yhteydessä", + "OptionNew": "Uusi...", + "OptionNameSort": "Nimi", + "OptionMonday": "Maanantai", + "OptionMissingEpisode": "Puuttuvat jaksot", + "OptionMax": "Maksimi", + "OptionList": "Lista", + "OptionLikes": "Likes", + "OptionIsSD": "SD", + "OptionIsHD": "HD", + "OptionImdbRating": "IMDb Luokitus", + "OptionHomeVideos": "Kuvat", + "OptionHideUser": "Piilota tämä käyttäjä kirjautumisnäkymästä", + "OptionHasTrailer": "Traileri", + "OptionHasThemeVideo": "Tunnusvideo", + "OptionHasThemeSong": "Tunnuskappale", + "OptionHasSubtitles": "Tekstitykset", + "OptionHasSpecialFeatures": "Erikoisominaisuudet", + "OptionFriday": "Perjantai", + "OptionFavorite": "Suosikit", + "OptionExtractChapterImage": "Ota käyttöön kappalekuvien luonti", + "OptionExternallyDownloaded": "Ulkoinen lataus", + "OptionEveryday": "Joka päivä", + "OptionEnded": "Loppuneet", + "OptionEnableM2tsMode": "Ota käyttöön M2ts tila", + "OptionEnableForAllTuners": "Ota käyttöön kaikille viritinlaitteille", + "OptionEnableAccessToAllLibraries": "Salli pääsy kaikkiin kirjastoihin", + "OptionEnableAccessToAllChannels": "Salli pääsy kaikille kanaville", + "OptionEnableAccessFromAllDevices": "Salli pääsy kaikista laitteista", + "OptionDvd": "DVD", + "OptionDownloadThumbImage": "Pienoiskuva", + "OptionDownloadPrimaryImage": "Ensisijainen", + "OptionDownloadMenuImage": "Valikko", + "OptionDownloadLogoImage": "Logo", + "OptionDownloadImagesInAdvance": "Lataa kuvat etukäteen", + "OptionDislikes": "Disliket", + "OptionCustomUsers": "Mukautettu", + "OptionCriticRating": "Kriitikoiden luokitus", + "OptionContinuing": "Jatkuvat", + "OptionCommunityRating": "Yhteisön luokitus", + "OptionBlockLiveTvChannels": "Live-TV kanavat", + "OptionBanner": "Lippu", + "OnlyForcedSubtitlesHelp": "Vain pakotetuiksi merkityt tekstitykset ladataan.", + "OnlyImageFormats": "Vain kuvaformaatit (VOBSUB, PGS, SUB)", + "OnlyForcedSubtitles": "Vain pakotetut", + "NoSubtitlesHelp": "Tekstityksiä ei ladata oletuksena. Ne voidaan silti kytkeä päälle manuaalisesti toiston aikana.", + "News": "Uutiset", + "Never": "Ei koskaan", + "MessageReenableUser": "Ottaaksesi uudelleen käyttöön, katso alempaa", + "MessagePluginConfigurationRequiresLocalAccess": "Kirjaudu suoraan paikalliselle palvelimellesi muokataksesi tätä liitännäistä.", + "MessagePleaseEnsureInternetMetadata": "Varmista, että metadatan lataus on käytössä.", + "MessageNoServersAvailable": "Automaattisen palvelintunnistuksen avulla ei löydy palvelimia.", + "MessageUnauthorizedUser": "Sinulla ei ole lupaa käyttää palvelinta tällä hetkellä. Ota yhteyttä palvelimen järjestelmänvalvojaan saadaksesi lisätietoja.", + "MessageInvalidForgotPasswordPin": "PIN-koodi on kelpaa tai vanhentunut. Yritä uudelleen.", + "MessageImageTypeNotSelected": "Valitse kuvatyyppi pudotusvalikosta.", + "MessageImageFileTypeAllowed": "Vain JPEG ja PNG tiedostomuotoja tuetaan.", + "MessageContactAdminToResetPassword": "Ota yhteyttä järjestelmänvalvojaan nollataksesi salasanasi.", + "MessageConfirmShutdown": "Haluatko varmasti sammuttaa palvelimen?", + "LabelUserLibrary": "Käyttäjän kirjasto:", + "LabelTranscodingProgress": "Transkoodauksen edistyminen:", + "LabelTranscodingFramerate": "Transkoodauksen ruudunpäivitysnopeus:", + "LabelTranscodes": "Transkoodaukset:", + "LabelTrackNumber": "Raidan numero:", + "LabelTitle": "Nimi:", + "LabelTagline": "Tunnisterivi:", + "LabelSubtitlePlaybackMode": "Tekstitystila:", + "LabelSortOrder": "Lajittelujärjestys:", + "LabelSerialNumber": "Sarjanumero", + "LabelSendNotificationToUsers": "Lähetä ilmoitus:", + "LabelSelectVersionToInstall": "Valitse asennettava versio:", + "LabelPublicHttpsPortHelp": "Paikalliseen HTTPS-porttiin liitettävä julkisen portin numero.", + "LabelPublicHttpPortHelp": "Paikalliseen HTTP-porttiin liitettävä julkisen portin numero.", + "LabelPreferredDisplayLanguage": "Ensisijainen näyttökieli:", + "LabelOriginalTitle": "Alkuperäinen nimi:", + "LabelOriginalAspectRatio": "Alkuperäinen kuvasuhde:", + "LabelEnableAutomaticPortMapHelp": "Yritä automaattisesti yhdistää julkinen ja paikallinen portti UPnP:n kautta. Tämä ei välttämättä toimi kaikkien reitittimien kanssa. Muutokset tulevat voimaan vasta palvelimen uudelleenkäynnistyksen yhteydessä.", + "LabelEnableAutomaticPortMap": "Salli reitittimen porttien automaattinen avaaminen (UPnP)", + "LabelDownloadLanguages": "Latauskielet:", + "LabelDisplaySpecialsWithinSeasons": "Näytä erityiset jaksot kausien sisällä, jolloin ne ilmestyivät", + "LabelDisplayOrder": "Näyttöjärjestys:", + "LabelDisplayName": "Näyttönimi:", + "LabelDisplayMode": "Näyttötila:", + "LabelDateTimeLocale": "Päivämäärä ja aika:", + "LabelCustomRating": "Mukautettu luokitus:", + "LabelCustomDeviceDisplayName": "Näyttönimi:", + "LabelCustomCss": "Mukautettu CSS:", + "LabelCertificatePassword": "Sertifikaatin salasana:", + "LabelAudio": "Audio", + "LabelArtistsHelp": "Erota useita käyttämällä ;", + "LabelAppNameExample": "Esimerkiksi: Sickbeard, Sonarr", + "LabelAppName": "Sovelluksen nimi", + "LabelAllowedRemoteAddressesMode": "Etä-IP-osoitesuodattimen tila:", + "LabelAllowedRemoteAddresses": "Etä-IP-osoitesuodatin:", + "LabelAllowServerAutoRestartHelp": "Palvelin käynnistyy uudelleen vain hiljaisina aikoina, kun yksikään käyttäjä ei ole aktiivinen.", + "LabelAllowServerAutoRestart": "Salli palvelimen automaattinen uudelleenkäynnistys päivitysten asentamiseksi", + "LabelAllowHWTranscoding": "Salli laitteistolla transkoodaus", + "LabelAlbumArtMaxWidth": "Albumin kuvan maksimileveys:", + "LabelAlbumArtMaxHeight": "Albumin kuvan maksimikorkeus:", + "LabelAbortedByServerShutdown": "(Keskeytetty palvelimen sammutuksen takia)", + "Identify": "Tunnista", + "Horizontal": "Horisontaalinen", + "HideWatchedContentFromLatestMedia": "Piilota toistettu sisältö \"uusin media\"-luettelosta", + "HeaderUpcomingOnTV": "Tulossa televisiossa", + "HeaderTypeImageFetchers": "{0} Kuvien hakijat", + "HeaderTranscodingProfile": "Transkoodausprofiili", + "HeaderTracks": "Raidat", + "HeaderThisUserIsCurrentlyDisabled": "Tämä käyttäjä on poistettu käytöstä", + "HeaderSystemDlnaProfiles": "Järjestelmäprofiilit", + "HeaderSubtitleDownloads": "Tekstitysten lataukset", + "HeaderSpecialFeatures": "Lisäominaisuudet", + "HeaderSpecialEpisodeInfo": "Erikoisjakson tiedot", + "HeaderSortOrder": "Lajittelujärjestys", + "HeaderSetupLibrary": "Aseta mediakirjastosi", + "HeaderSeriesStatus": "Sarjan status", + "HeaderSeriesOptions": "Sarjan asetukset", + "HeaderSelectTranscodingPath": "Valitse transkoodauksen väliaikainen polku", + "HeaderSchedule": "Ajastus", + "HeaderScenes": "Kohtaukset", + "HeaderResponseProfile": "Vastausprofiili", + "HeaderRemoveMediaLocation": "Poista mediasijainti", + "HeaderRecordingOptions": "Tallennusasetukset", + "HeaderRecentlyPlayed": "Äskettäin toistetut", + "HeaderProfileServerSettingsHelp": "Nämä arvot mukauttavat sitä, kuinka Jellyfin-palvelin esittää itsensä laitteelle.", + "HeaderProfileInformation": "Profiili-informaatio", + "HeaderPreferredMetadataLanguage": "Ensisijainen metadatan kieli", + "HeaderPinCodeReset": "Nollaa PIN-koodi", + "HeaderPhotoAlbums": "Kuva-albumit", + "HeaderPendingInvitations": "Odottavat kutsut", + "HeaderPaths": "Polut", + "HeaderPasswordReset": "Salasanan nollaus", + "HeaderNextVideoPlayingInValue": "Seuraava video alkaa {0}", + "HeaderNextEpisodePlayingInValue": "Seuraava jakso alkaa {0}", + "HeaderNewDevices": "Uudet laitteet", + "HeaderMyMediaSmall": "Minun mediani (pieni)", + "HeaderMyMedia": "Minun mediani", + "HeaderMyDevice": "Minun laitteeni", + "HeaderLoginFailure": "Kirjautumisvirhe", + "HeaderIdentifyItemHelp": "Anna yksi tai useampi hakukriteeri. Poista kriteerejä lisätäksesi hakutuloksia.", + "HeaderIdentificationCriteriaHelp": "Lisää ainakin yksi tunnistuskriteeri.", + "HeaderFeatures": "Ominaisuudet", + "HeaderFavoriteVideos": "Suosikkivideot", + "HeaderFavoritePeople": "Suosikki-ihmiset", + "HeaderFavoriteMovies": "Suosikkielokuvat", + "HeaderFavoriteBooks": "Suosikkikirjat", + "HeaderExternalIds": "Ulkoiset IDt:", + "HeaderDirectPlayProfile": "Suoratoistoprofiili", + "HeaderEasyPinCode": "Helppo PIN-koodi", + "HeaderDownloadSync": "Lataus ja synkronointi", + "HeaderDeveloperInfo": "Kehittäjäinfo", + "HeaderDetectMyDevices": "Havaitse laitteitani", + "HeaderDeleteProvider": "Poista tarjoaja", + "HeaderDefaultRecordingSettings": "Oletus tallennusasetukset", + "HeaderDateIssued": "Antopäivä", + "HeaderCustomDlnaProfiles": "Mukautetut profiilit", + "HeaderConfirmRevokeApiKey": "Peru API-avain", + "HeaderConfirmProfileDeletion": "Vahvista profiilin poisto", + "HeaderConfirmPluginInstallation": "Vahvista liitännäisen asennus", + "HeaderConfigureRemoteAccess": "Määritä etäkäyttö", + "HeaderChapterImages": "Kappalekuvat", + "HeaderChannels": "Kanavat", + "HeaderApp": "Sovellus", + "HeaderAllowMediaDeletionFrom": "Salli median poisto", + "HeaderAlert": "Hälytys", + "HeaderActivity": "Toiminta", + "HandledByProxy": "Reverse proxyn hoitama", + "HDPrograms": "HD-ohjelmat", + "OptionDownloadArtImage": "Taide", + "OptionDownloadDiscImage": "Levy", + "OptionDownloadBoxImage": "Laatikko", + "OptionDownloadBannerImage": "Lippu", + "OptionDownloadBackImage": "Tausta", + "OptionDisableUser": "Poista tämä käyttäjä käytöstä", + "OptionDescending": "Laskeva", + "OptionDatePlayed": "Toistopäivä", + "OptionDateAddedImportTime": "Käytä kirjastoon skannauspäivää", + "OptionDateAddedFileTime": "Käytä tiedoston luontipäivää", + "OptionDateAdded": "Lisäyspäivä", + "OptionDaily": "Päivittäinen", + "OptionBluray": "Blu-ray", + "TabTrailers": "Trailerit", + "OptionBlockTvShows": "TV-sarjat", + "OptionBlockTrailers": "Trailerit", + "OptionBlockMusic": "Musiikki", + "OptionBlockMovies": "Elokuvat", + "HeaderMovies": "Elokuvat", + "HeaderMoreLikeThis": "Lisää tällaista", + "HeaderMetadataSettings": "Metadata-asetukset", + "MoreMediaInfo": "Mediainfo", + "HeaderMediaInfo": "Mediainfo", + "HeaderMediaFolders": "Mediakansiot", + "HeaderMedia": "Media", + "HeaderLiveTv": "Live-TV", + "HeaderLibraryFolders": "Kirjaston kansiot", + "HeaderLatestMedia": "Uusin media", + "HeaderLatestRecordings": "Uusimmat tallenteet", + "HeaderLatestMusic": "Uusin musiikki", + "HeaderLatestMovies": "Uusimmat elokuvat", + "HeaderLatestEpisodes": "Uusimmat jaksot", + "HeaderInstall": "Asenna", + "HeaderGenres": "Tyylilajit", + "HeaderFrequentlyPlayed": "Usein toistetut", + "HeaderFetcherSettings": "Hakijan asetukset", + "HeaderFetchImages": "Hae kuvia:", + "HeaderFilters": "Suodattimet", + "OptionBlockBooks": "Kirjat", + "Filters": "Suodattimet", + "FastForward": "Hyppää eteenpäin", + "YadifBob": "YADIF Bob", + "MessageInvalidUser": "Väärä käyttäjätunnus tai salasana. Yritä uudelleen.", + "MessageConfirmRestart": "Haluatko varmasti uudelleenkäynnistää Jellyfin-palvelimen?", + "MessageConfirmProfileDeletion": "Haluatko varmasti poistaa tämän profiilin?", + "MessageConfirmDeleteTunerDevice": "Haluatko varmasti poistaa tämän laitteen?", + "MessageConfirmAppExit": "Haluatko poistua?", + "MessageAreYouSureYouWishToRemoveMediaFolder": "Haluatko varmasti poistaa tämän mediakansion?", + "MessageAreYouSureDeleteSubtitles": "Haluatko varmasti poistaa tämän tekstitystiedoston?", + "MessageAlreadyInstalled": "Tämä versio on jo asennettu.", + "Menu": "Valikko", + "MediaInfoStreamTypeVideo": "Video", + "MediaInfoStreamTypeSubtitle": "Tekstitys", + "MediaInfoStreamTypeData": "Data", + "MediaInfoStreamTypeAudio": "Audio", + "MediaInfoSoftware": "Ohjelmisto", + "MediaInfoTimestamp": "Aikaleima", + "MediaInfoResolution": "Resoluutio", + "MediaInfoSize": "Koko", + "MediaInfoProfile": "Profiili", + "MediaInfoLevel": "Taso", + "MediaInfoPath": "Polku", + "MediaInfoLanguage": "Kieli", + "MediaInfoInterlaced": "Lomiteltu", + "MediaInfoFramerate": "Ruudunpäivitysnopeus", + "MediaInfoForced": "Pakotettu", + "MediaInfoDefault": "Oletus", + "MediaInfoExternal": "Ulkoinen", + "MediaInfoChannels": "Kanavat", + "MediaInfoAspectRatio": "Kuvasuhde", + "MarkUnplayed": "Merkitse toistamattomaksi", + "MarkPlayed": "Merkitse toistetuksi", + "ManageRecording": "Hallitse tallennusta", + "ManageLibrary": "Hallitse kirjastoa", + "Logo": "Logo", + "LiveTV": "Live-TV", + "LiveBroadcasts": "Suorat lähetykset", + "Live": "Suora", + "List": "Lista", + "LinksValue": "Linkkejä: {0}", + "LearnHowYouCanContribute": "Katso, miten voit auttaa.", + "Large": "Suuri", + "LabelffmpegPath": "FFmpeg polku:", + "LabelZipCode": "Postinumero:", + "LabelYear": "Vuosi:", + "LabelVideoResolution": "Videon resoluutio:", + "LabelVideo": "Video", + "DashboardArchitecture": "Arkkitehtuuri: {0}", + "DashboardOperatingSystem": "Käyttöjärjestelmä: {0}", + "DashboardServerName": "Palvelin: {0}", + "DashboardVersionNumber": "Versio: {0}", + "LabelVersionInstalled": "{0} asennettu", + "LabelVersion": "Versio:", + "LabelValue": "Arvo:", + "LabelUsername": "Käyttäjätunnus:", + "LabelUser": "Käyttäjä:", + "LabelUseNotificationServices": "Käytä seuraavia palveluita:", + "LabelTypeText": "Teksti", + "LabelTypeMetadataDownloaders": "{0} metadatan lataajat:", + "LabelType": "Tyyppi:", + "LabelTunerType": "Virittimen tyyppi:", + "LabelTunerIpAddress": "Virittimen IP-osoite:", + "LabelTranscodingThreadCountHelp": "Valitse enimmäismäärä säikeitä, joita käytetään transkoodatessa. Säikeiden vähentäminen laskee prosessorin käyttöä, mutta myös lisää riskiä, että uudelleenkoodaus ei tapahdu riittävän nopeasti virheetöntä toistoa varten.", + "LabelTranscodingThreadCount": "Transkoodaus säikeidein lukumäärä:", + "LabelTranscodePath": "Transkoodauksen polku:", + "LabelTimeLimitHours": "Aikaraja (tunteina):", + "LabelTime": "Aika:", + "LabelTheme": "Teema:", + "LabelTextSize": "Tekstin koko:", + "LabelTextColor": "Tekstin väri:", + "LabelTextBackgroundColor": "Tekstin taustaväri:", + "LabelSupportedMediaTypes": "Tuetut mediatyypit:", + "LabelTag": "Tunniste:", + "LabelSubtitles": "Tekstitykset", + "LabelSubtitleFormatHelp": "Esimerkki: srt", + "LabelStatus": "Status:", + "LabelSource": "Lähde:", + "LabelSize": "Koko:", + "LabelServerName": "Palvelimen nimi:", + "LabelServerHostHelp": "192.168.1.100:8096 tai https://myserver.com", + "LabelSelectUsers": "Valitse käyttäjät:", + "LabelSeasonNumber": "Kauden numero:", + "LabelScreensaver": "Näytönsäästäjä:", + "LabelReasonForTranscoding": "Transkoodauksen syy:", + "LabelReadHowYouCanContribute": "Katso, miten voit auttaa.", + "LabelPublicHttpsPort": "Julkinen HTTPS-porttinumero:", + "LabelPublicHttpPort": "Julkinen HTTP-porttinumero:", + "LabelProtocolInfo": "Protokollan info:", + "LabelProtocol": "Protokolla:", + "LabelPreferredSubtitleLanguage": "Ensisijainen tekstityksen kieli:", + "LabelPreferredDisplayLanguageHelp": "Jellyfinin kääntäminen on käynnissä oleva projekti.", + "LabelPlayerDimensions": "Soittimen mitat:", + "LabelPlayer": "Soitin:", + "LabelPlaylist": "Soittolista:", + "LabelPlaceOfBirth": "Synnyinpaikka:", + "LabelPersonRoleHelp": "Esimerkki: Jäätelöauton ajaja", + "LabelPersonRole": "Rooli:", + "LabelPath": "Polku:", + "LabelPasswordRecoveryPinCode": "PIN-koodi:", + "LabelPasswordConfirm": "Salasanan varmistus:", + "LabelPassword": "Salasana:", + "LabelOptionalNetworkPath": "(Valinnainen) Jaettu verkkokansio:", + "LabelNumber": "Numero:", + "LabelNotificationEnabled": "Ota tämä ilmoitus käyttöön", + "LabelNewName": "Uusi nimi:", + "LabelName": "Nimi:", + "LabelMovieCategories": "Elokuvakategoriat:", + "LabelMinScreenshotDownloadWidth": "Pienin kuvakaappauksen latauksen leveys:", + "LabelMinResumePercentageHelp": "Kohteita pidetään toistamattomina, jos toisto keskeytetään ennen tätä aikaa.", + "LabelMinResumeDuration": "Minimi jatkamisen kesto (sekuntia):", + "LabelMinResumePercentage": "Vähimmäisaika jatkoa varten (%):", + "LabelMinResumeDurationHelp": "Kohteiden, joiden toistoaika on tätä lyhyempi, ei voi jatkaa.", + "LabelMethod": "Metodi:", + "LabelMetadataSaversHelp": "Valitse tiedostomuodot, joihin metadata tallennetaan.", + "LabelMetadataSavers": "Metadatan tallentajat:", + "LabelMetadataDownloadLanguage": "Ensisijainen latauskieli:", + "LabelMetadataReaders": "Metadatan lukijat:", + "LabelMetadataPath": "Metadatan polku:", + "LabelMetadata": "Metadata:", + "LabelMessageTitle": "Viestin otsikko:", + "LabelCachePath": "Välimuistin polku:", + "LabelCache": "Välimuisti:", + "LabelBurnSubtitles": "Polta tekstitykset:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Päivitä metadata automaattisesti:", + "LabelAuthProvider": "Todennuksen tarjoaja:", + "ExtraLarge": "Suurin", + "EveryNDays": "Joka {0} päivä", + "Raised": "Korotettu", + "TabShows": "Sarjat", + "Yesterday": "Eilen", + "Yes": "Kyllä", + "Unplayed": "Toistamattomat", + "Unmute": "Lopeta vaimennus", + "Tuesday": "Tiistai", + "Transcoding": "Transkoodaus", + "Trailers": "Trailerit", + "TitlePlayback": "Toistaminen", + "Thursday": "Torstai", + "TheseSettingsAffectSubtitlesOnThisDevice": "Nämä asetukset vaikuttavat tekstityksiin tällä laitteella", + "ThemeVideos": "Tunnusvideot", + "ThemeSongs": "Tunnuslaulut", + "TagsValue": "Tunnisteet: {0}", + "Tags": "Tunnisteet", + "TabUsers": "Käyttäjät", + "TabUpcoming": "Tulevat", + "TabTranscoding": "Transkoodaus", + "TabSuggestions": "Ehdotukset", + "TabSongs": "Kappaleet", + "TabSettings": "Asetukset", + "TabServer": "Palvelin", + "TabSeries": "Sarjat", + "TabScheduledTasks": "Ajastetut tehtävät", + "TabResumeSettings": "Jatka", + "TabResponses": "Vastaukset", + "TabRecordings": "Tallennukset", + "TabPlugins": "Liitännäiset", + "TabPlaylists": "Soittolistat", + "TabPlaylist": "Soittolista", + "TabPlayback": "Toistaminen", + "TabNfoSettings": "NFO-asetukset", + "TabNetworks": "Verkot", + "TabMyPlugins": "Omat liittännäiseni", + "TabMusicVideos": "Musiikkivideot", + "TabMusic": "Musiikki", + "TabMovies": "Elokuvat", + "TabMetadata": "Metadata", + "TabLogs": "Lokit", + "TabLiveTV": "Live-TV", + "TabLatest": "Uusimmat", + "TabInfo": "Tiedot", + "TabGenres": "Tyylilajit", + "TabFavorites": "Suosikit", + "TabEpisodes": "Jaksot", + "TabDisplay": "Näyttö", + "TabDirectPlay": "Suoratoisto", + "TabDevices": "Laitteet", + "TabDashboard": "Päänäkymä", + "TabCollections": "Kokoelmat", + "TabChannels": "Kanavat", + "TabCatalog": "Luettelo", + "TabArtists": "Artistit", + "TabAlbums": "Albumit", + "TabAlbumArtists": "Albumin artistit", + "TabAdvanced": "Edistynyt", + "TV": "TV", + "Sunday": "Sunnuntai", + "Subtitles": "Tekstitykset", + "Studios": "Studiot", + "StopRecording": "Lopeta tallennus", + "Sort": "Järjestä", + "Smart": "Älykäs", + "SkipEpisodesAlreadyInMyLibrary": "Älä tallenna jaksoja, jotka ovat jo kirjastossani", + "Shuffle": "Satunnaistoisto", + "ShowTitle": "Näytä nimi", + "ShowYear": "Näytä vuosi", + "ShowAdvancedSettings": "Näytä edistyneet asetukset", + "Share": "Jaa", + "Settings": "Asetukset", + "ServerRestartNeededAfterPluginInstall": "Jellyfin palvelin täytyy uudelleenkäynnistää liitännäisen asennuksen jälkeen.", + "ServerNameIsShuttingDown": "Jellyfin palvelin - {0} on sammumassa.", + "ServerNameIsRestarting": "Jellyfin palvelin - {0} uudelleenkäynnistyy.", + "Series": "Sarjat", + "SendMessage": "Lähetä viesti", + "SelectAdminUsername": "Valitse käyttäjätunnus järjestelmänvalvojan tilille.", + "SearchForCollectionInternetMetadata": "Etsi kuvamateriaalia ja metadataa internetistä", + "SearchForMissingMetadata": "Etsi puuttuvaa metadataa", + "Season": "Kausi", + "SearchResults": "Tulokset", + "SearchForSubtitles": "Etsi tekstityksiä", + "Search": "Etsi", + "Screenshots": "Kuvakaappaukset", + "Screenshot": "Kuvakaappaus", + "Schedule": "Ajasta", + "ScanLibrary": "Skannaa kirjasto", + "SaveSubtitlesIntoMediaFolders": "Tallenna tekstitykset mediakansioihin", + "Saturday": "Lauantai", + "ResumeAt": "Jatka kohdasta {0}", + "RestartPleaseWaitMessage": "Odota kunnes Jellyfin palvelin sammuu ja käynnistyy uudelleen. Tämä voi kestää hetken aikaa.", + "RequiredForAllRemoteConnections": "Vaadittu kaikille etäyhteyksille", + "ReplaceExistingImages": "Korvaa olemassaolevat kuvat", + "ReplaceAllMetadata": "Korvaa kaikki metadata", + "RepeatEpisodes": "Toista jaksot uudelleen", + "RepeatAll": "Toista kaikki uudelleen", + "Repeat": "Toista uudelleen", + "RemoveFromPlaylist": "Poista soittolistalta", + "RemoveFromCollection": "Poista kokoelmasta", + "RememberMe": "Muista minut", + "ReleaseDate": "Julkaisupäivä", + "RefreshMetadata": "Päivitä metadata", + "RefreshDialogHelp": "Metadata päivitetään asetuksien ja Internet palveluiden perusteella, jotka ovat kytkettynä päälle Jellyfin palvelimen päänäkymässä.", + "Refresh": "Päivitä", + "Recordings": "Tallennukset", + "RecordingScheduled": "Tallennus ajastettu.", + "RecordingCancelled": "Tallennus peruttu.", + "RecordSeries": "Tallenna sarja", + "Record": "Tallenna", + "OptionAutomatic": "Auto", + "OptionAuto": "Auto", + "OptionAscending": "Nousevassa järjestyksessä", + "OptionArtist": "Artisti", + "OptionAllowVideoPlaybackTranscoding": "Salli transkoodausta vaativan videon toistaminen", + "OptionAllowVideoPlaybackRemuxing": "Salli videon toistaminen, joka vaatii muuntamista ilman koodausta", + "OptionAllowMediaPlaybackTranscodingHelp": "Transkoodauksen estäminen voi aiheuttaa toistovirheitä Jellyfin-sovelluksissa ei-tuettujen mediaformaattien takia.", + "OptionAllowLinkSharingHelp": "Vain mediatietoja sisältävät web-sivut jaetaan. Mediatiedostoja ei koskaan jaeta julkisesti. Jaot ovat määräaikaisia ja päättyvät {0} päivän kuluttua.", + "OptionAllowUserToManageServer": "Salli tämän käyttäjän hallita palvelinta", + "OptionAllowSyncTranscoding": "Salli transkoodausta vaativan median lataaminen ja synkronointi", + "OptionAllowRemoteSharedDevicesHelp": "DLNA-laitteet katsotaan jaetuiksi kunnes käyttäjä alkaa ohjata niitä.", + "OptionAllowRemoteSharedDevices": "Salli jaettujen laitteiden etäohjaaminen", + "OptionAllowRemoteControlOthers": "Salli muiden käyttäjien etäohjaaminen", + "OptionAllowManageLiveTv": "Salli Live-TV tallenteiden hallinta", + "OptionAllowMediaPlayback": "Salli median toisto", + "OptionAllowContentDownloading": "Salli median lataaminen ja synkronointi", + "OptionAllowBrowsingLiveTv": "Salli Live-TV käyttöoikeus", + "HeaderPluginInstallation": "Liitännäisen asennus", + "HeaderPlaybackError": "Toistovirhe", + "HeaderPlayback": "Median toisto", + "HeaderPlayOn": "Toista laitteella", + "OptionAllowLinkSharing": "Salli jakaminen sosiaaliseen mediaan", + "OptionAllowAudioPlaybackTranscoding": "Salli äänen toistaminen joka vaatii uudelleenpakkausta", + "OptionAllUsers": "Kaikki käyttäjät", + "OptionAlbumArtist": "Albumin artisti", + "OptionAlbum": "Albumi", + "OptionAdminUsers": "Järjestelmänvalvojat", + "Option3D": "3D", + "MusicVideo": "Musiikkivideo", + "MoveRight": "Siirry oikealle", + "MoveLeft": "Siirry vasemmalle", + "Mobile": "Mobiili", + "EveryXHours": "Joka {0} tunti", + "EveryXMinutes": "Joka {0} minuutti", + "EveryHour": "Joka tunti", + "LastSeen": "Viimeksi nähty {0}", + "Yadif": "YADIF", + "Writer": "Kirjoittaja", + "WelcomeToProject": "Tervetuloa Jellyfiniin!", + "Wednesday": "Keskiviikko", + "ViewArtist": "Näytä artisti", + "ViewAlbum": "Näytä albumi", + "Vertical": "Vertikaalinen", + "ValueSongCount": "{0} kappaletta", + "ValueSeriesCount": "{0} sarjaa", + "ValueSeconds": "{0} sekuntia", + "ValueOneSong": "1 kappale", + "ValueOneSeries": "1 sarja", + "ValueOneMusicVideo": "1 musiikkivideo", + "ValueOneMovie": "1 elokuva", + "ValueOneEpisode": "1 jakso", + "ValueOneAlbum": "1 albumi", + "ValueMusicVideoCount": "{0} musiikkivideota", + "ValueMovieCount": "{0} elokuvaa", + "ValueMinutes": "{0} min", + "ValueEpisodeCount": "{0} jaksoa", + "ValueDiscNumber": "Levy {0}", + "ValueAlbumCount": "{0} albumia", + "Up": "Ylös", + "OnApplicationStartup": "Käynnistyksen yhteydessä", + "NumLocationsValue": "{0} kansiota", + "NoSubtitleSearchResultsFound": "Ei tuloksia.", + "NoPluginConfigurationMessage": "Tällä liitännäisellä ei ole asetuksia muokattavaksi.", + "NoCreatedLibraries": "Vaikuttaa siltä, ettet ole luonut vielä yhtään kirjastoa. {0} Haluaisitko luoda sellaisen nyt?{1}", + "No": "Ei", + "NextUp": "Seuraavana", + "Next": "Seuraava", + "NewEpisodesOnly": "Vain uudet jaksot", + "NewEpisodes": "Uusia jaksoja", + "NewCollectionNameExample": "Esimerkki: Star Wars Kokoelma", + "NewCollectionHelp": "Kokoelmat mahdollistavat elokuvien ja muun kirjastosisällön personalisoidun ryhmittämisen.", + "NewCollection": "Uusi kokoelma", + "Mute": "Vaimenna", + "Name": "Nimi", + "MySubtitles": "Minun tekstitykseni", + "MusicArtist": "Musiikkiartisti", + "MusicAlbum": "Musiikkialbumi", + "Movie": "Elokuva", + "Monday": "Maanantai", + "MetadataManager": "Metadatan hallintatyökalu", + "Metadata": "Metadata", + "MessageYouHaveVersionInstalled": "Sinulla on versio {0} asennettuna.", + "MessageSettingsSaved": "Asetukset tallennettu.", + "MessagePleaseWait": "Ole hyvä ja odota. Tämä voi kestää hetken.", + "MessageNothingHere": "Täällä ei ole mitään.", + "MessageNoPluginsInstalled": "Sinulla ei ole asennettuna yhtään liitännäistä.", + "MessageNoAvailablePlugins": "Ei saatavilla olevia liitännäisiä.", + "InstallingPackage": "Asennetaan {0} (versio {1})", + "HeaderVideoTypes": "Videotyypit", + "HeaderVideoType": "Videotyyppi", + "HeaderUploadImage": "Lataa kuva", + "HeaderTypeText": "Kirjoita teksti", + "HeaderTunerDevices": "Viritinlaitteet", + "HeaderTuners": "Virittimet", + "HeaderTaskTriggers": "Tehtävän laukaisijat", + "HeaderSubtitleProfilesHelp": "Tekstitysprofiilit kuvaavat tämän laitteen tukemia tekstitysformaatteja.", + "HeaderSubtitleProfiles": "Tekstitysprofiilit", + "HeaderSubtitleProfile": "Tekstitysprofiili", + "HeaderStartNow": "Aloita nyt", + "HeaderSortBy": "Lajittele", + "HeaderSelectServerCachePath": "Valitse palvelimen välimuistin polku", + "HeaderSelectPath": "Valitse polku", + "HeaderSelectCertificatePath": "Valitse sertifikaatin polku", + "HeaderSelectMetadataPath": "Valitse metadatan polku", + "HeaderSecondsValue": "{0} Sekuntia", + "HeaderRunningTasks": "Käynnissä olevat tehtävät", + "HeaderRevisionHistory": "Versiohistoria", + "HeaderRestartingServer": "Uudelleenkäynnistetään palvelinta", + "HeaderRemoveMediaFolder": "Poista mediakansio", + "HeaderRemoteControl": "Etäohjaus", + "HeaderPleaseSignIn": "Ole hyvä ja kirjaudu sisään", + "BoxSet": "Laatikkosarja", + "LabelAccessEnd": "", + "LabelManufacturerUrl": "Valmistajan verkko-osoite", + "LabelManufacturer": "Valmistaja:", + "LabelLogs": "Lokit:", + "LabelLanNetworks": "Lähiverkot:", + "LabelKodiMetadataDateFormat": "Julkaisupäivämäärän muoto:", + "LabelImageType": "Kuvan tyyppi:", + "LabelIconMaxWidth": "Ikonin enimmäisleveys:", + "LabelIconMaxHeight": "Ikonin enimmäiskorkeus:", + "LabelGroupMoviesIntoCollections": "Ryhmitä elokuvat kokoelmiin", + "LabelFormat": "Muoto:", + "LabelFont": "Kirjasinlaji:", + "LabelFolder": "Kansio:", + "LabelEpisodeNumber": "Jaksonumero:", + "LabelDropShadow": "Varjostus:", + "LabelDeathDate": "Kuolinpäivä:", + "LabelDay": "Päivä:", + "LabelDateAdded": "Lisäyspäivämäärä:", + "LabelCollection": "Kokoelma:", + "LabelBirthYear": "Syntymävuosi:", + "LabelBirthDate": "Syntymäaika:", + "LabelArtists": "Artistit:", + "LabelAll": "Kaikki", + "LabelAlbum": "Albumi:", + "LabelAirTime": "Lähetysaika:", + "LabelAccessDay": "Viikonpäivä:", + "Label3DFormat": "3D-formaatti:", + "Kids": "Lapset", + "Images": "Kuvat", + "Hide": "Piilota", + "HeadersFolders": "Kansiot", + "HeaderYears": "Vuodet", + "HeaderVideos": "Videot", + "HeaderVideoQuality": "Kuvanlaatu", + "HeaderUsers": "Käyttäjät", + "HeaderUser": "Käyttäjä", + "HeaderTags": "Tunnisteet", + "HeaderSubtitleAppearance": "Tekstityksen ulkonäkö", + "HeaderStatus": "Tila", + "HeaderShutdown": "Sammuta", + "HeaderServerSettings": "Palvelimen asetukset", + "HeaderSettings": "Asetukset", + "HeaderSendMessage": "Lähetä viesti", + "HeaderSelectServer": "Valitse palvelin", + "HeaderSeasons": "Kaudet", + "HeaderRestart": "Uudelleenkäynnistys", + "HeaderProfile": "Profiili", + "HeaderPlayAll": "Toista kaikki", + "HeaderPeople": "Ihmiset", + "HeaderPassword": "Salasana", + "HeaderNewApiKey": "Uusi API-avain", + "HeaderNavigation": "Navigaatio", + "HeaderMusicVideos": "Musiikkivideot", + "HeaderMusicQuality": "Musiikin laatu", + "HeaderLibraries": "Kirjastot", + "HeaderIdentification": "Tunnistautuminen", + "HeaderForgotPassword": "Unohtuiko salasana", + "HeaderForKids": "Lapsille", + "HeaderError": "Virhe", + "HeaderEpisodes": "Jaksot", + "HeaderEditImages": "Muokkaa kuvia", + "HeaderDisplay": "Näyttö", + "HeaderDevices": "Laitteet", + "HeaderDeleteItems": "Poista valitut", + "HeaderDeleteItem": "Poista valittu", + "HeaderDeleteDevice": "Poista laite", + "HeaderContinueListening": "Jatka kuuntelua", + "HeaderConnectionFailure": "Yhteys epäonnistui", + "HeaderConnectToServer": "Yhdistä palvelimeen", + "HeaderAudioSettings": "Ääniasetukset", + "GroupBySeries": "Ryhmitä sarjan perusteella", + "Fullscreen": "Kokonäyttötila", + "HeaderBooks": "Kirjat", + "HeaderAutomaticUpdates": "Automaattiset päivitykset", + "HeaderAudioBooks": "Äänikirjat", + "HeaderApiKeys": "API-avaimet", + "HeaderApiKey": "API-avain", + "HeaderAdmin": "Ylläpitäjä", + "HeaderAlbums": "Albumit", + "HeaderAddUser": "Lisää käyttäjä", + "HeaderAddUpdateImage": "Lisää/Päivitä kuva", + "HeaderAddToPlaylist": "Lisää soittolistaan", + "HeaderAddToCollection": "Lisää kokoelmaan", + "HeaderActiveDevices": "Aktiiviset laitteet", + "Friday": "Perjantai", + "Premiere": "Ensiesitys", + "Producer": "Tuottaja", + "Quality": "Laatu", + "LabelMessageText": "Viestin sisältö:", + "LabelMaxScreenshotsPerItem": "Kuvakaappausten enimmäismäärä per kohde:", + "LabelLoginDisclaimerHelp": "Viesti, joka näytetään kirjautumissivun alareunassa.", + "LabelLockItemToPreventChanges": "Lukitse tämä kohde estääksesi tulevat muutokset", + "LabelLocalHttpServerPortNumberHelp": "TCP-portin numero, jota Jellyfinin HTTP-palvelimen tulee kuunnella.", + "LabelLocalHttpServerPortNumber": "Paikallisen HTTP-portin numero:", + "LabelKodiMetadataSaveImagePaths": "Tallenna kuvien polut NFO-tiedostojen sisälle", + "LabelKidsCategories": "Lasten kategoriat:", + "LabelHttpsPortHelp": "TCP-portin numero, jota Jellyfinin HTTPS-palvelimen tulee kuunnella.", + "LabelHttpsPort": "Paikallisen HTTPS-portin numero:", + "LabelHardwareAccelerationTypeHelp": "Laitteistokiihdytys vaatii ylimääräistä määritystä.", + "LabelHardwareAccelerationType": "Laitteistokiihdytys:", + "LabelEncoderPreset": "H264 and H265 encoding preset:", + "LabelH264Crf": "H264 encoding CRF:", + "LabelForgotPasswordUsernameHelp": "Anna käyttäjätunnuksesi, jos muistat sen.", + "LabelEveryXMinutes": "Joka:", + "LabelEndDate": "Päättymispäivä:", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Määrittää, kuinka usein Jellyfin etsii SSDP-protokollaa käyttäviä laitteita.", + "LabelEnableDlnaDebugLoggingHelp": "Luo suuria lokitiedostoja ja tulisi käyttää vain tarvittaessa vianmääritystä varten.", + "LabelEnableDlnaServerHelp": "Sallii verkon UPnP-laitteiden selata ja toistaa sisältöä tältä palvelimelta.", + "LabelEnableDlnaServer": "Ota DLNA-palvelin käyttöön", + "LabelEnableDlnaPlayTo": "Salli DLNA toisto", + "LabelEnableDlnaDebugLogging": "Ota DLNA:n virheenjäljitys käyttöön", + "LabelEnableBlastAliveMessages": "Lähetä hereilläolo -viesti", + "LabelEnableBlastAliveMessagesHelp": "Ota tämä käyttöön, jos muilla verkon UPnP-laitteilla on ongelmia palvelimen havaitsemisessa.", + "LabelEnableDlnaClientDiscoveryInterval": "Asiakaslaitteiden havaintoväli (sekunteina)", + "LabelEasyPinCode": "Helppo PIN-koodi:", + "LabelDynamicExternalId": "{0} Id:", + "LabelDisplayLanguageHelp": "Jellyfinin kääntäminen on käynnissä oleva projekti.", + "LabelDisplayLanguage": "Näytön kieli:", + "LabelDiscNumber": "Levynumero:", + "LabelDeviceDescription": "Laitteen kuvaus", + "LabelDefaultScreen": "Oletusnäyttö:", + "LabelDefaultUser": "Oletuskäyttäjä:", + "LabelDashboardTheme": "Palvelimen päänäkymän teema:", + "LabelCustomCertificatePathHelp": "Polku PKCS # 12-tiedostoon, joka sisältää sertifikaatin ja yksityisen avaimen, jotta TLS-tuki voidaan sallia henkilökohtaiselle verkkotunnukselle.", + "LabelCustomCertificatePath": "Mukautetun SSL-sertifikaatin polku:", + "LabelContentType": "Sisältötyyppi:", + "LabelChannels": "Kanavat:", + "LabelCertificatePasswordHelp": "Jos sertifikaattisi vaatii salasanaa, laita se tähän.", + "OptionWednesday": "Keskiviikko", + "OptionTuesday": "Tiistai", + "OptionThursday": "Torstai", + "OptionSunday": "Sunnuntai", + "OptionSaturday": "Lauantai", + "LabelRuntimeMinutes": "Pituus (minuutteja):", + "LabelReleaseDate": "Julkaisupäivä:", + "Genre": "Tyylilaji", + "FolderTypeBooks": "Kirjat", + "FolderTypeMusicVideos": "Musiikkivideot", + "FolderTypeMusic": "Musiikki", + "FolderTypeMovies": "Elokuvat", + "File": "Tiedosto", + "Favorite": "Suosikki", + "Extras": "Extrat", + "ExitFullscreen": "Poistu kokonäyttötilasta", + "Episode": "Jakso", + "ButtonTogglePlaylist": "Soittolista", + "ButtonToggleContextMenu": "Lisää", + "Artist": "Artisti", + "RefreshQueued": "Päivitys odottamassa.", + "SeriesCancelled": "Sarja peruttu.", + "MediaInfoRefFrames": "Ref frames", + "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaCap": "X-DLNA cap:", + "Guide": "Opas", + "DailyAt": "Päivittäin klo {0}", + "Uniform": "Yhtenäinen", + "TrackCount": "{0} raitaa", + "Track": "Raita", + "TitleHardwareAcceleration": "Laitteistokiihdytys", + "Thumb": "Pikkukuva", + "TabStreaming": "Suoratoisto", + "TabParentalControl": "Lapsilukko", + "TabOther": "Muut", + "TabNotifications": "Ilmoitukset", + "TabNetworking": "Verkkoasetukset", + "TabGuide": "Opas", + "TabContainers": "Säiliöt", + "TabCodecs": "Codecit", + "Suggestions": "Ehdotukset", + "Sports": "Urheilu", + "Smaller": "Pienin", + "SmallCaps": "Small Caps", + "Small": "Pieni", + "Filter": "Suodata", + "New": "Uusi", + "Runtime": "Kesto", + "PlayAllFromHere": "Toista kaikki tästä lähtien", + "PlayNextEpisodeAutomatically": "Toista seuraava jakso automaattisesti", + "PlayCount": "Toistokerrat", + "PlaybackData": "Toistamisen tiedot", + "PinCodeResetComplete": "PIN-koodi on nollattu.", + "Overview": "Yleiskatsaus", + "OptionWakeFromSleep": "Herätä lepotilasta", + "OptionUnairedEpisode": "Julkaisemattomat jaksot", + "OptionParentalRating": "Ikäraja", + "OptionNone": "Ei mitään", + "OptionIgnoreTranscodeByteRangeRequests": "Ohita transkoodauksen tavualuepyynnöt", + "OptionHlsSegmentedSubtitles": "HLS segmentoidut tekstitykset", + "OptionEnableExternalContentInSuggestions": "Ota käyttöön ulkoinen sisältö ehdotuksissa", + "OptionEmbedSubtitles": "Upota säiliöön", + "OptionForceRemoteSourceTranscoding": "Pakota etämedialähteiden transkoodaus (kuten Live-TV)", + "OneChannel": "Yksi kanava", + "Off": "Poissa päältä", + "Normal": "Normaali", + "None": "Ei mitään", + "NoSubtitles": "Ei mitään", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Seuraavat mediasijainnit tullaan poistamaan kirjastostasi:", + "MessageItemsAdded": "Kohteet lisätty.", + "MessageItemSaved": "Kohde tallennettu.", + "MessageEnablingOptionLongerScans": "Tämän vaihtoehdon käyttöönottaminen voi johtaa huomattavasti pidempiin kirjastojen skannauksiin.", + "MessageDownloadQueued": "Lataus asetettu jonoon.", + "MessageConfirmRevokeApiKey": "Haluatko varmasti perua tämän API-avaimen? Sovelluksen yhteys Jellyfin-palvelimeen lopetetaan äkillisesti.", + "MessageConfirmRemoveMediaLocation": "Haluatko varmasti poistaa tämän sijainnin?", + "MessageConfirmRecordingCancellation": "Peruuta tallennus?", + "MessageConfirmDeleteGuideProvider": "Haluatko varmasti poistaa tämän ohjelmaoppaan tarjoajan?", + "MediaInfoStreamTypeEmbeddedImage": "Upotettu kuva", + "MediaInfoSampleRate": "Näytteenottotaajuus", + "MediaInfoPixelFormat": "Pikseliformaatti", + "MediaInfoLayout": "Asettelu", + "MediaInfoContainer": "Säiliö", + "MediaInfoCodecTag": "Codec-tunniste", + "MediaInfoCodec": "Codec", + "MediaInfoBitrate": "Bitrate", + "Like": "Tykkää", + "LabelVideoBitrate": "Videon bitrate:", + "LabelWeb": "Web:", + "LabelVideoCodec": "Videon codec:", + "LabelTranscodingVideoCodec": "Video codec:", + "LabelSkipIfGraphicalSubsPresent": "Ohita, jos video sisältää upotetut tekstitykset", + "LabelInternetQuality": "Verkkoyhteyden laatu:", + "LabelEmbedAlbumArtDidl": "Upota albumin kuvamateriaali Didl:iin", + "LabelDeinterlaceMethod": "Lomituksen poistamismenetelmä:", + "LabelAudioBitDepth": "Audion bittisyvyys:", + "LabelAlbumArtists": "Albumin artistit:", + "Items": "Kohteet", + "ItemCount": "{0} kohdetta", + "Home": "Koti", + "Help": "Apua", + "HeaderXmlSettings": "Xml-asetukset", + "HeaderXmlDocumentAttributes": "Xml-dokumentin attribuutit", + "HeaderXmlDocumentAttribute": "Xml-dokumentin attribuutti", + "HeaderStopRecording": "Lopeta tallennus", + "HeaderRecordingPostProcessing": "Tallennuksen jälkikäsittely", + "HeaderParentalRatings": "Ikärajat", + "HeaderOtherItems": "Muut kohteet", + "HeaderLiveTvTunerSetup": "Live-TV virittimen määritys", + "HeaderLibrarySettings": "Kirjaston asetukset", + "HeaderItems": "Kohteet", + "HeaderGuideProviders": "TV-ohjelmaoppaiden tarjoajat", + "HeaderFavoritePlaylists": "Suosikki soittolistat", + "HeaderEnabledFields": "Käytössä olevat kentät", + "HeaderCodecProfile": "Codec-profiili", + "HeaderContainerProfile": "Säiliöprofiili", + "PleaseSelectTwoItems": "Valitse ainakin kaksi kohdetta.", + "PleaseRestartServerName": "Ole hyvä ja uudelleenkäynnistä Jellyfin-palvelin - {0}.", + "PleaseEnterNameOrId": "Anna nimi tai ulkoinen ID.", + "PreferEmbeddedTitlesOverFileNames": "Suosi upotettuja otsikoita tiedostonimien sijasta", + "PreferredNotRequired": "Suositeltava, mutta ei vaadittu", + "Premieres": "Ensiesitys", + "Primary": "Ensisijainen", + "Previous": "Edellinen", + "RecommendationBecauseYouWatched": "Koska katsoit {0}", + "RecommendationBecauseYouLike": "Koska pidät {0}", + "RecentlyWatched": "Äskettäin katsotut", + "Programs": "Ohjelmat", + "LabelServerNameHelp": "Tätä nimeä käytetään palvelimen tunnistamiseen. Jos tyhjä, käytetään tietokoneen nimeä.", + "LabelEnableRealtimeMonitorHelp": "Tiedostojen muutokset käsitellään välittömästi tuetuissa tiedostojärjestelmissä.", + "LabelEnableRealtimeMonitor": "Ota reaaliaikainen seuranta käyttöön", + "LabelDropImageHere": "Pudota kuva tähän, tai paina selataksesi.", + "LabelDroppedFrames": "Pudotettuja kuvia:", + "LabelDidlMode": "DIDL tila:", + "LabelCustomDeviceDisplayNameHelp": "Tätä nimeä käytetään laitteen tunnistamiseen. Jos tyhjä, käytetään laitteen nimeä.", + "LabelCustomCssHelp": "Käytä omaa CSS: ää web-käyttöliittymään.", + "LabelCorruptedFrames": "Korruptoituneita kuvia:", + "LabelCriticRating": "Kriitikoiden luokitus:", + "LabelCommunityRating": "Yhteisön luokitus:", + "LabelCancelled": "Peruttu", + "LabelBlockContentWithTags": "Estä kohteet tunnisteilla:", + "LabelBitrate": "Bitrate:", + "LabelAudioSampleRate": "Audion näytteenottotaajuus:", + "LabelAudioChannels": "Audiokanavia:", + "LabelAudioBitrate": "Audion bitrate:", + "LabelAudioCodec": "Audio codec:", + "LabelTranscodingContainer": "Säiliö:", + "LabelTranscodingAudioCodec": "Audio codec:", + "LabelSubtitleDownloaders": "Tekstitysten lataajat:", + "LabelSpecialSeasonsDisplayName": "Erikoiskauden näyttönimi:", + "LabelSoundEffects": "Ääniefektit:", + "LabelSortTitle": "Lajitteluotsikko:", + "LabelSkipIfAudioTrackPresent": "Ohita, jos oletusääniraita vastaa latauskieltä", + "LabelSkipBackLength": "Taaksepäin hyppäämisen pituus:", + "LabelSkipForwardLength": "Eteenpäin hyppäämisen pituus:", + "LabelScheduledTaskLastRan": "Viimeisin ajo {0}, kesto {1}.", + "LabelRemoteClientBitrateLimitHelp": "Valinnainen bittinopeusraja yksittäisille suoratoistaville laitteille lähiverkon ulkopuolella. Tämä on hyödyllistä estääkseen laitteita pyytämästä suurempia bittinopeuksia kuin Internet-yhteys voi käsitellä. Tämä voi johtaa palvelimen prosessorin kuormituksen lisääntymiseen, jotta videot voidaan transkoodata pienempiin bittinopeuksiin.", + "LabelRemoteClientBitrateLimit": "Internetistä suoratoiston enimmäisnopeus (Mbps):", + "LabelRefreshMode": "Päivitystila:", + "LabelRecordingPathHelp": "Määritä oletussijainti tallennuksille. Jätä tyhjäksi käyttääksesi palvelimen datakansiota.", + "LabelRecordingPath": "Oletustallennuspolku:", + "LabelProtocolInfoHelp": "Arvo, jota käytetään vastattaessa laitteen GetProtocolInfo-pyyntöihin.", + "LabelProfileCodecsHelp": "Pilkulla erotettuna. Jätä tyhjäksi käyttääksesi kaikissa codeceissa.", + "LabelProfileContainersHelp": "Pilkulla erotettuna. Jätä tyhjäksi käyttääksesi kaikissa säiliöissä.", + "LabelProfileVideoCodecs": "Video codecs:", + "LabelProfileContainer": "Säiliö:", + "LabelProfileCodecs": "Codecs:", + "LabelProfileAudioCodecs": "Audio codecs:", + "LabelPostProcessor": "Jälkikäsittelysovellus:", + "LabelPostProcessorArguments": "Jälkikäsittelysovelluksen komentoriviargumentit:", + "LabelPleaseRestart": "Muutokset tulevat voimaan kun web-asiakasohjelma päivitetään manuaalisesti (reload).", + "LabelPlayDefaultAudioTrack": "Toista oletusraita kielestä riippumatta", + "LabelOverview": "Yleiskatsaus:", + "LabelPasswordResetProvider": "Salasanan nollauksen palveluntarjoaja:", + "LabelParentalRating": "Ikäraja:", + "LabelOptionalNetworkPathHelp": "Jos tämä kansio on jaettu verkossa, polun jakaminen voi mahdollistaa Jellyfin-sovellusten muilla laitteilla käyttää mediatiedostoja suoraan.", + "LabelMovieRecordingPath": "Elokuvien tallenteiden polku (valinnainen):", + "LabelMusicStreamingTranscodingBitrateHelp": "Määritä enimmäisnopeus musiikkia suoratoistettaessa.", + "LabelMusicStreamingTranscodingBitrate": "Musiikin transkoodauksen bitrate:", + "LabelMinBackdropDownloadWidth": "Taustan latauksen vähimmäisleveys:", + "LabelMetadataReadersHelp": "Järjestä ensisijaiset paikallisen metadatan lähteet prioriteettijärjestykseen. Ensimmäinen löydetty tiedosto luetaan.", + "LabelMetadataPathHelp": "Määrää mukautettu sijainti ladatulle kuvamateriaalille ja metadatalle.", + "LabelMetadataDownloadersHelp": "Ota käyttöön ja järjestä ensisijaiset metadatan lataajat prioriteettijärjestykseen. Alemman prioriteetin omaavia lataajia käytetään vain täyttämään puuttuvia tietoja.", + "LabelMaxResumePercentageHelp": "Kohteita pidetään toistettuina, jos toisto pysäytetään tämän ajan kuluttua.", + "LabelMaxResumePercentage": "Enimmäisaika jatkoa varten (%):", + "LabelMaxChromecastBitrate": "Chromecastin suoratoiston laatu:", + "LabelMaxBackdropsPerItem": "Taustojen maksimimäärä per kohde:", + "LabelLoginDisclaimer": "Sisäänkirjautumisen vastuuvapauslauseke:", + "LabelLibraryPageSize": "Kirjastosivun kohteiden määrä:", + "LabelLibraryPageSizeHelp": "Asettaa kirjastosivulla näytettävien kohteiden määrän. Arvo 0 poistaa sivutuksen käytöstä.", + "LabelLineup": "", + "Unrated": "Luokittelematon", + "ExtractChapterImagesHelp": "Pikkukuvien luominen mahdollistaa sovellusten näyttää graafiikkaa valintavalikoissa. Prosessi voi olla hidas, prosessoria kuormittava ja saattaa vaatia useita gigatavuja tilaa. Se suoritetaan, kun videoita havaitaan, ja myös yöksi suunniteltuna tehtävänä. Aikataulu on konfiguroitavissa ajoitetuissa tehtävissä. Tätä tehtävää ei ole suositeltavaa suorittaa korkean kuormituksen aikana.", + "OnWakeFromSleep": "Lepotilasta poistuttaessa", + "WeeklyAt": "{0}sin klo {1}", + "Whitelist": "Sallitut", + "Watched": "Katsotut", + "ViewPlaybackInfo": "Näytä toistamisen tiedot", + "ValueVideoCodec": "Video Codec: {0}", + "ValueTimeLimitSingleHour": "Aikaraja: 1 tunti", + "ValueTimeLimitMultiHour": "Aikaraja: {0} tuntia", + "ValueContainer": "Säiliö: {0}", + "ValueConditions": "Ehdot: {0]", + "ValueCodec": "Codec: {0}", + "ValueAudioCodec": "Audio Codec: {0}", + "SeriesYearToPresent": "{0} - Nykyhetki", + "DeinterlaceMethodHelp": "Valitse lomituksen poistomenetelmä, jota käytetään lomitetun sisällön transkoodaukseen.", + "FormatValue": "Muoto: {0}", + "General": "Yleinen", + "FolderTypeUnset": "Sekalainen sisältö", + "FetchingData": "Noudetaan lisätietoja", + "Features": "Ominaisuudet", + "ErrorMessageStartHourGreaterThanEnd": "Loppumisajan on oltava myöhemmin kuin aloitusaika.", + "MediaInfoAnamorphic": "Anamorfinen" } diff --git a/src/strings/fr-ca.json b/src/strings/fr-ca.json index 131be8a57f..1f74b7bd52 100644 --- a/src/strings/fr-ca.json +++ b/src/strings/fr-ca.json @@ -134,12 +134,12 @@ "BirthLocation": "Lieu de naissance", "BirthPlaceValue": "Lieu de naissance : {0}", "Blacklist": "Liste noire", - "BookLibraryHelp": "Les livres audios et numériques sont supportés. Consultez le {0}Guide de nommage pour livre de Jellyfin{1}.", + "BookLibraryHelp": "Les livres audios et formats textes sont supportés. Consultez le {0}Guide de nommage de livres de Jellyfin{1}.", "Box": "Boîtier", "BoxRear": "Dos de boîtier", "Browse": "Parcourir", "BrowsePluginCatalogMessage": "Explorer notre catalogue des plugins pour voir les plugins disponibles.", - "AllowHWTranscodingHelp": "Si l'option est activée, permet au récepteur TV de transcoder les flux à la volée. Cela peut aider à réduire le transcodage requis par le serveur Jellyfin.", + "AllowHWTranscodingHelp": "Permet au récepteur TV de transcoder les flux à la volée. Cela peut aider à réduire le transcodage requis par le serveur Jellyfin.", "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", "ButtonAccept": "Accepter", "ButtonAdd": "Ajouter", @@ -185,5 +185,13 @@ "ButtonManualLogin": "Connexion manuelle", "ButtonMenu": "Menu", "ButtonMore": "Plus", - "ButtonNetwork": "Réseau" + "ButtonNetwork": "Réseau", + "AspectRatio": "Format de visionnement", + "AskAdminToCreateLibrary": "Demander à l'administrateur pour créer une bibliothèque de média.", + "Artist": "Artiste", + "AllowFfmpegThrottlingHelp": "Quand un transcodage ou rémux se déplace après la position de relecture, suspendre le processus pour consommer moins de ressources. Ceci est le plus utile pour chercher moins. Désactiver s'il y a des problèmes de relecture.", + "AllowFfmpegThrottling": "Restreindre la vitesse de transcodage", + "AlbumArtist": "Artiste de l'Album", + "Album": "Album", + "AuthProviderHelp": "Sélectionner un fournisseur d'authentification pour authentifier le mot de passe de cet utilisateur." } diff --git a/src/strings/fr.json b/src/strings/fr.json index 428f19b3c0..3f1d22c75a 100644 --- a/src/strings/fr.json +++ b/src/strings/fr.json @@ -14,7 +14,7 @@ "Alerts": "Alertes", "All": "Tout", "AllChannels": "Toutes les chaînes", - "AllComplexFormats": "Tous les formats complexes (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc…)", + "AllComplexFormats": "Tous les formats complexes (ASS, SSA, VOBSUB, PGS, SUB, IDX, etc…)", "AllEpisodes": "Tous les épisodes", "AllLanguages": "Toutes les langues", "AllLibraries": "Toutes les médiathèques", @@ -23,11 +23,11 @@ "AllowMediaConversion": "Autoriser la conversion des médias", "AllowMediaConversionHelp": "Autoriser ou refuser l'accès à la fonctionnalité de conversion des médias.", "AllowOnTheFlySubtitleExtraction": "Autoriser l'extraction des sous-titres à la volée", - "AllowOnTheFlySubtitleExtractionHelp": "Les sous-titres intégrés peuvent être extraits des vidéos et distribués aux clients au format texte pour éviter le transcodage. Sur certains systèmes, cela peut prendre du temps et arrêter la lecture de la vidéo pendant le processus d'extraction. Désactivez cette option pour graver les sous-titres avec un transcodage quand l'appareil ne les prend pas en charge nativement.", + "AllowOnTheFlySubtitleExtractionHelp": "Les sous-titres intégrés peuvent être extraits des vidéos et distribués aux clients au format texte pour éviter le transcodage. Sur certains systèmes, cela peut prendre du temps et arrêter la lecture de la vidéo pendant le processus d'extraction. Désactivez cette option pour graver les sous-titres avec un transcodage quand l'appareil client ne les prend pas en charge nativement.", "AllowRemoteAccess": "Autoriser les connexions distantes à ce serveur Jellyfin.", "AllowRemoteAccessHelp": "Si l'option est désactivée, toutes les connexions distantes seront bloquées.", "AllowedRemoteAddressesHelp": "Liste d'adresses IP ou d'IP/masque de sous-réseau séparées par des virgules qui seront autorisées à se connecter à distance. Si la liste est vide, toutes les adresses distantes seront autorisées.", - "AlwaysPlaySubtitles": "Toujours lancer les sous-titres", + "AlwaysPlaySubtitles": "Toujours afficher les sous-titres", "AlwaysPlaySubtitlesHelp": "Les sous-titres correspondant à la préférence linguistique seront chargés indépendamment de la langue de l'audio.", "AnyLanguage": "N'importe quel langage", "Anytime": "N'importe quand", @@ -51,7 +51,7 @@ "BoxRear": "Dos de boîtier", "Browse": "Parcourir", "BrowsePluginCatalogMessage": "Explorer notre catalogue des plugins pour voir les plugins disponibles.", - "BurnSubtitlesHelp": "Détermine si le serveur doit incruster les sous-titres lors de la conversion vidéo en fonction du format des sous-titres. Éviter l'incrustation des sous-titres améliorera les performances du serveur. Sélectionnez Auto pour incruster les formats basés sur l'image (VOBSUB, PGS, SUB/IDX etc) et certains sous-titres ASS/SSA.", + "BurnSubtitlesHelp": "Détermine si le serveur doit incruster les sous-titres lors du transcodage de la vidéo. Éviter cela améliorera nettement la performance. Sélectionnez Auto pour incruster les formats basés sur l'image (VOBSUB, PGS, SUB, IDX etc) et certains sous-titres ASS ou SSA.", "ButtonAdd": "Ajouter", "ButtonAddMediaLibrary": "Ajouter une médiathèque", "ButtonAddScheduledTaskTrigger": "Ajouter un déclencheur", @@ -100,7 +100,7 @@ "ButtonRemove": "Supprimer", "ButtonRename": "Renommer", "ButtonRepeat": "Répéter", - "ButtonResetEasyPassword": "Réinitialiser le code Easy PIN", + "ButtonResetEasyPassword": "Réinitialiser le code easy PIN", "ButtonResetPassword": "Réinitialiser le mot de passe", "ButtonRestart": "Redémarrer", "ButtonResume": "Reprendre", @@ -130,7 +130,7 @@ "CancelRecording": "Annuler l'enregistrement", "CancelSeries": "Annuler la série", "Categories": "Catégories", - "ChangingMetadataImageSettingsNewContent": "Les modifications des réglages de téléchargement des métadonnées et des visuels ne seront appliquées qu'au nouveau contenu ajouté à votre médiathèque. Pour appliquer ces changements aux titres existants, vous devrez actualiser leurs métadonnées manuellement.", + "ChangingMetadataImageSettingsNewContent": "Les modifications des paramètres de téléchargement des métadonnées et des illustrations ne seront appliquées qu'au contenu nouvellement ajouté à votre médiathèque. Pour appliquer ces changements aux titres pré-existants, vous devrez actualiser leurs métadonnées manuellement.", "ChannelAccessHelp": "Sélectionnez les chaînes à partager avec cet utilisateur. Les administrateurs pourront modifier toutes les chaînes en utilisant le gestionnaire de métadonnées.", "ChannelNameOnly": "Seulement la chaîne {0}", "ChannelNumber": "Numéro de chaîne", @@ -176,8 +176,7 @@ "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}", + "Directors": "Réalisateurs", "Disabled": "Désactivé", "Disc": "Disque", "Disconnect": "Déconnecter", @@ -187,7 +186,7 @@ "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.", - "DisplayModeHelp": "Sélectionner le type d'écran sur lequel vous utilisez Jellyfin.", + "DisplayModeHelp": "Sélectionner l'agencement que vous désirez pour l'interface.", "DoNotRecord": "Ne pas enregistrer", "Down": "Bas", "Download": "Téléchargement", @@ -200,10 +199,10 @@ "EditMetadata": "Éditer les métadonnées", "EditSubtitles": "Modifier les sous-titres", "EnableBackdrops": "Images d'arrière-plans", - "EnableBackdropsHelp": "Afficher les images d'arrière-plans sur certaines pages pendant la navigation dans la médiathèque.", + "EnableBackdropsHelp": "Afficher des images d'arrière-plans sur certaines pages pendant la navigation dans la médiathèque.", "EnableCinemaMode": "Mode cinéma", "EnableColorCodedBackgrounds": "Fonds avec code couleur", - "EnableDisplayMirroring": "Partage d'écran", + "EnableDisplayMirroring": "Affichage en miroir", "EnableExternalVideoPlayers": "Lecteurs vidéo externes", "EnableExternalVideoPlayersHelp": "Une liste des lecteurs externes sera affichée au lancement de la lecture d'une vidéo.", "EnableHardwareEncoding": "Activer l'encodage matériel", @@ -232,7 +231,7 @@ "EveryNDays": "Tous les {0} jours", "ExitFullscreen": "Sortir du plein écran", "ExtraLarge": "Très Grand", - "ExtractChapterImagesHelp": "L'extraction d'images de chapitre permettra aux applications d'afficher des menus visuels pour la sélection des scènes. Le processus peut être long, consommateur de ressources et peut nécessiter de nombreux gigaoctets de stockage. Il s'exécute lorsque des vidéos sont découvertes et également comme tâche planifiée. La planification peut être modifiée dans les options du planificateur de tâches. Il n'est pas conseillé d'exécuter cette tâche pendant les heures d'usage intensif.", + "ExtractChapterImagesHelp": "L'extraction d'images de chapitre permettra aux applications d'afficher des menus visuels pour la sélection des scènes. Le processus peut être lent, gourmand en ressources et peut nécessiter plusieurs gigaoctets de stockage. Il s'exécute lorsque des vidéos sont découvertes et également comme tâche planifiée. L'horaire est configurable dans les options du planificateur de tâches. Il n'est pas recommandé d'exécuter cette tâche pendant les heures d'usage intensif.", "FFmpegSavePathNotFound": "Nous ne pouvons pas localiser FFmpeg en utilisant le chemin que vous avez saisi. FFprobe est également nécessaire et doit exister dans le même dossier. Ces composants sont généralement regroupés dans le même téléchargement. Veuillez vérifier le chemin et essayer à nouveau.", "FastForward": "Avance rapide", "Favorite": "Favori", @@ -259,10 +258,10 @@ "GuideProviderLogin": "Connexion", "GuideProviderSelectListings": "Sélectionner les listings", "H264CrfHelp": "Le facteur de débit constant (CRF) est le paramètre de qualité par défaut pour l'encodeur x264. Vous pouvez régler les valeurs entre 0 et 51, où des valeurs plus faibles se traduiraient par une meilleure qualité (en augmentant le taille des fichiers). De bonne valeurs se situent entre 18 et 28. La valeur par défaut pour le x264 est 23, vous pouvez l'utiliser comme point de départ.", - "H264EncodingPresetHelp": "Choisissez une valeur plus rapide pour améliorer la performance, ou plus lente pour améliorer la qualité.", + "EncoderPresetHelp": "Choisissez une valeur plus rapide pour améliorer la performance, ou plus lente pour améliorer la qualité.", "HDPrograms": "Programmes HD", "HandledByProxy": "Gérée par un proxy inverse", - "HardwareAccelerationWarning": "L'activation de l'accélération matérielle peut provoquer une instabilité dans certains environnements. Assurez-vous que votre système d'exploitation et vos pilotes vidéo sont complètement à jour. Si vous avez des difficultés pour lire des vidéos après l'activation, vous devrez remettre ce paramètre sur Auto.", + "HardwareAccelerationWarning": "L'activation de l'accélération matérielle peut provoquer une instabilité dans certains environnements. Assurez-vous que votre système d'exploitation et vos pilotes vidéo sont complètement à jour. Si vous avez des difficultés pour lire des vidéos après l'activation, vous devrez remettre ce paramètre sur Aucun.", "HeaderAccessSchedule": "Programme d'Accès", "HeaderAccessScheduleHelp": "Créez un programme d'accès pour limiter l'accès à certaines heures.", "HeaderActiveDevices": "Appareils actifs", @@ -275,7 +274,7 @@ "HeaderAddUser": "Ajouter un utilisateur", "HeaderAdditionalParts": "Parties additionelles", "HeaderAdmin": "Administrateur", - "HeaderAlbumArtists": "Artistes d'album", + "HeaderAlbumArtists": "Artistes de l'album", "HeaderAlert": "Alerte", "HeaderAllowMediaDeletionFrom": "Autoriser la suppression de médias à partir de", "HeaderApiKey": "Clé API", @@ -477,7 +476,7 @@ "Identify": "Identifier", "ImportFavoriteChannelsHelp": "Activez cette option pour n'importer que les chaînes ajoutées aux favoris sur le tuner.", "ImportMissingEpisodesHelp": "Les informations à propos des épisodes manquants seront importées dans votre base de donnée Jellyfin et affichées dans les saisons et séries. Cela peut accroître significativement la durée d'actualisation de la médiathèque.", - "InstallingPackage": "Installation de {0}", + "InstallingPackage": "Installation de {0} (version {1})", "InstantMix": "Mix instantané", "ItemCount": "{0} éléments", "Items": "Éléments", @@ -570,7 +569,7 @@ "LabelEmbedAlbumArtDidl": "Intégrer les images d'album dans le DIDL", "LabelEmbedAlbumArtDidlHelp": "Certains appareils préfèrent cette méthode pour obtenir les images d'album. D'autres peuvent échouer à lire avec cette option activée.", "LabelEnableAutomaticPortMap": "Autoriser le mapping automatique de port", - "LabelEnableAutomaticPortMapHelp": "Essayer de mapper automatiquement le port public au port local via UPnP. Cela peut ne pas fonctionner avec certains modèles de routeurs.", + "LabelEnableAutomaticPortMapHelp": "Essayer de mapper automatiquement le port public au port local via UPnP. Cela peut ne pas fonctionner avec certains modèles de routeurs. La modification de ce paramètre ne sera effective qu’après redémarrage du serveur.", "LabelEnableBlastAliveMessages": "Diffuser des message de présence", "LabelEnableBlastAliveMessagesHelp": "Activer cette option si le serveur n'est pas détecté de manière fiable par les autres appareils UPnP sur votre réseau.", "LabelEnableDlnaClientDiscoveryInterval": "Intervalle de découverte des clients (secondes)", @@ -603,9 +602,9 @@ "LabelGroupMoviesIntoCollections": "Grouper les films en collections", "LabelGroupMoviesIntoCollectionsHelp": "Dans l'affichage des listes de films, les films faisant partie d'une collection seront affichés comme un élément groupé.", "LabelH264Crf": "CRF d'encodage H264 :", - "LabelH264EncodingPreset": "Profil d'encodage H264 :", + "LabelEncoderPreset": "Profil d'encodage H264 :", "LabelHardwareAccelerationType": "Accélération matérielle :", - "LabelHardwareAccelerationTypeHelp": "Fonctionnalité expérimentale disponible sur les systèmes supportés.", + "LabelHardwareAccelerationTypeHelp": "L'accélération matérielle nécessite une configuration supplémentaire.", "LabelHomeNetworkQuality": "Qualité du réseau local :", "LabelHomeScreenSectionValue": "Section {0} de l'accueil :", "LabelHttpsPort": "Numéro de port HTTPS local :", @@ -625,7 +624,7 @@ "LabelKidsCategories": "Catégories jeunesse :", "LabelKodiMetadataDateFormat": "Format de la date de sortie :", "LabelKodiMetadataDateFormatHelp": "Toutes les dates des fichiers NFO seront anlysés en utilisant ce format.", - "LabelKodiMetadataEnableExtraThumbs": "Copier les extrafanart vers le champ extrathumbs", + "LabelKodiMetadataEnableExtraThumbs": "Copier les extrafanart dans les champs extrathumbs", "LabelKodiMetadataEnableExtraThumbsHelp": "Pendant le téléchargement, les images peuvent être enregistrées en tant qu'extrafanart et extrathumbs pour améliorer la compatibilité avec le skin Kodi.", "LabelKodiMetadataEnablePathSubstitution": "Activer la substitution des chemins", "LabelKodiMetadataEnablePathSubstitutionHelp": "Active la substitution du chemin des images en utilisant les paramètres de substitution des chemins du serveur.", @@ -659,7 +658,7 @@ "LabelMetadataDownloadLanguage": "Langue de téléchargement préférée :", "LabelMetadataDownloadersHelp": "Activez et classez vos sources de téléchargement de métadonnées préférées dans l'ordre de priorité. Les plus basses seront utilisées uniquement pour remplir les informations manquantes.", "LabelMetadataPath": "Chemin des métadonnées :", - "LabelMetadataPathHelp": "Veuillez spécifier un emplacement personnalisé pour les images et les métadonnées téléchargées.", + "LabelMetadataPathHelp": "Veuillez spécifier un emplacement personnalisé pour les illustrations et les métadonnées téléchargées.", "LabelMetadataReaders": "Lecteurs de métadonnées :", "LabelMetadataReadersHelp": "Classez vos sources locales de métadonnées préférées dans l'ordre de priorité. Le premier fichier trouvé sera lu.", "LabelMetadataSavers": "Enregistreurs de métadonnées :", @@ -738,8 +737,8 @@ "LabelRemoteClientBitrateLimit": "Limite de débit de streaming Internet (Mbps) :", "LabelRemoteClientBitrateLimitHelp": "Une limite de débit optionnelle par streaming pour les connexions hors du réseau local. Utile pour éviter que les appareils ne demandent un débit supérieur à ce que votre connexion internet peu fournir. Cela peut augmenter la charge du processeur de votre serveur pour transcoder les vidéos à la volée à un débit plus faible.", "LabelRuntimeMinutes": "Durée (minutes) :", - "LabelSaveLocalMetadata": "Enregistrer les images dans les dossiers multimédia", - "LabelSaveLocalMetadataHelp": "L'enregistrement des images dans les dossiers multimédia les placera à un endroit où elles seront facilement modifiables.", + "LabelSaveLocalMetadata": "Enregistrer les illustrations dans les dossiers des médias", + "LabelSaveLocalMetadataHelp": "L'enregistrement des illustrations dans les dossiers des médias les placera à un endroit où elles seront facilement modifiables.", "LabelScheduledTaskLastRan": "Dernière exécution {0}, durée {1}.", "LabelScreensaver": "Économiseur d'écran :", "LabelSeasonNumber": "Numéro de saison :", @@ -777,7 +776,7 @@ "LabelSubtitleDownloaders": "Outils de téléchargement de sous-titres :", "LabelSubtitleFormatHelp": "Exemple : srt", "LabelSubtitlePlaybackMode": "Mode des sous-titres :", - "LabelSubtitles": "Sous-titres :", + "LabelSubtitles": "Sous-titres", "LabelSupportedMediaTypes": "Types de médias supportés :", "LabelTVHomeScreen": "Écran d'accueil du mode TV :", "LabelTag": "Étiquette :", @@ -814,7 +813,7 @@ "LabelValue": "Valeur :", "LabelVersion": "Version :", "LabelVersionInstalled": "{0} installé(s)", - "LabelVideo": "Vidéo :", + "LabelVideo": "Vidéo", "LabelXDlnaCap": "Cap X-DLNA :", "LabelXDlnaCapHelp": "Détermine le contenu de l'élément X_DLNACAP dans l'espace de nom urn:schemas-dlna-org:device-1-0.", "LabelXDlnaDoc": "Doc X-DLNA :", @@ -916,7 +915,7 @@ "MetadataSettingChangeHelp": "Les modifications des paramètres des métadonnées auront une incidence sur le nouveau contenu ajouté. Pour actualiser le contenu existant, ouvrez l'écran des détails et cliquez sur le bouton Actualiser, ou effectuez des actualisations en masse en utilisant le gestionnaire de métadonnées.", "MinutesAfter": "minutes après", "MinutesBefore": "minutes avant", - "Mobile": "Mobile", + "Mobile": "Pour appareil Mobile", "Monday": "Lundi", "MoreFromValue": "Plus de {0}", "MoreUsersCanBeAddedLater": "D'autres utilisateurs pourront être ajoutés ultérieurement à partir du tableau de bord.", @@ -949,7 +948,7 @@ "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, etc)", + "OnlyImageFormats": "Seulement les formats image (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Administrateurs", "OptionAlbumArtist": "Artiste de l'album", "OptionAllUsers": "Tous les utilisateurs", @@ -1009,7 +1008,6 @@ "OptionEnableAccessFromAllDevices": "Autoriser l'accès depuis tous les appareils", "OptionEnableAccessToAllChannels": "Activer l'accès à toutes les chaînes", "OptionEnableAccessToAllLibraries": "Activer l'accès à toutes les librairies", - "OptionEnableAutomaticServerUpdates": "Activer les mises à jour automatiques du serveur", "OptionEnableExternalContentInSuggestions": "Activer le contenu externe dans les suggestions", "OptionEnableExternalContentInSuggestionsHelp": "Autoriser les bandes-annonces sur internet et les programmes TV en direct à être inclus dans le contenu suggéré.", "OptionEnableForAllTuners": "Autoriser pour tous les tuners", @@ -1060,7 +1058,7 @@ "OptionReportByteRangeSeekingWhenTranscodingHelp": "Nécessaire pour certains appareils qui ne sont pas capables d'effectuer une recherche dans le temps correctement.", "OptionRequirePerfectSubtitleMatch": "Télécharger uniquement les sous-titres qui correspondent parfaitement à mes fichiers vidéo", "OptionRequirePerfectSubtitleMatchHelp": "En activant cette option, seuls les sous-titres ayant été testés et vérifiés avec votre fichier vidéo seront téléchargés. En désactivant cette option, vous aurez plus de chance que des sous-titres soient téléchargés, mais ils risquent d'être décalés ou incorrects.", - "OptionResElement": "res element", + "OptionResElement": "Résolution d'élément", "OptionResumable": "Reprise possible", "OptionRuntime": "Durée", "OptionSaturday": "Samedi", @@ -1082,9 +1080,9 @@ "OptionWeekly": "Hebdomadaire", "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é.", + "PackageInstallCancelled": "L'installation de {0} (version {1}) a été annulée.", + "PackageInstallCompleted": "L'installation de {0} (version {1}) est terminée.", + "PackageInstallFailed": "L'installation de {0} (version {1}) a échoué.", "ParentalRating": "Classification parentale", "PasswordMatchError": "Le mot de passe et sa confirmation doivent correspondre.", "PasswordResetComplete": "Le mot de passe a été réinitialisé.", @@ -1101,7 +1099,7 @@ "PlayAllFromHere": "Tout lire à partir d'ici", "PlayCount": "Nombre de lectures", "PlayFromBeginning": "Lire depuis le début", - "PlayNext": "Lire le suivant", + "PlayNext": "Lire ensuite", "PlayNextEpisodeAutomatically": "Lancer l'épisode suivant automatiquement", "Played": "Lu", "Playlists": "Listes de lecture", @@ -1166,7 +1164,7 @@ "Screenshot": "Capture d'écran", "Screenshots": "Captures d'écran", "Search": "Recherche", - "SearchForCollectionInternetMetadata": "Rechercher sur Internet les images et les métadonnées", + "SearchForCollectionInternetMetadata": "Rechercher les illustrations et les métadonnées sur Internet", "SearchForMissingMetadata": "Rechercher les métadonnées manquantes", "SearchForSubtitles": "Rechercher des sous-titres", "SearchResults": "Résultats de la recherche", @@ -1330,9 +1328,8 @@ "ButtonPause": "Pause", "Collections": "Collections", "Extras": "Extras", - "GenreValue": "Genre: {0}", + "Genre": "Genre", "Genres": "Genres", - "GenresValue": "Genres: {0}", "Guide": "Guide", "GuestStar": "Guest star", "Photos": "Photos", @@ -1342,7 +1339,7 @@ "HeaderTuners": "Égaliseur", "Horizontal": "Horizontal", "Images": "Images", - "LabelAudio": "Audio :", + "LabelAudio": "Audio", "LabelVersionNumber": "Version {0}", "LeaveBlankToNotSetAPassword": "Laissez vide pour ne pas définir de mot de passe.", "Logo": "Logo", @@ -1393,7 +1390,7 @@ "LabelServerName": "Nom du serveur :", "DashboardVersionNumber": "Version : {0}", "DashboardServerName": "Serveur : {0}", - "LabelWeb": "Web : ", + "LabelWeb": "Web :", "MediaInfoSoftware": "Logiciel", "MediaInfoStreamTypeAudio": "Audio", "MediaInfoStreamTypeData": "Données", @@ -1402,7 +1399,7 @@ "AuthProviderHelp": "Sélectionner un fournisseur d'authentification pour authentifier le mot de passe de cet utilisateur.", "PasswordResetProviderHelp": "Choisissez un Fournisseur de réinitialisation de mot de passe à utiliser lorsqu'un utilisateur demande la réinitialisation de son mot de passe", "HeaderHome": "Accueil", - "LabelUserLoginAttemptsBeforeLockout": "Essais manqués restants avant verrouillage utilisateur :", + "LabelUserLoginAttemptsBeforeLockout": "Tentatives de connexion échouées avant que l'utilisateur ne soit verrouillé :", "DashboardOperatingSystem": "Système d'Exploitation: {0}", "DashboardArchitecture": "Architecture : {0}", "LaunchWebAppOnStartup": "Démarrer l'interface web dans mon navigateur quand le serveur est démarré", @@ -1412,7 +1409,7 @@ "MessageNoServersAvailable": "Aucun serveur n'a été trouvé en utilisant la recherche automatique de serveur.", "OptionBanner": "Bannière", "OptionList": "Liste", - "OptionLoginAttemptsBeforeLockout": "Détermine le nombre de tentative de connexion infructueuse avant le blocage d'accès.", + "OptionLoginAttemptsBeforeLockout": "Définis le nombre de tentatives de connexion échouées avant blocage du compte.", "OptionPoster": "Affiche", "OptionPosterCard": "Affichette", "OptionThumb": "Vignette", @@ -1440,19 +1437,75 @@ "LabelVideoBitrate": "Débit vidéo :", "LabelTranscodingProgress": "Progression du transcodage :", "LabelTranscodingFramerate": "Taux de rafraîchissement du transcodage :", - "LabelPleaseRestart": "Les changements prendront effet lors d'un rechargement manuel du client web.", + "LabelPleaseRestart": "Les changements prendront effet après un rechargement manuel du client web.", "LabelPlayMethod": "Méthode de lecture :", "LabelPlayer": "Lecteur :", - "LabelBaseUrl": "Lien d'origine:", + "LabelBaseUrl": "URL de base :", "LabelAudioSampleRate": "Taux d’échantillonnage audio :", "LabelAudioCodec": "Codec audio :", "LabelAudioChannels": "Canaux audio :", "HeaderFavoriteBooks": "Livres préférés", "FetchingData": "Récuperer des données suplémentaires", - "CopyStreamURLSuccess": "URL copiée.", + "CopyStreamURLSuccess": "URL copiée avec succès.", "CopyStreamURL": "Copier l'URL du flux", - "LabelBaseUrlHelp": "Vous pouvez ajouter un sous-répertoire personalisé ici pour accéder au serveur depuis une URL plus exclusive.", + "LabelBaseUrlHelp": "Vous pouvez ajouter un sous-répertoire personnalisé ici pour accéder au serveur via un lien unique.", "HeaderFavoritePeople": "Personnes préférées", "OptionRandom": "Aléatoire", - "ButtonSplit": "Découper" + "ButtonSplit": "Séparer", + "SelectAdminUsername": "Veuillez choisir un nom d'utilisateur pour le compte administrateur.", + "HeaderNavigation": "Navigation", + "OptionForceRemoteSourceTranscoding": "Transcodage forcé pour sources de media à distance (ex: TV en direct)", + "MessageConfirmAppExit": "Voulez-vous quitter ?", + "LabelVideoResolution": "Résolution vidéo :", + "LabelStreamType": "Type de flux :", + "EnableFastImageFadeInHelp": "Activer un fondu plus rapide pour l'animation des images chargées", + "EnableFastImageFadeIn": "Fondu d'image rapide", + "LabelPlayerDimensions": "Dimension du lecteur :", + "LabelDroppedFrames": "Images perdues :", + "LabelCorruptedFrames": "Images corrompues :", + "CopyStreamURLError": "Une erreur est survenue lors de la copie de l'URL.", + "AskAdminToCreateLibrary": "Demander à un administrateur de créer une médiathèque.", + "AllowFfmpegThrottlingHelp": "Quand le transcodage ou le remultiplexage est suffisamment en avant de la position de lecture, le processus se mettra en pause afin d’économiser des ressources. Plus utile lors d’une lecture continue. À désactiver en cas de problèmes de lecture.", + "AllowFfmpegThrottling": "Adapter la vitesse du transcodage", + "NoCreatedLibraries": "Il semble que vous n'ayez pas encore créé de bibliothèques. {0}Voulez-vous en créer une maintenant ?{1}", + "PlaybackErrorNoCompatibleStream": "Ce client n'est pas compatible avec le média et le serveur n'envoie pas de format compatible.", + "PreferEmbeddedEpisodeInfosOverFileNames": "Préférer les informations intégrées aux noms de fichiers", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Utilise les informations des métadonnées intégrées, si disponible.", + "ClientSettings": "Paramètres Client", + "Track": "Piste", + "Season": "Saison", + "ReleaseGroup": "Groupe de Parution", + "Person": "Personne", + "OtherArtist": "Autre Artiste", + "Movie": "Film", + "Episode": "Épisode", + "BoxSet": "Coffret", + "Artist": "Artiste", + "AlbumArtist": "Artiste de l'Album", + "Album": "Album", + "OnApplicationStartup": "Au démarrage de l'application", + "EveryXHours": "Toutes les {0} heures", + "EveryHour": "Toutes les heures", + "EveryXMinutes": "Toutes les {0} minutes", + "OnWakeFromSleep": "À la sortie de veille", + "WeeklyAt": "{0} à {1}", + "DailyAt": "Tous les jours à {0}", + "LastSeen": "Vu pour la dernière fois {0}", + "PersonRole": "en tant que {0}", + "ListPaging": "{0}-{1} de {2}", + "WriteAccessRequired": "Le serveur Jellyfin a besoin d'un accès en écriture à ce dossier. Merci de vérifier l’accès en écriture et réessayez.", + "PathNotFound": "Le chemin d'accès n'a pas pu être trouvé. Merci de le vérifier et de réessayer.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelDeinterlaceMethod": "Méthode de désentrelacement :", + "DeinterlaceMethodHelp": "Sélectionnes la méthode de désentrelacement à utiliser lors du transcodage de contenu entrelacé.", + "LabelLibraryPageSize": "Taille de la page de la médiathèque :", + "LabelLibraryPageSizeHelp": "Définit la quantité d'éléments à afficher sur une page de médiathèque. Définir à 0 afin de désactiver la pagination.", + "UnsupportedPlayback": "Jellyfin ne peut pas décoder du contenu protégé par un système de gestion des droits numériques, mais une tentative de lecture sera effectuée sur tout le contenu, y compris les titres protégés. Certains fichiers peuvent apparaître complètement noir, du fait de protections ou de fonctionnalités non supportées, comme les titres interactifs.", + "MessageUnauthorizedUser": "Vous n'êtes pas autorisé à accéder au serveur pour le moment. Veuillez contacter l'administrateur de votre serveur pour plus d'informations.", + "ButtonTogglePlaylist": "Liste de lecture", + "ButtonToggleContextMenu": "Plus", + "Filter": "Filtre", + "New": "Nouveau", + "HeaderFavoritePlaylists": "Listes de lecture favorites" } diff --git a/src/strings/gl.json b/src/strings/gl.json new file mode 100644 index 0000000000..5341462de7 --- /dev/null +++ b/src/strings/gl.json @@ -0,0 +1,15 @@ +{ + "AllowMediaConversion": "Permitir a conversión dos medios", + "AllComplexFormats": "Todos os formatos complexos (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllLibraries": "Todas as librarías", + "AllLanguages": "Todas as linguas", + "AllEpisodes": "Todos os episodios", + "All": "Todo", + "Albums": "Álbumes", + "Alerts": "Avisos", + "AllChannels": "Todos os canais", + "AirDate": "Data de emisión", + "Aired": "Emitido", + "AddToPlaylist": "Engadir á lista de reprodución", + "Add": "Engadir" +} diff --git a/src/strings/gsw.json b/src/strings/gsw.json index 7d0162e852..2c5210969a 100644 --- a/src/strings/gsw.json +++ b/src/strings/gsw.json @@ -7,7 +7,7 @@ "ButtonQuickStartGuide": "Schnellstart Instruktione", "ButtonResetPassword": "Passwort zrug setze", "ButtonSave": "Speichere", - "ButtonSignOut": "Sign out", + "ButtonSignOut": "Uslogge", "ButtonSort": "Sortiere", "ChannelAccessHelp": "Wähl en Kanal us, um de mit dem User z'teile. Administratore werded immer d'Möglichkeit ha alli Kanäl mitm Metadate Manager z'bearbeite.", "Continuing": "Fortlaufend", @@ -29,7 +29,7 @@ "HeaderLatestSongs": "Letschti Songs", "HeaderLatestTrailers": "Letschti Trailer", "HeaderManagement": "Verwaltig", - "HeaderNextUp": "Als nächts", + "HeaderNextUp": "Als Nächstes", "HeaderNowPlaying": "Jetz am spelle", "HeaderParentalRating": "Parental Rating", "HeaderPaths": "Pfad", @@ -131,22 +131,22 @@ "Wednesday": "Mittwoch", "WelcomeToProject": "Willkomme bi Jellyfin!", "WizardCompleted": "Das esch alles wo mer momentan müend wüsse. Jellyfin het i de zwüscheziit agfange informatione über diini medie-bibliothek z'sammle. Lueg der es paar vo eusne Apps a und denn klick uf Beende um zum Server Dashboard z'cho.", - "Albums": "Albom", - "Artists": "Könstler", - "Books": "Büecher", - "Channels": "Kanäu", - "Collections": "Sammlige", - "Favorites": "Favorite", + "Albums": "Alben", + "Artists": "Künstler", + "Books": "Bücher", + "Channels": "Kanäle", + "Collections": "Sammlungen", + "Favorites": "Favoriten", "Folders": "Ordner", "Genres": "Genres", - "HeaderAlbumArtists": "Albom-Könstler", - "HeaderContinueWatching": "Wiiterluege", - "HeaderFavoriteAlbums": "Lieblingsalbe", - "HeaderFavoriteArtists": "Lieblings-Interprete", - "HeaderFavoriteEpisodes": "Lieblingsepisode", - "HeaderFavoriteShows": "Lieblingsserie", + "HeaderAlbumArtists": "Album-Künstler", + "HeaderContinueWatching": "weiter schauen", + "HeaderFavoriteAlbums": "Lieblingsalben", + "HeaderFavoriteArtists": "Lieblings-Künstler", + "HeaderFavoriteEpisodes": "Lieblingsepisoden", + "HeaderFavoriteShows": "Lieblingsserien", "HeaderFavoriteSongs": "Lieblingslieder", - "HeaderLiveTV": "Live-Färnseh", + "HeaderLiveTV": "Live-Fernseh", "HeaderRecordingGroups": "Ufnahmegruppe", "LabelIpAddressValue": "IP-Adrässe: {0}", "LabelRunningTimeValue": "Loufziit: {0}", @@ -164,5 +164,8 @@ "Songs": "Lieder", "Sync": "Synchronisation", "ValueSpecialEpisodeName": "Extra - {0}", - "VersionNumber": "Version {0}" + "VersionNumber": "Version {0}", + "Absolute": "Absolut", + "Actor": "Schauspiler", + "AccessRestrictedTryAgainLater": "Zuegriff isch momentan beschränkt. Probier bitte später nomau. " } diff --git a/src/strings/he.json b/src/strings/he.json index 7a8aa6d9f3..a3e4bc9326 100644 --- a/src/strings/he.json +++ b/src/strings/he.json @@ -1,19 +1,19 @@ { "Actor": "שחקן", "Add": "הוסף", - "AddToCollection": "להוסיף לאוסף", - "AddToPlayQueue": "הוסף לתור הפעלה", + "AddToCollection": "הוסף לאוסף", + "AddToPlayQueue": "הוסף לרשימת ניגון", "AddToPlaylist": "הוסף לרשימת ניגון", - "AdditionalNotificationServices": "עיין בקטלוג התוספים להתקנת שרותי התראות נוספים", + "AdditionalNotificationServices": "עיין ברשימת התוספים להתקנת שירותי התראות נוספים.", "All": "הכל", "AllChannels": "כל הערוצים", "AllEpisodes": "כל הפרקים", - "AllLibraries": "כל הספרייה", + "AllLibraries": "כל הספריות", "Anytime": "בכל עת", "AroundTime": "בסביבות {0}", "AsManyAsPossible": "כמה שיותר", "AttributeNew": "חדש", - "Backdrops": "תפאורות", + "Backdrops": "תמונות רקע", "BirthLocation": "מיקום לידה", "BrowsePluginCatalogMessage": "עבור לקטלוג התוספים לראות אילו זמינים.", "ButtonAdd": "הוסף", @@ -46,27 +46,26 @@ "ChannelNameOnly": "ערוץ {0} בלבד", "ChannelNumber": "מספר ערוץ", "Composer": "מלחין", - "ConfigureDateAdded": "הגדר כיצד תאריך התוספת נקבע בלוח המחוונים של שרת Amby תחת הגדרות ספריה", + "ConfigureDateAdded": "‫הגדר כיצד תאריך ההוספה נקבע בלוח המחוונים של שרת ה-Jellyfin תחת הגדרות הספרייה", "ConfirmDeleteImage": "למחוק את התמונה?", "ConfirmDeleteItem": "מחיקת פריט זה תמחק אותו הן ממערכת הקבצים והן מספריית המדיה שלך. האם אתה בטוח שברצונך להמשיך?", "ConfirmDeleteItems": "מחיקת פריטים אלה תמחק אותם הן ממערכת הקבצים והן מספריית המדיה שלך. האם אתה בטוח שברצונך להמשיך?", "ConfirmDeletion": "אשר מחיקה", "Continuing": "ממשיך", - "CustomDlnaProfilesHelp": "צור פרופיל מותאם אישית למכשיר חדש או לעקוף פרופיל מערכת", + "CustomDlnaProfilesHelp": "צור פרופיל מותאם אישית למכשיר חדש או לעקיפת פרופיל מערכת.", "DefaultErrorMessage": "אירעה שגיאה בעיבוד הבקשה. בבקשה נסה שוב מאוחר יותר.", "Delete": "מחק", "DeleteImage": "מחק תמונה", "DeleteImageConfirmation": "האם אתה בטוח שברצונך למחוק תמונה זו?", "DeleteMedia": "מחק מדיה", "DeleteUser": "מחק משתמש", - "Director": "מנהל", "Dislike": "לא אוהב", "DoNotRecord": "אל תקליט", "Download": "הורדה", "Edit": "ערוך", "EditImages": "ערוך תמונות", "EditSubtitles": "ערוך כתוביות", - "EnableColorCodedBackgrounds": "אפשר רקע בצבע מקודד", + "EnableColorCodedBackgrounds": "רקע בצבע מקודד", "Ended": "הסתיים", "EndsAtValue": "מסתיים ב {0}", "Favorite": "מועדף", @@ -76,7 +75,7 @@ "FileReadError": "חלה שגיאה בקריאת הקובץ.", "FolderTypeMovies": "סרטים", "FolderTypeMusic": "מוזיקה", - "FolderTypeMusicVideos": "וידאו קליפ", + "FolderTypeMusicVideos": "קליפים", "FolderTypeTvShows": "תוכניות טלויזיה", "Friday": "שישי", "Genres": "ז'אנרים", @@ -102,7 +101,7 @@ "HeaderEditImages": "ערוך תמונות", "HeaderEnabledFields": "שדות זמינים", "HeaderEnabledFieldsHelp": "בטל את הסימון בשדה כדי לנעול אותו ולמנוע שינוי בנתונים.", - "HeaderExternalIds": "מזהים חיצוניים:", + "HeaderExternalIds": "‮מזהים חיצוניים:", "HeaderFeatureAccess": "גישה למאפיינים", "HeaderFetchImages": "הבא תמונות:", "HeaderFrequentlyPlayed": "נוגנו לרוב", @@ -111,15 +110,15 @@ "HeaderKeepRecording": "שמור על הקלטה", "HeaderKeepSeries": "שמור סדרה", "HeaderLatestEpisodes": "פרקים אחרונים", - "HeaderLatestMovies": "סרטים אחרונים שהוספו.", - "HeaderLatestMusic": "מוזיקה אחרונה.", + "HeaderLatestMovies": "סרטים אחרונים שהוספו", + "HeaderLatestMusic": "מוזיקה אחרונה", "HeaderLatestRecordings": "הקלטות אחרונות", - "HeaderLiveTV": "טלוויזיה בשידור חי", + "HeaderLiveTV": "שידורים חיים", "HeaderMediaFolders": "ספריות מדיה", "HeaderMetadataSettings": "הגדרות מטא נתונים", "HeaderMovies": "סרטים", "HeaderMusicVideos": "קליפים", - "HeaderMyMedia": "הספרייה שלי.", + "HeaderMyMedia": "הספרייה שלי", "HeaderNextUp": "הבא", "HeaderPaths": "נתיבים", "HeaderPlayAll": "נגן הכל", @@ -131,7 +130,7 @@ "HeaderSeries": "סדרה", "HeaderSeriesOptions": "אפשרויות סדרה", "HeaderServerSettings": "הגדרות שרת", - "HeaderSetupLibrary": "הגדר את ספריית המדיה שלך.", + "HeaderSetupLibrary": "הגדר את ספריית המדיה שלך", "HeaderSpecialEpisodeInfo": "פרטי אפיזודות מיוחדות", "HeaderSpecialFeatures": "מאפיינים מיוחדים", "HeaderStatus": "מצב", @@ -165,7 +164,7 @@ "LabelChannels": "ערוצים:", "LabelCollection": "אוספים:", "LabelCommunityRating": "דירוג הקהילה:", - "LabelContentType": "סוג התוכן", + "LabelContentType": "סוג התוכן:", "LabelCountry": "מדינה:", "LabelCriticRating": "דירוג ביקורת:", "LabelCurrentPassword": "סיסמא נוכחית:", @@ -222,7 +221,7 @@ "LabelNext": "הבא", "LabelNotificationEnabled": "אפשר התראה זו", "LabelNumber": "מספר:", - "LabelNumberOfGuideDays": "מספר ימי לוח שידורים להורדה", + "LabelNumberOfGuideDays": "מספר ימים להורדה מלוח השידורים:", "LabelNumberOfGuideDaysHelp": "הורדת יותר ימי לוח שידורים מאפשרת יכולת לתכנן ולראות יותר תוכניות קדימה, אבל גם זמן ההורדה יעלה. מצב אוטומטי ייקבע לפני מספר הערוצים.", "LabelOriginalAspectRatio": "יחס גובה-רוחב מקורי:", "LabelOriginalTitle": "כותרת מקורית:", @@ -235,14 +234,14 @@ "LabelPersonRoleHelp": "דוגמה: נהג משאית גלידה", "LabelPlaceOfBirth": "מקום לידה:", "LabelPlaylist": "רשימת ניגון:", - "LabelPreferredDisplayLanguage": "שפת ממשק מועדפת", - "LabelPreferredDisplayLanguageHelp": "תרגום הממשק של Jellyfin הוא תהליך ממושך", + "LabelPreferredDisplayLanguage": "שפת תצוגה מועדפת:", + "LabelPreferredDisplayLanguageHelp": "תרגום Jellyfin הוא תהליך מתמשך.", "LabelPrevious": "הקודם", - "LabelProfileAudioCodecs": "מקודדי צליל", - "LabelProfileCodecs": "מקודדים", - "LabelProfileVideoCodecs": "מקודדי וידאו", + "LabelProfileAudioCodecs": "מקודדי שמע:", + "LabelProfileCodecs": "מקודדים:", + "LabelProfileVideoCodecs": "‮מקודדי וידאו:", "LabelPublicHttpPort": "מספר פורט HTTP פומבי", - "LabelReadHowYouCanContribute": "למד איך תוכל לתרום", + "LabelReadHowYouCanContribute": "למד איך אתה יכול לתרום.", "LabelRecord": "הקלטה:", "LabelRefreshMode": "מצב רענון:", "LabelReleaseDate": "תאריך הוצאה:", @@ -255,17 +254,17 @@ "LabelSortTitle": "מיין כותרת:", "LabelStartWhenPossible": "התחל ברגע שניתן:", "LabelStatus": "סטטוס:", - "LabelStopWhenPossible": "הפסק ברגע שאפשר", + "LabelStopWhenPossible": "הפסק כשיתאפשר:", "LabelTagline": "שורת תיוג:", "LabelTime": "זמן:", - "LabelTimeLimitHours": "הגבלת זמן (בשעות)", + "LabelTimeLimitHours": "מגבלת זמן (שעות):", "LabelTitle": "כותרת:", "LabelTrackNumber": "קטע מספר:", "LabelTriggerType": "סוגר טריגר:", "LabelType": "סוג:", "LabelUseNotificationServices": "השתמש בשירותים הבאים:", "LabelUser": "משתמש:", - "LabelUserLibrary": "ספריית משתמש", + "LabelUserLibrary": "ספריית משתמש:", "LabelYear": "שנה:", "LabelYourFirstName": "שמך הפרטי:", "LabelYoureDone": "סיימת!", @@ -277,13 +276,13 @@ "MarkUnplayed": "סמן לא נוגן", "MaxParentalRatingHelp": "תוכן עם דירוג גובה יותר יוסתר מהמשתמש.", "MessageAreYouSureDeleteSubtitles": "האם אתה בטוח שברצונך למחוק קובץ כתובית זה?", - "MessageConfirmRecordingCancellation": "האם אתה בטוח שברצונך לבטל הקלטה זו?", - "MessageDownloadQueued": "הורד תור", + "MessageConfirmRecordingCancellation": "‏האם אתה בטוח שברצונך לבטל הקלטה זו?", + "MessageDownloadQueued": "הורדה נוספה לתור.", "MessageItemSaved": "הפריט נשמר.", "MessageItemsAdded": "פריטים נוספו.", - "MessageLeaveEmptyToInherit": "השאר ריק כדי לרשת את ההגדרות מפריט אב, או את ערך ברירת המחדל הגלובלי.", + "MessageLeaveEmptyToInherit": "השאר ריק כדי לרשת את ההגדרות מפריט אב או את ערך ברירת המחדל הגלובלי.", "MessageNothingHere": "אין כאן כלום.", - "MessagePleaseEnsureInternetMetadata": "בבקשה וודא כי הורדת מידע מהאינטרנט מאופשרת", + "MessagePleaseEnsureInternetMetadata": "אנא וודא כי הורדת מטא-דאטה מהאינטרנט מופעלת.", "MinutesAfter": "דקות אחרי", "MinutesBefore": "דקות לפני", "Monday": "שני", @@ -398,7 +397,7 @@ "RecentlyWatched": "נצפה לאחרונה", "Record": "הקלט", "RecordSeries": "הקלט סדרה", - "RecordingCancelled": "בטל הקלטה", + "RecordingCancelled": "הקלטה בוטלה.", "RecordingScheduled": "ההקלטה מתוזמנת.", "Refresh": "רענון", "RefreshDialogHelp": "המטא נתונים מתרעננים על סמך הגדרות ושירותי אינטרנט שמופעלים בלוח המחוונים של מרכז אמבי.", @@ -406,7 +405,7 @@ "ReleaseDate": "תאריך שיחרור", "RemoveFromCollection": "הסר מאוספים", "RemoveFromPlaylist": "הסר מרשימת הניגון", - "Repeat": "חזור", + "Repeat": "חזרה", "RepeatEpisodes": "חזור על פרקים", "ReplaceAllMetadata": "החלף את כל המטא נתונים", "ReplaceExistingImages": "החלף תמונות קיימות", @@ -420,7 +419,7 @@ "SearchForMissingMetadata": "חפש מטא נתונים חסרים", "SearchForSubtitles": "חיפוש של כתוביות", "SearchResults": "תוצאות חיפוש", - "SeriesCancelled": "בטל סדרות", + "SeriesCancelled": "סדרה בוטלה.", "SeriesRecordingScheduled": "הקלטת סדרה מתוזמנת.", "SeriesSettings": "הגדרות סדרה", "SeriesYearToPresent": "{0} - היום", @@ -431,7 +430,7 @@ "SettingsSaved": "ההגדרות נשמרו.", "Share": "שיתוף", "ShowIndicatorsFor": "הצג מחוונים עבור:", - "Shuffle": "ערבב", + "Shuffle": "ערבוב", "SkipEpisodesAlreadyInMyLibrary": "אל תקליטו פרקים שכבר נמצאים בספרייה שלי", "SkipEpisodesAlreadyInMyLibraryHelp": "פרקים יושוו באמצעות העונה ואת הפרק פרק, כאשר זמין.", "SortChannelsBy": "מיין ערוצים לפי:", @@ -508,11 +507,11 @@ "WelcomeToProject": "ברוך הבא ל Jellyfin!", "Writer": "כותב", "Albums": "אלבומים", - "Artists": "אמנים", + "Artists": "אומנים", "Books": "ספרים", "Absolute": "מוחלט", - "AccessRestrictedTryAgainLater": "הגישה כרגע מוגבלת. אנא נסה שוב מאוחר יותר.", - "AddedOnValue": "נוסף {0}", + "AccessRestrictedTryAgainLater": "הגישה מוגבלת כרגע, נסה שוב במועד מאוחר יותר.", + "AddedOnValue": "נוספו {0}", "Blacklist": "רשימה שחורה", "Banner": "באנר", "Auto": "אוטומטי", @@ -521,30 +520,257 @@ "AllowMediaConversion": "אפשר המרת מדיה", "AllLanguages": "כל השפות", "Alerts": "התראות", - "Box": "קופסה", + "Box": "מארז", "BirthPlaceValue": "מיקום לידה: {0}", "BirthDateValue": "תאריך לידה: {0}", "Backdrop": "רקע", "AuthProviderHelp": "בחר ספק אימות שישמש לאימות הסיסמה של משתמש זה.", "Audio": "שמע", "AspectRatio": "יחס גובה-רוחב", - "AlwaysPlaySubtitlesHelp": "כתוביות תואמות להעדפת שפה יטענו ללא קשר לשפת השמע.", - "AlwaysPlaySubtitles": "הפעל כתוביות תמיד", + "AlwaysPlaySubtitlesHelp": "כתוביות בשפה המועדפת ייטענו ללא קשר לשפת השמע.", + "AlwaysPlaySubtitles": "הפעל תמיד", "AllowRemoteAccessHelp": "אם לא מסומן, כל החיבורים המרוחקים ייחסמו.", "AllowRemoteAccess": "אפשר חיבור מרוחק לשרת Jellyfin זה.", - "AllowMediaConversionHelp": "אפשר או חסום גישה להמרת מדיה.", + "AllowMediaConversionHelp": "הענק או דחה גישה להמרת מדיה.", "Aired": "שודר", "AirDate": "תאריך שידור", "Yesterday": "אתמול", "HeaderAlbumArtists": "אמני האלבום", - "Favorites": "אהובים", + "Favorites": "מועדפים", "HeaderFavoriteAlbums": "אלבומים שאהבתי", - "HeaderFavoriteArtists": "אמנים שאהבתי", + "HeaderFavoriteArtists": "אמנים מועדפים", "Folders": "תיקיות", - "HeaderFavoriteShows": "תוכניות אהובות", - "HeaderFavoriteEpisodes": "פרקים אהובים", - "HeaderFavoriteSongs": "שירים שאהבתי", - "Collections": "קולקציות", + "HeaderFavoriteShows": "סדרות מועדפות", + "HeaderFavoriteEpisodes": "פרקים מועדפים", + "HeaderFavoriteSongs": "שירים מועדפים", + "Collections": "אוספים", "Channels": "ערוצים", - "HeaderContinueWatching": "המשך לצפות" + "HeaderContinueWatching": "המשך לצפות", + "AllowOnTheFlySubtitleExtraction": "אפשר חילוץ כתוביות בזמן אמת", + "AllowHWTranscodingHelp": "אפשר למלקט לקודד הזרמות בזמן אמת. זה עשוי לעזור בהפחתת הקידוד שנעשה ע\"י השרת.", + "AllComplexFormats": "כל הפורמטים המורכבים (ASS, SSA, VOBSUB, PGS, SUB/IDX)", + "AddItemToCollectionHelp": "הוסף חפצים לאוסף על ידי חיפושם ושימוש בתפריט הלחצן הימני או לחצן התפריט כדי להוסיפם לאוסף.", + "Songs": "שירים", + "Shows": "סדרות", + "DownloadsValue": "{0} הורדות", + "DisplayMissingEpisodesWithinSeasons": "הצג פרקים חסרים בתוך העונות", + "DisplayInMyMedia": "הצג בעמוד הבית", + "Disconnect": "התנתק", + "Director": "במאי", + "Directors": "במאים", + "Descending": "סדר יורד", + "Default": "ברירת מחדל", + "DeathDateValue": "נפטר: {0}", + "DatePlayed": "תאריך ניגון", + "DateAdded": "תאריך הוספה", + "CriticRating": "דירוג מבקרים", + "ContinueWatching": "המשך לצפות", + "ButtonUninstall": "הסר התקנה", + "ButtonTrailer": "קדימון", + "ButtonSubtitles": "כתוביות", + "ButtonSplit": "פיצול", + "ButtonStop": "עצור", + "ButtonSettings": "הגדרות", + "ButtonSend": "שלח", + "ButtonSelectView": "בחר תצוגה", + "ButtonSelectServer": "בחר שרת", + "ButtonRename": "שנה שם", + "ButtonPause": "השהה", + "ButtonParentalControl": "בקרת הורים", + "ButtonNetwork": "רשת", + "ButtonMore": "עוד", + "ButtonLearnMore": "למד עוד", + "ButtonInfo": "מידע", + "ButtonHome": "בית", + "ButtonHelp": "עזרה", + "ButtonFullscreen": "מסך מלא", + "ButtonEditImages": "ערוך תמונות", + "ButtonConnect": "התחבר", + "ButtonAddServer": "הוסף שרת", + "ButtonAddMediaLibrary": "הוסף ספריית מדיה", + "ButtonAddImage": "הוסף תמונה", + "AskAdminToCreateLibrary": "בקש ממנהל ליצור ספרייה.", + "Ascending": "סדר עולה", + "Photos": "תמונות", + "TabCollections": "אוספים", + "MessageConfirmShutdown": "‫האם אתה בטוח שברצונך לכבות את השרת?", + "MessageConfirmRestart": "‫האם אתה בטוח שברצונך לאתחל את שרת ה-Jellyfin‏?", + "HeaderThisUserIsCurrentlyDisabled": "משתמש זה אינו פעיל כרגע", + "HeaderTaskTriggers": "טריגרים של המשימה", + "HeaderTags": "תגיות", + "HeaderStopRecording": "עצור הקלטה", + "HeaderSortOrder": "סדר מיון", + "HeaderSortBy": "מיין לפי", + "HeaderShutdown": "כיבוי", + "HeaderSettings": "הגדרות", + "HeaderSendMessage": "שלח הודעה", + "HeaderSelectServer": "בחר שרת", + "HeaderSecondsValue": "{0} שניות", + "HeaderSeasons": "עונות", + "HeaderRestartingServer": "מאתחל שרת", + "HeaderRestart": "הפעלה מחדש", + "HeaderProfileInformation": "מידע פרופיל", + "HeaderProfile": "פרופיל", + "HeaderPreferredMetadataLanguage": "שפת מטא-נתונים מועדפת", + "HeaderPluginInstallation": "התקנת תוסף", + "HeaderPlayOn": "נגן על", + "HeaderPinCodeReset": "איפוס קוד סיכה", + "HeaderPhotoAlbums": "אלבומי תמונות", + "HeaderPeople": "אנשים", + "HeaderPendingInvitations": "הזמנות ממתינות", + "HeaderPasswordReset": "איפוס סיסמה", + "HeaderPassword": "סיסמה", + "HeaderOtherItems": "פריטים אחרים", + "HeaderNextVideoPlayingInValue": "הוידאו הבא יתחיל להתנגן בעוד {0}", + "HeaderNextEpisodePlayingInValue": "הפרק הבא יתחיל להתנגן בעוד {0}", + "HeaderNewDevices": "מכשירים חדשים", + "HeaderNewApiKey": "‫מפתח API חדש", + "HeaderNavigation": "ניווט", + "HeaderMyDevice": "המכשיר שלי", + "HeaderLiveTv": "שידורים חיים", + "HeaderLibrarySettings": "הגדרות ספרייה", + "HeaderLibraryFolders": "תיקיות הספרייה", + "HeaderLibraries": "ספריות", + "HeaderItems": "פריטים", + "HeaderInstall": "התקנה", + "HeaderImageOptions": "הגדרות תמונה", + "HeaderHome": "בית", + "HeaderGenres": "ז'אנרים", + "HeaderForKids": "עבור ילדים", + "HeaderFilters": "מסננים", + "HeaderFavoriteVideos": "סרטונים מועדפים", + "HeaderFavoritePeople": "אנשים מועדפים", + "HeaderFavoriteMovies": "סרטים מועדפים", + "HeaderFavoriteBooks": "ספרים מועדפים", + "HeaderError": "שגיאה", + "HeaderEpisodes": "פרקים", + "HeaderDownloadSync": "הורדה וסנכרון", + "TabDevices": "מכשירים", + "HeaderDevices": "מכשירים", + "HeaderDeveloperInfo": "מידע למפתח", + "HeaderDeleteTaskTrigger": "מחק טריגר משימה", + "HeaderDeleteProvider": "מחק ספק", + "HeaderDeleteDevice": "מחק מכשיר", + "HeaderContinueListening": "המשך להאזין", + "HeaderConnectToServer": "התחבר לשרת", + "HeaderConfirmRevokeApiKey": "‫בטל מפתח API", + "HeaderCastAndCrew": "שחקנים וצוות", + "HeaderBranding": "מיתוג", + "HeaderBooks": "ספרים", + "HeaderAudioSettings": "הגדרות שמע", + "HeaderAudioBooks": "ספרים מוקלטים", + "HeaderApiKeys": "‫מפתחות API", + "HeaderApiKey": "‫מפתח API", + "HeaderAlbums": "אלבומים", + "HeaderAddUpdateImage": "הוסף/עדכן תמונה", + "HeaderAddScheduledTaskTrigger": "הוסף טריגר", + "HeaderActivity": "פעילות", + "Guide": "מדריך", + "Genre": "ז'אנר", + "General": "כללי", + "Fullscreen": "מסך מלא", + "FolderTypeUnset": "תוכן מעורבב", + "FolderTypeBooks": "ספרים", + "Filters": "מסננים", + "Rewind": "הרצה לאחור", + "FastForward": "הרצה קדימה", + "Extras": "תוספות", + "ExtraLarge": "גדול מאוד", + "ExitFullscreen": "צא ממסך מלא", + "EveryNDays": "כל {0} ימים", + "ErrorMessageStartHourGreaterThanEnd": "שעת הסיום חייבת להיות לאחר שעת ההתחלה.", + "Episodes": "פרקים", + "EnableThemeSongsHelp": "נגן שירי פתיח ברגע בעת העיון בספרייה.", + "ThemeSongs": "שירי פתיח", + "EnableThemeSongs": "שירי פתיח", + "EnablePhotos": "הצג תמונות", + "EnableHardwareEncoding": "הפעל קידוד חומרה", + "EnableExternalVideoPlayers": "נגני וידאו חיצוניים", + "EnableCinemaMode": "מצב קולנוע", + "EnableBackdrops": "תמונות רקע", + "EditMetadata": "ערוך מטא-נתונים", + "DrmChannelsNotImported": "‫ערוצים בעלי ניהול זכויות דיגיטלי (DRM) לא ייובאו.", + "Down": "למטה", + "Display": "תצוגה", + "Disc": "דיסק", + "Disabled": "לא מאופשר", + "DirectStreaming": "הזרמה ישירה", + "DirectPlaying": "ניגון ישיר", + "DetectingDevices": "מזהה מכשירים", + "DefaultMetadataLangaugeDescription": "אלו הגדרות ברירת המחדל שלך וניתן להתאים אותן לכל ספרייה בנפרד.", + "CopyStreamURLError": "אירעה שגיאה במהלך העתקת הקישור.", + "CopyStreamURLSuccess": "הקישור הועתק בהצלחה.", + "CopyStreamURL": "העתק קישור זרם", + "Connect": "התחבר", + "ConfirmEndPlayerSession": "‫האם לכבות את Jellyfin על {0}?", + "CommunityRating": "דירוג קהילה", + "ButtonViewWebsite": "צפה באתר האינטרנט", + "ButtonWebsite": "אתר אינטרנט", + "ButtonUp": "למעלה", + "ButtonSubmit": "שלח", + "ButtonStart": "התחל", + "ButtonShuffle": "ערבוב", + "ButtonScanAllLibraries": "סרוק את כל הספריות", + "ButtonRevoke": "בטל", + "TabScheduledTasks": "משימות מתוזמנות", + "TabResumeSettings": "המשך צפייה", + "ButtonResume": "המשך", + "ButtonRepeat": "חזרה", + "ButtonRefresh": "רענון", + "ButtonProfile": "פרופיל", + "ButtonOpen": "פתח", + "HeaderTracks": "רצועות", + "ButtonPreviousTrack": "הרצועה הקודמת", + "ButtonNextTrack": "הרצועה הבאה", + "ButtonGuide": "מדריך", + "HeaderForgotPassword": "שחזור סיסמה", + "ButtonForgotPassword": "שחזור סיסמה", + "ButtonEditOtherUserPreferences": "ערוך את הפרופיל, התמונה וההגדרות האישיות של משתמש זה.", + "ButtonDownload": "הורדה", + "ButtonDown": "למטה", + "ButtonChangeServer": "החלף שרת", + "AutoBasedOnLanguageSetting": "אוטומטי (לפי הגדרות שפה)", + "ButtonBack": "חזרה", + "OptionBanner": "באנר", + "ButtonAudioTracks": "רצועות שמע", + "ButtonArrowDown": "למטה", + "ButtonArrowUp": "למעלה", + "ButtonArrowRight": "ימינה", + "ButtonArrowLeft": "שמאלה", + "ButtonAddScheduledTaskTrigger": "הוסף טריגר", + "Browse": "עיין", + "BoxRear": "מארז (מאחור)", + "BookLibraryHelp": "ניתן להוסיף ספרים מוקלטים וספרים כתובים. עיינו {0}במדריך מתן שמות לספרים{1}.", + "Desktop": "שולחן עבודה", + "MessageUnauthorizedUser": "אין לך גישה לשרת ברגע זה. אנא צור קשר עם מנהל השרת למידע נוסף.", + "MessageDeleteTaskTrigger": "האם אתה בטוח שברצונך למחוק את מפעיל המשימה הזה?", + "LastSeen": "נראה לאחרונה ב-{0}", + "PersonRole": "כ-{0}", + "ListPaging": "{0}-{1} מתוך {2}", + "EveryXHours": "בכל {0} שעות", + "OnApplicationStartup": "באתחול היישום", + "DeleteUserConfirmation": "האם אתה בטוח שברצונך למחוק את המשתמש?", + "DeleteDeviceConfirmation": "האם אתה בטוח שברצונך למחוק את המכשיר? הוא יופיע שוב בפעם הבאה שמשתמש ייכנס באמצעותו.", + "ColorSpace": "מרחב צבע", + "CinemaModeConfigurationHelp": "מצב קולנוע מביא את חוויית הקולנוע היישר אל הסלון עם האפשרות להפעיל טריילרים וקדימונים מותאמים אישית לפני הסרט.", + "ChannelAccessHelp": "בחר את הערוצים לשיתוף עם משתמש זה. מנהלים יוכלו לערוך את כל הערוצים בעזרת \"מנהל המטא-דאטה\".", + "ButtonResetEasyPassword": "אתחל קוד פין פשוט", + "ButtonOff": "כיבוי", + "ButtonLibraryAccess": "הרשאות גישה לספרייה", + "BurnSubtitlesHelp": "מחליט אם על השרת לצרוב כתוביות בזמן קידוד וידאו. הימנעות מכך תשפר מאוד את הביצועים. בחר \"אוטומטי\" לצריבת כתוביות על בסיס פורמט תמונה (VOBSUB, PGS, SUB, IDX) וכתוביות ASS או SSA מסויימות.", + "Artist": "אמן", + "AllowedRemoteAddressesHelp": "רשימת IP \\ מיסוך רשת המופרדת בפסיקים עבור רשתות שיורשו להתחבר מרחוק. במידה ותישאר ריקה, כל הכתובות יורשו להתחבר.", + "Album": "אלבום", + "AlbumArtist": "אמן האלבום", + "LabelSortOrder": "מיין סדר:", + "ShowYear": "הצג שנה", + "ShowTitle": "הצג כותרת", + "DropShadow": "צייר צל", + "Playlists": "רשימות הפעלה", + "Raised": "מורם", + "LabelSpecialSeasonsDisplayName": "שם תצוגת \"עונה מיוחדת\":", + "LabelSource": "מקור:", + "LabelSoundEffects": "אפקטי סאונד:", + "ButtonTogglePlaylist": "רשימת ניגון", + "ButtonToggleContextMenu": "עוד" } diff --git a/src/strings/hi-in.json b/src/strings/hi-in.json index 38674eff00..122f4aa98b 100644 --- a/src/strings/hi-in.json +++ b/src/strings/hi-in.json @@ -13,5 +13,26 @@ "UserProfilesIntro": "एम्बि में उपयोगकर्ता प्रोफाइल अन्तर्निहित मौजूद है, जो हर उपयोगकर्ता को अपनी अलग प्रदर्शन सेटिंग्स, प्ले-अवस्था, पैतृक नियंत्रणो में सक्षम करता है।", "WelcomeToProject": "एम्बी में आपका स्वागत है!", "WizardCompleted": "अभी के लिए बस हमें यही जानना है। एम्बि ने आपकी मीडिया लाइब्रेरी के बारे में जानकारी जमा करना आरंभ कर दिया है। हमारी कुछ एेप्स को देखें, और फिर सर्वर डैशबोर्ड देखने के लिए समाप्त पर क्लिक करें।", - "Absolute": "पूर्ण" + "Absolute": "पूर्ण", + "AllLibraries": "सभी संग्रह", + "All": "सारे", + "AirDate": "प्रसारित होने की तिथि", + "AddToPlayQueue": "सक्रिय कतार में जोड़ें", + "AddToCollection": "संग्रह में जोड़ें", + "Add": "जोड़ें", + "Actor": "अभिनेता", + "AccessRestrictedTryAgainLater": "अभी प्रवेश प्रतिबंधित है। थोड़ी देर बाद कोशिश करें।", + "AllowHWTranscodingHelp": "ट्यूनर को निरंतर रूप से धाराओं को ट्रांसकोड करने दें। यह सर्वर द्वारा ट्रांसकोडिंग को कम करने में मदद कर सकता है।", + "AllLanguages": "सभी भाषाएं", + "AllEpisodes": "सभी प्रकरण", + "AllComplexFormats": "सभी जटिल प्रारूप (ASS, SSA, VOBSUB, PGS, SUB / IDX, आदि)", + "AllChannels": "सभी चैनल्स", + "Alerts": "चेतावनियां", + "Albums": "संग्रहिकाएँ", + "Aired": "प्रसारित हो चुका", + "AdditionalNotificationServices": "अतिरिक्त सूचना सेवाओं को स्थापित करने के लिए प्लगइन सूची पर नज़र डालें।", + "AddedOnValue": "जोड़ दिया", + "AddToPlaylist": "प्लेलिस्ट में जोड़ें", + "AllowMediaConversionHelp": "मीडिया परिवर्तन के लिये अनुमति दें", + "AllowMediaConversion": "मीडिया रूपांतरण की अनुमति दें" } diff --git a/src/strings/hr.json b/src/strings/hr.json index a1c700df64..107014626e 100644 --- a/src/strings/hr.json +++ b/src/strings/hr.json @@ -156,7 +156,7 @@ "GuideProviderLogin": "Prijava", "GuideProviderSelectListings": "Odaberi ispis", "H264CrfHelp": "Konstante brzine faktora (CRF) je postavka zadane kvalitete za x264 enkodera. Možete postaviti vrijednosti između 0 i 51, gdje će niže vrijednosti rezultirati boljom kvalitetom (na račun veće veličine datoteka). Razumne vrijednosti su između 18 i 28. Zadana za x264 je 23, tako da to možete koristiti kao početnu točku.", - "H264EncodingPresetHelp": "Odaberite bržu vrijednost za poboljšanje performansi ili sporiju za poboljšanje kvalitete.", + "EncoderPresetHelp": "Odaberite bržu vrijednost za poboljšanje performansi ili sporiju za poboljšanje kvalitete.", "HDPrograms": "HD programi", "HardwareAccelerationWarning": "Omogućavanje hardverskog ubrzanja može uzrokovati nestabilnostima u nekim sredinama. Pobrinite se da Vaš operativni sustav i video drajveri su u potpunosti ažurni. Ako imate poteškoća s reprodukcijom videa nakon omogućavanja ovoga, morat ćete promijeniti postavku natrag na Automatski.", "HeaderAccessSchedule": "Raspored pristupa", @@ -426,7 +426,7 @@ "LabelGroupMoviesIntoCollections": "Grupiraj filmove u kolekciju", "LabelGroupMoviesIntoCollectionsHelp": "Kada se prikazuje lista filmova, filmovi koji pripadaju kolekciji biti će prikazani kao jedna stavka.", "LabelH264Crf": "H264 kodiranje CRF:", - "LabelH264EncodingPreset": "H264 unaprijed kodiranje:", + "LabelEncoderPreset": "H264 unaprijed kodiranje:", "LabelHardwareAccelerationType": "Hardversko ubrzanje:", "LabelHardwareAccelerationTypeHelp": "Dostupno samo na podržanim sustavima.", "LabelHttpsPort": "Lokalni broj https porta:", @@ -755,7 +755,6 @@ "OptionEnableAccessFromAllDevices": "Omogući pristup svim uređajima", "OptionEnableAccessToAllChannels": "Omogući pristup svim kanalima", "OptionEnableAccessToAllLibraries": "Omogući pristup svim bibliotekama", - "OptionEnableAutomaticServerUpdates": "Omogući automatska ažuriranja servera", "OptionEnableExternalContentInSuggestions": "Omogući vanjske sadržaje u prijedlozima", "OptionEnableExternalContentInSuggestionsHelp": "Dopusti internet kratkim filmovima i TV programima uživo da budu uključeni u preporučenom sadržaju.", "OptionEnableForAllTuners": "Omogući za sve TV/Radio uređaje", @@ -1010,5 +1009,6 @@ "AllComplexFormats": "Svi kompleksni formati (ASS, SSA, VOBSUB, PGS, SUB/IDX, itd.)", "Books": "Knjige", "Channels": "Kanali", - "Collections": "Kolekcije" + "Collections": "Kolekcije", + "Artists": "Izvođači" } diff --git a/src/strings/hu.json b/src/strings/hu.json index 4cc1fde947..61d4dfbf08 100644 --- a/src/strings/hu.json +++ b/src/strings/hu.json @@ -1,10 +1,10 @@ { - "Add": "Hozzáad", + "Add": "Hozzáadás", "AddToCollection": "Hozzáadás gyűjteményhez", - "AddToPlaylist": "Lejátszási listához adni", + "AddToPlaylist": "Hozzáadás lejátszási listához", "AddedOnValue": "Hozzáadva: {0}", "AdditionalNotificationServices": "Keresd meg a Bővítmények katalógust további értesítési szolgáltatások telepítéséhez.", - "Alerts": "Riasztások", + "Alerts": "Értesítések", "All": "Összes", "AllEpisodes": "Összes epizód", "AllLanguages": "Összes nyelv", @@ -17,8 +17,8 @@ "BirthPlaceValue": "Születési hely: {0}", "Books": "Könyvek", "Browse": "Tallózás", - "ButtonAdd": "Hozzáad", - "ButtonAddMediaLibrary": "Új Média Könyvtár felvétele", + "ButtonAdd": "Hozzáadás", + "ButtonAddMediaLibrary": "Médiakönyvtár hozzáadása", "ButtonAddServer": "Szerver Hozzáadása", "ButtonAddUser": "Új felhasználó", "ButtonArrowDown": "Le", @@ -74,7 +74,7 @@ "ButtonStop": "Leállít", "ButtonSubmit": "Elküld", "ButtonSubtitles": "Feliratok", - "ButtonTrailer": "Filmelőzetes", + "ButtonTrailer": "Előzetes", "ButtonUninstall": "Eltávolítás", "ButtonWebsite": "Weboldal", "Channels": "Csatornák", @@ -84,11 +84,10 @@ "DateAdded": "Hozzáadva", "DatePlayed": "Lejátszás dátuma", "Delete": "Törlés", - "DeleteMedia": "Média törlés", + "DeleteMedia": "Média törlése", "Descending": "Csökkenő", "Director": "Rendező", - "DirectorValue": "Rendező: {0}", - "DirectorsValue": "Rendezők: {0}", + "Directors": "Rendezők", "Dislike": "Nem tettszik", "Display": "Megjelenítés", "DisplayMissingEpisodesWithinSeasons": "Hiányzó évad epizódok megjelenítése", @@ -97,13 +96,13 @@ "Download": "Letöltés", "Edit": "Szerkesztés", "EditImages": "Képek szerkesztése", - "EditMetadata": "Metaadat szerkesztés", + "EditMetadata": "Metaadat szerkesztése", "EditSubtitles": "Feliratok szerkesztése", "EnableBackdrops": "Háttérképek", "EnableBackdropsHelp": "A háttérképek a könyvtár böngészése közben néhány oldal hátterében jelennek meg.", "EnableHardwareEncoding": "Hardveres kódolás engedélyezése", - "EnableThemeSongs": "Főcím dalok", - "EnableThemeSongsHelp": "Főcím dalok lejátszása háttérben a könyvtár böngészése közben.", + "EnableThemeSongs": "Főcímdalok", + "EnableThemeSongsHelp": "Főcímdalok lejátszása háttérben a könyvtár böngészése közben.", "EndsAtValue": "Várható befejezés {0}", "Episodes": "Epizódok", "ExitFullscreen": "Kilépés a teljes képernyőből", @@ -124,10 +123,9 @@ "Fullscreen": "Teljes képernyő", "General": "Általános", "Genres": "Műfajok", - "GenresValue": "Műfajok: {0}", "HeaderActiveDevices": "Aktív eszközök", "HeaderAddToCollection": "Hozzáadás gyűjteményhez", - "HeaderAddToPlaylist": "Lejátszási listához adni", + "HeaderAddToPlaylist": "Hozzáadás lejátszási listához", "HeaderAddUpdateImage": "Kép hozzáadása / frissítése", "HeaderAddUser": "Új felhasználó", "HeaderAlbums": "Albumok", @@ -138,14 +136,14 @@ "HeaderCastCrew": "Szereplők és Stáb", "HeaderChannels": "Csatornák", "HeaderConnectToServer": "Kapcsolódás a Szerverhez", - "HeaderContinueWatching": "Folyamatban lévő filmek", + "HeaderContinueWatching": "Megtekintés folytatása", "HeaderCustomDlnaProfiles": "Egyedi profilok", "HeaderDetectMyDevices": "Eszközök érzékelése", "HeaderDeveloperInfo": "Fejlesztői információk", "HeaderDeviceAccess": "Eszköz Hozzáférések", "HeaderDevices": "Eszközök", "HeaderDisplay": "Megjelenítés", - "HeaderDownloadSync": "Letöltés & Sync", + "HeaderDownloadSync": "Letöltés és szinkronizálás", "HeaderEasyPinCode": "Pin kód", "HeaderEditImages": "Képek szerkesztése", "HeaderEnabledFields": "Engedélyezett mezők", @@ -165,14 +163,14 @@ "HeaderLibraries": "Könyvtárak", "HeaderLibraryAccess": "Könyvtár Hozzáférés", "HeaderLibraryFolders": "Médiatár mappák", - "HeaderLibraryOrder": "Médiatár rendezés", + "HeaderLibraryOrder": "Médiatár elrendezése", "HeaderLibrarySettings": "Médiatár beállítások", "HeaderLiveTvTunerSetup": "Élő TV tuner beállítása", "HeaderMedia": "Média", - "HeaderMediaFolders": "Média Könyvtárak", + "HeaderMediaFolders": "Médiakönyvtárak", "HeaderMediaInfo": "Média Infó", "HeaderMetadataSettings": "Metaadat Beállítások", - "HeaderMoreLikeThis": "További ehhez hasonló", + "HeaderMoreLikeThis": "Több ehhez hasonló", "HeaderMovies": "Filmek", "HeaderMusicVideos": "Zenei videók", "HeaderMyDevice": "Jelenlegi eszköz", @@ -198,7 +196,7 @@ "HeaderRevisionHistory": "Módosítási előzmények", "HeaderRunningTasks": "Futó folyamatok", "HeaderScenes": "Jelenetek", - "HeaderSeasons": "Évad", + "HeaderSeasons": "Évadok", "HeaderSelectMetadataPath": "Válaszd ki a metaadat útvonalat", "HeaderSelectServer": "Szerver Kiválasztás", "HeaderSendMessage": "Üzenet küldése", @@ -217,7 +215,7 @@ "HeaderUploadImage": "Kép feltöltés", "HeaderUser": "Felhasználó", "HeaderUsers": "Felhasználók", - "HeaderVideoType": "Videó típusa:", + "HeaderVideoType": "Videó típusa", "HeaderVideos": "Videók", "HeaderYears": "Év", "HeadersFolders": "Könyvtárak", @@ -226,14 +224,14 @@ "Home": "Kezdőlap", "Identify": "Azonosítás", "Images": "Képek", - "InstallingPackage": "{0} Telepítése", + "InstallingPackage": "{0} ({1} verzió) telepítése", "Label3DFormat": "3D formátum:", "LabelAlbumArtists": "Album előadók:", "LabelAll": "Összes", "LabelAllowServerAutoRestart": "Automatikus újraindítás engedélyezése a szervernek a frissítések telepítéséhez", "LabelAllowServerAutoRestartHelp": "A szerver csak akkor indul újra ha nincs felhasználói tevékenység.", "LabelArtists": "Előadók:", - "LabelAudio": "Audió:", + "LabelAudio": "Audió", "LabelAudioLanguagePreference": "Audió nyelvének beállítása:", "LabelBirthYear": "Születési év:", "LabelCachePath": "Gyorsítótár útvonal:", @@ -246,7 +244,7 @@ "LabelCustomDeviceDisplayName": "Megjelenítendő név:", "LabelCustomDeviceDisplayNameHelp": "Adj meg egy egyedi nevet, vagy hagyd üresen a készülék által elküldött név használatához.", "LabelCustomRating": "Egyéni értékelés:", - "LabelDashboardTheme": "Szerver vezérlőpult kinézet:", + "LabelDashboardTheme": "Szerver vezérlőpult kinézete:", "LabelDateAdded": "Hozzáadva:", "LabelDateTimeLocale": "Dátum és idő formátum:", "LabelDay": "Nap:", @@ -265,17 +263,17 @@ "LabelFinish": "Befejez", "LabelForgotPasswordUsernameHelp": "Add meg a felhasználóneved, ha emlékszel rá.", "LabelGroupMoviesIntoCollections": "Filmek csoportosítása gyűjteményekbe", - "LabelH264EncodingPreset": "H264 enkóder beállítások:", + "LabelEncoderPreset": "H264 enkóder beállítások:", "LabelHardwareAccelerationType": "Hardveres gyorsítás:", - "LabelHardwareAccelerationTypeHelp": "Ez egy kísérleti szolgáltatás, amely csak a támogatott rendszereken érhető el.", - "LabelHomeScreenSectionValue": "Kezdőképernyő blokk {0}:", + "LabelHardwareAccelerationTypeHelp": "A hardveres gyorsítás további konfigurálást igényel.", + "LabelHomeScreenSectionValue": "{0}. kezdőképernyő blokk:", "LabelImageType": "Kép típusa:", "LabelKodiMetadataDateFormat": "Megjelenési dátum formátuma:", "LabelLanguage": "Nyelv:", "LabelLogs": "Naplók:", "LabelMessageText": "Üzenet szövege:", "LabelMessageTitle": "Üzenet címe:", - "LabelMetadata": "Metaadat:", + "LabelMetadata": "Metaadatok:", "LabelMetadataDownloadLanguage": "Előnyben részesített letöltendő nyelv:", "LabelMetadataPath": "Metaadat útvonal:", "LabelMetadataReaders": "Metaadat olvasók:", @@ -297,7 +295,7 @@ "LabelPlayDefaultAudioTrack": "Az alapértelmezett hangsáv lejátszása a nyelvtől függetlenül", "LabelPlaylist": "Lejátszási lista:", "LabelPreferredDisplayLanguage": "Elsődleges megjelenítendő nyelv:", - "LabelPreferredDisplayLanguageHelp": "A Jellyfin fordítása egy folyamatban lévő project.", + "LabelPreferredDisplayLanguageHelp": "A Jellyfin fordítása egy folyamatos projekt.", "LabelPrevious": "Előző", "LabelProfileAudioCodecs": "Audió kódekek:", "LabelProfileCodecs": "Kódek:", @@ -321,7 +319,7 @@ "LabelStopping": "Megállítás", "LabelSubtitleFormatHelp": "Például: srt", "LabelSubtitlePlaybackMode": "Felirat mód:", - "LabelSubtitles": "Feliratok:", + "LabelSubtitles": "Feliratok", "LabelTagline": "Címke:", "LabelTheme": "Kinézet:", "LabelTime": "Idő:", @@ -338,11 +336,11 @@ "LabelUsername": "Felhasználónév:", "LabelVersionInstalled": "{0} telepítve", "LabelVersionNumber": "Verzió {0}", - "LabelVideo": "Videó:", + "LabelVideo": "Videó", "LabelYear": "Év:", "LabelYourFirstName": "Keresztneved:", "LabelYoureDone": "Készen vagy!", - "LatestFromLibrary": "Nemrég hozzáadva: {0}", + "LatestFromLibrary": "Nemrég hozzáadott {0}", "Like": "Tettszik", "Live": "Élő", "ManageLibrary": "Könyvtár kezelése", @@ -411,7 +409,6 @@ "OptionEnableAccessFromAllDevices": "Hozzáférés engedélyezése minden eszközről", "OptionEnableAccessToAllChannels": "Hozzáférés engedélyezése minden csatornához", "OptionEnableAccessToAllLibraries": "Hozzáférés engedélyezése minden könyvtárhoz", - "OptionEnableAutomaticServerUpdates": "Automatikus szerverfrissítés engedélyezése", "OptionExternallyDownloaded": "Külső letöltés", "OptionFavorite": "Kedvencek", "OptionFriday": "Péntek", @@ -419,7 +416,7 @@ "OptionHasSubtitles": "Feliratok", "OptionHasThemeSong": "Főcímdal", "OptionHasThemeVideo": "Filmzene", - "OptionHasTrailer": "Filmelőzetes", + "OptionHasTrailer": "Előzetes", "OptionHideUser": "Felhasználó elrejtése a bejelentkezési képernyőn", "OptionHomeVideos": "Fényképek", "OptionImdbRating": "IMDb értékelés", @@ -427,7 +424,7 @@ "OptionMissingEpisode": "Hiányzó Epizódok", "OptionMonday": "Hétfő", "OptionNameSort": "Név", - "OptionNew": "Új...", + "OptionNew": "Új…", "OptionParentalRating": "Korhatár besorolás", "OptionPlayCount": "Lejátszások száma", "OptionPlayed": "Megnézett", @@ -446,9 +443,9 @@ "OptionWednesday": "Szerda", "OptionWeekly": "Heti", "OriginalAirDateValue": "Eredeti vetítés dátuma: {0}", - "PackageInstallCancelled": "{0} telepítése megszakítva.", - "PackageInstallCompleted": "{0} telepítése befejezve.", - "PackageInstallFailed": "{0} telepítése nem sikerült.", + "PackageInstallCancelled": "{0} ({1} verzió) telepítése megszakítva.", + "PackageInstallCompleted": "{0} ({1} verzió) telepítése befejezve.", + "PackageInstallFailed": "{0} ({1} verzió) telepítése nem sikerült.", "ParentalRating": "Korhatár besorolás", "People": "Személyek", "Play": "Lejátszás", @@ -458,26 +455,26 @@ "PleaseRestartServerName": "Kérlek indítsd újra a Jellyfin Szerver-t - {0}.", "Quality": "Minőség", "RecommendationBecauseYouLike": "Mert tetszett a(z) {0}", - "RecommendationBecauseYouWatched": "Ha már megnézted a(z) {0}", + "RecommendationBecauseYouWatched": "Amiért megnézted ezt: {0}", "RecommendationDirectedBy": "Rendezte: {0}", "RecommendationStarring": "Főszerepben: {0}", "Record": "Felvétel", "Refresh": "Frissítés", "RefreshDialogHelp": "A metaadatok frissítése a 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", + "RefreshMetadata": "Metaadat frissítése", "ReleaseDate": "Megjelenés dátuma", "RememberMe": "Emlékezz rám", "Repeat": "Ismétlés", - "RepeatAll": "Folyamatos ismétlés", - "RepeatMode": "Ismétlő mód", - "RepeatOne": "Ismétlés egyszer", + "RepeatAll": "Összes ismétlése", + "RepeatMode": "Ismétlés módja", + "RepeatOne": "Aktuális ismétlése", "ReplaceAllMetadata": "Összes metaadat cseréje", "ReplaceExistingImages": "Cserélje ki a meglévő képeket", "Rewind": "Ugrás vissza", "Runtime": "Játékidő", "Saturday": "Szombat", "Save": "Mentés", - "ScanForNewAndUpdatedFiles": "Keresés az új és frissített fileokra", + "ScanForNewAndUpdatedFiles": "Keresés az új és frissített fájlokra", "ScanLibrary": "Könyvtár beolvasása", "Search": "Keresés", "SearchForMissingMetadata": "Keresés a hiányzó metaadatokra", @@ -494,8 +491,8 @@ "ShowTitle": "Név megjelenítése", "Shuffle": "Keverés", "SkipEpisodesAlreadyInMyLibraryHelp": "Az epizódokat összehasonlítjuk az évad és az epizód számával, ha rendelkezésre állnak.", - "Sort": "Rendezés:", - "SortByValue": "Rendezés {0}", + "Sort": "Rendezés", + "SortByValue": "Rendezés {0} szerint", "Studios": "Stúdiók", "Subtitles": "Feliratok", "Suggestions": "Javaslatok", @@ -576,7 +573,7 @@ "Writer": "Író", "Yesterday": "Tegnap", "FormatValue": "Formátum: {0}", - "GenreValue": "Műfaj: {0}", + "Genre": "Műfaj", "HeaderServerSettings": "Szerver beállítások", "LabelDropImageHere": "Húzz ide egy képet, vagy kattints a böngészéshez.", "LabelDropShadow": "Árnyék:", @@ -584,15 +581,15 @@ "AccessRestrictedTryAgainLater": "A hozzáférés jelenleg korlátozott. Kérlek próbáld újra később.", "Actor": "Színész", "AirDate": "Vetítés dátuma", - "Aired": "Vetítve:", + "Aired": "Adásban", "Albums": "Albumok", "AllChannels": "Minden csatorna", - "AllComplexFormats": "Minden összetett formátum (ASS, SSA, VOBSUB, PGS, SUB/IDX, stb.)", + "AllComplexFormats": "Minden összetett formátum (ASS, SSA, VOBSUB, PGS, SUB, IDX, ...)", "AllowMediaConversion": "Média konvertálás engedélyezése", "AllowMediaConversionHelp": "Add meg vagy tiltsd le a média konvertálás funkcióhoz való hozzáférést.", "AllowRemoteAccess": "Engedélyezze a távoli kapcsolatokat a Jellyfin szerverhez.", "AllowRemoteAccessHelp": "Ha nincs bekapcsolva, minden távoli kapcsolat blokkolva lesz.", - "AlwaysPlaySubtitles": "A feliratokat mindig jelenítse meg", + "AlwaysPlaySubtitles": "Mindig jelenjen meg", "AnyLanguage": "Bármelyik nyelv", "Anytime": "Bármikor", "AroundTime": "{0} körül", @@ -603,7 +600,7 @@ "Backdrops": "Háttér", "Banner": "Banner", "BirthLocation": "Születési hely", - "Box": "Box", + "Box": "Doboz", "AlwaysPlaySubtitlesHelp": "A nyelvi beállításoknak megfelelő feliratok az audió nyelvétől függetlenül kerülnek betöltésre.", "Artists": "Előadók", "Blacklist": "Feketelista", @@ -633,7 +630,7 @@ "ChannelAccessHelp": "Válaszd ki a megosztani kívánt csatornákat a felhasználóval. A rendszergazdák a metaadatkezelő segítségével szerkeszthetik az összes csatornát.", "ChannelNameOnly": "Csak {0} csatorna", "ChannelNumber": "Csatorna száma", - "CinemaModeConfigurationHelp": "A Cinema Mode igazi mozi élményt nyújt előzetessel és egyedi intróval a film vetítése előtt.", + "CinemaModeConfigurationHelp": "A Mozi mód igazi mozi élményt nyújt előzetessel és egyedi intróval a film vetítése előtt.", "ColorSpace": "Színtér", "ColorTransfer": "Színátvitel", "Composer": "Zeneszerző", @@ -643,7 +640,7 @@ "ConfirmDeleteItems": "Az elem törlése mind a fájlrendszerből, mind a médiakönyvtárból törlődik. Biztosan folytatni akarod?", "ConfirmDeletion": "Törlés megerősítése", "ConfirmEndPlayerSession": "Szeretnéd leállítani a Jellyfin-t {0}?", - "ContinueWatching": "Folyamatban lévő filmek", + "ContinueWatching": "Megtekintés folytatása", "Continuing": "Folyamatos", "CriticRating": "Kritikus értékelés", "CustomDlnaProfilesHelp": "Hozz létre egyéni profilt az új eszközhöz, vagy módosítsd a rendszerprofilt.", @@ -660,19 +657,19 @@ "DirectPlaying": "Közvetlen lejátszás", "DirectStreamHelp1": "Az adathordozó kompatibilis a készülékkel a felbontás és a médiatípus (H.264, AC3, stb.) tekintetében, de nem kompatibilis a fájltárolóban (.mkv, .avi, .wmv, stb.). A videófelvétel újra csomagolásra kerül, mielőtt azt a készülékre továbbítaná.", "DirectStreamHelp2": "A fájl közvetlen közvetítése (Direct Streaming) nagyon kevés feldolgozási erőforrást használ, ennek ellenére a videó nem veszít a minőségéből.", - "DirectStreaming": "Direct streaming", + "DirectStreaming": "Közvetlen streaming", "Disabled": "Tiltva", "Disc": "Lemez", "Disconnect": "Szétkapcsol", "DisplayInMyMedia": "Megjelenítés a kezdőképernyőn", "DisplayInOtherHomeScreenSections": "Megjelenítés a kezdőképernyőn, mint például a Legújabb Média, és a Folyamatban lévő filmek", - "DisplayModeHelp": "Válaszd ki a Jellyfin-n futó képernyő típusát.", + "DisplayModeHelp": "Válaszd ki a használni kívánt elrendezést.", "DoNotRecord": "Ne rögzítsen", "DownloadsValue": "{0} letöltés", "DrmChannelsNotImported": "A csatornák DRM-el nem kerülnek importálásra.", "DropShadow": "Árnyék", "EasyPasswordHelp": "Az egyszerű PIN kódot az offline hozzáféréshez használják a támogatott kliens alkalmazásokban, valamint hálózaton belüli bejelentkezéshez is használható.", - "EnableCinemaMode": "Cinema Mode", + "EnableCinemaMode": "Mozi mód", "EnableColorCodedBackgrounds": "Színkódolt háttérképek", "EnableDisplayMirroring": "Kijelző tükrözés", "EnableExternalVideoPlayers": "Külső videolejátszók", @@ -684,7 +681,7 @@ "Ended": "Befejeződött", "ErrorAddingMediaPathToVirtualFolder": "Hiba történt a média elérésekor. Kérlek győződjön meg róla, hogy az elérési út érvényes és a Jellyfin szerver hozzáfér az adott helyhez.", "ErrorAddingTunerDevice": "Hiba történt a tuner eszköz hozzáadásakor. Kérlek győződj meg róla, hogy az eszköz elérhető és próbáld meg újra.", - "ErrorAddingXmlTvFile": "Hiba történt az XmlTV fájl elérésekor. Győződj meg róla, hogy a fájl létezik és próbáld meg újra.", + "ErrorAddingXmlTvFile": "Hiba történt az XMLTV fájl elérésekor. Győződj meg róla, hogy a fájl létezik és próbáld meg újra.", "ErrorDeletingItem": "Hiba történt az elem törlése során a Jellyfin Szerverről. Ellenőrizd, hogy a Jellyfin Szerver rendelkezik-e írási jogosultsággal a média mappához és próbálja újra.", "ErrorMessageStartHourGreaterThanEnd": "A befejezési időnek nagyobbnak kell lennie mint a kezdési idő.", "ErrorSavingTvProvider": "Hiba történt a TV szolgáltató mentésekor. Kérlek győződj meg róla, hogy elérhető és próbálkozz meg újra.", @@ -700,14 +697,14 @@ "GuestStar": "Vendég sztár", "GuideProviderLogin": "Bejelentkezés", "GuideProviderSelectListings": "Válassz listát", - "H264EncodingPresetHelp": "Válassz egy gyorsabb értéket a teljesítmény javítása érdekében, vagy egy lassabb értéket a minőség javítása érdekében.", + "EncoderPresetHelp": "Válassz egy gyorsabb értéket a teljesítmény javítása érdekében, vagy egy lassabb értéket a minőség javítása érdekében.", "HDPrograms": "HD programok", "HandledByProxy": "Reverse proxy segítségével kezelhető", - "HardwareAccelerationWarning": "A hardveres gyorsítás engedélyezése bizonyos környezetekben instabilitást okozhat. Győződj meg róla, hogy az operációs rendszer és a videó-illesztőprogramok teljesen naprakészek. Ha a beállítás után problémába ütközik a videólejátszás, akkor vissza kell állítani a beállítást Auto-ra.", + "HardwareAccelerationWarning": "A hardveres gyorsítás engedélyezése bizonyos környezetekben instabilitást okozhat. Győződj meg róla, hogy az operációs rendszer és a videó-illesztőprogramok teljesen naprakészek. Ha a beállítás után problémába ütközik a videólejátszás, akkor vissza kell állítani a beállítást Nincs-re.", "HeaderAccessSchedule": "Hozzáférési Ütemezés", "HeaderAccessScheduleHelp": "Hozz létre hozzáférési ütemezést, hogy korlátozd a hozzáférést bizonyos időben.", "HeaderActiveRecordings": "Aktív Felvételek", - "HeaderActivity": "Tevékenység", + "HeaderActivity": "Tevékenységek", "HeaderAdditionalParts": "További részek", "HeaderAdmin": "Adminisztrátor", "HeaderAlbumArtists": "Album előadók", @@ -749,7 +746,7 @@ "HeaderIdentificationCriteriaHelp": "Adj meg legalább egy azonosítási kritériumot.", "HeaderIdentificationHeader": "Azonosító fejléc", "HeaderImageOptions": "Képbeállítások", - "HeaderInstantMix": "Instant Mix", + "HeaderInstantMix": "Azonnali keverés", "HeaderItems": "Elemek", "HeaderKeepRecording": "Felvétel készítése", "HeaderKodiMetadataHelp": "Az Nfo metaadatok engedélyezéséhez vagy letiltásához szerkeszd a könyvtárat a Jellyfin Médiatár beállításaiban és keresd meg a metaadat letöltő részt.", @@ -761,7 +758,7 @@ "HeaderMusicQuality": "Zene minősége", "HeaderNewApiKey": "Új API kulcs", "HeaderNewDevices": "Új eszközök", - "HeaderNextEpisodePlayingInValue": "Következő epizód lejátszása {0}", + "HeaderNextEpisodePlayingInValue": "A következő epizód {0} múlva automatikusan elindul", "HeaderNextVideoPlayingInValue": "Következő videó lejátszása {0}", "HeaderOtherItems": "Egyéb elemek", "HeaderPasswordReset": "Jelszó visszaállítása", @@ -789,10 +786,10 @@ "MediaInfoCodecTag": "Kódek címke", "Photos": "Fényképek", "Playlists": "Lejátszási listák", - "Shows": "Műsorok", + "Shows": "Sorozatok", "Songs": "Dalok", "ValueSpecialEpisodeName": "Special - {0}", - "EnableThemeVideos": "Videók témák", + "EnableThemeVideos": "Videótémák", "EnableThemeVideosHelp": "Videó témájának lejátszása háttérben a könyvtár böngészése közben.", "HeaderBlockItemsWithNoRating": "Blokkolja azokat az elemeket amelyek tiltott, vagy nem felismerhető minősítésűek:", "HeaderSchedule": "Ütemezés", @@ -800,7 +797,7 @@ "HeaderSpecialEpisodeInfo": "Speciális epizód információ", "HeaderStartNow": "Indítás most", "HeaderStopRecording": "Felvétel leállítása", - "HeaderSubtitleAppearance": "Felirat megjelenés", + "HeaderSubtitleAppearance": "Felirat kinézete", "HeaderSubtitleProfile": "Felirat profil", "HeaderSubtitleProfiles": "Feliratok profilok", "HeaderSubtitleProfilesHelp": "A feliratprofilok leírják a készülék által támogatott feliratformátumokat.", @@ -817,11 +814,11 @@ "HeaderXmlDocumentAttribute": "XML dokumentum attribútum", "HeaderXmlDocumentAttributes": "XML dokumentum attribútumok", "HeaderXmlSettings": "XML beállítások", - "Hide": "Elrejt", + "Hide": "Elrejtés", "Horizontal": "Vízszintes", "HttpsRequiresCert": "A biztonságos kapcsolatok engedélyezéséhez megbízható SSL-tanúsítványt kell használni, mint például a Let's Encrypt. Kérlek add meg a tanúsítványt, vagy tiltsd le a biztonságos kapcsolatokat.", "ImportMissingEpisodesHelp": "Ha engedélyezve van, a hiányzó epizódokra vonatkozó információk a Jellyfin adatbázisába kerülnek importálásra és megjelenítésre kerülnek az évadokban és sorozatokban. Ez jelentősen hosszabb könyvtárvizsgálatot okozhat.", - "InstantMix": "Instant mix", + "InstantMix": "Azonnali keverés", "ItemCount": "{0} elem", "Items": "Elemek", "Kids": "Gyerekek", @@ -872,7 +869,7 @@ "LabelArtistsHelp": "Ha több van használd a következő elválasztót ;", "LabelDisplayCollectionsView": "Jelenítse meg a Gyűjtemények menüpontot a filmgyűjtemények megjelenítéséhez", "LabelDisplayCollectionsViewHelp": "Ez külön menüpontot hoz létre a filmgyűjtemények megjelenítéséhez. Gyűjtemény létrehozásához kattints jobb gombbal vagy kattints a három pontra bármelyik filmen, és válaszd a 'Hozzáadás gyűjteményhez' lehetőséget. ", - "LabelEnableAutomaticPortMapHelp": "A szerver az UPnP segítségével a routeren megpróbálja automatikusan átirányítani a nyilvános portot a helyi portra. Előfordulhat, hogy egyes router modelleken ez nem működik.", + "LabelEnableAutomaticPortMapHelp": "A szerver az UPnP segítségével a routeren megpróbálja automatikusan átirányítani a nyilvános portot a helyi portra. Előfordulhat, hogy egyes router modelleken ez nem működik. A módosítások újraindítás után lépnek életbe.", "LabelEnableBlastAliveMessagesHelp": "Engedélyezd ezt ha a szerver nem észleli megbízhatóan a hálózat más UPnP-eszközeit.", "LabelEnableDlnaClientDiscoveryInterval": "Kliens felderítési intervallum (másodperc)", "LabelEnableDlnaClientDiscoveryIntervalHelp": "A Jellyfin által végrehajtott SSDP keresések időtartamát határozza meg másodpercben.", @@ -915,7 +912,7 @@ "LabelLockItemToPreventChanges": "Az elem zárolása a jövőbeni változások elkerülése érdekében", "LabelLoginDisclaimer": "Bejelentkezési nyilatkozat:", "LabelLoginDisclaimerHelp": "Ez az üzenet a bejelentkezési oldal alján jelenik meg.", - "LabelManufacturer": "Gyártó", + "LabelManufacturer": "Gyártó:", "LabelManufacturerUrl": "Gyártó URL címe", "LabelMatchType": "Egyezés típusa:", "LabelMaxBackdropsPerItem": "A hátterek maximális száma elemenként:", @@ -1056,7 +1053,7 @@ "LiveBroadcasts": "Élő adások", "MessageConfirmRevokeApiKey": "Biztosan visszavonod ezt az API kulcsot? Az alkalmazás csatlakozása a Jellyfin Szerverhez hirtelen megszűnik.", "MessageDirectoryPickerInstruction": "A hálózati útvonalak manuálisan megadhatók abban az esetben, ha a Hálózati gomb nem találja meg a készülékeket. Például: {0} vagy {1}.", - "MessageDirectoryPickerLinuxInstruction": "Az Arch Linux, CentOS, Debian, Fedora, OpenSuse vagy Ubuntu Linux operációs rendszereken a Jellyfin rendszer felhasználójának legalább olvasási hozzáférést kell biztosítania a tárolóhelyekhez.", + "MessageDirectoryPickerLinuxInstruction": "Az Arch Linux, CentOS, Debian, Fedora, openSUSE vagy Ubuntu Linux operációs rendszereken a Jellyfin szolgáltatás felhasználójának legalább olvasási hozzáférést kell biztosítania a tárolóhelyekhez.", "MessageForgotPasswordInNetworkRequired": "Kérlek próbáld meg újra a jelszó visszaállítási folyamatot az otthoni hálózatban.", "MessageNoMovieSuggestionsAvailable": "Jelenleg nincsenek filmajánlatok. Kezdj el nézni és értékelni a filmeket, majd térj vissza, hogy megtekinthesd az ajánlásokat.", "MessagePasswordResetForUsers": "A következő felhasználók jelszavai visszaálltak. Most már bejelentkezhetnek a visszaállításhoz használt PIN kódokkal.", @@ -1084,11 +1081,11 @@ "NoNewDevicesFound": "Nem található új eszköz. Új tuner hozzáadásához zárd be ezt a párbeszédablakot és add meg kézzel az eszköz adatait.", "NoNextUpItemsMessage": "Nem található. Kezdj el nézni műsorokat!", "NoPluginConfigurationMessage": "Ez a bővítmény nem rendelkezik konfigurációs beállításokkal.", - "NoSubtitles": "Nincs felirat", + "NoSubtitles": "Nincs", "NoSubtitlesHelp": "A feliratok alapértelmezés szerint nem lesznek betöltve. Lejátszás közben kézzel is bekapcsolhatók.", "Off": "Ki", "OneChannel": "Egy csatorna", - "OnlyImageFormats": "Csak képformátumok (VOBSUB, PGS, SUB stb.)", + "OnlyImageFormats": "Csak képformátumok (VOBSUB, PGS, SUB)", "Option3D": "3D", "OptionAlbum": "Album", "OptionAlbumArtist": "Album előadó", @@ -1101,7 +1098,7 @@ "OptionAllowSyncTranscoding": "Engedélyezze a média letöltését és szinkronizálását, amely átkódolást igényel", "OptionAllowVideoPlaybackRemuxing": "Olyan videólejátszás engedélyezése, amely átalakítást igényel újrakódolás nélkül", "OptionAllowVideoPlaybackTranscoding": "Engedélyezze az átkódolást igénylő videó lejátszást", - "OptionArtist": "Művész", + "OptionArtist": "Előadó", "OptionAuto": "Auto", "OptionAutomatic": "Auto", "OptionAutomaticallyGroupSeries": "A több mappában elosztott sorozat automatikus összevonása", @@ -1114,7 +1111,7 @@ "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)", "OptionContinuing": "Folytatva", "OptionDateAddedImportTime": "Használja a könyvtárba beolvasási dátumot", - "OptionDisableUserHelp": "Ha letiltod, a szerver nem engedélyezi a felhasználó csatlakozását. A meglévő kapcsolatok hirtelen megszűnnek.", + "OptionDisableUserHelp": "Ha letiltod, a szerver nem engedélyezi a felhasználó csatlakozását. A meglévő kapcsolatok azonnal megszűnnek.", "OptionDisplayFolderView": "Az egyszerű média mappák mappanézetének megjelenítése", "OptionDisplayFolderViewHelp": "Jelenítse meg a mappákat a többi médiakönyvtár mellett. Ez hasznos lehet, ha egyszerű mappa nézeteket szeretnél látni.", "OptionDownloadImagesInAdvance": "Képek előzetes letöltése", @@ -1128,8 +1125,8 @@ "PlayNextEpisodeAutomatically": "A következő epizód automatikus lejátszása", "ShowAdvancedSettings": "Speciális beállítások megjelenítése", "ValueSeconds": "{0} másodperc", - "AddToPlayQueue": "Lejátszási listához adni", - "AllowHWTranscodingHelp": "Ha engedélyezve van akkor lehetővé teszi a tuner számára, hogy át tudja kódolni a streameket valós időben. Ez segíthet csökkenteni a Jellyfin Szerver által igényelt átkódolást.", + "AddToPlayQueue": "Hozzáadás a lejátszási sorhoz", + "AllowHWTranscodingHelp": "Lehetővé teszi a tuner számára, hogy át tudja kódolni a streameket valós időben. Ez segíthet csökkenteni a Szerver által igényelt átkódolást.", "AllowOnTheFlySubtitleExtraction": "Felirat kinyerésének engedélyezése valós időben", "MessageNoTrailersFound": "Nincsenek előzetesek. Telepítsd a Trailer csatornát, hogy javítsd a filmélményt az internetes előzetesek könyvtárának hozzáadásával.", "OptionEnableM2tsMode": "M2ts mód engedélyezése", @@ -1214,7 +1211,7 @@ "Screenshots": "Képernyőképek", "SearchForCollectionInternetMetadata": "Keresés az interneten artwork és metaadat után", "Series": "Sorozatok", - "SeriesCancelled": "A sorozat törölt.", + "SeriesCancelled": "Sorozat törölve.", "SeriesRecordingScheduled": "A sorozatfelvétel ütemezett.", "SeriesSettings": "Sorozat beállítások", "ServerRestartNeededAfterPluginInstall": "A bővítmény telepítése után újra kell indítani a Jellyfin Szerver-t.", @@ -1257,7 +1254,7 @@ "UserProfilesIntro": "A Jellyfin beépített támogatást tartalmaz a felhasználói profilokhoz lehetővé téve, hogy minden felhasználó rendelkezzen saját megjelenítési beállításokkal, lejátszási és szülői felügyelettel.", "ValueAlbumCount": "{0} album", "ValueConditions": "Feltételek: {0}", - "ValueDiscNumber": "Lemez {0}", + "ValueDiscNumber": "{0}. lemez", "ValueMinutes": "{0} perc", "ValueOneAlbum": "1 album", "ValueOneEpisode": "1 epizód", @@ -1270,7 +1267,7 @@ "Vertical": "Függőleges", "VideoRange": "Videó tartomány", "ViewAlbum": "Album megtekintése", - "ViewArtist": "Művész megtekintése", + "ViewArtist": "Előadó megtekintése", "Whitelist": "Fehérlista", "WizardCompleted": "Ez most minden amire szükség volt. A Jellyfin megkezdte a médiakönyvtáraddal kapcsolatos információk gyűjtését. Nézz meg néhány alkalmazásunkat, majd kattints a Befejezés gombra a Vezérlőpult megtekintéséhez.", "XmlTvKidsCategoriesHelp": "Az ilyen kategóriákkal rendelkező programok gyerekeknek szóló programokként jelennek meg. Válaszd el őket a '|' elválasztóval.", @@ -1283,10 +1280,10 @@ "LabelMaxResumePercentageHelp": "A címeket teljesen lejátszottnak tekintjük, ha ezen idő után fejezed be.", "LabelMaxStreamingBitrateHelp": "Adj meg egy maximum bitrátát a streameléshez.", "LabelMinResumePercentageHelp": "A címeket nem lejátszottnak tekintjük, ha ez alatt az idő alatt fejezed be.", - "LabelMusicStreamingTranscodingBitrateHelp": "Határozz meg egy streamelési max bitrátát a zenékhez", + "LabelMusicStreamingTranscodingBitrateHelp": "Határozz meg egy streamelési max bitrátát a zenékhez.", "DashboardVersionNumber": "Verzió: {0}", "DashboardServerName": "Szerver: {0}", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "MediaInfoSoftware": "Szoftver", "MediaInfoStreamTypeAudio": "Audió", "MediaInfoStreamTypeSubtitle": "Felirat", @@ -1305,7 +1302,7 @@ "AllowOnTheFlySubtitleExtractionHelp": "A beágyazott feliratokat ki lehet nyerni a videókból és elküldeni az alkalmazásoknak sima szöveg formátumba, hogy ne legyen átkódolás. Néhány eszközön ez hosszú ideig is eltarthat, valamint a videó lejátszás megakadhat az eltávolítási folyamat futása közben. Ezt kikapcsolva a beágyazott feliratok videó átkódolással beégetésre kerülnek azon kliens eszközökre melyek nem támogatják a külső feliratokat.", "Art": "ClearArt", "AuthProviderHelp": "Válaszd ki az azonosítási szolgáltatást amely ezen felhasználó jelszavának ellenőrzését valósítja meg.", - "BurnSubtitlesHelp": "Meghatározza, hogy a szervernek be kell-e égetnie a feliratot videó átkódolás esetén a felirat típusának függvényében. A beégetés elkerülésével a szerver teljesítménye javul. Válaszd az Auto lehetőséget a kép alapú feliratok (pl. VOBSUB, PGS, SUB/IDX, stb) és bizonyos ASS/SSA feliratok beégetéséhez.", + "BurnSubtitlesHelp": "Meghatározza, hogy a szervernek be kell-e égetnie a feliratot videó átkódolás esetén a felirat típusának függvényében. Ennek elkerülésével a szerver teljesítménye javul. Válaszd az Auto lehetőséget a kép alapú feliratok (pl. VOBSUB, PGS, SUB/IDX, stb) és bizonyos ASS/SSA feliratok beégetéséhez.", "ButtonAddScheduledTaskTrigger": "Vezérlő Hozzáadása", "ButtonGuide": "Műsorújság", "ButtonRefreshGuideData": "Műsorújság Frissítése", @@ -1359,7 +1356,7 @@ "LabelLocalHttpServerPortNumberHelp": "A TCP port száma, melyen a Jellyfin HTTP szerver figyel.", "UserAgentHelp": "Adj meg egy egyedi HTTP user-agent fejlécet.", "XmlDocumentAttributeListHelp": "Ezek a tulajdonságok minden XML válaszüzenet gyökér elemére alkalmazásra kerülnek.", - "Thumb": "Thumb", + "Thumb": "Miniatűr", "MediaInfoStreamTypeData": "Adat", "MediaInfoStreamTypeEmbeddedImage": "Beágyazott kép", "LabelBitrate": "Bitráta:", @@ -1376,5 +1373,144 @@ "LabelPasswordResetProvider": "Jelszó Visszaállítási Szolgáltató:", "FetchingData": "További adatok lekérése", "LabelBaseUrl": "Alap URL:", - "Depressed": "Nyomott" + "Depressed": "Nyomott", + "Desktop": "Asztal", + "LabelTrackNumber": "Sáv száma:", + "LabelSize": "Méret:", + "LabelSimultaneousConnectionLimit": "Egyidejű streamek maximális száma:", + "LabelServerName": "Szerver neve:", + "LabelPleaseRestart": "A változtatások a weboldal manuális újratöltése után lépnek életbe.", + "LabelPlayMethod": "Lejátszási mód:", + "LabelPlayer": "Lejátszó:", + "LabelPersonRole": "Szerep:", + "LabelNumberOfGuideDays": "Előre letöltött műsorújságbeli napok száma:", + "LabelFolder": "Mappa:", + "HeaderNavigation": "Navigáció", + "HeaderFavoritePeople": "Kedvenc emberek", + "HeaderApp": "Alkalmazás", + "GroupVersions": "Verziók csoportosítása", + "CopyStreamURLError": "Hiba történt az URL másolása közben.", + "OptionSubstring": "Szövegrészlet", + "ButtonSplit": "Szétvág", + "Absolute": "Abszolút", + "LabelSkipIfAudioTrackPresentHelp": "Vedd ki a pipát, ha minden videóhoz szeretnél feliratot az audio nyelvétől függetlenül.", + "EnableFastImageFadeInHelp": "Gyorsabb előtűnés animáció a betöltött képekhez", + "EnableFastImageFadeIn": "Gyors kép-előtűnés", + "SubtitleOffset": "Felirat eltolása", + "SeriesDisplayOrderHelp": "Rakd sorba az epizódokat az adásba kerülésük dátuma, a DVD sorszám, vagy az abszolút számozás szerint.", + "SelectAdminUsername": "Kérjük válassz felhasználónevet az adminisztrátor fiók számára.", + "QueueAllFromHere": "Az összes sorba állítása innen", + "OptionThumbCard": "Miniatűr kártya", + "OptionThumb": "Miniatűr", + "OptionSpecialEpisode": "Különkiadások", + "OptionRandom": "Véletlenszerű", + "OptionPosterCard": "Poszter kártya", + "OptionPoster": "Poszter", + "OptionLoginAttemptsBeforeLockoutHelp": "A 0 érték beállítással az alapértelmezett beállítások lesznek bekapcsolva. A sima felhasználóknak 3, az adminisztrátoroknak 5 lehetőségük lesz. A -1 érték kikapcsolja ezt a funkciót.", + "OptionList": "Lista", + "OptionDownloadThumbImage": "Miniatűr", + "OptionDownloadBannerImage": "Banner", + "OptionDownloadArtImage": "Grafika", + "OptionCustomUsers": "Egyéni", + "OptionBlockChannelContent": "Internetes csatornatartalmak", + "OptionBanner": "Banner", + "OnlyForcedSubtitlesHelp": "Csak a kényszerítettnek jelölt feliratok fognak megjelenni.", + "OnlyForcedSubtitles": "Csak kényszerített", + "Normal": "Normális", + "MusicVideo": "Videoklip", + "MusicLibraryHelp": "Nézd meg a {0}zenék elnevezési útmutatóját{1}.", + "MusicArtist": "Zenei előadó", + "MusicAlbum": "Zenealbum", + "MoreMediaInfo": "Média információ", + "MetadataSettingChangeHelp": "A metaadat beállítások módosítása az ezután újonnan hozzáadott médiát fogja befolyásolni. A már meglévő tartalom frissítéséhez nyisd meg a részletek képernyőt, és kattints a frissítésre, vagy végezz tömeges frissítést a Metaadat Managerben.", + "MessageConfirmDeleteGuideProvider": "Biztosan törölni szeretnéd ezt a műsorújság szolgáltatót?", + "MessageConfirmAppExit": "Ki szeretnél lépni?", + "LaunchWebAppOnStartupHelp": "A web kliens indítása az alapértelmezett böngészőben a szerver indítása után. A kliens nem fog elindulni a szerver újraindítása után.", + "LabelVideoResolution": "Videó felbontás:", + "LabelVideoCodec": "Videó kodek:", + "LabelVideoBitrate": "Videó bitráta:", + "LabelStreamType": "Stream típusa:", + "LabelSkipIfGraphicalSubsPresentHelp": "A feliratok szöveges verziójának megtartása hatékonyabb kézbesítést eredményez és csökkenti az átkódolás valószínűségét.", + "LabelNumberOfGuideDaysHelp": "Több napnyi műsorújság letöltése hosszabb távú időzítést tesz lehetővé, valamint több napra előre tekinthető meg a műsorújság, azonban hosszabb ideig fog tartani a letöltés. Az automatikus lehetőség a csatornák számától függően állítja be az értéket.", + "LabelMonitorUsers": "Tevékenység követése tőle:", + "LabelDroppedFrames": "Eldobott képkockák:", + "LabelDisplaySpecialsWithinSeasons": "Speciális epizódok megjelenítése abban az évadban, amiben adásban voltak", + "LabelCorruptedFrames": "Sérült képkockák:", + "HeaderKeepSeries": "Sorozat megtartása", + "ErrorGettingTvLineups": "Hiba történt a TV kínálat letöltése során. Kérjük ellenőrizd a megadott információkat és próbáld újra.", + "LabelTranscodes": "Átkódolások:", + "AskAdminToCreateLibrary": "Kérj meg egy adminisztrátort könyvtár létrehozására.", + "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaCap": "X-DLNA cap:", + "MapChannels": "Csatornák feltérképezése", + "PasswordResetProviderHelp": "Válassz egy jelszó-visszaállítási szolgáltatót, amelyet akkor kell használni, amikor a felhasználó jelszó-visszaállítást kér", + "OptionResElement": "res elem", + "OptionReportByteRangeSeekingWhenTranscodingHelp": "Erre olyan készülékek esetében van szükség, amelyek időigénye nem nagyon jó.", + "OptionPlainVideoItemsHelp": "Ha engedélyezve van, akkor az összes videót a DIDL-ben \"object.item.videoItem\" -ként ábrázolja, nem pedig egy specifikusabb típusként, például \"object.item.videoItem.movie\" .", + "OptionPlainStorageFoldersHelp": "Ha engedélyezve van, akkor az összes mappa a DIDL-ben \"object.container.storageFolder\" lesz, nem pedig egy specifikusabb típusként, például \"object.container.person.musicArtist\".", + "OptionHlsSegmentedSubtitles": "HLS szegmentált feliratok", + "OptionEquals": "Egyenlő", + "OptionForceRemoteSourceTranscoding": "A távoli médiaforrások (például az élő TV) átkódolásának kényszerítése", + "NoCreatedLibraries": "Úgy tűnik még nem hoztál létre egy könyvtárat sem. {0}Szeretnél létrehozni egyet most?{1}", + "MessageDirectoryPickerBSDInstruction": "A BSD esetében valószínűleg konfigurálni kell a FreeNAS Jailben lévő tárolót, hogy a Jellyfin hozzáférhest kapjon.", + "LabelXDlnaDocHelp": "Meghatározza az X_DLNADOC elem tartalmát az urn: schemas-dlna-org: device-1-0 névtérben.", + "LabelXDlnaCapHelp": "Meghatározza az X_DLNACAP elem tartalmát az urn: schemas-dlna-org: eszköz-1-0 névtérben.", + "LabelVaapiDeviceHelp": "Ez a render csomópont, amelyet a hardveres gyorsításhoz használunk.", + "LabelTriggerType": "Trigger típusa:", + "LabelTranscodingProgress": "Átkódolás folyamatban:", + "LabelTranscodingFramerate": "Átkódolás framerate:", + "LabelTranscodePath": "Átkódolási útvonal:", + "LabelSonyAggregationFlagsHelp": "Meghatározza az aggregationFlags elem tartalmát az urn: schemas-sonycom: av névtérben.", + "LabelPostProcessorArguments": "Utófeldolgozási parancssori paraméterek:", + "LabelPlayerDimensions": "Lejátszó méretei:", + "LabelParentNumber": "Szülő száma:", + "LabelMetadataReadersHelp": "Rangsorold az előnyben részesített metaadat forrásokat. Az a forrás kerül sorsolásra, amelyben először találunk információt.", + "LabelLineup": "Felhozatal:", + "LabelBaseUrlHelp": "Ide hozzáadhatsz egy egyéni alkönyvtárat, hogy a szerverhez egyedibb URL-címről férj hozzá.", + "ErrorPleaseSelectLineup": "Kérjük, válassz ki egy felhozatalt, és próbáld újra. Ha nem állnak rendelkezésre felsorolások, akkor ellenőrizd, hogy helyes-e felhasználóneved, jelszavad és irányítószámod.", + "ErrorAddingListingsToSchedulesDirect": "Hiba történt a felhozatal hozzáadása közben a Schedules Direct fiókhoz. A Schedules Direct csak korlátozott számú fiók hozzáadását támogatja. Lehetséges, hogy be kell jelentkezned a Schedules Direct weboldalán és eltávolítani néhány más listát a fiókodról mielőtt továbblépsz.", + "DeviceAccessHelp": "Ez csak azokra az eszközökre alkalmazható, amelyek egyedileg vannak azonosítva és nem gátolják meg a böngészőből való elérést. A felhasználói eszközök kiszűrése meg fogja akadályozni az új eszközök használatát addig, amíg itt nem engedélyezed őket.", + "PlaybackErrorNoCompatibleStream": "Ez a kliens nem kompatibilis ezzel a médiával és a szerver nem tud kompatibilis streamet küldeni az eszközre.", + "AllowFfmpegThrottlingHelp": "Ha az átkódolás vagy remux eléggé előtöltődött a jelenlegi lejátszási pozícióhoz képest, ez megállítja a folyamatot, hogy kevesebb erőforrást vegyen igénybe. Ez akkor hasznos, ha ritkán ugrálsz előre a lejátszott videókban. Kapcsold ki, ha lejátszási problémákba ütközöl.", + "AllowFfmpegThrottling": "Átkódolás visszafogása", + "PreferEmbeddedEpisodeInfosOverFileNames": "Az epizódból elérhető beágyazott információkat használja inkább, fájlnevek helyett", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Ez az epizóddal kapcsolatos beágyazott metaadatokat használja, ha azok elérhetőek.", + "OnApplicationStartup": "Az alkalmazás indításakor", + "EveryXHours": "{0} óránként", + "EveryHour": "Óránként", + "EveryXMinutes": "{0} percenként", + "OnWakeFromSleep": "Alvó módból visszatéréskor", + "WeeklyAt": "Minden {0} ekkor: {1}", + "DailyAt": "Naponta ekkor: {0}", + "LastSeen": "Utoljára elérhető {0}", + "PersonRole": "mint {0}", + "ListPaging": "{0}-{1} / {2}", + "WriteAccessRequired": "A Jellyfin Szerver írási jogosultságot igényel ehhez a könyvtárhoz. Kérjük, ellenőrizd, hogy van-e jogod írni ide, majd próbáld újra.", + "PathNotFound": "Az elérési út nem található. Kérjük, ellenőrizd, hogy az elérési út megfelelő-e, majd próbáld újra.", + "Track": "Szám", + "Season": "Évad", + "Person": "Személy", + "OtherArtist": "Más előadók", + "Movie": "Film", + "Episode": "Epizód", + "ClientSettings": "Kliens beállítások", + "BoxSet": "Dobozos kiadások", + "Artist": "Előadó", + "AlbumArtist": "Album előadó", + "Album": "Album", + "LabelLibraryPageSizeHelp": "Az oldalnként megmutatott elemek száma. Nullára állítva a lapozási funkció ki lesz kapcsolva.", + "LabelLibraryPageSize": "Könyvtár oldalméret:", + "LabelDeinterlaceMethod": "Deinterlacing mód:", + "DeinterlaceMethodHelp": "Válassza ki a váltottsorosság megszűntetéséhez használandó módszert a váltottsoros tartalmak transzkódolásakor.", + "UnsupportedPlayback": "Jellyfin nem tud DRM-titkosított tartalmak dekriptálására, ettől függetlenül a lejátszással mindig megpróbálkozik. Néhány fájl emiatt teljesen fekete képernyőt ad, amely vagy a titkosítás miatt van, vagy nem olyan nem támogatott tartalmak miatt, mint az interaktív címek.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "ReleaseGroup": "Kiadócsoport", + "MessageUnauthorizedUser": "Jelenleg nincs jogosultságod a szerverhez való hozzáféréshez. Kérjük, lépj kapcsolatba az adminisztrátorral további információkért!", + "ButtonTogglePlaylist": "Lejátszási listák", + "ButtonToggleContextMenu": "Továbbiak", + "Filter": "Szűrés", + "New": "Új", + "HeaderFavoritePlaylists": "Kedvenc lejátszási listák", + "ApiKeysCaption": "A jelenleg engedélyezett API kulcsok listája" } diff --git a/src/strings/id.json b/src/strings/id.json index f8b8b676f3..8085767984 100644 --- a/src/strings/id.json +++ b/src/strings/id.json @@ -47,5 +47,162 @@ "HeaderAlbumArtists": "Album Artis", "HeaderContinueWatching": "Masih Melihat", "Artists": "Artis", - "HeaderLiveTV": "TV Live" + "HeaderLiveTV": "TV Live", + "AllowMediaConversion": "Izinkan konversi media", + "AllEpisodes": "Semua episode", + "AllChannels": "Semua saluran", + "All": "Semua", + "Add": "Tambah", + "Actor": "Aktor", + "Delete": "Hapus", + "DefaultMetadataLangaugeDescription": "Berikut ini adalah standar Anda dan dapat dikustomisasi pada tiap pustakanya.", + "DefaultErrorMessage": "Terdapat galat dalam memproses permintaan. Silakan coba kembali nanti.", + "Default": "Standar", + "DeathDateValue": "Meninggal: {0}", + "DatePlayed": "Tanggal dimainkan", + "DateAdded": "Tanggal ditambahkan", + "CriticRating": "Kritik peringkat", + "CopyStreamURLError": "Terdapat galat dalam penyalinan pranala.", + "CopyStreamURLSuccess": "Pranala berhasil disalin.", + "CopyStreamURL": "Salin Pranala Stream", + "Continuing": "Melanjutkan", + "ContinueWatching": "Lanjutkan menonton", + "Connect": "Sambung", + "ConfirmEndPlayerSession": "Apakah Anda ingin mematikan Jellyfin pada {0}?", + "ConfirmDeletion": "Konfirmasi Penghapusan", + "ConfirmDeleteItems": "Penghapusan item-item ini akan menghapus baik pada sistem berkas maupun pustaka media Anda. Apakah Anda yakin untuk melanjutkan?", + "ConfirmDeleteItem": "Penghapusan item ini akan menghapus baik pada sistem berkas maupun pustaka media Anda. Apakah Anda yakin untuk melanjutkan?", + "ConfirmDeleteImage": "Hapus gambar?", + "ConfigureDateAdded": "Atur cara penentuan penambahan tanggal dalam dasbor Peladen Jellyfin lewat pengaturan Pustaka", + "Composer": "Komposer", + "CommunityRating": "Peringkat komunitas", + "ChannelNumber": "Nomor saluran", + "ChannelNameOnly": "Hanya saluran {0}", + "ChannelAccessHelp": "Pilih saluran untuk dibagikan ke pengguna ini. Admin akan dapat mengubah seluruh saluran menggunakan pengelola metadata.", + "Categories": "Kategori", + "CancelRecording": "Batalkan perekaman", + "ButtonWebsite": "Situs web", + "ButtonViewWebsite": "Tampilkan situs web", + "ButtonUp": "Atas", + "ButtonTrailer": "Cuplikan", + "ButtonSubmit": "Kirim", + "ButtonStop": "Berhenti", + "ButtonStart": "Mulai", + "ButtonSort": "Urutkan", + "ButtonSignIn": "Masuk", + "ButtonShutdown": "Matikan", + "ButtonShuffle": "Acak", + "ButtonSettings": "Pengaturan", + "ButtonSend": "Kirim", + "ButtonSelectView": "Pilih tampilan", + "ButtonSelectServer": "Pilih Peladen", + "ButtonSelectDirectory": "Pilih Direktori", + "ButtonSearch": "Cari", + "ButtonScanAllLibraries": "Pindai Semua Pustaka", + "ButtonSave": "Simpan", + "ButtonResume": "Lanjutkan", + "ButtonResetPassword": "Atur ulang Kata sandi", + "ButtonResetEasyPassword": "Atur ulang kode pin mudah", + "ButtonRepeat": "Ulangi", + "ButtonRename": "Ubah nama", + "ButtonRemove": "Hapus", + "ButtonRefreshGuideData": "Muat ulang Data Panduan", + "ButtonRefresh": "Muat ulang", + "ButtonProfile": "Profil", + "ButtonPlay": "Mainkan", + "ButtonPause": "Jeda", + "ButtonParentalControl": "Kendali orang tua", + "ButtonOpen": "Buka", + "ButtonOk": "Baik", + "ButtonOff": "Matikan", + "ButtonNew": "Baru", + "ButtonNetwork": "Jaringan", + "ButtonMore": "Lebih banyak", + "ButtonLibraryAccess": "Akses pustaka", + "ButtonLearnMore": "Pelajari lebih lanjut", + "ButtonInfo": "Info", + "ButtonHome": "Beranda", + "ButtonHelp": "Bantuan", + "ButtonGuide": "Panduan", + "ButtonGotIt": "Paham", + "ButtonFullscreen": "Layar penuh", + "ButtonForgotPassword": "Lupa Kata Sandi", + "ButtonFilter": "Penyaring", + "ButtonEditOtherUserPreferences": "Ubah profil, gambar, dan preferensi pribadi pengguna ini.", + "ButtonEditImages": "Ubah gambar", + "ButtonEdit": "Ubah", + "ButtonDownload": "Unduh", + "ButtonDown": "Bawah", + "ButtonDeleteImage": "Hapus Gambar", + "ButtonDelete": "Hapus", + "ButtonConnect": "Sambung", + "ButtonChangeServer": "Ubah Peladen", + "ButtonCancel": "Batalkan", + "ButtonBack": "Kembali", + "ButtonAudioTracks": "Trek Audio", + "ButtonArrowUp": "Atas", + "ButtonArrowRight": "Kanan", + "ButtonArrowLeft": "Kiri", + "ButtonArrowDown": "Turun", + "ButtonAddUser": "Tambah Pengguna", + "ButtonAddServer": "Tambah Peladen", + "ButtonAddScheduledTaskTrigger": "Tambah Pemicu", + "ButtonAddMediaLibrary": "Tambah Pustaka Media", + "ButtonAddImage": "Tamba gambar", + "ButtonAdd": "Tambah", + "BrowsePluginCatalogMessage": "Jelajahi katalog plugin kamu untuk melihat plugin yang tersedia.", + "Browse": "Jelajah", + "BoxRear": "Kotak (belakang)", + "Box": "Kotak", + "BookLibraryHelp": "Buku audio dan teks didukung. Perhatikan {0}panduan penamaan buku{1}.", + "Blacklist": "Daftar hitam", + "BirthPlaceValue": "Tempat lahir: {0}", + "BirthLocation": "Tempat lahir", + "BirthDateValue": "Lahir: {0}", + "Banner": "Spanduk", + "Backdrops": "Latar belakang", + "Backdrop": "Latar belakang", + "AutoBasedOnLanguageSetting": "Auto (berdasarkan pengaturan bahasa)", + "Auto": "Auto", + "AuthProviderHelp": "Pilih Penyedia Autentikasi yang akan digunakan untuk mengautentikasi kata sandi pengguna ini.", + "Audio": "Audio", + "AttributeNew": "Baru", + "AspectRatio": "Rasio perbandingan", + "Ascending": "Urutan naik", + "AsManyAsPossible": "Sebanyak mungkin", + "Art": "Seni", + "AroundTime": "Sekitar {0}", + "Anytime": "Kapanpun", + "AnyLanguage": "Bahasa apapun", + "AlwaysPlaySubtitlesHelp": "Talop yang cocok dengan preferensi bahasa akan dimuat tanpa memperhatikan bahasa suaranya.", + "AlwaysPlaySubtitles": "Selalu putar talop", + "AllowedRemoteAddressesHelp": "Daftar yang dipisahkan dengan koma dari alamat IP atau catatan netmask untuk jaringan yang akan diperbolehkan untuk tersambuh dari jarak jauh. Jika dibiarkan kosong, seluruh alamat jarak jauh akan diperbolehkan.", + "AllowRemoteAccessHelp": "Jika centang dihapus, semua koneksi jarak jauh akan diblokir.", + "AllowRemoteAccess": "Izinkan koneksi jarak jauh ke Peladen Jellyfin ini.", + "AllowOnTheFlySubtitleExtraction": "Izinkan ekstraksi talop dengan cepat", + "AllowMediaConversionHelp": "Izinkan atau tolak akses ke fitur konversi media.", + "AllLibraries": "Semua pustaka", + "AllLanguages": "Semua bahasa", + "AllComplexFormats": "Semua format kompleks (ASS, SSA, VOBSUB, PGS, SUB/IDK, dll.)", + "Channels": "Saluran", + "Aired": "Disiarkan", + "AirDate": "Tanggal siaran", + "AdditionalNotificationServices": "Jelajahi katalog plugin untuk memasang layanan pemberitahuan tambahan.", + "AddToPlaylist": "Tambah ke dalam daftar putar", + "AddToPlayQueue": "Tambah ke dalam antrean putar", + "AddToCollection": "Tambah ke dalam koleksi", + "AddItemToCollectionHelp": "Tambahkan item ke dalam koleksi melalui pencarian dan gunakan klik kanan atau ketuk menu untuk menambahkannya ke dalam koleksi.", + "AccessRestrictedTryAgainLater": "Akses sedang dibatasi. Silakan coba kembali nanti.", + "Absolute": "Mutlak", + "Songs": "Lagu", + "Playlists": "Daftar putar", + "ValueSpecialEpisodeName": "Spesial - {0}", + "Sync": "Sinkron", + "Shows": "Tayangan", + "Photos": "Foto", + "Movies": "Film", + "Alerts": "Peringatan", + "AddedOnValue": "Ditambahkan {0}", + "AllowFfmpegThrottling": "Transcode Tercekik", + "AllowOnTheFlySubtitleExtractionHelp": "Subtitle yang melekat di video dapat dikeluarkan dan dikirimkan kepada klien dalam bentuk text biasa dengan tujuan untuk menghalau terjadinya transcoding pada video. Pada beberapa system ini membutuhkan waktu yang lama dan dapat menyebabkan video playback menjadi terhenti dikarenakan proses ekstraksi. Non-aktifkan fitur ini untuk membiarkan subtitle langsung dilekatkan kepada video dengan cara transcoding ketika klien tidak mendukung fitur ini." } diff --git a/src/strings/is-is.json b/src/strings/is-is.json index 36eba8ff7a..70fc891193 100644 --- a/src/strings/is-is.json +++ b/src/strings/is-is.json @@ -232,24 +232,66 @@ "ButtonResetPassword": "Endurstilla lykilorð", "ButtonOpen": "Opna", "Songs": "Lög", - "ButtonProfile": "", - "ButtonPreviousTrack": "", - "ButtonPause": "", - "ButtonRemove": "", - "ButtonResume": "", - "ButtonQuickStartGuide": "", - "ConfirmDeleteImage": "", - "ButtonRename": "", + "ButtonProfile": "Prófíll", + "ButtonPreviousTrack": "Fyrra lag", + "ButtonPause": "Pása", + "ButtonRemove": "Fjarlægja", + "ButtonResume": "Halda áfram", + "ButtonQuickStartGuide": "Byrjunar leiðarvísir", + "ConfirmDeleteImage": "Eyða mynd?", + "ButtonRename": "Endurnefna", "Sync": "Samstilla", "Never": "", "News": "", - "ButtonRevoke": "", - "ButtonRepeat": "", + "ButtonRevoke": "Afturkalla", + "ButtonRepeat": "Endurtaka", "MusicArtist": "", "MusicAlbum": "", "No": "", - "Monday": "", + "Monday": "Mánudagur", "Name": "", "Mute": "", - "MusicVideo": "" + "MusicVideo": "", + "ButtonRefresh": "Endurhlaða", + "ButtonParentalControl": "Foreldraeftirlit", + "ButtonOff": "Af", + "ButtonNextTrack": "Næsta lag", + "ButtonNetwork": "Net", + "ButtonMore": "Meira", + "ButtonManualLogin": "Handvirkt Auðkenni", + "ButtonLibraryAccess": "Aðgangur að safni", + "ButtonLearnMore": "Læra meira", + "ButtonInfo": "Upplýsingar", + "ButtonHome": "Heim", + "ButtonHelp": "Hjálp", + "ButtonGuide": "Sjónvarpsvísir", + "ButtonGotIt": "Skilið", + "ButtonFullscreen": "Fylla upp í skjá", + "ButtonForgotPassword": "Gleymt Lykilorð", + "ButtonFilter": "Sía", + "ButtonEditOtherUserPreferences": "Breyta stillingum notanda, mynd og persónulegum stillingum.", + "ButtonEditImages": "Breyta myndum", + "ButtonEdit": "Breyta", + "ButtonDownload": "Sækja", + "ButtonDown": "Niður", + "ButtonDeleteImage": "Eyða Mynd", + "ButtonDelete": "Eyða", + "ButtonConnect": "Tengjast", + "ButtonChangeServer": "Skipta um þjón", + "ButtonBack": "Til baka", + "ButtonAudioTracks": "Hljóðspor", + "BookLibraryHelp": "Hljóð og texta bækur eru stuttar. Lesið {0}book naming guide{1}.", + "Backdrops": "Bakgrunnar", + "Backdrop": "Bakgrunnur", + "AuthProviderHelp": "Veljið vottunaraðila til þess að sannvotta lykilorð notanta.", + "AskAdminToCreateLibrary": "Biðjið stjórnanda að gera nýtt gagnasafn.", + "MoreFromValue": "Meira frá {0}", + "AlwaysPlaySubtitlesHelp": "Allir textar sem samsvara við túngumáli valið verða alltaf hlaðnir óháð hljóðmáls túngumáli.", + "AllowedRemoteAddressesHelp": "Kommu aðskilinn listi yfir ip tölur eða ip-númeramát fyrir net sem mega fjartengjas. Ef þetta er autt eru allar fjartengingar leyfðar.", + "AllowHWTranscodingHelp": "Leyfa viðtæki að umbreyta straumi í rauntíma.Þetta getur minnkað álag á þjón.", + "ValueSpecialEpisodeName": "Sérstakt - {0}", + "Shows": "Þættir", + "Playlists": "Spilunarlisti", + "ButtonScanAllLibraries": "Skanna Öll Gagnasöfn", + "AllLibraries": "Öll gagnasöfn" } diff --git a/src/strings/it.json b/src/strings/it.json index 5f81717e8a..f24282786e 100644 --- a/src/strings/it.json +++ b/src/strings/it.json @@ -3,28 +3,28 @@ "AccessRestrictedTryAgainLater": "L'accesso è attualmente limitato. Si prega di riprovare più tardi.", "Actor": "Attore", "Add": "Aggiungi", - "AddItemToCollectionHelp": "Aggiungi elementi alle collezioni ricercandoli e utilizzando il pulsante destro del mouse o toccare i menu per aggiungerli a una raccolta.", + "AddItemToCollectionHelp": "Aggiungi elementi alle collezioni ricercandoli e utilizzando il pulsante destro del mouse o tocca i menu per aggiungerli a una raccolta.", "AddToCollection": "Aggiunto alla collezione", "AddToPlayQueue": "Aggiungi alla coda di riproduzione", "AddToPlaylist": "Aggiungi alla playlist", "AddedOnValue": "Aggiunto {0}", "AdditionalNotificationServices": "Sfoglia il catalogo plugin per installare i servizi di notifica aggiuntivi.", - "AirDate": "Data messa in Onda", + "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.)", + "AllComplexFormats": "Tutti i formati complessi (ASS, SSA, VOBSUB, PGS, SUB, IDX, ...)", "AllEpisodes": "Tutti gli episodi", "AllLanguages": "Tutte le lingue", "AllLibraries": "Tutte le librerie", "AllowHWTranscodingHelp": "Abilita il sintonizzatore per codificare i flussi al volo. Ciò potrebbe contribuire a ridurre la transcodifica richiesta dal server.", "AllowOnTheFlySubtitleExtraction": "Consenti l'estrazione sottotitoli al volo", - "AllowOnTheFlySubtitleExtractionHelp": "I sottotitoli incorporati possono essere estratti dai video e consegnati ad applicazioni in testo semplice per evitare la transcodifica dei video. In alcuni sistemi questo può richiedere molto tempo e causare un rallentamento della riproduzione video durante il processo di estrazione. Disattivare questa opzione per avere i sottotitoli incorporati con la transcodifica video quando non sono supportati nativamente dal dispositivo client.", + "AllowOnTheFlySubtitleExtractionHelp": "I sottotitoli incorporati possono essere estratti dai video e consegnati ai client in testo semplice per evitare la transcodifica dei video. In alcuni sistemi questo può richiedere molto tempo e causare un rallentamento della riproduzione video durante il processo di estrazione. Disattivare questa opzione per avere i sottotitoli incorporati con la transcodifica video quando non sono supportati nativamente dal dispositivo client.", "AllowRemoteAccess": "Abilita connessioni remote a questo Server Jellyfin.", "AllowRemoteAccessHelp": "Se deselezionato, tutte le connessioni remote saranno bloccate.", "AllowedRemoteAddressesHelp": "Elenco separato da virgola di indirizzi IP o voci IP / maschera di rete per reti che potranno connettersi da remoto. Se lasciato vuoto, saranno consentiti tutti gli indirizzi remoti.", - "AlwaysPlaySubtitles": "Visualizza sempre i sottotitoli", + "AlwaysPlaySubtitles": "Riproduci sempre", "AlwaysPlaySubtitlesHelp": "I sottotitoli corrispondenti alla lingua preferita saranno caricati a prescindere dalla lingua dell'audio.", "AnyLanguage": "Qualsiasi lingua", "Anytime": "In qualsiasi momento", @@ -32,7 +32,7 @@ "Artists": "Artisti", "AsManyAsPossible": "Tutto il possibile", "Ascending": "Crescente", - "AspectRatio": "Rapporto d'aspetto", + "AspectRatio": "Rapporto d'Aspetto", "AttributeNew": "Nuovo", "AutoBasedOnLanguageSetting": "Auto (basato sull'impostazione della lingua)", "Backdrop": "Sfondo", @@ -40,12 +40,12 @@ "BirthDateValue": "Nato il: {0}", "BirthLocation": "Luogo di nascita", "BirthPlaceValue": "nato a: {0}", - "BookLibraryHelp": "Libri e audiolibri sono supportati. Rivedere {0}la guida ai nomi dei libri di Jellyfin{1}", + "BookLibraryHelp": "Libri e audiolibri sono supportati. Rivedere {0}la guida ai nomi dei libri di Jellyfin{1}.", "Books": "Libri", "BoxRear": "Box (retro)", "Browse": "Esplora", "BrowsePluginCatalogMessage": "Sfoglia il catalogo dei Plugins.", - "BurnSubtitlesHelp": "Determina se il server deve applicare i sottotitoli quando si convertono 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 (VOBSUB, PGS, SUB / IDX, ecc.) e alcuni sottotitoli ASS / SSA.", + "BurnSubtitlesHelp": "Determina se il server deve imprimere i sottotitoli quando i video vengono convertiti. Evitare ciò migliorerà di molto le prestazioni. Selezionare Auto per imprimere formati basati sull'immagine (VOBSUB, PGS, SUB, IDX, ...) e alcuni sottotitoli ASS o SSA.", "ButtonAdd": "Aggiungi", "ButtonAddMediaLibrary": "Aggiungi raccolta multimediale", "ButtonAddScheduledTaskTrigger": "Aggiungi operazione", @@ -93,7 +93,7 @@ "ButtonRename": "Rinomina", "ButtonRepeat": "Ripeti", "ButtonResetEasyPassword": "Resetta codice PIN", - "ButtonResetPassword": "Ripristina Password", + "ButtonResetPassword": "Reset Password", "ButtonRestart": "Riavvia", "ButtonResume": "Riprendi", "ButtonRevoke": "Revocare", @@ -123,14 +123,14 @@ "ChannelAccessHelp": "Seleziona i canali da condividere con questo utente. Gli amministratori saranno in grado di modificare tutti i canali usando il gestore dei metadati.", "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", + "CinemaModeConfigurationHelp": "La modalità Cinema porta l'esperienza del teatro direttamente nel tuo salotto con la possibilità di vedere trailer e intro personalizzati prima della visione.", "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.", + "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?", @@ -140,7 +140,7 @@ "ContinueWatching": "Continua a guardare", "Continuing": "In corso", "CriticRating": "Voto della critica", - "CustomDlnaProfilesHelp": "Crea un profilo personalizzato per un nuovo dispositivo o sovrascrivi quello di sistema", + "CustomDlnaProfilesHelp": "Crea un profilo personalizzato per un nuovo dispositivo o sovrascrivi quello di sistema.", "DateAdded": "Aggiunto il", "DatePlayed": "Visto il", "DeathDateValue": "Morto: {0}", @@ -162,11 +162,10 @@ "DeviceAccessHelp": "Si applica solo ai dispositivi che possono essere identificati univocamente e non impedirà l'accesso dal browser. Filtrare l'accesso ai dispositivi dell'utente impedirà di usare nuovi dispositivi fino a quando non saranno stati approvati qui.", "DirectPlaying": "Riproduzione Diretta", "DirectStreamHelp1": "Il file multimediale è compatibile con il dispositivo per quanto riguarda la risoluzione e il tipo di supporto (H. 264, AC3, ecc), ma è in un contenitore file incompatibile (mkv, avi, wmv, ecc). 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", + "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}", + "Directors": "Registi", "Disabled": "Disabilitato", "Disc": "Disco", "Disconnect": "Disconnetti", @@ -176,7 +175,7 @@ "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.", - "DisplayModeHelp": "Scegli il tipo di schermo su cui stai utilizzando Jellyfin.", + "DisplayModeHelp": "Seleziona lo stile del layout che vuoi per l'interfaccia.", "DoNotRecord": "Non registrare", "Down": "Giù", "Download": "Scarica", @@ -200,10 +199,10 @@ "EnablePhotos": "Mostra foto", "EnablePhotosHelp": "Le immagini saranno rilevate e visualizzate accanto ad altri file multimediali.", "EnableStreamLooping": "Auto-loop streaming in diretta", - "EnableStreamLoopingHelp": "Abilita questo se gli streaming in diretta contengono solo pochi secondi di dati e devono essere costantemente richiesti. L'abilitazione di questa funzione quando non è servita può causare problemi", + "EnableStreamLoopingHelp": "Abilita questo se gli streaming in diretta contengono solo pochi secondi di dati e devono essere costantemente richiesti. L'abilitazione di questa funzione quando non è servita può causare problemi.", "EnableThemeSongs": "Canzoni a tema", "EnableThemeSongsHelp": "Le canzoni a tema saranno riprodotte mentre visualizzi la tua libreria.", - "EnableThemeVideos": "VIdeo a tema", + "EnableThemeVideos": "Video a tema", "EnableThemeVideosHelp": "Riproduzione dei video a tema sullo sfondo mentre visualizzi la tua libreria.", "Ended": "Finito", "EndsAtValue": "Finirà alle {0}", @@ -240,9 +239,8 @@ "FormatValue": "Formato: {0}", "Friday": "Venerdì", "Fullscreen": "Schermo Intero", - "GenreValue": "Genere: {0}", + "Genre": "Genere", "Genres": "Generi", - "GenresValue": "Generi: {0}", "GroupBySeries": "Raggruppa per serie", "GroupVersions": "Raggruppa versioni", "GuestStar": "Personaggio famoso", @@ -250,10 +248,10 @@ "GuideProviderLogin": "Accedi", "GuideProviderSelectListings": "selezionare Annunci", "H264CrfHelp": "Il fattore di frequenza costante (CRF) è l'impostazione di qualità predefinita per l'encoder x264. È possibile impostare i valori compresi tra 0 e 51, in cui valori inferiori potrebbero determinare una migliore qualità (a discapito delle dimensioni superiori dei file). I valori normali sono compresi tra 18 e 28. L'impostazione predefinita per x264 è 23, quindi è possibile utilizzare questo come punto di partenza.", - "H264EncodingPresetHelp": "Scegli una velocità maggiore per migliorare le performance, o minore per incrementare la qualità.", + "EncoderPresetHelp": "Scegli una velocità maggiore per migliorare le performance, o minore per incrementare la qualità.", "HDPrograms": "Programmi HD", "HandledByProxy": "Gestito dal reverse proxy", - "HardwareAccelerationWarning": "L'attivazione dell'accelerazione hardware potrebbe causare instabilità in qualche sistema. Assicurarsi che il sistema operativo e i driver video siano completamente aggiornati. Se hai difficoltà a riprodurre video dopo aver abilitato questa operazione, dovrai cambiare l'impostazione in Auto.", + "HardwareAccelerationWarning": "L'attivazione dell'accelerazione hardware potrebbe causare instabilità in qualche sistema. Assicurarsi che il sistema operativo e i driver video siano completamente aggiornati. Se hai difficoltà a riprodurre video dopo aver abilitato questa operazione, dovrai cambiare l'impostazione in None.", "HeaderAccessSchedule": "Orario di accesso", "HeaderAccessScheduleHelp": "Creare un programma di accesso per limitare l'accesso a determinate ore.", "HeaderActiveDevices": "Dispositivi Connessi", @@ -265,8 +263,8 @@ "HeaderAddUpdateImage": "Aggiungi/aggiorna Immagine", "HeaderAddUser": "Aggiungi utente", "HeaderAdditionalParts": "Parti addizionali", - "HeaderAdmin": "Ammin.", - "HeaderAlbumArtists": "Artisti dell' Album", + "HeaderAdmin": "Admin", + "HeaderAlbumArtists": "Artisti degli Album", "HeaderAlbums": "Album", "HeaderAlert": "Avviso", "HeaderAllowMediaDeletionFrom": "Abilita Eliminazione Media Da", @@ -276,7 +274,7 @@ "HeaderAudioBooks": "Audiolibri", "HeaderAudioSettings": "Impostazioni audio", "HeaderAutomaticUpdates": "Aggiornamenti Automatici", - "HeaderBlockItemsWithNoRating": "Blocca elementi sconosciuti o senza informazione", + "HeaderBlockItemsWithNoRating": "Blocca elementi sconosciuti o senza informazioni:", "HeaderBooks": "Libri", "HeaderBranding": "Personalizza", "HeaderCancelRecording": "Annulla la Registrazione", @@ -408,16 +406,16 @@ "HeaderSelectPath": "Seleziona Percorso", "HeaderSelectServer": "Scegli Server", "HeaderSelectServerCachePath": "Seleziona percorso Cache Server", - "HeaderSelectServerCachePathHelp": "Sfoglia o immetti il percorso da utilizzare per i file di cache server. La cartella deve essere scrivibile", + "HeaderSelectServerCachePathHelp": "Sfoglia o immetti il percorso da utilizzare per i file di cache server. La cartella deve essere scrivibile.", "HeaderSelectTranscodingPath": "Selezionare Percorso Temporaneo Transcodifica", "HeaderSelectTranscodingPathHelp": "Sfoglia o immettere il percorso da utilizzare per la transcodifica dei file temporanei. La cartella deve essere scrivibile.", "HeaderSendMessage": "Invia un messaggio", - "HeaderSeries": "Serie:", + "HeaderSeries": "Serie", "HeaderSeriesOptions": "Impostazioni Serie TV", "HeaderSeriesStatus": "Stato Serie TV", "HeaderServerSettings": "Impostazioni server", "HeaderSettings": "Impostazioni", - "HeaderSetupLibrary": "Imposta le tue librerie multimediali.", + "HeaderSetupLibrary": "Imposta le tue librerie multimediali", "HeaderShutdown": "Spegni", "HeaderSortBy": "Ordina per", "HeaderSortOrder": "Ordinamento", @@ -463,7 +461,7 @@ "Images": "Immagini", "ImportFavoriteChannelsHelp": "Se abilitata, solo i canali che sono contrassegnati come preferiti sul dispositivo di sintonizzazione verranno importati.", "ImportMissingEpisodesHelp": "Se abilitato, le informazioni relative agli episodi mancanti saranno importate nel database di Jellyfin e mostrate all'interno di Serie e Stagioni. Questo può causare scansioni della libreria più lente.", - "InstallingPackage": "Installazione di {0}", + "InstallingPackage": "Installazione di {0} (versione {1})", "InstantMix": "Mix istantaneo", "ItemCount": "{0} elementi", "Items": "Elementi", @@ -480,9 +478,9 @@ "LabelAirsBeforeSeason": "In onda prima della stagione:", "LabelAlbumArtHelp": "PN utilizzato per le copertine degli album, all'interno dell'attributo dlna:profileID su upnp:albumArtURI. Alcuni dispositivi richiedono un valore specifico, indipendentemente dalla dimensione dell'immagine.", "LabelAlbumArtMaxHeight": "Altezza massima copertina Album:", - "LabelAlbumArtMaxHeightHelp": "Risoluzione massima copertina Album inviata tramite upnp:albumArtURI", + "LabelAlbumArtMaxHeightHelp": "Risoluzione massima copertina Album inviata tramite upnp:albumArtURI.", "LabelAlbumArtMaxWidth": "Larghezza massima copertina Album:", - "LabelAlbumArtMaxWidthHelp": "Risoluzione massima copertina Album inviata tramite upnp:albumArtURI", + "LabelAlbumArtMaxWidthHelp": "Risoluzione massima copertina album inviata tramite upnp:albumArtURI.", "LabelAlbumArtPN": "Copertine Album PN:", "LabelAlbumArtists": "Artisti album:", "LabelAll": "Tutti", @@ -509,7 +507,7 @@ "LabelCachePathHelp": "Specificare un percorso personalizzato per i file della cache del server, ad esempio le immagini. Lasciare vuoto per usare il predefinito del server.", "LabelCancelled": "Annullato", "LabelCertificatePassword": "Password Certificato:", - "LabelCertificatePasswordHelp": "Se il tuo certificato richiede una password, per favore inseriscila qui", + "LabelCertificatePasswordHelp": "Se il tuo certificato richiede una password, per favore inseriscila qui.", "LabelChannels": "Canali:", "LabelCollection": "Collezione:", "LabelCommunityRating": "Voto del pubblico:", @@ -549,15 +547,15 @@ "LabelDownloadLanguages": "Scarica lingue:", "LabelDropImageHere": "Rilasciare l'immagine qui, oppure clicca per sfogliare.", "LabelDropShadow": "Ombreggiatura:", - "LabelEasyPinCode": "Codice Pin", + "LabelEasyPinCode": "Codice Pin:", "LabelEmbedAlbumArtDidl": "Inserisci le copertine degli Album in Didl", "LabelEmbedAlbumArtDidlHelp": "Alcuni dispositivi preferiscono questo metodo per ottenere le copertine degli album. Altri possono non riuscire a riprodurli con questa opzione abilitata.", "LabelEnableAutomaticPortMap": "Abilita mappatura automatica delle porte", - "LabelEnableAutomaticPortMapHelp": "Tenta di mappare automaticamente la porta pubblica sulla porta locale tramite UPnP. Questo potrebbe non funzionare con alcuni modelli di router.", + "LabelEnableAutomaticPortMapHelp": "Tenta di mappare automaticamente la porta pubblica sulla porta locale tramite UPnP. Questo potrebbe non funzionare con alcuni modelli di router. I cambiamenti non saranno applicati fino ad un riavvio del server.", "LabelEnableBlastAliveMessages": "Invia segnale di presenza", "LabelEnableBlastAliveMessagesHelp": "Attivare questa opzione se il server non viene rilevato in modo affidabile da altri dispositivi UPnP in rete.", "LabelEnableDlnaClientDiscoveryInterval": "Intervallo di ricerca dispositivi (secondi)", - "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina la durata in secondi tra le ricerche SSDP effettuate da Jellyfin", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determina la durata in secondi tra le ricerche SSDP effettuate da Jellyfin.", "LabelEnableDlnaDebugLogging": "Abilita il debug del DLNA", "LabelEnableDlnaDebugLoggingHelp": "Crea file di grandi dimensioni e dovrà essere usato solo quando necessario per risolvere problemi.", "LabelEnableDlnaPlayTo": "Abilita DLNA su", @@ -574,57 +572,57 @@ "LabelEvent": "Evento:", "LabelEveryXMinutes": "Tutti:", "LabelExtractChaptersDuringLibraryScan": "Estrarre immagini capitolo durante la scansione della libreria", - "LabelExtractChaptersDuringLibraryScanHelp": "Se abilitata, le immagini capitolo verranno estratti quando i video vengono importati durante la scansione della libreria. Se disabilitata verranno estratti durante l'operazione pianificata di estrazione delle immagini capitolo, permettendo la scansione della libreria più velocemente.", + "LabelExtractChaptersDuringLibraryScanHelp": "Genera le immagini capitolo quando i video vengono importati durante la scansione della libreria. Alternativamente, verranno estratti durante l'operazione pianificata di estrazione delle immagini capitolo, permettendo la scansione della libreria più velocemente.", "LabelFailed": "Fallito", "LabelFileOrUrl": "File o URL:", "LabelFinish": "Finito", "LabelForgotPasswordUsernameHelp": "Inserisci il tuo nome utente, se te lo ricordi.", "LabelFormat": "Formato:", "LabelFriendlyName": "Nome Condiviso:", - "LabelServerNameHelp": "Questo nome è usato per identificare il server sulla rete.Se lasciato vuoto verra usato il nome del pc", + "LabelServerNameHelp": "Questo nome è usato per identificare il server e avrà come default il nome del pc.", "LabelGroupMoviesIntoCollections": "Raggruppa i film nelle collezioni", "LabelGroupMoviesIntoCollectionsHelp": "Quando si visualizzano le liste di film, quelli appartenenti ad una collezione saranno visualizzati come un elemento raggruppato.", "LabelH264Crf": "CRF di codifica H264:", - "LabelH264EncodingPreset": "Preset di codifica H264:", + "LabelEncoderPreset": "Preset di codifica H264:", "LabelHardwareAccelerationType": "Accelerazione Hardware:", - "LabelHardwareAccelerationTypeHelp": "Disponibile solo su sistemi supportati.", + "LabelHardwareAccelerationTypeHelp": "L'accelerazione hardware richiede un'ulteriore configurazione.", "LabelHomeNetworkQuality": "Qualità della rete domestica:", "LabelHomeScreenSectionValue": "Pagina iniziale Sezione {0}:", - "LabelHttpsPort": "Porta HTTPS locale", - "LabelHttpsPortHelp": "Numero di porta TCP da associare al server https di Jellyfin", - "LabelIconMaxHeight": "Altezza Icona massima:", + "LabelHttpsPort": "Porta HTTPS locale:", + "LabelHttpsPortHelp": "Numero di porta TCP da associare al server HTTPS di Jellyfin.", + "LabelIconMaxHeight": "Altezza icona massima:", "LabelIconMaxHeightHelp": "Risoluzione massima delle icone inviate tramite upnp:icon.", - "LabelIconMaxWidth": "Larghezza massima Icona:", - "LabelIconMaxWidthHelp": "Risoluzione massima delle icone inviate tramite upnp:icon.", + "LabelIconMaxWidth": "Larghezza massima icona:", + "LabelIconMaxWidthHelp": "Risoluzione massima delle icone esposte tramite upnp:icon.", "LabelIdentificationFieldHelp": "Una stringa o espressione regex sensibile a maiuscole e minuscole.", "LabelImageFetchersHelp": "Abilitare e classificare i tuoi Fetchers immagini preferite in ordine di priorità.", "LabelImageType": "Tipo immagine:", "LabelImportOnlyFavoriteChannels": "Limitare ai canali segnato come", - "LabelInNetworkSignInWithEasyPassword": "Abilita l'accesso da rete locale tramite codice PIN.", - "LabelInNetworkSignInWithEasyPasswordHelp": "Se attivata, sarai in grado di utilizzare il tuo codice pin facile per accedere alle app di Jellyfin all'interno della tua rete domestica. La tua password usuale sarà necessaria solo per accedere alle app quando sei fuori casa. Se il codice PIN viene lasciato vuoto, non avrai bisogno di una password quando sei all'interno della tua rete domestica.", + "LabelInNetworkSignInWithEasyPassword": "Abilita l'accesso da rete locale tramite codice pin", + "LabelInNetworkSignInWithEasyPasswordHelp": "Usa il codice pin facile per accedere alle app all'interno della tua rete domestica. La tua password usuale sarà necessaria solo per accedere alle app quando sei fuori casa. Se il codice PIN viene lasciato vuoto, non avrai bisogno di una password quando sei all'interno della tua rete domestica.", "LabelInternetQuality": "Qualità Internet:", "LabelKeepUpTo": "Conservane fino a:", "LabelKidsCategories": "Categorie bambini:", "LabelKodiMetadataDateFormat": "Data di uscita Formato:", - "LabelKodiMetadataDateFormatHelp": "Tutte le date all'interno del nfo verranno letti e scritti utilizzando questo formato.", - "LabelKodiMetadataEnableExtraThumbs": "Copia extrafanart in extrathumbs", - "LabelKodiMetadataEnableExtraThumbsHelp": "Copia extrafanart in extrathumbs", + "LabelKodiMetadataDateFormatHelp": "Tutte le date all'interno dei files NFO verranno analizzate utilizzando questo formato.", + "LabelKodiMetadataEnableExtraThumbs": "Copia extrafanart nel campo extrathumbs", + "LabelKodiMetadataEnableExtraThumbsHelp": "Quando scarichi delle immagini, queste possono essere salvate entrambe sia in extrafanart e extrathumbs per la massima compatibilità di skin con Kodi.", "LabelKodiMetadataEnablePathSubstitution": "Abilita sostituzione di percorso", "LabelKodiMetadataEnablePathSubstitutionHelp": "Consente percorso sostituzione dei percorsi delle immagini utilizzando le impostazioni di sostituzione percorso del server.", "LabelKodiMetadataSaveImagePaths": "Salva percorsi delle immagini all'interno dei file NFO", "LabelKodiMetadataSaveImagePathsHelp": "Questo è consigliato se si dispone di nomi di file immagine che non sono conformi alle linee guida Kodi.", - "LabelKodiMetadataUser": "Salva dati utente in file nfo per:", - "LabelKodiMetadataUserHelp": "Abilita questa opzione per salvare i dati in file Nfo per usarli in altre applicazioni", + "LabelKodiMetadataUser": "Salva dati utente nei files NFO per:", + "LabelKodiMetadataUserHelp": "Salvare i dati nei filse NFO per usarli in altre applicazioni.", "LabelLanNetworks": "Reti LAN:", "LabelLanguage": "Lingua:", "LabelLineup": "Allineare:", - "LabelLocalHttpServerPortNumber": "Porta HTTP locale", - "LabelLocalHttpServerPortNumberHelp": "Numero di porta TCP da associare al server http di Jellyfin", + "LabelLocalHttpServerPortNumber": "Porta HTTP locale:", + "LabelLocalHttpServerPortNumberHelp": "Numero di porta TCP da associare al server HTTP di Jellyfin.", "LabelLockItemToPreventChanges": "Blocca questo elemento per impedire modifiche future", "LabelLoginDisclaimer": "Avviso Login:", - "LabelLoginDisclaimerHelp": "Questo verrà visualizzato nella parte inferiore della pagina di accesso.", + "LabelLoginDisclaimerHelp": "Un messaggio che verrà visualizzato nella parte inferiore della pagina di accesso.", "LabelLogs": "Log:", - "LabelManufacturer": "Produttore", + "LabelManufacturer": "Produttore:", "LabelManufacturerUrl": "URL del produttore", "LabelMaxBackdropsPerItem": "Massimo numero di sfondi per oggetto:", "LabelMaxChromecastBitrate": "Qualità streaming su Chromecast:", @@ -643,25 +641,25 @@ "LabelMetadataPathHelp": "Specificare un percorso personalizzato per le immagini e i metadati scaricati.", "LabelMetadataReaders": "Lettori Metadati:", "LabelMetadataReadersHelp": "Classificare le origini metadati locali preferite in ordine di priorità. Il primo file trovato verrà letto.", - "LabelMetadataSaversHelp": "Scegliere i formati di file per salvare i metadati", + "LabelMetadataSaversHelp": "Scegliere i formati di file per salvare i metadati.", "LabelMethod": "Metodo:", "LabelMinBackdropDownloadWidth": "Massima larghezza sfondo:", - "LabelMinResumeDuration": "Durata minima per il riprendi (secondi)", - "LabelMinResumeDurationHelp": "I film più corti non saranno riprendibili", - "LabelMinResumePercentage": "Percentuale minima per il riprendi", - "LabelMinResumePercentageHelp": "I film Sono considerati non visti se fermati prima di questo tempo", + "LabelMinResumeDuration": "Durata minima per il riprendi:", + "LabelMinResumeDurationHelp": "La durata video più corta in secondi che salverà la locazione di riproduzione e ti permetterà di riprendere.", + "LabelMinResumePercentage": "Percentuale minima per il riprendi:", + "LabelMinResumePercentageHelp": "I film sono considerati non visti se fermati prima di questo tempo.", "LabelMinScreenshotDownloadWidth": "Larghezza minima screenshot scaricati:", "LabelModelDescription": "Descrizione Modello", "LabelModelName": "Nome Modello", "LabelModelNumber": "Numero Modello", - "LabelModelUrl": "Url Modello", + "LabelModelUrl": "Modello URL", "LabelMonitorUsers": "Monitora l'attività da:", "LabelMovieCategories": "Categorie film:", "LabelMoviePrefix": "Prefisso film:", - "LabelMoviePrefixHelp": "Se un prefisso viene applicato ai titoli di film, inseriscilo qui in modo che Jellyfin possa gestirlo correttamente.", + "LabelMoviePrefixHelp": "Se un prefisso viene applicato ai titoli di film, inseriscilo qui in modo che il server possa gestirlo correttamente.", "LabelMovieRecordingPath": "Percorso di registrazione film (opzionale):", "LabelMusicStreamingTranscodingBitrate": "Musica trascodifica bitrate:", - "LabelMusicStreamingTranscodingBitrateHelp": "Specifica il max Bitrate per lo streaming musica", + "LabelMusicStreamingTranscodingBitrateHelp": "Specifica il massimo bitrate per lo streaming musicale.", "LabelName": "Nome:", "LabelNewName": "Nuovo nome:", "LabelNewPassword": "Nuova password:", @@ -687,9 +685,9 @@ "LabelPlaceOfBirth": "Luogo di nascita:", "LabelPlayDefaultAudioTrack": "Riprodurre la traccia audio di default indipendentemente dalla lingua", "LabelPostProcessor": "Applicazione Post-processing:", - "LabelPostProcessorArguments": "Argomenti linea di comando del Post-processor", + "LabelPostProcessorArguments": "Argomenti linea di comando del Post-processor:", "LabelPostProcessorArgumentsHelp": "Usa {path} come percorso al file di registrazione.", - "LabelPreferredDisplayLanguage": "Lingua preferita visualizzata", + "LabelPreferredDisplayLanguage": "Lingua preferita visualizzata:", "LabelPreferredDisplayLanguageHelp": "La traduzione di Jellyfin è un progetto attivo.", "LabelPreferredSubtitleLanguage": "Lingua dei sottotitoli preferita:", "LabelPrevious": "Precedente", @@ -702,9 +700,9 @@ "LabelProtocol": "Protocollo:", "LabelProtocolInfo": "Info protocollo:", "LabelProtocolInfoHelp": "Il valore che verrà utilizzato quando si risponde a richieste GetProtocolInfo dal dispositivo.", - "LabelPublicHttpPort": "Porta HTTP pubblica", + "LabelPublicHttpPort": "Porta HTTP pubblica:", "LabelPublicHttpPortHelp": "Numero di porta pubblica che dovrebbe essere mappato sulla porta HTTP locale.", - "LabelPublicHttpsPort": "Numero porta HTTPS pubblica", + "LabelPublicHttpsPort": "Numero porta HTTPS pubblica:", "LabelPublicHttpsPortHelp": "Numero della porta pubblica che dovrebbe essere mappato sulla porta HTTPS locale.", "LabelReadHowYouCanContribute": "Scopri come puoi contribuire.", "LabelReasonForTranscoding": "Motivo per la transcodifica:", @@ -722,8 +720,8 @@ "LabelScreensaver": "Salvaschermo:", "LabelSeasonNumber": "Numero stagione:", "LabelSecureConnectionsMode": "Modalità connessione sicura:", - "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", + "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.", "LabelSelectUsers": "Seleziona Utenti:", "LabelSelectVersionToInstall": "Selezionare la versione da installare:", "LabelSendNotificationToUsers": "Invia notifiche a:", @@ -735,7 +733,7 @@ "LabelSkipIfAudioTrackPresent": "Ignora se la traccia audio di default corrisponde alla lingua di download", "LabelSkipIfAudioTrackPresentHelp": "Deselezionare questa opzione per assicurare che tutti i video abbiano i sottotitoli, a prescindere dalla lingua audio.", "LabelSkipIfGraphicalSubsPresent": "Ignora se il video integra già dei sottotitoli", - "LabelSkipIfGraphicalSubsPresentHelp": "Mantenere le versioni testuali dei sottotitoli si tradurrà in una riproduzione più efficiente e diminuirà la probabilità che sia necessaria la transcodifica video", + "LabelSkipIfGraphicalSubsPresentHelp": "Mantenere le versioni testuali dei sottotitoli si tradurrà in una riproduzione più efficiente e diminuirà la probabilità che sia necessaria la transcodifica video.", "LabelSonyAggregationFlagsHelp": "Determina il contenuto dell'elemento aggregationFlags in urn:schemas-sonycom: namespace av.", "LabelSortBy": "Ordina per:", "LabelSortOrder": "Ordinato per:", @@ -751,7 +749,7 @@ "LabelSubtitleDownloaders": "Downloader sottotitoli:", "LabelSubtitleFormatHelp": "Esempio: srt", "LabelSubtitlePlaybackMode": "Modalità Sottotitolo:", - "LabelSubtitles": "Sottotitoli:", + "LabelSubtitles": "Sottotitoli", "LabelSupportedMediaTypes": "Tipi di media supportati:", "LabelTVHomeScreen": "Schermata iniziale della modalità TV:", "LabelTagline": "Slogan:", @@ -765,9 +763,9 @@ "LabelTrackNumber": "Numero traccia:", "LabelTranscodingAudioCodec": "Codec Audio:", "LabelTranscodingContainer": "contenitore:", - "LabelTranscodingTempPathHelp": "Questa cartella contiene i file di lavoro utilizzati dal transcoder. Specificare un percorso personalizzato, oppure lasciare vuoto per utilizzare l'impostazione predefinita all'interno della cartella dei dati del server.", + "LabelTranscodingTempPathHelp": "Specifica un percorso personalizzato per la transcodifica dei files utilizzati dai client. Lasciare vuoto per utilizzare l'impostazione predefinita dal server.", "LabelTranscodingThreadCount": "Transcodifica numero di thread:", - "LabelTranscodingThreadCountHelp": "Selezionare il numero massimo di thread da utilizzare durante la transcodifica. Ridurre il numero di thread si abbasserà l'utilizzo della CPU, ma non può convertire abbastanza veloce per un'esperienza di riproduzione fluida.", + "LabelTranscodingThreadCountHelp": "Selezionare il numero massimo di thread da utilizzare durante la transcodifica. Ridurre il numero di thread si abbasserà l'utilizzo della CPU, ma può non convertire abbastanza veloce per un'esperienza di riproduzione fluida.", "LabelTranscodingVideoCodec": "Codec Video:", "LabelTriggerType": "Tipo Evento:", "LabelTunerIpAddress": "Tuner Indirizzo IP:", @@ -779,8 +777,8 @@ "LabelUserAgent": "Agente utente:", "LabelUserLibrary": "Libreria utente:", "LabelUserLibraryHelp": "Selezionare la libreria utente da visualizzare sul dispositivo. Lasciare vuoto per ereditare l'impostazione predefinita.", - "LabelUserRemoteClientBitrateLimitHelp": "Questo sovrascriverà il valore globale predefinito impostato nelle impostazioni di riproduzione del server.", - "LabelUsername": "Nome utente", + "LabelUserRemoteClientBitrateLimitHelp": "Sovrascrive il valore globale predefinito impostato nelle impostazioni di riproduzione del server.", + "LabelUsername": "Nome utente:", "LabelVaapiDevice": "Dispositivo VA API:", "LabelVaapiDeviceHelp": "Questo è il nodo rendering usato dall'accelerazione hardware.", "LabelValue": "valore:", @@ -799,7 +797,7 @@ "Large": "Grande", "LatestFromLibrary": "Ultimi {0}", "LearnHowYouCanContribute": "Scopri come puoi contribuire.", - "LibraryAccessHelp": "Seleziona le cartelle multimediali da condividere con questo utente. Gli amministratori saranno in grado di modificare tutte le cartelle utilizzando il gestore dei metadati.", + "LibraryAccessHelp": "Seleziona le librerie da condividere con questo utente. Gli amministratori saranno in grado di modificare tutte le cartelle utilizzando il gestore dei metadati.", "Like": "Mi piace", "List": "Lista", "Live": "In diretta", @@ -828,7 +826,7 @@ "MediaInfoProfile": "Profilo", "MediaInfoRefFrames": "Ref frame", "MediaInfoResolution": "Risoluzione", - "MediaInfoSampleRate": "frequenza di campion.", + "MediaInfoSampleRate": "Frequenza di campione", "MediaInfoSize": "Dimensione", "MediaIsBeingConverted": "Il file multimediale viene convertito in un formato che è compatibile con il dispositivo che sta riproducendo il file multimediale.", "Menu": "Menù", @@ -841,39 +839,39 @@ "MessageConfirmRecordingCancellation": "Cancellare la registrazione?", "MessageConfirmRemoveMediaLocation": "Sei sicuro di voler rimuovere questa posizione?", "MessageConfirmRestart": "Sei sicuro di voler riavviare il Server Jellyfin?", - "MessageConfirmRevokeApiKey": "Sei sicuro di voler revocare questa chiave api? La connessione dell'applicazione al Server Jellyfin terminerà immediatamente", - "MessageConfirmShutdown": "Sei sicuro di voler spegnere il Server Jellyfin?", + "MessageConfirmRevokeApiKey": "Sei sicuro di voler revocare questa chiave api? La connessione dell'applicazione al Server Jellyfin terminerà immediatamente.", + "MessageConfirmShutdown": "Sei sicuro di voler spegnere il server?", "MessageContactAdminToResetPassword": "Si prega di contattare l'amministratore di sistema per reimpostare la password.", "MessageCreateAccountAt": "Crea un account a {0}", "MessageDeleteTaskTrigger": "Sei sicuro di voler cancellare questo evento?", "MessageDirectoryPickerBSDInstruction": "Per BSD, potrebbe essere necessario per configurare le unità all'interno della vostra prigione FreeNAS al fine di permettere ricamato accedervi.", - "MessageDirectoryPickerInstruction": "Percorsi di rete possono essere inseriti manualmente nel caso in cui il pulsante Rete non riesce a individuare i vostri dispositivi. Ad esempio, {0} o {1}", - "MessageDirectoryPickerLinuxInstruction": "Per Linux su Arch Linux, CentOS, Debian, Fedora, OpenSuse o Ubuntu, è necessario concedere all'utente del sistema Jellyfin almeno l'accesso alle posizioni di archiviazione.", + "MessageDirectoryPickerInstruction": "Percorsi di rete possono essere inseriti manualmente nel caso in cui il pulsante Rete non riesce a individuare i vostri dispositivi. Ad esempio, {0} o {1}.", + "MessageDirectoryPickerLinuxInstruction": "Per Linux su Arch Linux, CentOS, Debian, Fedora, openSUSE o Ubuntu, è necessario concedere all'utente del servizio almeno l'accesso alle posizioni di archiviazione.", "MessageDownloadQueued": "Scaricamento programmato.", "MessageEnablingOptionLongerScans": "L'abilitazione di questa opzione può rallentare significativamente le scansioni della libreria.", "MessageFileReadError": "Si è verificato un errore durante la lettura del file. Si prega di riprovare.", "MessageForgotPasswordFileCreated": "Il seguente file è stato creato sul server e contiene le istruzioni su come procedere:", "MessageForgotPasswordInNetworkRequired": "Riprova all'interno della rete domestica per avviare il processo di reimpostazione della password.", - "MessageInstallPluginFromApp": "Questo Plugin deve essere installato dall'app in cui vuoi farlo funzionare", - "MessageInvalidForgotPasswordPin": "Un pin Invalido o scaduto è stato inserito. Riprova.", - "MessageInvalidUser": "Utente o password errato. Riprova", + "MessageInstallPluginFromApp": "Questo plugin deve essere installato dall'app in cui vuoi farlo funzionare.", + "MessageInvalidForgotPasswordPin": "É stato inserito un codice pin invalido o scaduto . Riprova.", + "MessageInvalidUser": "Utente o password errato. Riprova.", "MessageItemSaved": "Elemento salvato.", "MessageItemsAdded": "Elementi aggiunti.", - "MessageLeaveEmptyToInherit": "Lascia vuoto per ereditare le impostazioni dall'elemento principale, o il valore predefinito globale.", + "MessageLeaveEmptyToInherit": "Lascia vuoto per ereditare le impostazioni dall'elemento principale o il valore predefinito globale.", "MessageNoAvailablePlugins": "Nessun plugin disponibile.", "MessageNoMovieSuggestionsAvailable": "Nessun suggerimento di film attualmente disponibile. Iniziare a guardare e valutare i vostri film, e poi tornare per i suggerimenti.", - "MessageNoPluginsInstalled": "Non hai plugin installati", - "MessageNoTrailersFound": "Nessun Trailer trovato.Installa Il plug in dei trailer per importare la libreria dei trailer da internet", + "MessageNoPluginsInstalled": "Non hai plugin installati.", + "MessageNoTrailersFound": "Nessun trailer trovato. Installa il canale dei Trailer per migliorare la tua esperienza cinematografica importando una libreria di trailer da internet.", "MessageNothingHere": "Non c'è niente qui.", - "MessagePasswordResetForUsers": "Le password sono state rimosse dai seguenti utenti. Per accedere lasciare vuoto il campo password.", - "MessagePlayAccessRestricted": "Le riproduzione di questi contenuti è bloccata. Per favore contatta il tuo amministratore Jellyfin Server per maggiori informazioni.", + "MessagePasswordResetForUsers": "I seguenti utenti havvo avuto le loro password resettate. Adesso possono accedere con i codici pin che sono stati utilizzati per eseguire il reset.", + "MessagePlayAccessRestricted": "Le riproduzione di questi contenuti è bloccata. Per favore contatta il tuo amministratore del server per maggiori informazioni.", "MessagePleaseEnsureInternetMetadata": "Assicurarsi che il download dei metadati Internet sia abilitato.", "MessagePleaseWait": "Per favore attendi. La procedura potrebbe impiegare qualche minuto.", "MessagePluginConfigurationRequiresLocalAccess": "Per configurare questo plugin si prega di accedere al proprio server locale direttamente.", "MessagePluginInstallDisclaimer": "I plugin creati dai membri della comunità Jellyfin sono un ottimo modo per migliorare l'esperienza di Jellyfin con funzionalità e vantaggi aggiuntivi. Prima di installare, si prega di notare gli effetti che possono avere sul tuo server Jellyfin, come le scansioni più lunghe della libreria, l'elaborazione di sfondo aggiuntiva e la stabilità del sistema diminuita.", "MessageReenableUser": "Guarda in basso per ri-abilitare", "MessageSettingsSaved": "Settaggi salvati.", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "I seguenti percorsi ai file multimediali saranno rimossi dalla tua libreria Jellyfin:", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "I seguenti percorsi ai file multimediali saranno rimossi dalla tua libreria:", "MessageUnableToConnectToServer": "Non siamo in grado di connettersi al server selezionato al momento. Per favore assicurati che sia in esecuzione e riprova.", "MessageUnsetContentHelp": "Il contenuto verrà visualizzato come pianura cartelle. Per ottenere i migliori risultati utilizzare il gestore di metadati per impostare i tipi di contenuto di sottocartelle.", "MessageYouHaveVersionInstalled": "Attualmente hai la versione {0} installato.", @@ -883,10 +881,10 @@ "MinutesBefore": "minuti prima", "Monday": "Lunedì", "MoreFromValue": "Altro di {0}", - "MoreUsersCanBeAddedLater": "Altri utenti possono essere aggiunti in un secondo momento dal Pannello di Controllo.", + "MoreUsersCanBeAddedLater": "Altri utenti possono essere aggiunti in un secondo momento dal pannello di controllo.", "MoveLeft": "Sposta a sinistra", "MoveRight": "Sposta a destra", - "MovieLibraryHelp": "Rivedere la {0} guida di denominazione del film Jellyfin {1}.", + "MovieLibraryHelp": "Rivedere la {0} guida di denominazione dei film{1}.", "Movies": "Film", "Mute": "Muto", "MySubtitles": "I miei Sottotitoli", @@ -903,16 +901,16 @@ "NoNextUpItemsMessage": "Trovato niente. Inizia a guardare i tuoi programmi!", "NoPluginConfigurationMessage": "Questo Plugin non ha impostazioni da configurare.", "NoSubtitleSearchResultsFound": "Nessun risultato.", - "NoSubtitles": "Nessun Sottotitolo", + "NoSubtitles": "Nessuno", "NoSubtitlesHelp": "I sottotitoli non verranno caricati per impostazione predefinita.Possono essere ancora caricati manualmente durante la riproduzione.", "None": "Nessuno", "Normal": "Normale", "NumLocationsValue": "{0} cartelle", "Off": "Spento", "OneChannel": "Un canale", - "OnlyForcedSubtitles": "Solo i sottotitoli forzati", + "OnlyForcedSubtitles": "Solo forzati", "OnlyForcedSubtitlesHelp": "Solo i sottotitoli contrassegnati come forzati saranno caricati.", - "OnlyImageFormats": "Solo formati immagine (VOBSUB, PGS, SUB / IDX, ecc.)", + "OnlyImageFormats": "Solo formati immagine (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Amministratori", "OptionAlbumArtist": "Artista Album", "OptionAllUsers": "Tutti gli utenti", @@ -949,19 +947,19 @@ "OptionCustomUsers": "Personalizza", "OptionDaily": "Giornaliero", "OptionDateAdded": "Aggiunto il", - "OptionDateAddedFileTime": "Utilizzare file di data di creazione", - "OptionDateAddedImportTime": "Utilizza la data scansionato in biblioteca", + "OptionDateAddedFileTime": "Utilizzare la data di creazione del file", + "OptionDateAddedImportTime": "Utilizza la data di scansione nella libreria", "OptionDatePlayed": "Visto il", "OptionDescending": "Decrescente", "OptionDisableUser": "Disabilita questo utente", "OptionDisableUserHelp": "Se disabilitato, il server non sarà disponibile per questo utente. Le connessioni esistenti verranno terminate.", "OptionDislikes": "Non mi piace", "OptionDisplayFolderView": "Visualizza cartelle come normali cartelle dei media", - "OptionDisplayFolderViewHelp": "Se abilitato, le applicazioni Jellyfin visualizzeranno una categoria Cartelle accanto alla libreria multimediale. Ciò è utile se si desidera avere viste di cartelle semplici.", + "OptionDisplayFolderViewHelp": "Visualizza le cartelle accanto alle librerie multimediali. Questo può essere utile se si desidera avere una vista di cartelle semplici.", "OptionDownloadBackImage": "Indietro", "OptionDownloadDiscImage": "Disco", "OptionDownloadImagesInAdvance": "Scarica preventivamente le immagini", - "OptionDownloadImagesInAdvanceHelp": "Di default, la maggior parte delle immagini vengono scaricate solo quando richieste da un'applicazione Jellyfin. Abilita questa opzione per scaricare tutte le immagini in anticipo, quando nuovi file multimediali vengono importati. Ciò può causare scansioni librarie molto più lunghe.", + "OptionDownloadImagesInAdvanceHelp": "Di default, la maggior parte delle immagini vengono scaricate solo quando richieste da un'applicazione Jellyfin. Abilita questa opzione per scaricare tutte le immagini in anticipo, quando nuovi file multimediali vengono importati. Ciò può causare scansioni delle librerie molto più lunghe.", "OptionDownloadMenuImage": "Menù", "OptionDownloadPrimaryImage": "Locandina", "OptionDownloadThumbImage": "Foto", @@ -969,9 +967,8 @@ "OptionEnableAccessFromAllDevices": "Abilita l'accesso da tutti i dispositivi", "OptionEnableAccessToAllChannels": "Abilita l'accesso a tutti i canali", "OptionEnableAccessToAllLibraries": "Abilita l'accesso a tutte le librerie", - "OptionEnableAutomaticServerUpdates": "Attiva aggiornamenti automatici del server", "OptionEnableExternalContentInSuggestions": "Abilita contenuto remoto nei suggerimenti", - "OptionEnableExternalContentInSuggestionsHelp": "Consenti l'inclusione di trailer Internet e programmi TV tra i contenuti suggeriti.", + "OptionEnableExternalContentInSuggestionsHelp": "Consenti l'inclusione di trailer da Internet e programmi TV in diretta tra i contenuti suggeriti.", "OptionEnableForAllTuners": "Abilita per tutti i sintonizzatori", "OptionEnableM2tsMode": "Attiva modalità M2TS", "OptionEnableM2tsModeHelp": "Attivare la modalità m2ts durante la codifica di mpegts.", @@ -988,9 +985,9 @@ "OptionHasThemeSong": "Sigla", "OptionHasThemeVideo": "Video Sigla", "OptionHideUser": "Nascondi questo utente dalla schermata di accesso", - "OptionHideUserFromLoginHelp": "Utile per account nascosti o amministratore. L'utente avrà bisogno di accedere manualmente utilizzando la propria username e password", - "OptionHlsSegmentedSubtitles": "Hls segmentato sottotitoli", - "OptionHomeVideos": "Video e foto personali", + "OptionHideUserFromLoginHelp": "Utile per account nascosti o amministratore. L'utente avrà bisogno di accedere manualmente utilizzando la propria username e password.", + "OptionHlsSegmentedSubtitles": "HLS sottotitoli segmentati", + "OptionHomeVideos": "Foto", "OptionIgnoreTranscodeByteRangeRequests": "Ignorare le richieste di intervallo di byte di trascodifica", "OptionIgnoreTranscodeByteRangeRequestsHelp": "Se abilitata, queste richieste saranno onorate, ma ignorano l'intervallo di byte.", "OptionImdbRating": "Voto IMDB", @@ -998,7 +995,7 @@ "OptionMissingEpisode": "Episodi mancanti", "OptionMonday": "Lunedì", "OptionNameSort": "Nome", - "OptionNew": "Nuovo...", + "OptionNew": "Nuovo…", "OptionNone": "Nessuno", "OptionOnAppStartup": "All'avvio", "OptionOnInterval": "Su intervallo", @@ -1016,7 +1013,7 @@ "OptionReportByteRangeSeekingWhenTranscodingHelp": "Questo è necessario per alcuni dispositivi che non hanno l'avanzamento rapido che funziona bene.", "OptionRequirePerfectSubtitleMatch": "Scarica solo i sottotitoli che corrispondono perfettamente ai miei file video", "OptionRequirePerfectSubtitleMatchHelp": "La richiesta di una corrispondenza perfetta filtrerà i sottotitoli per includere solo quelli che sono stati testati e verificati con il file video esatto. Deselezionando questo aumenterà la probabilità che i sottotitoli vengono scaricati, ma aumenteranno le probabilità di testo sottotitolato impreciso o errato.", - "OptionResElement": "elemento res", + "OptionResElement": "res element", "OptionResumable": "Interrotto", "OptionRuntime": "Durata", "OptionSaturday": "Sabato", @@ -1028,29 +1025,29 @@ "OptionThursday": "Giovedì", "OptionTrackName": "Titolo Traccia", "OptionTuesday": "Martedì", - "OptionTvdbRating": "Voto Tvdb", + "OptionTvdbRating": "Voto TVDB", "OptionUnairedEpisode": "Episodi mai andati in onda", "OptionUnplayed": "Non visto", - "OptionWakeFromSleep": "Risveglio:", + "OptionWakeFromSleep": "Risveglio", "OptionWednesday": "Mercoledì", "OptionWeekdays": "Feriali", "OptionWeekends": "Il Weekend", "OptionWeekly": "Settimanale", "OriginalAirDateValue": "Prima messa in onda (originale): {0}", "Overview": "Trama", - "PackageInstallCancelled": "Installazione di {0} annullata.", - "PackageInstallCompleted": "Installazione di {0} completa.", - "PackageInstallFailed": "Installazione di {0} fallita.", + "PackageInstallCancelled": "Installazione di {0} (versione {1}) annullata.", + "PackageInstallCompleted": "Installazione di {0} (versione {1}) completata.", + "PackageInstallFailed": "Installazione di {0} (versione {1}) fallita.", "ParentalRating": "Classificazione per genitori", "PasswordMatchError": "Le password non coincidono.", - "PasswordResetComplete": "la password è stata ripristinata.", - "PasswordResetConfirmation": "Sei sicuro di voler ripristinare la password?", - "PasswordResetHeader": "Ripristina Password", + "PasswordResetComplete": "Reset della password eseguito.", + "PasswordResetConfirmation": "Sicuro di voler eseguire il reset della password?", + "PasswordResetHeader": "Reset Password", "PasswordSaved": "Password salvata.", "People": "Attori", "PerfectMatch": "Corrispondenza perfetta", "Photos": "Foto", - "PinCodeResetComplete": "Il codice PIN è stato resettato", + "PinCodeResetComplete": "Il codice pin è stato resettato.", "PinCodeResetConfirmation": "Sei sicuro di voler resettare il codice PIN?", "PlaceFavoriteChannelsAtBeginning": "Mostra prima i canali preferiti", "Play": "Riproduci", @@ -1063,7 +1060,7 @@ "Playlists": "Playlist", "PleaseAddAtLeastOneFolder": "Per favore aggiungi almeno una cartella alla raccolta cliccando sul pulsante Aggiungi.", "PleaseConfirmPluginInstallation": "Per favore premi OK per confermare che hai letto quanto precede e che vuoi procedere all'installazione del plug-in.", - "PleaseEnterNameOrId": "Per favore inserisci un nome o un id esterno.", + "PleaseEnterNameOrId": "Per favore inserisci un nome o un ID esterno.", "PleaseRestartServerName": "Per favore riavvia Jellyfin Server - {0}.", "PleaseSelectTwoItems": "Seleziona almeno due elementi.", "PluginInstalledMessage": "Il plugin è stato installato correttamente. Il server Jellyfin dovrà essere riavviato affinché le modifiche abbiano effetto.", @@ -1079,7 +1076,7 @@ "Programs": "Programmi", "Quality": "Qualità", "QueueAllFromHere": "In coda tutto da qui in poi", - "Raised": "Sospeso", + "Raised": "Rilievo", "Rate": "Vota", "RecentlyWatched": "Visti di recente", "RecommendationBecauseYouLike": "Perché ti piace {0}", @@ -1130,7 +1127,7 @@ "SendMessage": "Invio messaggio", "Series": "Serie TV", "SeriesCancelled": "Serie TV annullate.", - "SeriesDisplayOrderHelp": "Ordina gli episodi per data messa in onda, ordine dvd o numerazione assoluta.", + "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", @@ -1162,7 +1159,7 @@ "Sports": "Sport", "StopRecording": "Ferma registrazione", "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).", + "SubtitleAppearanceSettingsDisclaimer": "Queste impostazioni non si applicano a sottotitoli grafici (PGS, DVD, ecc.) o sottotitoli ASS/SSA che hanno i propri stili.", "SubtitleDownloadersHelp": "Abilita e classifica i tuoi downloader di sottotitoli preferiti in ordine di priorità.", "Subtitles": "Sottotitoli", "Suggestions": "Suggerimenti", @@ -1171,7 +1168,7 @@ "SystemDlnaProfilesHelp": "I profili di sistema sono in sola lettura. Le modifiche ad un profilo di sistema verranno salvate in un nuovo profilo personalizzato.", "TabAccess": "Accesso", "TabAdvanced": "Avanzato", - "TabAlbumArtists": "Artisti degli album", + "TabAlbumArtists": "Artisti degli Album", "TabAlbums": "Album", "TabArtists": "Artisti", "TabCatalog": "Catalogo", @@ -1195,7 +1192,7 @@ "TabMusicVideos": "Video Musicali", "TabMyPlugins": "I miei Plug-in", "TabNetworks": "Reti", - "TabNfoSettings": "Impostazioni nfo", + "TabNfoSettings": "Impostazioni NFO", "TabNotifications": "Notifiche", "TabOther": "Altro", "TabParentalControl": "Controllo Genitore", @@ -1205,7 +1202,7 @@ "TabProfiles": "Profili", "TabRecordings": "Registrazioni", "TabResponses": "Risposte", - "TabResumeSettings": "Ripristina Impostazioni", + "TabResumeSettings": "Riprendi", "TabScheduledTasks": "Operazioni Pianificate", "TabSeries": "Serie TV", "TabSettings": "Impostazioni", @@ -1224,14 +1221,14 @@ "ThisWizardWillGuideYou": "Questa procedura ti guiderà attraverso il processo di installazione. Per iniziare, per favore scegli la tua lingua preferita.", "Thumb": "Miniatura", "Thursday": "Giovedì", - "TitleHardwareAcceleration": "Accelerazione Hardware:", + "TitleHardwareAcceleration": "Accelerazione Hardware", "TitleHostingSettings": "Impostazioni hosting", "TitlePlayback": "Riproduzione", "TrackCount": "{0} tracce", "Trailers": "Trailer", "Transcoding": "Trascodifica", "Tuesday": "Martedì", - "TvLibraryHelp": "Rivedere la {0} guida di denominazione Jellyfin TV {1}.", + "TvLibraryHelp": "Rivedere la {0} guida di denominazione TV{1}.", "Uniform": "Uniforme", "UninstallPluginConfirmation": "Sei sicuro di voler Disinstallare {0}?", "UninstallPluginHeader": "Disinstalla Plugin", @@ -1240,8 +1237,8 @@ "Unrated": "Non votato", "Up": "Su", "Upload": "Carica", - "UserAgentHelp": "Fornire un'intestazione http personalizzata per utente-agente, se necessario.", - "UserProfilesIntro": "Jellyfin include il supporto integrato per i profili utente, che permette ad ogni utente di avere le proprie impostazioni di visualizzazione, stato di riproduzione e controlli parentali.", + "UserAgentHelp": "Fornire un'intestazione HTTP personalizzata per utente-agente.", + "UserProfilesIntro": "Jellyfin include il supporto per i profili utente con impostazioni di visualizzazione granulare, stato di riproduzione, e controlli parentali.", "ValueAlbumCount": "{0} album", "ValueAudioCodec": "Codec Audio: {0}", "ValueConditions": "Condizioni: {0}", @@ -1270,13 +1267,13 @@ "Watched": "Visto", "Wednesday": "Mercoledì", "WelcomeToProject": "Benvenuto in Jellyfin!", - "WizardCompleted": "Questo è tutto ciò che serve per ora. Jellyfin ha iniziato a raccogliere informazioni sulla tua libreria di media. Scopri alcune delle nostre app, quindi clicca su Fine per visualizzare il Pannello di Controllo del server.", + "WizardCompleted": "Questo è tutto ciò che serve per ora. Jellyfin ha iniziato a raccogliere informazioni sulla tua libreria di media. Scopri alcune delle nostre app, quindi clicca su Fine per visualizzare il Pannello di Controllo.", "Writer": "Scrittore", "XmlDocumentAttributeListHelp": "Questi attributi vengono applicati all'elemento radice di ogni risposta XML.", "XmlTvKidsCategoriesHelp": "I programmi con queste categorie saranno visualizzati come programmi per i bambini. Separa multipli con '|'.", "XmlTvMovieCategoriesHelp": "I programmi con queste categorie saranno visualizzati come filmati. Separa multipli con '|'.", "XmlTvNewsCategoriesHelp": "I programmi con queste categorie saranno visualizzati come programmi di news. Separa multipli con '|'.", - "XmlTvPathHelp": "Un percorso di un file xml tv. Jellyfin leggerà questo file e controlla periodicamente per gli aggiornamenti. Sei responsabile della creazione e dell'aggiornamento del file.", + "XmlTvPathHelp": "Un percorso di un file XMLTV. Jellyfin leggerà questo file e controlla periodicamente per gli aggiornamenti. Sei responsabile della creazione e dell'aggiornamento del file.", "XmlTvSportsCategoriesHelp": "I programmi con queste categorie saranno visualizzati come programmi sportivi. Separa multipli con '|'.", "Yes": "Si", "Yesterday": "Ieri", @@ -1307,20 +1304,20 @@ "HeaderCastCrew": "Cast", "HeaderMedia": "Media", "HeaderPassword": "Password", - "AuthProviderHelp": "Selezionare un Provider di Autenticazione da utilizzare per autenticare la password dell'utente", + "AuthProviderHelp": "Selezionare un Provider di Autenticazione da utilizzare per autenticare la password dell'utente.", "HeaderFavoriteMovies": "Film Preferiti", "HeaderFavoriteShows": "Serie TV Preferite", "HeaderFavoriteEpisodes": "Episodi Preferiti", - "HeaderFavoriteAlbums": "Album preferiti", + "HeaderFavoriteAlbums": "Album Preferiti", "HeaderFavoriteArtists": "Artisti Preferiti", "HeaderFavoriteSongs": "Brani Preferiti", "HeaderFavoriteVideos": "Video Preferiti", - "HeaderFetcherSettings": "Impostazioni Fetcher", + "HeaderFetcherSettings": "Impostazioni del Fetcher", "HeaderImageOptions": "Opzioni Immagine", "HeaderRestartingServer": "Riavvio Server", "Home": "Home", "LabelAlbum": "Album:", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelCache": "Cache:", "ButtonAddImage": "Aggiungi Immagine", "CopyStreamURL": "Copia Indirizzo dello Stream", @@ -1358,7 +1355,7 @@ "OptionProtocolHls": "Streaming in Diretta HTTP", "OptionDownloadArtImage": "Art", "OptionMax": "Massimo", - "PasswordResetProviderHelp": "Scegli un Provider Reset Password da utilizzare quando questo utente richiede un reset della password", + "PasswordResetProviderHelp": "Scegli un Provider Reset Password da utilizzare quando questo utente ne richiede il reset", "PlaybackData": "Dati di Riproduzione", "TagsValue": "Tag: {0}", "Whitelist": "Lista bianca", @@ -1401,9 +1398,9 @@ "LabelTranscodingProgress": "Progresso di trascodifica:", "DashboardVersionNumber": "Versione: {0}", "DashboardServerName": "Server: {0}", - "LabelVideo": "Video:", + "LabelVideo": "Video", "DashboardArchitecture": "Architettura: {0}", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "LaunchWebAppOnStartup": "Lancia l'interfaccia web quando viene avviato il server", "LaunchWebAppOnStartupHelp": "Apri il client web nel tuo web browser quando il server si avvia inizialmente. Ciò non accadrà quando si usa la funzione riavvio server.", "LeaveBlankToNotSetAPassword": "Puoi lasciare questo campo vuoto per non impostare alcuna password.", @@ -1451,5 +1448,64 @@ "TabStreaming": "Streaming", "ValueCodec": "Codec: {0}", "ValueMinutes": "{0} min", - "ValueOneAlbum": "1 album" + "ValueOneAlbum": "1 album", + "ButtonSplit": "Dividi", + "SelectAdminUsername": "Scegli un nome utente per l'account d'amministratore.", + "OptionRandom": "Casuale", + "MessageConfirmAppExit": "Vuoi uscire?", + "HeaderNavigation": "Navigazione", + "CopyStreamURLError": "Si è verificato un errore nel copiare l'indirizzo.", + "EnableFastImageFadeInHelp": "Abilita la dissolvenza veloce per le immagini caricate", + "EnableFastImageFadeIn": "Dissolvenza immagine veloce", + "PlaybackErrorNoCompatibleStream": "Il client è incompatibile con il media e il server non sta inviando un formato compatibile.", + "OptionForceRemoteSourceTranscoding": "Forza la transcodifica da fonti di media remoti (come LiveTV)", + "NoCreatedLibraries": "Sembra che tu non abbia ancora creato delle librerie. {0}Vuoi crearne una adesso?{1}", + "LabelVideoResolution": "Risoluzione video:", + "LabelStreamType": "Tipo di stream:", + "LabelPlayerDimensions": "Dimensioni player:", + "LabelDroppedFrames": "Frame persi:", + "LabelCorruptedFrames": "Frame corrotti:", + "AskAdminToCreateLibrary": "Chiedi ad un amministratore di creare una libreria.", + "AllowFfmpegThrottlingHelp": "Quando una transcodifica o un remux sono abbastanza avanti rispetto alla corrente posizione di riproduzione, pausa il processo così da consumare meno risorse. Questo è utile quando si guarda un video senza avanzare spesso durante la riproduzione. Disattiva questa opzione se stai avendo problemi di riproduzione.", + "AllowFfmpegThrottling": "Acceleratore Transcodifica", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferisci le informazioni incorporate nell'episodio rispetto ai nomi dei file", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Questo utilizza le informazioni dell'episodio provenienti dai metadata incorporati, se disponibili.", + "ClientSettings": "Impostazioni del client", + "Album": "Album", + "OnWakeFromSleep": "Al risveglio", + "Person": "Persona", + "LabelDeinterlaceMethod": "Metodo di deinterlacciamento:", + "DeinterlaceMethodHelp": "Metodo di deinterlacciamento da usare durante la transcodifica.", + "Artist": "Artista", + "OnApplicationStartup": "All'avvio", + "EveryXHours": "Ogni {0} ore", + "EveryHour": "Ogni ora", + "EveryXMinutes": "Ogni {0} minuti", + "WeeklyAt": "Tutti i {0} alle {1}", + "DailyAt": "Tutti i giorni alle {0}", + "LastSeen": "Visto l'ultima volta {0}", + "PersonRole": "nel ruolo di {0}", + "ListPaging": "{0}-{1} di {2}", + "WriteAccessRequired": "Jellyfin Server richiede il permesso di scrittura su questa cartella. Verificare l'autorizzazione e riprovare.", + "PathNotFound": "Percorso non trovato. Assicurarsi che sia valido e riprovare.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Traccia", + "Season": "Stagione", + "OtherArtist": "Altri Artisti", + "Movie": "Film", + "LabelLibraryPageSizeHelp": "Numero di elementi presenti nella paginazione della libreria. Il valore 0 disabilita la paginazione.", + "LabelLibraryPageSize": "Elementi nella paginazione della libreria:", + "Episode": "Episodio", + "BoxSet": "Cofanetto", + "AlbumArtist": "Artisti dell'Album", + "ReleaseGroup": "Release Group", + "UnsupportedPlayback": "Jellyfin non è in grado di decriptare i contenuti protetti da DRM ma tutti i contenuti verranno tentati a prescindere, compresi quelli protetti. Alcuni file potrebbero apparire completamente neri a causa della crittografia o di altre funzionalità non supportate, come i titoli interattivi.", + "MessageUnauthorizedUser": "Non sei autorizzato ad accedere in questo momento al server. Contatta l'amministratore per ulteriori dettagli.", + "ButtonTogglePlaylist": "Playlist", + "ButtonToggleContextMenu": "Altro", + "HeaderFavoritePlaylists": "Playlist Favorite", + "Filter": "Filtro", + "New": "Nuovo", + "ApiKeysCaption": "Elenco chiavi API abilitate" } diff --git a/src/strings/ja.json b/src/strings/ja.json index ee0ef90de1..0f90a05c40 100644 --- a/src/strings/ja.json +++ b/src/strings/ja.json @@ -53,7 +53,7 @@ "BoxRear": "ボックス(後)", "Browse": "ブラウズ", "BrowsePluginCatalogMessage": "利用可能なプラグインを表示するには、プラグインカタログを参照してください。", - "BurnSubtitlesHelp": "字幕フォーマットに応じて、ビデオを変換するときにサーバーが字幕を直接書き込むかどうかを決定します。 字幕の書き込みを避けると、サーバーのパフォーマンスが向上します。 特定のASS / SSA字幕だけでなく画像ベースのフォーマット(e.g. VOBSUB, PGS, SUB/IDX, etc.)を焼くには自動を選択します", + "BurnSubtitlesHelp": "字幕フォーマットに応じて、ビデオを変換するときにサーバーが字幕を直接書き込むかどうかを決定します。 字幕の書き込みを避けると、サーバーのパフォーマンスが向上します。 特定のASS / SSA字幕だけでなく画像ベースのフォーマット(VOBSUB, PGS, SUB/IDX, etc)を焼くには自動を選択します", "ButtonAdd": "追加", "ButtonAddMediaLibrary": "メディアライブラリを追加", "ButtonAddScheduledTaskTrigger": "トリガーを追加", @@ -176,8 +176,7 @@ "DirectStreamHelp2": "ファイルのダイレクトストリーミングは、ビデオ品質を損なうことなく、Jellyfin Serverにもほとんど負荷がありません。", "DirectStreaming": "ダイレクトストリーミング", "Director": "ディレクター", - "DirectorValue": "ディレクター: {0}", - "DirectorsValue": "ディレクターズ: {0}", + "Directors": "ディレクターズ", "Disabled": "無効", "Disc": "ディスク", "Disconnect": "切断", @@ -266,9 +265,8 @@ "Friday": "金曜日", "Fullscreen": "フルスクリーン", "General": "全般", - "GenreValue": "ジャンル: {0}", + "Genre": "ジャンル", "Genres": "ジャンル", - "GenresValue": "ジャンル: {0}", "GroupBySeries": "シリーズグループ", "GroupVersions": "グループバージョン", "GuestStar": "ゲストスター", @@ -276,10 +274,10 @@ "GuideProviderLogin": "ログイン", "GuideProviderSelectListings": "リストを選択", "H264CrfHelp": "固定レートファクタ(CRF)は、x264エンコーダのデフォルトの品質設定です。 0から51までの値を設定できます。値が小さいほど品質が高くなります(ファイルサイズが大きくなりますが)。 正しい値は18から28の間です。x264のデフォルトは23なので、これを出発点として使用できます。", - "H264EncodingPresetHelp": "パフォーマンスを向上させるには小さい値を、品質を向上させるには大きい値を選択してください。", + "EncoderPresetHelp": "パフォーマンスを向上させるには小さい値を、品質を向上させるには大きい値を選択してください。", "HDPrograms": "HD番組", "HandledByProxy": "リバースプロキシで処理", - "HardwareAccelerationWarning": "ハードウェアアクセラレーションを有効にすると、環境によっては不安定になる可能性があります。 オペレーティングシステムとビデオドライバが完全に最新であることを確認してください。 これを有効にした後でビデオの再生が困難な場合は、設定を[自動]に戻す必要があります。", + "HardwareAccelerationWarning": "ハードウェアアクセラレーションを有効にすると、環境によっては不安定になる可能性があります。 オペレーティングシステムとビデオドライバが完全に最新であることを確認してください。 これを有効にした後でビデオの再生が困難な場合は、設定を[なし]に戻す必要があります。", "HeaderAccessSchedule": "アクセススケジュール", "HeaderAccessScheduleHelp": "アクセススケジュールを作成して、アクセスを特定の時間に制限します。", "HeaderActiveDevices": "アクティブデバイス", @@ -541,7 +539,7 @@ "LabelDidlMode": "DIDLモード:", "LabelEmbedAlbumArtDidl": "DIDLのアルバムアートを埋め込む", "LabelFailed": "失敗", - "LabelH264EncodingPreset": "H264エンコーディングプリセット:", + "LabelEncoderPreset": "H264エンコーディングプリセット:", "LabelHardwareAccelerationType": "ハードウェアアクセラレーション:", "LabelH264Crf": "H264エンコーディングCRF:", "LabelHttpsPortHelp": "JellyfinのHTTPSサーバーがバインドするTCPポート番号。", @@ -560,7 +558,7 @@ "LabelOriginalAspectRatio": "元のアスペクト比:", "LabelPrevious": "前へ", "LabelServerName": "サーバー名:", - "LabelSubtitles": "字幕:", + "LabelSubtitles": "字幕", "LabelSupportedMediaTypes": "サポートされているメディアタイプ:", "LabelTVHomeScreen": "TVモードホームスクリーン:", "LabelTextColor": "文字色:", @@ -643,7 +641,6 @@ "OptionDownloadLogoImage": "ロゴ", "OptionEnableAccessToAllChannels": "すべてのチャンネルへのアクセスを有効化", "OptionEnableAccessToAllLibraries": "すべてのライブラリへのアクセスを優幸化", - "OptionEnableAutomaticServerUpdates": "サーバーの自動アップデートを有効化", "OptionWeekly": "週間", "OriginalAirDateValue": "元の公開日: {0}", "RepeatOne": "リピート", @@ -700,7 +697,7 @@ "LabelLoginDisclaimer": "ログイン免責事項:", "LabelSendNotificationToUsers": "通知を送る:", "LabelVideoCodec": "映像コーデック:", - "LabelWeb": "ウェブ: ", + "LabelWeb": "ウェブ:", "LabelYear": "年:", "MediaInfoExternal": "外部", "MediaInfoLanguage": "言語", @@ -861,7 +858,7 @@ "LabelAllowedRemoteAddresses": "リモートIPアドレスフィルター:", "LabelAppNameExample": "例: スケートボード、ソナー", "LabelArtists": "アーティスト:", - "LabelAudio": "音声:", + "LabelAudio": "音声", "LabelAudioBitDepth": "音声ビット深度:", "LabelAudioBitrate": "音声ビットレート:", "LabelAudioChannels": "音声チャンネル:", @@ -966,7 +963,7 @@ "DashboardVersionNumber": "バージョン: {0}", "DashboardServerName": "サーバー: {0}", "DashboardArchitecture": "アーキテクチャ: {0}", - "LabelVideo": "映像:", + "LabelVideo": "映像", "LabelVideoBitrate": "映像ビットレート:", "LabelYourFirstName": "名前:", "Share": "共有", @@ -1116,5 +1113,36 @@ "LabelPreferredDisplayLanguage": "優先する表示言語:", "ImportMissingEpisodesHelp": "有効にすると、所有してないエピソードの情報がJellyfinデータベースにインポートされ、シーズンとシリーズに表示されます。これは、ライブラリスキャンに莫大な時間が掛かる可能性があります。", "LabelBindToLocalNetworkAddress": "ローカルネットワークアドレスにバインド:", - "LabelDownMixAudioScale": "ダウンミキシング時の音声ブースト:" + "LabelDownMixAudioScale": "ダウンミキシング時の音声ブースト:", + "HeaderNavigation": "ナビゲーション", + "CopyStreamURLError": "URLのコピー中にエラーが発生しました。", + "ButtonSplit": "分ける", + "LabelEnableDlnaServer": "DLNAサーバーの有効化", + "LabelEnableDlnaDebugLogging": "DLNAデバッグログの有効化", + "LabelDroppedFrames": "ドロップフレーム:", + "LabelDisplayMissingEpisodesWithinSeasons": "シーズン中の見つからなかったエピソードを表示", + "LabelCustomDeviceDisplayNameHelp": "任意の表示名を提供するか、空白のままにしてデバイスネームで報告する。", + "LabelArtistsHelp": "分けますと使用;", + "Identify": "識別する", + "TabRecordings": "録画", + "Recordings": "録画", + "RecordingScheduled": "録画をスケジュールしました。", + "RecordingCancelled": "録画をキャンセルしました。", + "LabelMaxChromecastBitrate": "Chromecastのストリーミング品質:", + "LabelImportOnlyFavoriteChannels": "お気に入りのチャンネルだけ", + "LabelIdentificationFieldHelp": "大文字小文字を区別しない部分文字列や正規表現です。", + "LabelCustomRating": "カスタム格付け:", + "LabelCorruptedFrames": "破損したフレーム:", + "LabelFriendlyName": "フレンドリ名:", + "LabelEveryXMinutes": "毎:", + "LabelEnableSingleImageInDidlLimit": "単一の埋め込み画像に制限", + "LabelEnableBlastAliveMessages": "アライブメッセージを配信する", + "LabelDateAddedBehaviorHelp": "メタデータある場合、これらのオプションの前にメタデータ使います。", + "AskAdminToCreateLibrary": "管理者にライブラリを作成する依頼をしてください。", + "AllowFfmpegThrottling": "トランスコードをスロットルする", + "Episode": "エピソード", + "ClientSettings": "クライアント設定", + "Artist": "アーティスト", + "AlbumArtist": "アルバム アーティスト", + "Album": "アルバム" } diff --git a/src/strings/kk.json b/src/strings/kk.json index 45025bb1bd..a31d2b3758 100644 --- a/src/strings/kk.json +++ b/src/strings/kk.json @@ -15,7 +15,7 @@ "Alerts": "Eskertýler", "All": "Bári", "AllChannels": "Barlyq arnalar", - "AllComplexFormats": "Barlyq kúrdeli pishimderi (ASS, SSA, VOBSUB, PGS, SUB/IDX jáne t.b.)", + "AllComplexFormats": "Barlyq kúrdeli pishimder (ASS, SSA, VOBSUB, PGS, SUB jáne IDX)", "AllEpisodes": "Barlyq bólimder", "AllLanguages": "Barlyq tilder", "AllLibraries": "Barlyq tasyǵyshhanalar", @@ -27,7 +27,7 @@ "AllowRemoteAccess": "Osy Jellyfin Serverine syrtqy qosylymdar úshin ruqsat etý.", "AllowRemoteAccessHelp": "Eger jalaýsha alastalǵan bolsa, baryq syrtqy baılanystar qursaýlanady.", "AllowedRemoteAddressesHelp": "Qashyqtan qosylýǵa ruqsat etiletin jeliler úshin útirlermen bólingen IP-mekenjaılarynyń tizbesi nemese IP/netmask jazbalar Eger bos qaldyrylsa, barlyq qashyqtaǵy mekenjaılarǵa ruqsat etiledi.", - "AlwaysPlaySubtitles": "Sýbtıtrlerdi árqashan oınatý", + "AlwaysPlaySubtitles": "Árqashan oınatý", "AlwaysPlaySubtitlesHelp": "Til teńshelimine sáıkes kelgen sýbtıtrler dybys tiline qatyssyz júkteledi.", "AnamorphicVideoNotSupported": "Anamorftyq beıne úshin qoldaý kórsetilmeıdi", "AndroidUnlockRestoreHelp": "Aldyńǵy satyp alýdy qalpyna keltirý úshin, bastapqyda satyp alý jasalǵan naq sol Google (nemese Amazon) tirkelgisimen qurylǵyǵa kirińiz. Qoldanba dúkeni qosylǵan jáne kezkelgen ata-ana shekteýsiz, jáne belsendi ınternet baılanysy bar ekenine kóz jetkizińiz. Aldyńǵy satyp alý qalpyna keltirý úshin muny tek qana bir ret isteý kerek.", @@ -56,7 +56,7 @@ "BoxRear": "Qorap arty", "Browse": "Sharlaý", "BrowsePluginCatalogMessage": "Qoljetimdi plagındermen tanysý úshin plagın tizimdemesin sholyńyz.", - "BurnSubtitlesHelp": "Sýbtıtrler pishimine baılanysty beıneni túrlendirgen kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Sýbtıtrler jazýdy qashqaqtaý serverdiń ónimdiligin jaqsartady. Sýretke negizdelgen pishimderdi (VOBSUB, PGS, SUB/IDX j.t.b.) jáne keıbir ASS/SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz.", + "BurnSubtitlesHelp": "Beıneni qaıta kodtaǵan kezde server sýbtıtrlerdi jazyýyn anyqtaıdy. Onan qashqaqtaý serverdiń ónimdiligin biraz jaqsartady. Sýretke negizdelgen pishimderdi (VOBSUB, PGS, SUB jáne IDX) jáne keıbir ASS nemese SSA sýbtıtrlerin jazý úshin Avtomattyny tańdańyz.", "ButtonAdd": "Ústeý", "ButtonAddMediaLibrary": "Tasyǵyshhana ústeý", "ButtonAddScheduledTaskTrigger": "Trıger ústeý", @@ -188,8 +188,7 @@ "DirectStreamHelp2": "Faıldy tikeleı taratý beıne sapasyn joǵaltpaı óte az esepteý qýatyn paıdalanady.", "DirectStreaming": "Tikeleı tasymaldanýda", "Director": "Rejısór", - "DirectorValue": "Rejısóri: {0}", - "DirectorsValue": "Rejısórler; {0}", + "Directors": "Rejısórler", "Disabled": "Ajyratylǵan", "Disc": "Dıski", "Disconnect": "Ajyratý", @@ -199,7 +198,7 @@ "DisplayInOtherHomeScreenSections": "Basqy ekran bólimderinde beıneleý (mys. Eń sońǵy tasyǵyshderekter jáne Kórýdi jalǵastyrý)", "DisplayMissingEpisodesWithinSeasons": "Joq bólimderdi maýsym ishinde beıneleý", "DisplayMissingEpisodesWithinSeasonsHelp": "Bul sondaı-aq server konfıgýrasýasyndaǵy TD tasyǵyshhanalary úshin qosýlýy qajet.", - "DisplayModeHelp": "Jellyfin iske qosylǵanda ekran túrin tańdańyz.", + "DisplayModeHelp": "Interfeıs úshin laıyqty ornalasý mánerin tańdańyz.", "DoNotRecord": "Jazýǵa bolmaıdy", "Down": "Tómenge", "Download": "Júktep alý", @@ -235,7 +234,7 @@ "ErrorAddingListingsToSchedulesDirect": "Schedules Direct tirkelgińizge tizbek ústeý kezinde qate oryn aldy. Schedules Direct tirkelgisinde tizbekterdiń tek qana shekteýli sany rýqsat etiledi. Oryndamas buryn Schedules Direct saıtyna kirip jáne tirkelgiden basqa tizbelerdi alastaý qajet bolýy múmkin.", "ErrorAddingMediaPathToVirtualFolder": "Tasyǵyshderekter jolyn ústegen kezinde qate oryn aldy. Jol durys ekenine jáne Jellyfin Server prosesi osy jaıǵasymǵa qatynaıtyna kóz jetkizińiz.", "ErrorAddingTunerDevice": "Túner qurylǵysyn ústeý kezinde qate oryn aldy. Bul qatynaýly ekenine kóz jetkizińiz de áreketti qaıtalańyz.", - "ErrorAddingXmlTvFile": "XmlTV faılyna qatynaý kezinde qate oryn aldy. Faıl bar bolýyna kóz jetkizińiz de áreketti qaıtalańyz.", + "ErrorAddingXmlTvFile": "XMLTV-faılyna qatynaý kezinde qate oryn aldy. Faıl bar bolýyna kóz jetkizińiz de áreketti qaıtalańyz.", "ErrorDeletingItem": "Jellyfin Server elementin joıý kezinde qate oryn aldy. Jellyfin Server tasyǵysh qaltasyna jazýǵa ruqsaty bar ekenin tekserip, qaıtalap kórińiz.", "ErrorGettingTvLineups": "TD kezekterin júktep alý kezinde qate oryn aldy. Málimetterińiz durys ekenine kóz jetkizińiz de áreketti qaıtalańyz.", "ErrorMessageStartHourGreaterThanEnd": "Aıaqtalý ýaqyty bastaý ýaqytynan keıinrek bolýy qajet etedi.", @@ -267,9 +266,8 @@ "Friday": "juma", "Fullscreen": "Tolyq ekran", "General": "Jalpy", - "GenreValue": "Janr: {0}", + "Genre": "Janr", "Genres": "Janrlar", - "GenresValue": "Janrlar: {0}", "GroupBySeries": "Telehıkaıalar boıynsha toptastyrý", "GroupVersions": "Nusqalardy toptastyrý", "GuestStar": "Shaqyrylǵan aktór", @@ -277,10 +275,10 @@ "GuideProviderLogin": "Kirý", "GuideProviderSelectListings": "Tizbelerdi tańdaý", "H264CrfHelp": "Baǵalaýdyń turaqty máni (Constant Rate Factor, CRF) x264 kodtaýyshy úshin ádepki sapa parametri bolyp tabylady. Siz 0 jáne 51 arasyndaǵy mánderin belgileı alasyz, onda tómen mánder (joǵary faıl ólshemderi esebinen) nátıjesinde jaqsy sapaǵa keltiredi. Taǵylyp mánder 18 jáne 28 arasynda bolady. x264 úshin ádepkisi 23 bolyp tabylady, sondyqtan bastaý núktesi retinde osyny paıdalanýyńyzǵa bolady.", - "H264EncodingPresetHelp": "Ónimdilikti jaqsartý úshin jyldam mánin, nemese sapasyn jaqsartý úshin baıaý mánin tańdańyz.", + "EncoderPresetHelp": "Ónimdilikti jaqsartý úshin jyldam mánin, nemese sapasyn jaqsartý úshin baıaý mánin tańdańyz.", "HDPrograms": "HD-kórsetimder", "HandledByProxy": "Keri proksı arqyly óńdeldi", - "HardwareAccelerationWarning": "Apparattyq jedeldetýdi qosý keıbir ortalarda turaqsyzdyq týdyrýy múmkin. Amaldyq júıeńiz ben beıne draıverlerińiz tolyq jańartylǵanyna kóz jetkizińiz. Eger osyny qosqannan keıin beıne oınatýda qıyndyq bolsa, parametrdi qaıta Avto úshin ózgertýińiz qajet.", + "HardwareAccelerationWarning": "Apparattyq jedeldetýdi qosý keıbir ortalarda turaqsyzdyq týdyrýy múmkin. Amaldyq júıeńiz ben beıne draıverlerińiz tolyq jańartylǵanyna kóz jetkizińiz. Eger osyny qosqannan keıin beıne oınatýda qıyndyq bolsa, parametrdi qaıta Eshqanadaǵa ózgertýińiz qajet.", "HeaderAccessSchedule": "Qatynaý kestesi", "HeaderAccessScheduleHelp": "Qatynaýdy belgili saǵattarǵa shekteý úshin qatynaý kestesin jasańyz.", "HeaderActiveDevices": "Belsendi qurylǵylar", @@ -505,7 +503,7 @@ "Images": "Sýretter", "ImportFavoriteChannelsHelp": "Qosylǵanda, túner qurylǵysyndaǵy tańdaýly retinde belgilengen ǵana arnalar shetten ákelinetin bolady.", "ImportMissingEpisodesHelp": "Qosylǵanda, joq epızodtar týraly aqparat sizdiń Jellyfin derekqorǵa ákelinedi jáne maýsymdar men telehıkaıalar aıasynda paıda bolady. Tasyǵyshhana skanerleýde bul aıtarlyqtaı uzaq ýaqyt alýy múmkin.", - "InstallingPackage": "{0} ornatylýda", + "InstallingPackage": "{0} ({1} nusqasy) ornatylýda", "InstantMix": "Lezdik qospalaý", "ItemCount": "{0} tarmaq", "Items": "Tarmaqtar", @@ -538,7 +536,7 @@ "LabelAppNameExample": "Mysaly: Sickbeard, Sonarr", "LabelArtists": "Oryndaýshylar:", "LabelArtistsHelp": "Birneshýin mynaýmen bólińiz ;", - "LabelAudio": "Dybys:", + "LabelAudio": "Dybys", "LabelAudioLanguagePreference": "Dybys tiliniń teńshelimi:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Metaderekterdi Internetten avtomatty jańartý:", "LabelBindToLocalNetworkAddress": "Jergilikti jeli mekenjaıyna baılastyrý:", @@ -602,7 +600,7 @@ "LabelEmbedAlbumArtDidl": "DIDL ishine álbom sýretin endirý", "LabelEmbedAlbumArtDidlHelp": "Álbom sýretin alý úshin keıbir qurylǵylar osy ádisti qalaıdy. Basqalar úshin, osy opsıa qosylǵanda, oınatý sátsiz bolýy múmkin.", "LabelEnableAutomaticPortMap": "Avtomatty port salǵastyrýyn qosý", - "LabelEnableAutomaticPortMapHelp": "Jarıa portty jergilikti portqa UPnP arqyly avtomatty salǵastyrý áreketi. Bul keıbir jol josparlaǵysh ulgilerimen jumys istemeıtini múmkin.", + "LabelEnableAutomaticPortMapHelp": "Jarıa portty jergilikti portqa UPnP arqyly avtomatty salǵastyrý áreketi. Bul keıbir jol josparlaǵysh ulgilerimen jumys istemeıtini múmkin. Ózgerister server qaıta iske qosylǵansha deıin qoldanylmaıdy.", "LabelEnableBlastAliveMessages": "Belsendilikti tekserý habarlaryn jaýdyrý", "LabelEnableBlastAliveMessagesHelp": "Eger jelidegi basqa UPnP qurylǵylarymen server nyq tabylmasa buny qosyńyz.", "LabelEnableDlnaClientDiscoveryInterval": "Klıentterdi taýyp ashý aralyǵy, s", @@ -635,9 +633,9 @@ "LabelGroupMoviesIntoCollections": "Jıyntyqtar ishindegi fılmderdi toptastyrý", "LabelGroupMoviesIntoCollectionsHelp": "Fılm tizimderin beınelegen kezde jıyntyqqa kiretin fılmder toptalǵan biryńǵaı tarmaq bolyp kórsetiledi.", "LabelH264Crf": "H264 kodtaý CRF máni:", - "LabelH264EncodingPreset": "H264 kodtaý daıyndamasy:", + "LabelEncoderPreset": "H264 kodtaý daıyndamasy:", "LabelHardwareAccelerationType": "Apparatyq jedeldetý:", - "LabelHardwareAccelerationTypeHelp": "Bul tájirıbelik múmkindik tek qoldaý kórsetiletin júıelerde qoljetimdi.", + "LabelHardwareAccelerationTypeHelp": "Apparattyq jedeldetý úshin qosymsha konfıgýrasýa qajet.", "LabelHomeNetworkQuality": "Úılik jeli sapasy:", "LabelHomeScreenSectionValue": "Basqy bet {0}-bólim:", "LabelHttpsPort": "Jergilikti HTTPS-port nómiri:", @@ -674,7 +672,7 @@ "LabelLoginDisclaimer": "Kirgendegi eskertý:", "LabelLoginDisclaimerHelp": "Kirý beti tómengi jaǵynda beınelenetin habar.", "LabelLogs": "Jurnaldar:", - "LabelManufacturer": "Óndirýshi", + "LabelManufacturer": "Óndirýshi:", "LabelManufacturerUrl": "Óndirýshi URL mekenjaıy", "LabelMatchType": "Sáıkes túri:", "LabelMaxBackdropsPerItem": "Tarmaq boıynsha artqy sýretterdiń eń kóp sany:", @@ -713,7 +711,7 @@ "LabelMoviePrefixHelp": "Eger fılmderdiń ataýynda prefıks qoldanylsa, server durys óńdeı alý úshin buny munda engizińiz.", "LabelMovieRecordingPath": "Fılm jazbalardyń joly (mindetti emes):", "LabelMusicStreamingTranscodingBitrate": "Mýzykany qaıta kodtaý qarqyny:", - "LabelMusicStreamingTranscodingBitrateHelp": "Mýzyka tasymaldaný kezinde eń joǵary qarqyndy anyqtańyz", + "LabelMusicStreamingTranscodingBitrateHelp": "Mýzyka tasymaldaný kezinde eń joǵary qarqyndy anyqtańyz.", "LabelName": "Aty:", "LabelNewName": "Jańa aty:", "LabelNewPassword": "Jańa paról:", @@ -809,7 +807,7 @@ "LabelSubtitleDownloaders": "Sýbtıtrler júkteýshileri:", "LabelSubtitleFormatHelp": "Mysal: srt", "LabelSubtitlePlaybackMode": "Sýbtıtr rejimi:", - "LabelSubtitles": "Sýbtıtrler:", + "LabelSubtitles": "Sýbtıtrler", "LabelSupportedMediaTypes": "Qoldaýdaǵy tasyǵyshderekter túrleri:", "LabelTVHomeScreen": "TD rejimindegi basqy ekran:", "LabelTag": "Teg:", @@ -851,7 +849,7 @@ "LabelVersion": "Nusqa:", "LabelVersionInstalled": "{0} ornatylǵan", "LabelVersionNumber": "Nýsqasy: {0}", - "LabelVideo": "Beıne:", + "LabelVideo": "Beıne", "LabelXDlnaCap": "X-DLNA sıpattary:", "LabelXDlnaCapHelp": "urn:schemas-dlna-org:device-1-0 ataýlar keńistigindegi X_DLNACAP elementi mazmunyn anyqtaıdy.", "LabelXDlnaDoc": "X-DLNA tásimi:", @@ -988,16 +986,16 @@ "NoNextUpItemsMessage": "Eshteńe tabylmady. Kórsetimderińizdi qaraı bastańyz!", "NoPluginConfigurationMessage": "Osy plagınde teńsheletin parametrler joq.", "NoSubtitleSearchResultsFound": "Eshqandaı nátıjeler tabylmady.", - "NoSubtitles": "Sýbtıtrlersiz", + "NoSubtitles": "Eshqandaı", "NoSubtitlesHelp": "Ádepkide sýbtıtrler júktelmeıdi. Olardy oınatý kezinde áli de qolmen qosýǵa bolady.", "None": "Eshqandaı", "Normal": "Kádimgi", "NumLocationsValue": "{0} qalta", "Off": "Óshir", "OneChannel": "Bir arnadan", - "OnlyForcedSubtitles": "Tek qana májbúrli sýbtıtrler", + "OnlyForcedSubtitles": "Tek qana májbúrli", "OnlyForcedSubtitlesHelp": "Tek qana májbúrli dep belgilengen sýbtıtrler júkteledi.", - "OnlyImageFormats": "Tek keskin pishimder (VOBSUB, PGS, SUB j.t.b.)", + "OnlyImageFormats": "Tek keskin pishimder (VOBSUB, PGS jáne SUB)", "Open": "Ashý", "OptionActor": "Aktór", "OptionActors": "Aktórler", @@ -1065,7 +1063,6 @@ "OptionEnableAccessFromAllDevices": "Barlyq qurylǵylardan qatynaýdy qosý", "OptionEnableAccessToAllChannels": "Barlyq arnalarǵa qatynaýdy qosý", "OptionEnableAccessToAllLibraries": "Barlyq tasyǵyshhanalarǵa qatynaýdy qosý", - "OptionEnableAutomaticServerUpdates": "Serverdiń avtomatty jańartylýyn qosý", "OptionEnableExternalContentInSuggestions": "Uynystarǵa syrtqy mazmundy qosý", "OptionEnableExternalContentInSuggestionsHelp": "Internet-treılerler men efırlik kórsetimderge usynǵan mazmunǵa kirý úshin ruqsat etedi.", "OptionEnableForAllTuners": "Barlyq túner qurylǵylary úshin qosý", @@ -1141,9 +1138,9 @@ "OptionWeekly": "Apta saıyn", "OriginalAirDateValue": "Bastapqy efır: {0}", "Overview": "Jalpy sholý", - "PackageInstallCancelled": "{0} ornatylýy boldyrylmady.", - "PackageInstallCompleted": "{0} ornatylýy aıaqtaldy.", - "PackageInstallFailed": "{0} ornatylýy sátsiz.", + "PackageInstallCancelled": "{0} ({1} nusqasy) ornatylýy boldyrylmady.", + "PackageInstallCompleted": "{0} ({1} nusqasy) ornatylýy aıaqtaldy.", + "PackageInstallFailed": "{0} ({1} nusqasy) ornatylýy sátsiz.", "ParentalRating": "Jastas sanaty", "PasswordMatchError": "Paróli men Paróldi rastaý óristeri sáıkes bolý kerek.", "PasswordResetComplete": "Paról ysyryldy.", @@ -1402,7 +1399,7 @@ "XmlTvKidsCategoriesHelp": "Osy sanattaǵy baǵdarlamalar balalyq baǵdarlamary retinde beınelenedi. Birneshýin '|' arqyly bólińiz.", "XmlTvMovieCategoriesHelp": "Osy sanattaǵy baǵdarlamalar fılmder retinde beınelenedi. Birneshýin '|' arqyly bólińiz.", "XmlTvNewsCategoriesHelp": "Osy sanattaǵy baǵdarlamalar jańalyq baǵdarlamary retinde beınelenedi. Birneshýin '|' arqyly bólińiz.", - "XmlTvPathHelp": "XML TV faılynyń joly. Jellyfin osy faıldy oqıdy jáne ony jańartýlar úshin mezgilinde tekserip shyǵady. Faıldy jasaý jáne jańartý úshin ózińiz jaýapty bolyp tabylasyz.", + "XmlTvPathHelp": "XMLTV-faılynyń joly. Jellyfin osy faıldy oqıdy jáne ony jańartýlar úshin mezgilinde tekserip shyǵady. Faıldy jasaý jáne jańartý úshin ózińiz jaýapty bolyp tabylasyz.", "XmlTvSportsCategoriesHelp": "Osy sanattaǵy baǵdarlamalar sporttyq baǵdarlamary retinde beınelenedi. Birneshýin '|' arqyly bólińiz.", "Yes": "Iá", "Yesterday": "Keshe", @@ -1432,7 +1429,7 @@ "DashboardServerName": "Server: {0}", "DashboardOperatingSystem": "Operasıalyq júıe: {0}", "DashboardArchitecture": "Arhıtektýrasy: {0}", - "LabelWeb": "Ýeb: ", + "LabelWeb": "Ýeb:", "LaunchWebAppOnStartup": "Serverdi iske qosqan kezde ýeb-ınterfeısti iske qosý", "LaunchWebAppOnStartupHelp": "Server bastapqyda iske qosylǵan kezde, ýeb-klıent ádepki sholǵyshta ashylady. Bul serverdi qaıta iske qosý fýnksıasyn qoldanǵanda oryn almaıdy.", "MediaInfoSoftware": "Baǵdarlamalyq jasaqtama", @@ -1486,5 +1483,53 @@ "FetchingData": "Qosymsha derekterdi shyǵaryp alý", "ButtonAddImage": "Sýret ústeý", "MusicLibraryHelp": "{0}Mýzyka ataý nusqaýlyǵyn{1} qarap shyǵý.", - "HeaderFavoritePeople": "Tańdaýly adamdar" + "HeaderFavoritePeople": "Tańdaýly adamdar", + "NoCreatedLibraries": "Eshqandaı tasyǵyshhanany jasamaǵanyńyz sıaqty. {0}Qazir bireýin jasaısyz ba?{1}", + "SelectAdminUsername": "Ákimshi tirkelgisi úshin paıdalanýshy atyn tańdańyz.", + "OptionRandom": "Kezdeısoq", + "OptionForceRemoteSourceTranscoding": "Alystaǵy tasyǵyshderekter kózin qaıta kodtaýdy májbúrleý (efırlik TD sıaqty)", + "MessageConfirmAppExit": "Shyǵýdy qalaısyz ba?", + "LabelVideoResolution": "Beıne ajyratymdylyǵy:", + "LabelStreamType": "Aǵyn túri:", + "EnableFastImageFadeInHelp": "Júktelgen sýretter úshin shapshan kórsetilýin qosý", + "EnableFastImageFadeIn": "Sýrettiń shapshan kórsetilýi", + "LabelPlayerDimensions": "Oınatqysh ólshemderi:", + "LabelDroppedFrames": "Ótkizilgen kadrlar:", + "LabelCorruptedFrames": "Búlingen kadrlar:", + "HeaderNavigation": "Sharlaý", + "CopyStreamURLError": "URL kóshirgende qate oryn aldy.", + "ButtonSplit": "Bólý", + "AskAdminToCreateLibrary": "Tasýǵyshanany jasaý úshin ákimshiden suraý.", + "AllowFfmpegThrottling": "Qaıta kodtaýdy retteý", + "PlaybackErrorNoCompatibleStream": "Bul klıent tasyǵysh derektermen úılesimsiz jáne server úılesimdi pishiminde tasyǵysh derekterin jibermedi.", + "AllowFfmpegThrottlingHelp": "Qaıta kodtaý nemese qaıta býmalaý aǵymdyq oınatý jaıǵasymynan edáýir alǵa ozǵanda, qor kózderin azdaý tutynatyndaı etip údiristi kidirtedi. Bul jıi izdemeı qaraý kezinde paıdaly. Eger oınatý máseleleri bolsa, ony óshirińiz.", + "Album": "Álbom", + "DeinterlaceMethodHelp": "Jol aralyq jaımaly mazmundy qaıta kodtaý kezinde paıdalaný úshin jol aralyq jaımany joıý ádisin tańdańyz.", + "LabelDeinterlaceMethod": "Jol aralyq jaımany joıý ádisi:", + "YadifBob": "YADIF eki eseleýimen", + "OnApplicationStartup": "Qoldanba iske qosylǵanda", + "EveryXHours": "Ár {0} saǵ", + "EveryHour": "Ár saǵat", + "EveryXMinutes": "Ár {0} mın", + "OnWakeFromSleep": "Uıqylyqtan oıanǵanda", + "WeeklyAt": "{0} {1} kezinde", + "DailyAt": "Kúnde {0} kezinde", + "LastSeen": "Sońǵy kóringeni {0}", + "PersonRole": "- {0}", + "ListPaging": "{0}-{1} {2} ishinen", + "Yadif": "YADIF", + "Track": "Jolshyq", + "Season": "Maýsym", + "ReleaseGroup": "Shyǵarýshy top", + "Person": "Tulǵa", + "OtherArtist": "Basqa oryndaýshy", + "Movie": "Fılm", + "LabelLibraryPageSize": "Tasyǵyshhana betiniń ólshemi:", + "Episode": "Bólim", + "ClientSettings": "Týtynýshy parametrleri", + "ButtonTogglePlaylist": "Oýnatý tizimi", + "ButtonToggleContextMenu": "Kúbirek", + "BoxSet": "Jıyntyq", + "Artist": "Ornatýshy", + "AlbumArtist": "Álbom ornatýshysy" } diff --git a/src/strings/ko.json b/src/strings/ko.json index e6e54557af..33c44334ae 100644 --- a/src/strings/ko.json +++ b/src/strings/ko.json @@ -94,7 +94,7 @@ "DeleteMedia": "미디어 제거", "DeleteUser": "사용자 제거", "DeleteUserConfirmation": "이 사용자를 제거하겠습니까?", - "DeviceAccessHelp": "이것은 고유하게 식별할 수 있고 브라우저 접근을 방해하지 않는 장치에만 적용됩니다. 사용자 장치 접근을 필터링하면 여기에서 승인될 때까지 새 장치를 사용할 수 없게 됩니다.", + "DeviceAccessHelp": "이것은 고유하게 식별할 수 있는 장치에만 적용되므로 브라우저를 통한 접근은 차단할 수 없습니다. 사용자 장치 접근을 필터링하면 이곳에서 승인될 때까지 새 장치를 사용할 수 없게 됩니다.", "Director": "감독", "Dislike": "싫어요", "Download": "다운로드", @@ -209,7 +209,7 @@ "HeaderRemoteControl": "원격 제어", "HeaderRemoveMediaFolder": "미디어 폴더 제거", "HeaderRemoveMediaLocation": "미디어 위치 제거", - "HeaderResponseProfile": "프로필 회신", + "HeaderResponseProfile": "응답 프로파일", "HeaderRestart": "다시 시작", "HeaderRevisionHistory": "리비전 이력", "HeaderRunningTasks": "실행중인 작업", @@ -231,7 +231,7 @@ "HeaderSetupLibrary": "미디어 라이브러리 설정", "HeaderShutdown": "종료", "HeaderSpecialEpisodeInfo": "스페셜 에피소드 정보", - "HeaderSpecialFeatures": "특수 기능", + "HeaderSpecialFeatures": "특별 배역", "HeaderStatus": "상태", "HeaderSubtitleProfile": "자막 프로필", "HeaderSubtitleProfilesHelp": "자막 프로필은 장치에서 지원하는 자막 형식을 나타냅니다.", @@ -256,7 +256,7 @@ "Images": "이미지", "ImportFavoriteChannelsHelp": "활성화 시, 튜너 장치에서 즐겨찾기로 표시된 채널만 불러옵니다.", "ImportMissingEpisodesHelp": "이 기능을 사용하면 누락 된 에피소드에 대한 정보가 Jellyfin 데이터베이스로 가져와 시즌 및 시리즈 내에서 표시됩니다. 이로 인해 상당히 긴 라이브러리 스캔이 발생할 수 있습니다.", - "InstallingPackage": "{0} 설치 중", + "InstallingPackage": "{0} 설치 중 ( {1} 버전)", "InstantMix": "인스턴트 믹스", "ItemCount": "{0} 항목", "Label3DFormat": "3D 포맷:", @@ -295,14 +295,14 @@ "LabelCriticRating": "평론가 평점:", "LabelCurrentPassword": "현재 비밀번호:", "LabelCustomCertificatePath": "사용자 지정 SSL 인증서 경로:", - "LabelCustomCertificatePathHelp": "자기 소유의 SSL 인증서을 제공하십시오. PFX 파일 형식이어야 합니다.", + "LabelCustomCertificatePathHelp": "커스텀 도메인에서 TLS를 지원할 수 있도록 인증서 및 개인키가 포함 된 PKCS #12 파일의 경로입니다.", "LabelCustomCss": "사용자 지정 CSS:", "LabelCustomCssHelp": "사용자 정의 스타일링을 웹 인터페이스에 적용합니다.", "LabelCustomDeviceDisplayName": "표시 이름:", "LabelCustomRating": "사용자 평점:", "LabelDateAdded": "추가한 날짜:", "LabelDateAddedBehavior": "새 콘텐츠에 대한 날짜 추가 동작:", - "LabelDateAddedBehaviorHelp": "메타데이터에 지정된 값이 있으면 이 옵션에 우선하여 사용합니다.", + "LabelDateAddedBehaviorHelp": "메타데이터에 지정된 값이 있으면 항상 이 옵션들에 우선하여 사용됩니다.", "LabelDay": "날짜:", "LabelDeathDate": "사망일:", "LabelDefaultUser": "기본 사용자:", @@ -310,9 +310,9 @@ "LabelDeviceDescription": "장치 설명", "LabelDidlMode": "DIDL 모드:", "LabelDisplayMissingEpisodesWithinSeasons": "각 시즌의 누락된 에피소드 표시", - "LabelDisplayName": "디스플레이 이름:", - "LabelDisplayOrder": "디스플레이 순서:", - "LabelDisplaySpecialsWithinSeasons": "방송한 시즌 내의 스페셜을 표시합니다", + "LabelDisplayName": "표시 이름:", + "LabelDisplayOrder": "표시 순서:", + "LabelDisplaySpecialsWithinSeasons": "방송한 시즌 내에서 스페셜을 표시합니다", "LabelDownMixAudioScale": "다운믹싱할 때 오디오 증폭:", "LabelDownMixAudioScaleHelp": "다운믹싱할 때 오디오를 증폭합니다. 원래 음량을 유지하려면 1로 설정하세요.", "LabelDownloadLanguages": "다운로드 언어:", @@ -320,7 +320,7 @@ "LabelEmbedAlbumArtDidl": "DIDL에 앨범 아트 삽입", "LabelEnableAutomaticPortMap": "자동 포트 맵핑 사용", "LabelEnableDlnaClientDiscoveryInterval": "클라이언트 탐색 간격 (초)", - "LabelEnableDlnaClientDiscoveryIntervalHelp": "Jellyfin이 수행한 SSDP검색 간의 시간 간격(초)을 결정합니다.", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Jellyfin이 수행하는 SSDP 검색 간격(초)을 결정합니다.", "LabelEnableDlnaDebugLogging": "DNLA 디버그 로그 사용", "LabelEnableDlnaDebugLoggingHelp": "매우 큰 로그 파일을 생성합니다. 문제해결을 위해 필요한 경우에만 사용하여야 합니다.", "LabelEnableDlnaPlayTo": "다음에서 DNLA 재생 사용:", @@ -331,7 +331,7 @@ "LabelEnableRealtimeMonitorHelp": "지원하는 파일 시스템에서는 변경 사항이 즉시 실행됩니다.", "LabelEndDate": "종료일 :", "LabelEvent": "이벤트:", - "LabelEveryXMinutes": "매일 :", + "LabelEveryXMinutes": "마다:", "LabelExtractChaptersDuringLibraryScan": "라이브러리를 스캔할 때 챕터 이미지 추출", "LabelExtractChaptersDuringLibraryScanHelp": "라이브러리를 스캔하여 비디오를 가져올 때 챕터 이미지를 생성합니다. 옵션을 끄면 챕터 이미지 예약 작업 중에 생성되어 일반 라이브러리 스캔이 더 빨리 완료될 수 있습니다.", "LabelFailed": "실패", @@ -343,7 +343,7 @@ "LabelGroupMoviesIntoCollections": "컬렉션으로 영화 묶기", "LabelGroupMoviesIntoCollectionsHelp": "영화 목록을 표시할 때 컬렉션에 포함된 영화가 한 개로 묶여진 항목으로 보여줍니다.", "LabelHardwareAccelerationType": "하드웨어 가속:", - "LabelHardwareAccelerationTypeHelp": "지원하는 시스템에서만 사용할 수 있습니다.", + "LabelHardwareAccelerationTypeHelp": "하드웨어 가속은 추가 설정이 필요합니다.", "LabelHttpsPort": "로컬 HTTPS 포트 번호:", "LabelHttpsPortHelp": "Jellyfin의 HTTPS 서버가 바인딩해야하는 TCP포트 번호", "LabelIconMaxHeight": "아이콘 최대 높이:", @@ -366,7 +366,7 @@ "LabelLoginDisclaimer": "로그인 고지사항:", "LabelLoginDisclaimerHelp": "로그인 페이지 하단에 표시할 메세지", "LabelLogs": "로그:", - "LabelManufacturer": "제작사", + "LabelManufacturer": "제작사:", "LabelManufacturerUrl": "제작사 URL", "LabelMaxBackdropsPerItem": "항목별 최대 배경 이미지 수:", "LabelMaxParentalRating": "최대 허용 연령:", @@ -379,7 +379,7 @@ "LabelMetadataDownloadersHelp": "선호하는 메타데이터 다운로더를 우선 순위에 따라 정렬합니다. 낮은 우선 순위의 다운로더는 누락된 정보를 가져오는 데만 사용합니다.", "LabelMetadataPath": "메타데이터 경로:", "LabelMetadataPathHelp": "다운로드한 아트워크와 메타데이터를 저장할 위치를 지정합니다.", - "LabelMetadataSavers": "메타데이터 보호기:", + "LabelMetadataSavers": "메타데이터 저장기:", "LabelMetadataSaversHelp": "메타데이터를 저장할 형식을 선택합니다.", "LabelMethod": "방법:", "LabelMinBackdropDownloadWidth": "다운로드할 배경 이미지 최소 넓이:", @@ -391,7 +391,7 @@ "LabelMonitorUsers": "다음의 활동 모니터링:", "LabelMovieRecordingPath": "영화 녹화 경로 (옵션):", "LabelMusicStreamingTranscodingBitrate": "음악 트랜스코딩 비트레이트:", - "LabelMusicStreamingTranscodingBitrateHelp": "음악 스트리밍 시 최대 비트 전송률 지정", + "LabelMusicStreamingTranscodingBitrateHelp": "음악 스트리밍 시 최대 비트 전송률을 지정합니다.", "LabelName": "이름:", "LabelNewName": "새 이름:", "LabelNewPassword": "새 비밀번호:", @@ -455,7 +455,7 @@ "LabelTrackNumber": "트랙 번호:", "LabelTranscodingAudioCodec": "오디오 코덱:", "LabelTranscodingContainer": "컨테이너:", - "LabelTranscodingTempPathHelp": "", + "LabelTranscodingTempPathHelp": "클라이언트로 제공될 트랜스코딩 파일이 위치한 사용자 경로를 설정합니다. 서버 기본값을 사용하려면 공백으로 두십시오.", "LabelTranscodingVideoCodec": "비디오 코덱:", "LabelTriggerType": "트리거 종류:", "LabelTunerIpAddress": "튜너 IP 주소:", @@ -472,7 +472,7 @@ "LabelYoureDone": "완료!", "LabelZipCode": "우편 번호:", "LibraryAccessHelp": "이 사용자와 공유할 라이브러리를 선택합니다. 관리자는 메타데이터 관리자를 사용하여 모든 폴더를 수정할 수 있습니다.", - "Like": "좋아함", + "Like": "좋아요", "Live": "라이브", "MaxParentalRatingHelp": "더 높은 연령 등급의 콘텐츠가 이 사용자에게 표지 되지 않습니다.", "MediaInfoAnamorphic": "아나몰픽", @@ -585,7 +585,6 @@ "OptionEnableAccessFromAllDevices": "모든 기기에서 접속 허용", "OptionEnableAccessToAllChannels": "모든 채널에 접속 허용", "OptionEnableAccessToAllLibraries": "모든 라이브러리에 접속 허용", - "OptionEnableAutomaticServerUpdates": "서버 자동 업데이트 사용", "OptionEnableM2tsMode": "M2ts 모드 활성화", "OptionEnded": "종료됨", "OptionEveryday": "매일", @@ -811,7 +810,7 @@ "AirDate": "방영 일자", "Aired": "방영됨", "Alerts": "알림", - "AllComplexFormats": "모든 복잡한 포맷 (ASS, SSA, VOBSUB, PGS, SUB/IDX 등)", + "AllComplexFormats": "모든 복잡한 포맷 (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AllLibraries": "모든 라이브러리", "AllowMediaConversion": "미디어 변환 허용", "AllowOnTheFlySubtitleExtraction": "실시간 자막 추출 허용", @@ -819,7 +818,7 @@ "AllowRemoteAccess": "이 Jellyfin 서버에 원격 접속을 허용합니다.", "AllowRemoteAccessHelp": "체크 해제 시 모든 외부 접속은 차단됩니다.", "AllowedRemoteAddressesHelp": "외부 접속을 허용할 IP 혹은 IP 넷마스크를 반점(,)으로 구분하여 입력하십시오. 공란일시, 모든 외부 접속이 허용됩니다.", - "AlwaysPlaySubtitles": "항상 자막 표시", + "AlwaysPlaySubtitles": "항상 표시", "AlwaysPlaySubtitlesHelp": "오디오 언어를 불문하고 언어 설정에 적합한 자막을 불러옵니다.", "AnyLanguage": "모든 언어", "AroundTime": "대략 {0}", @@ -859,7 +858,7 @@ "Blacklist": "블랙리스트", "HeaderConfirmPluginInstallation": "플러그인 설치 확인", "HeaderChapterImages": "챕터 이미지", - "H264EncodingPresetHelp": "성능을 높이려면 더 빠른 값을 선택하고, 품질을 높이려면 더 느린 값을 선택하십시오.", + "EncoderPresetHelp": "성능을 높이려면 더 빠른 값을 선택하고, 품질을 높이려면 더 느린 값을 선택하십시오.", "HDPrograms": "HD 프로그램", "Guide": "가이드", "GroupVersions": "그룹 버전", @@ -881,7 +880,6 @@ "DoNotRecord": "녹화 안 함", "Disconnect": "연결 끊기", "Disabled": "비활성화됨", - "DirectorValue": "감독: {0}", "DirectPlaying": "다이렉트 재생", "DirectStreaming": "다이렉트 스트리밍", "DirectStreamHelp2": "다이렉트 스트리밍은 비디오 퀄리티의 손실없이 매우 적은 처리능력을 사용합니다.", @@ -978,7 +976,7 @@ "OptionEnableForAllTuners": "모든 튜너 장치 활성화", "OptionBanner": "배너", "Option3D": "3D", - "OnlyImageFormats": "이미지 포맷만 (VOBSUB, PGS, SUB 등)", + "OnlyImageFormats": "이미지 포맷만 (VOBSUB, PGS, SUB)", "Off": "끄기", "NumLocationsValue": "{0} 폴더", "Normal": "보통", @@ -1012,7 +1010,7 @@ "MediaInfoSoftware": "소프트웨어", "MediaInfoTimestamp": "타임스탬프", "MediaInfoSize": "크기", - "MediaInfoLevel": "레벨", + "MediaInfoLevel": "수준", "MediaInfoForced": "강제", "MarkUnplayed": "재생하지 않은 것으로 표시", "MarkPlayed": "재생한 것으로 표시", @@ -1024,10 +1022,10 @@ "LearnHowYouCanContribute": "당신이 기여할 수 있는 방법을 배우십시오.", "LeaveBlankToNotSetAPassword": "비밀번호를 설정하지 않으려면 빈칸으로 두십시오.", "LabelffmpegPath": "FFmpeg 경로:", - "LabelWeb": "웹: ", + "LabelWeb": "웹:", "LabelVideoCodec": "비디오 코덱:", "LabelVideoBitrate": "비디오 비트레이트:", - "LabelVideo": "비디오:", + "LabelVideo": "비디오", "DashboardArchitecture": "아키텍처: {0}", "DashboardOperatingSystem": "운영체제: {0}", "DashboardServerName": "서버: {0}", @@ -1044,7 +1042,7 @@ "LabelTheme": "테마:", "LabelTextSize": "글자 크기:", "LabelTextColor": "글자 색:", - "LabelSubtitles": "자막:", + "LabelSubtitles": "자막", "LabelSubtitleFormatHelp": "예시: srt", "LabelSubtitleDownloaders": "자막 다운로더:", "LabelStopping": "중지", @@ -1069,7 +1067,7 @@ "LabelLanNetworks": "LAN 네트워크:", "LabelInternetQuality": "인터넷 퀄리티:", "LabelHomeNetworkQuality": "홈 네트워크 퀄리티:", - "LabelH264EncodingPreset": "H264 인코딩 프리셋:", + "LabelEncoderPreset": "H264 인코딩 프리셋:", "LabelFont": "폰트:", "LabelFolder": "폴더:", "LabelFileOrUrl": "파일 또는 URL:", @@ -1084,7 +1082,7 @@ "LabelAudioCodec": "오디오 코덱:", "LabelAudioChannels": "오디오 채널:", "LabelAudioBitrate": "오디오 비트레이트:", - "LabelAudio": "오디오:", + "LabelAudio": "오디오", "Items": "항목", "Kids": "어린이", "Home": "홈", @@ -1110,7 +1108,7 @@ "MessageNoServersAvailable": "자동 서버 탐색을 사용했지만, 서버가 발견되지 않았습니다.", "MessageDownloadQueued": "다운로드 대기 중.", "MessageDirectoryPickerInstruction": "네트워크 버튼으로 장치를 찾지 못하면 네트워크 경로를 수동으로 입력할 수 있습니다. 예를 들어, {0} 또는 {1}.", - "MessageDirectoryPickerLinuxInstruction": "Linux on Arch Linux, CentOS, Debian, Fedora, OpenSuse, Ubuntu의 경우 서비스 사용자에게 최소한 저장 위치에 대한 읽기 권한을 부여해야 합니다.", + "MessageDirectoryPickerLinuxInstruction": "Linux on Arch Linux, CentOS, Debian, Fedora, OpenSUSE, Ubuntu의 경우 서비스 사용자에게 최소한 저장 위치에 대한 읽기 권한을 부여해야 합니다.", "MessageDirectoryPickerBSDInstruction": "BSD의 경우, Jellyfin이 FreeNAS Jail에 액세스할 수 있도록 하려면 FreeNAS Jail 내에 스토리지를 구성해야 할 수도 있습니다.", "LinksValue": "링크: {0}", "LatestFromLibrary": "최근 {0}", @@ -1127,7 +1125,7 @@ "LabelSortBy": "정렬 기준:", "LabelBaseUrl": "기본 URL:", "LabelEnableHardwareDecodingFor": "다음에서 하드웨어 디코딩 활성화:", - "LabelDisplayMode": "디스플레이 모드:", + "LabelDisplayMode": "표시 모드:", "LabelBindToLocalNetworkAddress": "로컬 네트워크 주소로 바인드:", "LabelAutomaticallyRefreshInternetMetadataEvery": "인터넷에서 자동으로 메타데이터를 리프레시:", "LabelAuthProvider": "인증 제공자:", @@ -1143,11 +1141,10 @@ "HeaderBlockItemsWithNoRating": "등급 정보가 없거나 인식 불가능한 항목 차단:", "HeaderApiKeysHelp": "외부 애플리케이션은 Jellyfin 서버와 통신하기 위해 API키를 가지고 있어야 합니다. 키는 Jellyfin 계정으로 로그인하거나 수동으로 키를 부여하여 발급할 수 있습니다.", "HeaderAllowMediaDeletionFrom": "미디어 제거 허용", - "HardwareAccelerationWarning": "하드웨어 가속을 활성화하면 일부 환경에서 불안정해질 수 있습니다. 운영체제 및 비디오 드라이버가 최신 상태인지 확인하십시오. 이 기능을 활성화한 후 비디오를 재생하는 데 어려움이 있을 경우 설정을 다시 자동으로 변경하십시오.", - "GuestStar": "게스트 스타", + "HardwareAccelerationWarning": "하드웨어 가속을 활성화하면 일부 환경에서 불안정해질 수 있습니다. 운영체제 및 비디오 드라이버가 최신 상태인지 확인하십시오. 이 기능을 활성화한 후 비디오를 재생하는 데 어려움이 있을 경우 설정을 다시 '사용 안 함'으로 변경하십시오.", + "GuestStar": "게스트 출연", "GroupBySeries": "시리즈별로 그룹화", - "GenresValue": "장르: {0}", - "GenreValue": "장르: {0}", + "Genre": "장르", "General": "일반", "FileReadCancelled": "파일 읽기 작업이 취소되었습니다.", "FetchingData": "추가 데이터를 가져오는 중", @@ -1191,7 +1188,7 @@ "LabelCertificatePasswordHelp": "인증서가 비밀번호를 요구하면, 여기에 입력하십시오.", "LabelCertificatePassword": "인증서 비밀번호:", "LabelBurnSubtitles": "자막 굽기:", - "LabelAppNameExample": "예시: Sickbeard, NzbDrone", + "LabelAppNameExample": "예시: Sickbeard, Sonarr", "LabelAllowedRemoteAddressesMode": "원격 IP 주소 필터 모드:", "LabelAllowedRemoteAddresses": "원격 IP 주소 필터:", "LabelAllowHWTranscoding": "하드웨어 트랜스코딩 허용", @@ -1234,11 +1231,11 @@ "ConfigureDateAdded": "라이브러리 설정의 Jellyfin 서버 대시보드에서 추가된 날짜를 결정하는 방법 구성", "EnableStreamLoopingHelp": "라이브 스트림에 몇 초의 데이터만 포함되어 있고 지속적으로 요청해야하는 경우, 이 옵션을 활성화하십시오. 필요하지 않은 경우, 이 기능을 사용하면 문제가 발생할 수 있습니다.", "FolderTypeUnset": "혼합 콘텐츠", - "BurnSubtitlesHelp": "자막 포맷에 따라 비디오를 변환할 때 서버에서 자막을 구워야 하는지를 결정합니다. 자막을 굽지 않으면 서버 성능이 향상됩니다. 이미지 기반 포맷(VOBSUB, PGS, SUB/IDX 등) 및 특정 ASS/SSA 자막을 구우려면 자동을 선택하십시오.", + "BurnSubtitlesHelp": "영상을 트랜스코딩할 때 자막 포맷에 따라 서버에서 영상 안에 자막을 입힐지를 결정합니다. 영상에 자막을 입히지 않으면 서버 성능이 향상됩니다. 일부 ASS/SSA 자막을 포함하여 자막 포맷(VOBSUB, PGS, SUB/IDX 등)에 따라 자막을 영상에 입히려면 자동을 선택하십시오.", "EnableNextVideoInfoOverlay": "재생 중에 다음 비디오 정보 표시", "EnablePhotosHelp": "이미지가 다른 미디어 파일과 함께 감지되어 표시됩니다.", "ButtonParentalControl": "자녀 보호", - "DisplayModeHelp": "Jellyfin이 실행 중인 화면의 유형을 선택하십시오.", + "DisplayModeHelp": "원하는 인터페이스 레이아웃 스타일을 선택하십시오.", "DefaultSubtitlesHelp": "자막은 내장된 메타데이터에 있는 기본 플래그와 강제 플래그를 기반으로 불러옵니다. 언어 선호도는 여러 옵션을 사용할 수 있을 때 고려됩니다.", "Disc": "디스크", "EnableExternalVideoPlayersHelp": "비디오 재생을 시작할 때 외부 재생기 메뉴가 표시됩니다.", @@ -1253,7 +1250,7 @@ "DisplayMissingEpisodesWithinSeasons": "시즌 내 누락된 에피소드 표시", "EnableBackdrops": "배경", "EnableBackdropsHelp": "라이브러리를 탐색하는 동안 일부 페이지의 배경을 표시합니다.", - "ErrorAddingXmlTvFile": "XmlTV 파일에 액세스하는 동안 오류가 발생했습니다. 파일이 존재하는지 확인한 후 다시 시도하십시오.", + "ErrorAddingXmlTvFile": "XMLTV 파일에 액세스하는 동안 오류가 발생했습니다. 파일이 존재하는지 확인 후 다시 시도하십시오.", "ErrorDeletingItem": "Jellyfin 서버에서 항목을 제거하는 중에 오류가 발생했습니다. Jellyfin 서버가 미디어 폴더에 대해 쓰기 권한이 있는지 확인한 후 다시 시도하십시오.", "HeaderConfigureRemoteAccess": "원격 접근 구성", "HeaderCastAndCrew": "배역 및 제작진", @@ -1268,7 +1265,7 @@ "MediaInfoBitDepth": "비트뎁스", "LabelPostProcessor": "후처리 애플리케이션:", "RefreshQueued": "새로 고침 대기 중", - "NoPluginConfigurationMessage": "", + "NoPluginConfigurationMessage": "이 플러그인은 설정할 것이 없습니다.", "OptionExtractChapterImage": "챕터 이미지 추출 활성화", "RestartPleaseWaitMessage": "Jellyfin 서버가 종료되었다가 다시 시작될 때까지 기다리십시오. 1-2분 정도 걸릴 수 있습니다.", "Up": "위", @@ -1280,5 +1277,161 @@ "ErrorAddingMediaPathToVirtualFolder": "미디어 경로를 추가하는 데에 오류가 발생했습니다. 경로를 다시 확인하거나 Jellyfin 서버가 해당 경로에 접근할 수 있는지 확인해 주세요.", "ErrorGettingTvLineups": "TV 구성을 다운로드 하는 중에 오류가 발생하였습니다. 정보가 맞는지 확인한 후 다시 시도해 주세요.", "BoxRear": "상자 (후면)", - "Absolute": "절대" + "Absolute": "절대", + "LabelDropShadow": "하단 그림자:", + "LabelDiscNumber": "디스크 번호:", + "Identify": "식별자", + "HeaderMoreLikeThis": "비슷한 작품", + "Directors": "감독", + "ButtonSplit": "나누기", + "HeaderContainerProfileHelp": "컨테이너 프로파일은 사용자의 디바이스에서 재생 가능한 파일 형식을 나타냅니다. 다이렉트 플레이가 설정된 경우에도 디바이스에서 지원되지 않는 형식이라면 트랜스코딩이 적용됩니다.", + "HeaderCodecProfileHelp": "코덱 프로파일은 사용자의 디바이스에서 재생 가능한 코덱을 가리킵니다. 다이렉트 플레이가 설정된 경우에도 디바이스에서 지원되지 않는 코덱이라면 트랜스코딩이 적용됩니다.", + "HeaderAppearsOn": "표시", + "HandledByProxy": "리버스 프록시로 처리", + "Features": "기능", + "ErrorPleaseSelectLineup": "라인업을 선택하고 다시 시도하십시오. 이용 가능한 라인업이 없으면 계정, 비밀번호, 우편번호가 정확한지 확인하십시오.", + "ErrorAddingListingsToSchedulesDirect": "Schedules Direct 계정에 라인업을 추가하는 중에 오류가 발생했습니다. Schedules Direct는 계정 당 제한된 수의 라인업만이 허용됩니다. 계속하려면 Schedules Direct 웹사이트에 로그인하여 다른 항목을 삭제해야 할 수 있습니다.", + "CopyStreamURLError": "URL을 복사하는 중에 오류가 발생했습니다.", + "ColorTransfer": "컬러 변환", + "AskAdminToCreateLibrary": "라이브러리를 생성하려면 관리자에게 문의하십시오.", + "LabelCorruptedFrames": "손상된 프레임:", + "LabelBindToLocalNetworkAddressHelp": "(선택) 로컬 IP 주소 대신 이 주소로 http 서버를 바인딩합니다. 비어있으면 서버가 가능한 모든 주소로 바인딩합니다. 이 항목을 수정하면 Jellyfin 서버를 재시작해야 합니다.", + "LabelAirsBeforeSeason": "시즌 이전 방송:", + "LabelAirsBeforeEpisode": "에피소드 이전 방송:", + "LabelAirsAfterSeason": "시즌 이후 방송:", + "HttpsRequiresCert": "암호화 접속을 위해서는 Let's Encrypt 등의 신뢰할 수 있는 SSL 인증서가 필요합니다. 인증서를 제공하거나 암호화 접속을 비활성화하십시오.", + "Horizontal": "수평", + "HeaderUpcomingOnTV": "방송 예정", + "HeaderTranscodingProfileHelp": "트랜스코딩이 필요할 때 사용될 포맷을 지정하기 위해 트랜스코딩 프로파일을 추가합니다.", + "HeaderResponseProfileHelp": "응답 프로파일을 통해 특정 미디어를 재생했을 때 장치로 전송되는 정보를 사용자화할 수 있습니다.", + "HeaderPlayOn": "여기부터 재생", + "HeaderNavigation": "탐색", + "HeaderKeepSeries": "시리즈 유지", + "HeaderFavoritePeople": "즐겨찾는 인물", + "HeaderEnabledFieldsHelp": "데이터 변경을 방지하고 잠그기 위해서는 필드를 비활성화하십시오.", + "HeaderEnabledFields": "활성화된 필드", + "HeaderDirectPlayProfileHelp": "디바이스가 원본 재생할 수 있는 파일 형식을 표시하기 위해 다이렉트 재생 프로파일을 추가합니다.", + "Extras": "기타 항목", + "AllowFfmpegThrottlingHelp": "트랜스코딩이나 리먹스 작업이 현재 재생 중인 위치를 넘어 충분히 진행되면 리소스를 절약하기 위해 작업을 중지합니다. 이는 재생 구간을 자주 변경하지 않을 경우에 가장 적합합니다. 재생 시 문제가 발생하면 이 항목을 비활성화하십시오.", + "AllowFfmpegThrottling": "트랜스코딩 시 스로틀링", + "MessageLeaveEmptyToInherit": "상위 항목의 설정이나 전역 설정값을 그대로 적용하기 위해서는 공백으로 두십시오.", + "MessageInstallPluginFromApp": "이 플러그인은 사용할 앱 내부에서 설치해야 합니다.", + "MessageImageTypeNotSelected": "드롭다운 메뉴에서 이미지 유형을 선택하십시오.", + "MessageCreateAccountAt": "{0}에서 계정 만들기", + "MessageConfirmRevokeApiKey": "정말 api 키를 무효화하시겠습니까? Jellyfin 서버와의 연결이 예고 없이 중단될 수 있습니다.", + "MessageConfirmAppExit": "종료하시겠습니까?", + "MediaIsBeingConverted": "미디어가 재생 중인 디바이스와 호환되는 형식으로 변환되는 중입니다.", + "MediaInfoRefFrames": "참조 프레임", + "MediaInfoPixelFormat": "픽셀 형식", + "MapChannels": "채널 매핑", + "LaunchWebAppOnStartupHelp": "서버가 처음 시작되면 웹 브라우저에서 웹 클라이언트를 실행하십시오. 서버 재시작의 경우에는 적용되지 않습니다.", + "Large": "크게", + "LanNetworksHelp": "대역폭을 강제로 제한할 때 로컬 네트워크로 간주되는 쉼표로 구분된 IP 주소 및 IP/서브넷 마스크 목록입니다. 지정될 경우 모든 다른 IP 주소는 외부 네트워크로 간주되며 외부 대역폭 제한이 적용됩니다. 공백일 경우 서버의 서브넷만이 로컬 네트워크로 간주됩니다.", + "LabelffmpegPathHelp": "ffmpeg 실행 파일 혹은 ffmpeg를 포함하는 폴더 경로입니다.", + "LabelXDlnaDocHelp": "urn:schemas-dlna-org:device-1-0 네임스페이스에 포함된 X_DLNADOC 요소의 내용을 결정합니다.", + "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaCapHelp": "urn:schemas-dlna-org:device-1-0 네임스페이스에 포함된 X_DLNACAP 요소의 내용을 결정합니다.", + "LabelXDlnaCap": "X-DLNA cap:", + "LabelVideoResolution": "비디오 해상도:", + "LabelTVHomeScreen": "TV 모드 홈 화면:", + "LabelStreamType": "스트리밍 유형:", + "LabelSpecialSeasonsDisplayName": "스페셜 시즌 표시명:", + "LabelSonyAggregationFlagsHelp": "urn:schemas-sonycom:av 네임스페이스에 포함된 집계 플래그(aggregationFlags) 요소의 내용을 결정합니다.", + "LabelSonyAggregationFlags": "Sony 집계 플래그:", + "LabelSkipIfGraphicalSubsPresentHelp": "텍스트 형식의 자막은 전송이 더 효율적이며 비디오 트랜스코딩이 필요할 가능성이 적습니다.", + "LabelSkipIfGraphicalSubsPresent": "비디오에 내장 자막이 있으면 건너뛰기", + "LabelSkipIfAudioTrackPresentHelp": "오디오 언어와 상관없이 모든 비디오가 자막을 갖추도록 하려면 이 항목을 체크하지 마십시오.", + "LabelSelectFolderGroupsHelp": "체크되지 않은 폴더는 폴더 고유의 보기 방식으로 표시됩니다.", + "LabelSelectFolderGroups": "자동으로 이하의 폴더의 항목을 영화, 음악, TV 와 같은 보기 방식으로 그룹화:", + "EnableFastImageFadeInHelp": "로드된 이미지에 더 빠른 페이드 인 효과를 적용", + "EnableFastImageFadeIn": "빠른 이미지 페이드 인 효과", + "LabelScheduledTaskLastRan": "최근 실행: {0}, 소모시간: {1}.", + "LabelRemoteClientBitrateLimitHelp": "(선택) 모든 외부 네트워크로 접속된 장치들에 적용되는 각 스트리밍별 비트레이트 제한입니다. 이는 서버의 인터넷이 처리할 수 있는 한계보다 더 높은 비트레이트를 요청하는 것을 방지할 수 있습니다. 비디오를 더 낮은 비트레이트로 트랜스코딩하기 위해 서버에 높은 CPU 부하를 줄 수 있습니다.", + "LabelReasonForTranscoding": "트랜스코딩 원인:", + "LabelProtocolInfoHelp": "디바이스에서 GetProtocolInfo 요청을 처리할 때 사용될 값입니다.", + "LabelPostProcessorArguments": "후처리 명령어:", + "LabelOptionalNetworkPathHelp": "이 폴더가 네트워크 공유 폴더라면 네트워크 공유 경로를 제공하여 Jellyfin 클라이언트가 미디어 파일에 직접 접속하도록 설정할 수 있습니다.", + "LabelMoviePrefixHelp": "영화 제목에 접두사가 적용되었다면 서버가 제대로 처리할 수 있도록 여기에 입력하십시오.", + "LabelMoviePrefix": "영화 접두사:", + "LabelMinResumePercentageHelp": "이 비율을 넘기 전에 정지되면 재생되지 않은 것으로 간주됩니다.", + "LabelMinResumePercentage": "최소 이어보기 재생률:", + "LabelMinResumeDurationHelp": "재생 위치를 저장해서 나중에 이어보기 위한 최소 비디오 길이(초)를 설정합니다.", + "LabelMinResumeDuration": "최소 이어보기 시간:", + "LabelMetadataReadersHelp": "선호하는 순으로 로컬 메타데이터 우선순위를 결정하십시오. 가장 먼저 발견된 파일을 읽어옵니다.", + "LabelMetadataReaders": "메타데이터 리더:", + "LabelMaxResumePercentageHelp": "이 비율을 넘었을 때 정지되면 완전히 재생된 것으로 간주됩니다.", + "LabelMaxResumePercentage": "최대 이어보기 진행률:", + "LabelMatchType": "일치 유형:", + "LabelKodiMetadataSaveImagePathsHelp": "Kodi 가이드라인에 어긋나는 파일명을 가진 이미지가 있을 때 권장되는 설정입니다.", + "LabelKodiMetadataEnablePathSubstitutionHelp": "서버의 경로 대체 설정을 이용하여 이미지 경로 대체를 활성화합니다.", + "LabelKodiMetadataEnablePathSubstitution": "경로 대체 활성화", + "LabelKodiMetadataEnableExtraThumbsHelp": "이미지를 다운로드할 때는 Kodi 스킨과의 최대한의 호환성을 위해 추가 팬아트와 추가 섬네일 중 어느 형식으로도 저장될 수 있습니다.", + "LabelKodiMetadataEnableExtraThumbs": "추가 팬아틀 추가 섬네일 필드로 복사하기", + "LabelKeepUpTo": "대기 한계:", + "LabelHomeScreenSectionValue": "홈 화면 영역 {0}:", + "LabelBaseUrlHelp": "서버에 더 세부적인 URL로 접속하려면 여기에 서브 디렉토리를 추가하십시오.", + "LabelEnableSingleImageInDidlLimitHelp": "Dili 내에 여러 이미지가 삽입되면 일부 디바이스가 제대로 작동하지 않을 수 있습니다.", + "LabelEnableSingleImageInDidlLimit": "하나의 내장 이미지로 제한", + "LabelEnableBlastAliveMessagesHelp": "네트워크 상의 다른 UPnP 장치가 안정적으로 발견되지 않는다면 이 옵션을 활성화하십시오.", + "LabelEnableAutomaticPortMapHelp": "UPnp를 통해 로컬 포트를 외부 포트에 자동으로 매핑하도록 시도합니다. 일부 공유기 기종에서는 지원하지 않을 수 있습니다. 변경사항을 적용하려면 서버를 다시 시작하십시오.", + "LabelEmbedAlbumArtDidlHelp": "일부 디바이스는 앨범아트를 얻을 때 이 방법을 선호합니다. 다른 디바이스에서는 실패할 수 있습니다.", + "LabelDefaultScreen": "기본 화면:", + "LabelDateTimeLocale": "날짜/시간 로케일:", + "XmlTvPathHelp": "XMLTV 파일을 저장할 경로를 설정합니다. Jellyfin은 이 파일을 읽어 주기적으로 변경 사항을 확인합니다. 파일 생성 및 파일 업데이트는 사용자가 수동으로 해야 합니다.", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "다음과 같은 미디어 저장소들을 라이브러리에서 제거합니다:", + "MessageReenableUser": "재활성화는 아래를 참조하십시오", + "MessagePluginConfigurationRequiresLocalAccess": "이 플러그인을 구성하려면 로컬 서버에 직접 로그인하십시오.", + "MessageNoCollectionsAvailable": "컬렉션을 사용하면 영화, 시리즈 및 앨범의 개인화 된 그룹을 즐길 수 있습니다. + 버튼을 클릭하여 컬렉션 만들기를 시작합니다.", + "LabelPlayerDimensions": "플레이어 화면 크기:", + "LabelParentNumber": "부모 번호:", + "LabelLineup": "라인업:", + "LabelDroppedFrames": "드롭 프레임:", + "LabelDeinterlaceMethod": "디인터레이싱 방법:", + "LabelCustomDeviceDisplayNameHelp": "기기에 표시할 이름을 지정하거나 공란으로 두어 등록된 기기 명을 사용합니다.", + "Episode": "에피소드", + "EnableColorCodedBackgrounds": "컬러코드가 삽입된 배경", + "DropShadow": "하단 그림자", + "Depressed": "압축된", + "DeinterlaceMethodHelp": "비월주사식 콘텐츠를 순차주사로 변환할시 사용할 비월제거 방법을 선택하십시오.", + "ClientSettings": "클라이언트 설정", + "BoxSet": "박스 세트", + "Artist": "아티스트", + "AlbumArtist": "앨범 아티스트", + "Album": "앨범", + "NoCreatedLibraries": "라이브러리가 없습니다. {0}지금 생성하겠습니까?{1}", + "NewCollectionHelp": "영화 및 다른 라이브러리 콘텐츠들을 묶어 개인화된 컬렉션을 구성할 수 있습니다.", + "Never": "항상 안 함", + "Movie": "영화", + "MoveRight": "오른쪽으로 이동", + "MoveLeft": "왼쪽으로 이동", + "MoreFromValue": "{0} 에서 더 자세히", + "MetadataSettingChangeHelp": "변경된 메타데이터 설정은 새 콘텐츠에 적용됩니다. 기존의 콘텐츠에 적용하려면 상세 화면에서 새로 고침 버튼을 누르거나 메타데이터 매니저를 통해 일괄적으로 새로 고침을 수행하십시오.", + "MessagePluginInstallDisclaimer": "Jellyfin 커뮤니티에서 만들어진 플러그인은 Jellyfin의 기능과 편의성을 향상시킬 수 있습니다. 다만 이러한 플러그인은 라이브러리 스캔 속도 저하, 추가 백그라운드 프로세싱, 시스템 불안정과 같은 문제를 야기할 수 있다는 것을 유념하시기 바랍니다.", + "LabelLibraryPageSizeHelp": "라이브러리 페이지에 표시될 항목 수를 조절합니다. 0으로 지정 시 페이징을 비활성화합니다.", + "LabelLibraryPageSize": "라이브러리 페이지 크기:", + "LabelEnableBlastAliveMessages": "서버 활성화 메세지", + "OptionEnableExternalContentInSuggestionsHelp": "제안 항목에 인터넷 예고편과 라이브 TV 프로그램이 포함되도록 허용합니다.", + "OptionEnableExternalContentInSuggestions": "제안 항목에 외부 콘텐츠 허용", + "OptionDownloadImagesInAdvanceHelp": "기본적으로 대부분의 이미지는 Jellyfin 앱에서 요청할 때에만 다운로드됩니다. 새 미디어를 추가할 때 모든 이미지를 미리 다운로드하려면 이 옵션을 활성화하십시오. 라이브러리 스캔이 심각하게 지연될 수도 있습니다.", + "OptionDownloadImagesInAdvance": "미리 이미지 다운로드", + "OptionDisplayFolderView": "일반적인 미디어 폴더를 볼 수 있는 폴더 보기를 표시합니다", + "OptionAutomaticallyGroupSeriesHelp": "활성화하면 라이브러리 내의 여러 폴더에 분산된 시리즈를 하나의 시리즈로 병합합니다.", + "OptionAutomaticallyGroupSeries": "여러 폴더에 분산된 시리즈를 자동으로 병합합니다", + "OptionAllowVideoPlaybackRemuxing": "변환이 필요한 비디오를 재인코딩하지 않고 재생하는 것을 허용", + "OptionAllowSyncTranscoding": "트랜스코딩이 필요한 미디어의 다운로드 및 싱크 허용", + "OptionAllowMediaPlaybackTranscodingHelp": "트랜스코딩 접근을 제한하면 Jellyfin 앱에서 지원되지 않는 미디어 형식을 재생할 때 문제가 발생할 수 있습니다.", + "OptionForceRemoteSourceTranscoding": "원격 미디어 소스를 강제 트랜스코딩 (라이브 TV 등)", + "OnlyForcedSubtitlesHelp": "'강제'로 표시된 자막만 불러옵니다.", + "OnlyForcedSubtitles": "강제로 설정한 자막만", + "OneChannel": "단채널", + "NoSubtitlesHelp": "자막을 자동으로 불러오지 않습니다. 재생 중에 수동으로 켤 수 있습니다.", + "MusicLibraryHelp": "{0}음악 이름 지정 규칙{1}을 확인하십시오.", + "MovieLibraryHelp": "{0}영화 이름 지정 규칙{1}을 확인하십시오.", + "MessageUnauthorizedUser": "현재 서버에 접속할 권한이 없습니다. 자세한 정보는 서버 관리자에게 문의하십시오.", + "HeaderFavoritePlaylists": "즐겨찾는 플레이리스트", + "ButtonTogglePlaylist": "플레이리스트", + "ButtonToggleContextMenu": "더보기", + "Rate": "평", + "PerfectMatch": "정확히 일치", + "OtherArtist": "다른 아티스트" } diff --git a/src/strings/lt-lt.json b/src/strings/lt-lt.json index 169ecdb035..c87628316c 100644 --- a/src/strings/lt-lt.json +++ b/src/strings/lt-lt.json @@ -624,8 +624,7 @@ "ConfirmEndPlayerSession": "Ar norite išjungti Jellyfin ant {0}?", "Descending": "Mažėjančia tvarka", "DetectingDevices": "Ieškomi įrenginiai", - "DirectorValue": "Režisierius: {0}", - "DirectorsValue": "Režisieriai: {0}", + "Directors": "Režisieriai", "Disabled": "Išjungtas", "Disc": "Diskas", "Disconnect": "Atsijungti", @@ -785,7 +784,7 @@ "HeaderLoginFailure": "Prisijungimo klaida", "Hide": "Paslėpti", "LabelAll": "Visi", - "LabelAudio": "Garsas:", + "LabelAudio": "Garsas", "LabelCancelled": "Atšaukta", "LabelCertificatePassword": "Sertifikato slaptažodis:", "LabelCertificatePasswordHelp": "Jei sertifikatui reikalingas slaptažodis, jį įveskite čia.", @@ -805,7 +804,7 @@ "ExtraLarge": "Labai didelis", "Fullscreen": "Viso ekrano režimas", "General": "Bendri", - "GenreValue": "Žanras: {0}", + "Genre": "Žanras", "ErrorPleaseSelectLineup": "Pasirinkite TV programą ir bandykite dar kartą. Jei TV programos nerodoma, patikrinkite ar teisingas jūsų vartotojo vardas, slaptažodis ir pašto kodas.", "HeaderRevisionHistory": "Versijų istorija", "HeaderShutdown": "Išjungti", @@ -912,7 +911,7 @@ "Filters": "Filtrai", "FormatValue": "Formatas: {0}", "GuideProviderSelectListings": "Sąrašų pasirinkimas", - "H264EncodingPresetHelp": "Pasirinkite greitesnę reikšmę, kad pagerintumėte našumą, arba mažesnę, norėdami pagerinti kokybę.", + "EncoderPresetHelp": "Pasirinkite greitesnę reikšmę, kad pagerintumėte našumą, arba mažesnę, norėdami pagerinti kokybę.", "HeaderRestart": "Perkrauti", "LabelDateTimeLocale": "Data ir laikas:", "LabelEnableSingleImageInDidlLimit": "Apriboti iki vieno įterpto vaizdo", @@ -924,7 +923,6 @@ "ErrorAddingXmlTvFile": "Atidarant XMLTV failą įvyko klaida. Įsitikinkite, ar failas egzistuoja, ir bandykite dar kartą.", "ErrorGettingTvLineups": "Atsisiunčiant TV programas įvyko klaida. Įsitikinkite, kad jūsų informacija teisinga, ir bandykite dar kartą.", "Features": "Medžiagos", - "GenresValue": "Žanrai: {0}", "GroupBySeries": "Grupuoti pagal serialus", "Guide": "Gidas", "GuideProviderLogin": "Prisijungti", diff --git a/src/strings/lv.json b/src/strings/lv.json new file mode 100644 index 0000000000..8c19b23ad7 --- /dev/null +++ b/src/strings/lv.json @@ -0,0 +1,1085 @@ +{ + "Absolute": "Absolūts", + "HeaderFavoriteSongs": "Dziesmu Favorīti", + "HeaderFavoriteShows": "Raidījumu Favorīti", + "HeaderFavoriteEpisodes": "Episožu Favorīti", + "HeaderFavoriteArtists": "Izpildītāju Favorīti", + "HeaderFavoriteAlbums": "Albumu Favorīti", + "MusicArtist": "Mūzikas Izpildītājs", + "MusicAlbum": "Mūzikas Albums", + "Movies": "Filmas", + "MoreMediaInfo": "Media info", + "MoreFromValue": "Vairāk no {0}", + "Monday": "Pirmdiena", + "Mobile": "Mobilā", + "MinutesBefore": "minūtes pirms", + "MinutesAfter": "minūtes pēc", + "MetadataManager": "Metadatu Pārvaldnieks", + "Metadata": "Metadati", + "MessageYouHaveVersionInstalled": "", + "MessageUnableToConnectToServer": "Mēs pašlaik nevaram sazināties ar izvēlēto serveri. Pārliecinies ka tas strādā, un mēģini vēlreiz.", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Sekojošie multvides ceļi tiks noņemti no tavas bibliotēkas:", + "MessageSettingsSaved": "Iestatījumi saglabāti.", + "MessagePleaseWait": "Lūdzu uzgaidi. Tas var aizņemt pāris minūtes.", + "MessageNothingHere": "Šeit nekā nav.", + "MessageNoPluginsInstalled": "Tev nav uzstādīti paplašinājumi.", + "MessageNoAvailablePlugins": "Nav pieejamu paplašinājumu.", + "MessageItemsAdded": "Vienums pievienots.", + "MessageItemSaved": "Vienums saglabāts.", + "MessageInvalidUser": "Nepareizs lietotājvārds vai parole. Lūdzu mēģini vēlreiz.", + "MessageImageFileTypeAllowed": "Tikai JPEG un PNG datnes tiek atbalstītas.", + "MessageFileReadError": "Lasot datni notika kļūda. Lūdzu mēģini vēlreiz.", + "MessageDownloadQueued": "Lejupielāde ierindota.", + "MessageCreateAccountAt": "Izveido kontu {0}", + "MessageContactAdminToResetPassword": "Lūdzu sazinies ar sistēmas administratoru lai atiestatītu paroli.", + "MessageConfirmShutdown": "Vai tu tiešām vēlies izslēgt serveri?", + "MessageConfirmRestart": "Vai tu tiešām vēlies restartēt Jellyfin Server?", + "MessageConfirmRemoveMediaLocation": "Vai tu tiešām vēlies noņemt šo ceļu?", + "MessageConfirmRecordingCancellation": "Atcelt ierakstu?", + "MessageConfirmAppExit": "Vai tu vēlies iziet?", + "MessageAlreadyInstalled": "Šī versija jau ir uzstādīta.", + "MediaInfoStreamTypeVideo": "Video", + "MediaInfoStreamTypeSubtitle": "Subtitri", + "MediaInfoStreamTypeData": "Dati", + "MediaInfoStreamTypeAudio": "Audio", + "MediaInfoSoftware": "Programmatūras", + "MediaInfoSize": "Lielums", + "MediaInfoResolution": "Izšķirtspēja", + "MediaInfoProfile": "Profils", + "MediaInfoPixelFormat": "Pikseļu formāts", + "LabelYear": "Gads:", + "LabelWeb": "Tīkls:", + "LabelVideoResolution": "Video izšķirtspēja:", + "LabelVideoCodec": "Video kodeks:", + "LabelVideoBitrate": "Video bitu-ātrums:", + "LabelVideo": "Video", + "DashboardArchitecture": "Arhitektūra: {0}", + "DashboardOperatingSystem": "Operētājsistēma: {0}", + "DashboardServerName": "Serveris: {0}", + "DashboardVersionNumber": "Versija: {0}", + "LabelVersionInstalled": "{0} instalēti", + "LabelVersion": "Versija:", + "LabelValue": "Vērtība:", + "LabelVaapiDevice": "VA API Ierīce:", + "LabelUsername": "Lietotājvārds:", + "LabelUserLibrary": "Lietotāja bibliotēka:", + "LabelUserAgent": "Lietotāja aģents:", + "LabelUser": "Lietotājs:", + "LabelUseNotificationServices": "Izmantot sekojošos servisus:", + "LabelTypeText": "Teksts", + "LabelTypeMetadataDownloaders": "{0} metadatu lejupielādētāji:", + "LabelTunerIpAddress": "Tūnera IP Addrese:", + "LabelTunerType": "Tūnera tips:", + "LabelType": "Tips:", + "LabelTranscodingVideoCodec": "Video kodeks:", + "LabelTranscodePath": "Trans-kodēšanas ceļš:", + "LabelTranscodingContainer": "Konteineris:", + "LabelTranscodingAudioCodec": "Audio kodeks:", + "LabelTrackNumber": "Celiņa numurs:", + "LabelTimeLimitHours": "Laika limits (stundas):", + "LabelTime": "Laiks:", + "LabelTheme": "Tēma:", + "LabelTextSize": "Teksta lielums:", + "LabelTextColor": "Teksta krāsa:", + "LabelTextBackgroundColor": "Teksta fona krāsa:", + "LabelTag": "Tags:", + "LabelTVHomeScreen": "TV režīma mājas ekrāns:", + "LabelSupportedMediaTypes": "Atbalstītie Multivides Veidi:", + "LabelSubtitles": "Subtitri", + "LabelSubtitlePlaybackMode": "Subtitru veids:", + "LabelSubtitleFormatHelp": "Piemērs: srt", + "LabelSubtitleDownloaders": "Subtitru lejupielādētāji:", + "LabelStreamType": "Straumes veids:", + "LabelStopping": "Aptur", + "LabelStopWhenPossible": "Apturēt kad iespējams:", + "LabelStatus": "Status:", + "LabelStartWhenPossible": "Sākt kad iespējams:", + "LabelSportsCategories": "Sporta kategorijas:", + "LabelSpecialSeasonsDisplayName": "Speciālās sezonas displeja nosaukums:", + "LabelSource": "Avots:", + "LabelSoundEffects": "Skaņas efekti:", + "LabelSortTitle": "Kārtošanas nosaukums:", + "LabelSortOrder": "Kārtošanas secība:", + "LabelSortBy": "Kārtot pēc:", + "LabelSize": "Ilgums:", + "LabelServerName": "Servera nosaukums:", + "LabelSeriesRecordingPath": "Sērijas ieraksta ceļā (neobligāts):", + "LabelSerialNumber": "Sērijas numurs", + "LabelSendNotificationToUsers": "Sūtīt paziņojumu uz:", + "LabelSelectVersionToInstall": "Izvēlies versiju, ko uzstādīt:", + "LabelSelectUsers": "Izvēlies lietotājus:", + "LabelSecureConnectionsMode": "Drošā savienojuma veids:", + "LabelSeasonNumber": "Sezonas numurs:", + "LabelScreensaver": "Ekrānsaudzētājs:", + "LabelRuntimeMinutes": "Ilgums (minūtes):", + "LabelRemoteClientBitrateLimit": "Interneta straumēšanas bitu ātruma limits (Mb/s):", + "LabelRefreshMode": "Atjaunināšanās režīms:", + "LabelRecordingPath": "Noklusējuma ierakstīšanas ceļš:", + "LabelRecord": "Ierakstīt:", + "LabelReasonForTranscoding": "Trans-kodēšanas iemesls:", + "LabelPublicHttpsPort": "Publiskā HTTPS porta numurs:", + "LabelPublicHttpPort": "Publiskā HTTP porta numurs:", + "LabelProtocolInfo": "Protokola info:", + "LabelProtocol": "Protokols:", + "LabelProfileVideoCodecs": "Video kodeksi:", + "LabelProfileContainersHelp": "Atdalīti ar komatu. Var atstāt tukšu, lai pielietotu visiem konteineriem.", + "LabelProfileContainer": "Konteineriem:", + "LabelProfileCodecsHelp": "Atdalīti ar komatu. Var atstāt tukšu, lai pielietotu visiem kodeksiem.", + "LabelProfileCodecs": "Kodeksi:", + "LabelProfileAudioCodecs": "Audio kodeksi:", + "LabelPreferredDisplayLanguage": "Ieteicamā displeja valoda:", + "LabelPostProcessorArgumentsHelp": "Izmantot {path} kā ceļu ieraksta datnei.", + "LabelPostProcessor": "Pēcapstrādes lietotne:", + "LabelPlayMethod": "Atskaņošanas metode:", + "LabelPlaylist": "Atskaņošanas saraksts:", + "LabelPlayer": "Atskaņotājs:", + "LabelPlayDefaultAudioTrack": "Atskaņot noklusējuma audio celiņu neatkarīgi no valodas", + "LabelPlaceOfBirth": "Dzimšanas vieta:", + "LabelPersonRoleHelp": "Piemēram: saldējuma furgona šoferis", + "LabelPath": "Ceļš:", + "LabelPasswordRecoveryPinCode": "Pin kods:", + "LabelPasswordResetProvider": "Paroles maiņas Nodrošinātājs:", + "LabelPasswordConfirm": "Parole (apstiprinājums):", + "LabelPassword": "Parole:", + "LabelParentNumber": "Vecāku numurs:", + "LabelOverview": "Pārskats:", + "LabelOriginalTitle": "Oriģinālais nosaukums:", + "LabelNumber": "Numurs:", + "LabelNotificationEnabled": "Iespējot šo paziņojumu", + "LabelNext": "Nākamais", + "LabelNewsCategories": "Ziņu kategorijas:", + "LabelNewPasswordConfirm": "Jaunās paroles apstiprinājums:", + "LabelNewPassword": "Jaunā parole:", + "LabelNewName": "Jaunais nosaukums:", + "LabelName": "Nosaukums:", + "LabelMovieRecordingPath": "Filmu ieraksta ceļš (neobligāts):", + "LabelMoviePrefix": "Filmu prefikss:", + "LabelMovieCategories": "Filmu kategorijas:", + "LabelMethod": "Metode:", + "LabelMetadataSavers": "Metadatu serveri:", + "LabelMetadataReaders": "Metadatu lasītāji:", + "LabelMetadataPath": "Metadatu ceļš:", + "LabelMetadata": "Metadati:", + "LabelMessageTitle": "Ziņojuma virsraksts:", + "LabelMessageText": "Ziņojuma teksts:", + "LabelMaxStreamingBitrate": "Maksimālā straumēšanas kvalitāte:", + "LabelMaxChromecastBitrate": "Chromecast straumēšanas kvalitāte:", + "LabelManufacturerUrl": "Ražotāja URL", + "LabelManufacturer": "Ražotājs:", + "LabelLogs": "Logs:", + "LabelLanNetworks": "LAN tīkli:", + "LabelLanguage": "Valoda:", + "LabelInternetQuality": "Tīkla kvalitāte:", + "LabelImageType": "Attēla veids:", + "LabelIconMaxWidth": "Ikonas maksimālais platums:", + "LabelHttpsPort": "Vietējā HTTPS porta numurs:", + "LabelHomeScreenSectionValue": "Mājas ekrāna sekcija {0}:", + "LabelHomeNetworkQuality": "Mājas tīkla kvalitāte:", + "LabelHardwareAccelerationType": "Aparatūras paātrināšana:", + "LabelFriendlyName": "Draudzīgs nosaukums:", + "LabelFormat": "Formāts:", + "LabelForgotPasswordUsernameHelp": "Ievadi savu lietotājvārdu, ja tu to atceries.", + "LabelFont": "Fonts:", + "LabelFolder": "Mape:", + "LabelFinish": "Pabeigt", + "LabelFileOrUrl": "Fails vai URL:", + "LabelFailed": "Neizdevās", + "LabelEveryXMinutes": "Katru:", + "LabelEvent": "Notikums:", + "LabelEpisodeNumber": "Epizodes numurs:", + "LabelEndDate": "Beigu datums:", + "LabelEnableHardwareDecodingFor": "Iespējot aparatūras atkodēšanu priekš:", + "LabelEnableDlnaServer": "Iespējot DLNA serveri", + "LabelEnableDlnaPlayTo": "Iespējot DLNA atskaņošanu uz", + "LabelEnableDlnaDebugLogging": "Iespējot DLNA atkļūdošanas logošanu", + "LabelEnableDlnaClientDiscoveryInterval": "Klientu meklēšanas intervāls (sekundes)", + "LabelEasyPinCode": "Vieglais pin kods:", + "LabelDownloadLanguages": "Lejupielādēt valodas:", + "LabelDisplayOrder": "Displeja kārtojums:", + "LabelDisplayName": "Displeja nosaukums:", + "LabelDisplayMode": "Displeja režīms:", + "LabelDisplayLanguageHelp": "Jellyfin tulkošana ir notiekošs projekts.", + "LabelDisplayLanguage": "Displeja valoda:", + "LabelDiscNumber": "Diska numurs:", + "LabelDeviceDescription": "Ierīces apraksts", + "LabelDefaultScreen": "Noklusējuma ekrāns:", + "LabelDefaultUser": "Noklusējuma lietotājs:", + "LabelDay": "Diena:", + "LabelDateAdded": "Pievienošanas datums:", + "LabelCustomDeviceDisplayName": "Displeja nosaukums:", + "LabelCurrentPassword": "Pašreizējā parole:", + "LabelCriticRating": "Kritiķu reitings:", + "LabelCountry": "Valsts:", + "LabelContentType": "Satura veids:", + "LabelCommunityRating": "Kopienas vēŗtējums:", + "LabelCollection": "Kolekcija:", + "LabelChannels": "Kanāli:", + "LabelCertificatePassword": "Sertifikāta parole:", + "LabelCancelled": "Atcelts", + "LabelCachePath": "Keša ceļš:", + "LabelCache": "Kešs:", + "LabelBurnSubtitles": "Iededzināt subtitrus:", + "LabelBirthYear": "Dzimšanas gads:", + "LabelBirthDate": "Dzimšanas datums:", + "LabelAudioLanguagePreference": "Ieteicamā audio valoda:", + "LabelAudio": "Audio", + "LabelArtistsHelp": "Atdali vairākus izmantojot ;", + "LabelArtists": "Izpildītājs:", + "LabelAppNameExample": "Piemēram: Sickbeard, Sonarr", + "LabelAppName": "Lietotnes nosaukums", + "LabelAll": "Viss", + "LabelAlbumArtists": "Albuma izpildītāji:", + "LabelAlbum": "Albums:", + "LabelAirTime": "Tiešraides laiks:", + "LabelAirDays": "Tiešraides dienas:", + "LabelAccessStart": "Sākuma laiks:", + "LabelAccessEnd": "Beigu laiks:", + "LabelAccessDay": "Nedēļas diena:", + "Label3DFormat": "3D formāts:", + "Kids": "Bērni", + "Items": "Vienumi", + "ItemCount": "{0} vienumi", + "InstallingPackage": "Instalē {0}", + "Images": "Attēli", + "Identify": "Identificēt", + "Horizontal": "Horizontāls", + "Home": "Mājas", + "HideWatchedContentFromLatestMedia": "Paslēpt skatītos vienumus no jaunākās multvides", + "Hide": "Paslēpt", + "HeaderStopRecording": "Apturēt Ierakstu", + "HeaderStatus": "Status", + "HeaderStartNow": "Sākt Tagad", + "HeaderSpecialEpisodeInfo": "Speciālās Epizodes Info", + "HeaderSortOrder": "Kārtošanas Secība", + "HeaderSortBy": "Kārtot Pēc", + "HeaderShutdown": "Izslēgt", + "HeaderSetupLibrary": "Uzstādīt multvides bibliotēkas", + "HeaderSettings": "Iestatījumi", + "HeaderServerSettings": "Servera Iestatījumi", + "HeaderSeriesStatus": "Sēriju Status", + "HeaderSeriesOptions": "Sēriju Opcijas", + "HeaderSeries": "Sērijas", + "HeaderSendMessage": "Sūtīt Ziņojumu", + "HeaderSelectServerCachePath": "Izvēlies Servera Keša Ceļu", + "HeaderSelectServer": "Izvēlies Serveri", + "HeaderSecondsValue": "{0} Sekundes", + "HeaderSeasons": "Sezonas", + "HeaderSchedule": "Grafiks", + "HeaderRevisionHistory": "Revīziju Vēsture", + "HeaderRestartingServer": "Restartē Serveri", + "HeaderRestart": "Restartēt", + "HeaderRemoveMediaLocation": "Noņemt Multvides Atrašanās Vietu", + "HeaderRemoveMediaFolder": "Noņemt Multvides Mapi", + "HeaderRecordingOptions": "Ierakstu Opcijas", + "HeaderRecentlyPlayed": "Nesen Atskaņots", + "HeaderProfileInformation": "Profila Informācija", + "HeaderProfile": "Profils", + "HeaderPleaseSignIn": "Lūdzu ieej", + "HeaderPlaybackError": "Atskaņošanas Kļūda", + "HeaderPlayback": "Multvides Atskaņošanas", + "HeaderPlayAll": "Atskaņot Visu", + "HeaderPinCodeReset": "Atiestatīt Pin Kodu", + "HeaderPhotoAlbums": "Foto Albūmi", + "HeaderPeople": "Cilvēki", + "HeaderPaths": "Ceļi", + "HeaderPasswordReset": "Paroles Nomaiņa", + "HeaderPassword": "Parole", + "HeaderNextVideoPlayingInValue": "Nākamais Video tiks atskaņots pēc {0}", + "HeaderNextUp": "Nākamais", + "HeaderNextEpisodePlayingInValue": "Nākamā Epizode tiks atskaņota pēc: {0}", + "HeaderNewDevices": "Jaunas Ierīces", + "HeaderNewApiKey": "Jauna API Atslēga", + "HeaderNavigation": "Navigācija", + "HeaderMyMediaSmall": "Mana Multvide (mazs)", + "HeaderMyMedia": "Mana Multvide", + "HeaderMyDevice": "Mana Ierīce", + "HeaderMusicVideos": "Mūzikas Video", + "HeaderMusicQuality": "Audio Kvalitāte", + "HeaderMovies": "Filmas", + "HeaderMoreLikeThis": "Vairāk Kā Šis", + "HeaderMetadataSettings": "Metadatu Iestatījumi", + "HeaderMediaInfo": "Multvides informācija", + "HeaderMediaFolders": "Multvides Mapes", + "HeaderMedia": "Multvide", + "HeaderLiveTvTunerSetup": "Tiešraides TV Tūnera Uzstādīšana", + "HeaderLiveTv": "Tiešraides TV", + "HeaderLiveTV": "Tiešraides TV", + "HeaderLibrarySettings": "Bibliotēku Iestatījumi", + "HeaderLibraryOrder": "Bibliotēku Kārtojums", + "HeaderLibraryFolders": "Bibliotēku Mapes", + "HeaderLibraryAccess": "Bibliotēku Piekļuves", + "HeaderLibraries": "Bibliotēkas", + "HeaderLatestRecordings": "Jaunākie Ieraksti", + "HeaderLatestMusic": "Jaunākā Mūzika", + "HeaderLatestMovies": "Jaunākās Filmas", + "HeaderLatestMedia": "Jaunākā Multvide", + "HeaderLatestEpisodes": "Jaunākās Epizodes", + "HeaderKeepRecording": "Turpināt Ierakstu", + "HeaderItems": "Vienumi", + "HeaderInstall": "Uzstādīt", + "HeaderImageSettings": "Attēlu Iestatījumi", + "HeaderImageOptions": "Attēlu Opcijas", + "HeaderIdentificationHeader": "Identifikācijas Headers", + "HeaderIdentificationCriteriaHelp": "Ievadi vismaz vienu identifikācijas kritēriju.", + "HeaderIdentification": "Identifikācija", + "HeaderHttpHeaders": "HTTP Headeri", + "HeaderHome": "Mājas", + "HeaderGuideProviders": "TV Gida Datu Nodrošinātāji", + "HeaderGenres": "Žanri", + "HeaderFrequentlyPlayed": "Bieži Atskaņots", + "HeaderForgotPassword": "Aizmirst PAroli", + "HeaderForKids": "Priekš Bērniem", + "HeaderFilters": "Filtri", + "HeaderFavoriteVideos": "Video Favorīti", + "MediaInfoPath": "Ceļš", + "MediaInfoLevel": "Līmenis", + "MediaInfoLayout": "Izkārtojums", + "MediaInfoLanguage": "Valoda", + "MediaInfoExternal": "Ārējs", + "MediaInfoDefault": "Noklusējums", + "MediaInfoContainer": "Konteiners", + "MediaInfoCodecTag": "Kodeksa tags", + "MediaInfoCodec": "Kodeks", + "MediaInfoChannels": "Kanāli", + "MediaInfoAnamorphic": "Anamorfisks", + "MarkUnplayed": "Atzīmēt neatskaņotu", + "MarkPlayed": "Atzīmēt atskaņotu", + "ManageRecording": "Pārvaldīt ierakstu", + "ManageLibrary": "Pārvaldīt bibliotēku", + "Logo": "Logo", + "LiveTV": "Tiešraides TV", + "LiveBroadcasts": "Tiešraides:", + "Live": "Tiešraide", + "List": "Saraksts", + "LinksValue": "Linki: {0}", + "Like": "Patīk", + "LeaveBlankToNotSetAPassword": "Tu vari atstāt šo lauku tukšu, lai neiestatītu paroli.", + "LaunchWebAppOnStartup": "Palaist web interfeisu kad serveris tiek startēts", + "LatestFromLibrary": "Jaunākais {0}", + "Large": "Liels", + "LabelffmpegPath": "FFmped ceļš:", + "LabelZipCode": "Zip Kods:", + "LabelYoureDone": "Esi pabeidzis!", + "LabelYourFirstName": "Tavs vārds:", + "HeaderFavoritePeople": "Cilvēku Favorīti", + "HeaderFavoriteMovies": "Filmu Favorīti", + "HeaderFavoriteBooks": "Grāmatu Favorīti", + "HeaderExternalIds": "Ārējie ID:", + "HeaderError": "Kļūda", + "HeaderEpisodes": "Epizodes", + "HeaderEditImages": "Rediģēt Attēlus", + "HeaderDownloadSync": "Lejupielādēt & Sinhronizēt", + "HeaderDisplay": "Displejs", + "HeaderDevices": "Ierīces", + "HeaderDeviceAccess": "Ierīču Piekļuve", + "HeaderDeveloperInfo": "Izstrādātāju Info", + "HeaderDeleteItems": "Noņemt Vienumus", + "HeaderDeleteItem": "Noņemt Vienumu", + "HeaderDeleteDevice": "Noņemt Ierīci", + "HeaderContinueWatching": "Turpināt Skatīšanos", + "HeaderContinueListening": "Turpināt Klausīšanos", + "HeaderContainerProfile": "Konteinera Profils", + "HeaderConnectionFailure": "Savienojuma Kļūda", + "HeaderConnectToServer": "Pievienoties pie Servera", + "HeaderConfirmRevokeApiKey": "Atsaukt API Atslēgu", + "HeaderConfirmPluginInstallation": "Apstiprināt Palašinājumu Uzstādījumu", + "HeaderConfigureRemoteAccess": "Konfigurēt Attālināto Piekļuvi", + "HeaderCodecProfile": "Kodeksu Profils", + "HeaderChannels": "Kanāli", + "HeaderChannelAccess": "Kanālu Piekļuve", + "HeaderCancelSeries": "Atcelt Sēriju", + "HeaderCancelRecording": "Atcelt Ierakstus", + "HeaderBooks": "Grāmatas", + "HeaderAutomaticUpdates": "Automātiskie Atjauninājumi", + "HeaderAudioSettings": "Audio Iestatījumi", + "HeaderAudioBooks": "Audio Grāmatas", + "HeaderApp": "Lietotne", + "HeaderApiKeys": "API Atslēgas", + "HeaderApiKey": "API Atslēga", + "HeaderAllowMediaDeletionFrom": "Atļaut Multvides Dzēšanu no", + "HeaderAlert": "Paziņojums", + "HeaderAlbums": "Albumi", + "HeaderAlbumArtists": "Albumu Izpildītāji", + "HeaderAdmin": "Admin", + "HeaderAddUser": "Pievienot Lietotāju", + "HeaderAddToPlaylist": "Pievienot Atskaņošanas Sarakstam", + "HeaderAddToCollection": "Pievienot kolekcijai", + "HeaderActivity": "Aktivitāte", + "HeaderActiveRecordings": "Aktīvie Ieraksti", + "HeaderActiveDevices": "Aktīvās Ierīces", + "HDPrograms": "HD programmas", + "Guide": "Gids", + "GuestStar": "Vieszvaigzne", + "GroupVersions": "Grupēt versijas", + "GroupBySeries": "Grupēt pēc sērijām", + "Genres": "Žanri", + "Genre": "Žanrs", + "General": "Vispārīgs", + "Fullscreen": "Pilnekrāns", + "Friday": "Piektdiena", + "FormatValue": "Formāts: {0}", + "Folders": "Mapes", + "FolderTypeTvShows": "TV Raidījumi", + "FolderTypeMusicVideos": "Mūzikas Video", + "FolderTypeMusic": "Mūzika", + "FolderTypeMovies": "Filmas", + "FolderTypeBooks": "Grāmatas", + "Filters": "Filtri", + "FileReadError": "Datnes lasīšanas laikā notika kļūda.", + "FileReadCancelled": "Datnes lasīšana tika atcelta.", + "FileNotFound": "Datne nav atrasta.", + "File": "Datne", + "Favorites": "Favorīti", + "Favorite": "Favorīts", + "ExitFullscreen": "Iziet no pilnekrāna", + "EveryNDays": "Ik pa {0} dienām", + "Episodes": "Epizodes", + "EndsAtValue": "Beigsies {0}", + "EnableThemeVideosHelp": "Atskaņot tēmas video fonā bibliotēkas pārlūkošanas laikā.", + "EnableThemeSongsHelp": "Atskaņot tēmas mūziku fonā bibliotēkas pārlūkošanas laikā.", + "EnableThemeVideos": "Tēmas video", + "EnableThemeSongs": "Tēmas mūzika", + "EnablePhotos": "Rādīt attēlus", + "EnableNextVideoInfoOverlayHelp": "Video beigās rādīt informāciju par nākamo video atskaņošanas sarakstā.", + "EnableNextVideoInfoOverlay": "Rādīt nākamā video informāciju atskaņošanas laikā", + "EnableHardwareEncoding": "Iespējot aparatūras kodēšanu", + "EnableExternalVideoPlayers": "Ārējie video atskaņotāji", + "EnableDisplayMirroring": "Displeju spoguļošana", + "EnableCinemaMode": "Teātra režīms", + "EnableBackdrops": "Foni", + "EditSubtitles": "Rediģēt subtitrus", + "EditMetadata": "Rediģēt metadatus", + "EditImages": "Rediģēt attēlus", + "Edit": "Rediģēt", + "EasyPasswordHelp": "Tavs vieglais pin kods tiek izmantots priekš bezsaistes piekļuves atbalstošos klientos, un arī var tikt izmantots priekš vieglas tīkla piekļuves.", + "DrmChannelsNotImported": "Kanāli ar DRM netiks importēti.", + "DownloadsValue": "{0} lejupielādes", + "Download": "Lejupielādēt", + "DisplayModeHelp": "Izvēlies ekrāna veidu, uz kura tu izmanto Jellyfin.", + "DoNotRecord": "Neierakstīt", + "DisplayInOtherHomeScreenSections": "Rādīt mājas ekrāna sadaļās kā jaunākā multvide un turpini skatīties", + "DisplayInMyMedia": "Rādīt mājas ekrānā", + "Display": "Displejs", + "Dislike": "Nepatīk", + "Disc": "Disks", + "Disabled": "Atspējots", + "Directors": "Direktori", + "Director": "Direktors", + "DirectStreaming": "Tiešā straumēšana", + "DirectPlaying": "Tiešā Atskaņošana", + "DetectingDevices": "Meklē Ierīces", + "Desktop": "Darbvirsma", + "DeleteImage": "Dzēst Attēlu", + "Delete": "Izdzēst", + "Default": "Noklusējums", + "DatePlayed": "Atskaņošanas datums", + "DateAdded": "Pievienošanas datums", + "CriticRating": "Kritiķu reitings", + "CopyStreamURLError": "Kļūda kopējot URL.", + "CopyStreamURLSuccess": "URL veiksmīgi nokopēts.", + "CopyStreamURL": "Kopēt Straumes URL", + "Continuing": "Turpina", + "ContinueWatching": "Turpināt skatīties", + "Connect": "Savienot", + "ConfirmDeletion": "Apstiprināt Dzēšanu", + "ConfirmDeleteImage": "Dzēst attēlu?", + "CommunityRating": "Kopienas reitings", + "Collections": "Kolekcijas", + "ChannelNameOnly": "Tikai kanāls {0}", + "Channels": "Kanāli", + "ChannelNumber": "Kanāla numurs", + "Categories": "Kategorijas", + "CancelSeries": "Atcelt sēriju", + "CancelRecording": "Atcelt ierakstu", + "ButtonWebsite": "Web vietne", + "ButtonViewWebsite": "Skatīt web vietni", + "ButtonUninstall": "Atinstalēt", + "ButtonTrailer": "Treileri", + "ButtonSubtitles": "Subtitri", + "ButtonSplit": "Sadalīt", + "ButtonStop": "Apturēt", + "ButtonStart": "Sākt", + "ButtonSignOut": "Iziet", + "ButtonSignIn": "Ieiet", + "ButtonShutdown": "Izslēgt", + "ButtonShuffle": "Jaukt", + "ButtonSettings": "Iestatījumi", + "ButtonSend": "Nosūtīt", + "ButtonSelectView": "Izvēlies Skatu", + "ButtonSelectServer": "Izvēlies Serveri", + "ButtonSelectDirectory": "Izvēlies Mapi", + "ButtonSearch": "Meklēt", + "ButtonScanAllLibraries": "Skanēt Visas Bibliotēkas", + "ButtonSave": "Saglabāt", + "ButtonRevoke": "Atsaukt", + "ButtonResume": "Turpināt", + "ButtonRestart": "Restartēt", + "ButtonResetPassword": "Nomainīt Paroli", + "ButtonResetEasyPassword": "Nomainīt vieglo pin kodu", + "ButtonRepeat": "Atkārtot", + "ButtonRename": "Pārsaukt", + "ButtonRemove": "Noņemt", + "ButtonRefreshGuideData": "Atjaunot Gida Datus", + "ButtonRefresh": "Atjaunot", + "ButtonProfile": "Profils", + "ButtonPreviousTrack": "Iepriekšējais celiņš", + "ButtonPlay": "Atskaņot", + "ButtonPause": "Pauzēt", + "ButtonParentalControl": "Vecāku Pārvaldība", + "ButtonOpen": "Atvērt", + "ButtonOk": "Labi", + "ButtonOff": "Izslēgt", + "ButtonNextTrack": "Nākamais Celiņš", + "ButtonNew": "Jauns", + "ButtonNetwork": "Tīkls", + "ButtonMore": "Vairāk", + "ButtonLibraryAccess": "Bibliotēku piekļuve", + "ButtonLearnMore": "Uzzināt vairāk", + "ButtonInfo": "Info", + "ButtonHome": "Mājas", + "ButtonHelp": "Palīdzība", + "ButtonGuide": "Gids", + "ButtonGotIt": "Sapratu", + "ButtonFullscreen": "Pilnekrāna", + "ButtonForgotPassword": "Aizmirsu Paroli", + "ButtonFilter": "Filtrs", + "ButtonEditImages": "Rediģēt attēlus", + "ButtonEdit": "Rediģēt", + "ButtonDownload": "Lejupielāde", + "ButtonDeleteImage": "Izdzēst Attēlu", + "ButtonDelete": "Izdzēst", + "ButtonConnect": "Pieslēgties", + "ButtonChangeServer": "Nomainīt Serveri", + "ButtonCancel": "Atcelt", + "ButtonBack": "Atpakaļ", + "ButtonAudioTracks": "Audio Celiņi", + "ButtonAddUser": "Pievienot Lietotāju", + "ButtonAddServer": "Pievienot Serveri", + "ButtonAddMediaLibrary": "Pievienot Multimēdiju Bibliotēku", + "ButtonAddImage": "Pievienot attēlu", + "ButtonAdd": "Pievienot", + "BrowsePluginCatalogMessage": "Pārlūko mūsu paplašinājumu katalogu, lai redzētu pieejamos paplašinājumus.", + "Browse": "Pārlūkot", + "BoxRear": "Kaste (aizmugure)", + "Box": "Kaste", + "Books": "Grāmatas", + "Help": "Palīdzība", + "HeadersFolders": "Mapes", + "HeaderYears": "Gadi", + "HeaderXmlSettings": "Xml Iestatījumi", + "HeaderXmlDocumentAttribute": "Xml Dokumenta Atribūts", + "HeaderXmlDocumentAttributes": "Xml Dokumenta Atribūti", + "HeaderVideos": "Video", + "HeaderVideoTypes": "Video Veidi", + "HeaderVideoType": "Video Veids", + "HeaderVideoQuality": "Video Kvalitāte", + "HeaderUsers": "Lietotāji", + "HeaderUser": "Lietotājs", + "HeaderUploadImage": "Augšupielādēt Attēlu", + "HeaderUpcomingOnTV": "Nākamais Televīzijā", + "HeaderTypeText": "Ievadīt Tekstu", + "HeaderTypeImageFetchers": "{0} Attēlu Sagādnieki", + "HeaderTuners": "Tūneri", + "HeaderTunerDevices": "Tūnera Ierīces", + "HeaderTranscodingProfile": "Transkodēšanas Profils", + "HeaderTracks": "Celiņi", + "HeaderThisUserIsCurrentlyDisabled": "Šis lietotājs pašlaik ir atspējots", + "HeaderTags": "Tagi", + "HeaderSystemDlnaProfiles": "Sistēmas Profili", + "HeaderSubtitleProfiles": "Subtitru Profili", + "HeaderSubtitleProfile": "Subtitru Profils", + "HeaderSubtitleDownloads": "Subtitru Lejupielāde", + "HeaderSubtitleAppearance": "Subtitru Izskats", + "BirthPlaceValue": "Dzimšanas vieta: {0}", + "BirthLocation": "Dzimšanas vieta", + "BirthDateValue": "Dzimis: {0}", + "Banner": "Karogattēls", + "Backdrops": "Foni", + "Backdrop": "Fons", + "AutoBasedOnLanguageSetting": "Auto (atkarībā no valodas iestatījumiem)", + "Auto": "Auto", + "Audio": "Audio", + "AttributeNew": "Jauns", + "AsManyAsPossible": "Cik vien iespējams", + "Artists": "Izpildītāji", + "Art": "Māksla", + "AroundTime": "Ap {0}", + "Anytime": "Jebkad", + "AnyLanguage": "Jebkura valoda", + "AlwaysPlaySubtitles": "Vienmēr rādīt subtitrus", + "AllowedRemoteAddressesHelp": "Ar komatiem atdalīts IP adrešu vai IP/tīkla masku saraksts, kas norāda uz tīkliem, kas var pieslēgties attālināti. Ja atstāts tukšs, visas attālinātās adreses tiks atļautas.", + "AllowRemoteAccessHelp": "Ja atķeksēts, visi attālinātie savienojumi tiks bloķēti.", + "AllowRemoteAccess": "Atļaut attālinātus savienojumus šim Jellyfin Serverim.", + "AllowOnTheFlySubtitleExtraction": " ", + "AllowMediaConversion": "Atļaut multimēdiju pārveidošanu", + "AllLibraries": "Visas bibliotēkas", + "AllLanguages": "Visas valodas", + "AllEpisodes": "Visas epizodes", + "AllComplexFormats": "Visi sarezģītie formāti (ASS, SSA, VOBSUB, PGS, SUB/IDX, utt.)", + "AllChannels": "Visi kanāli", + "All": "Viss", + "Alerts": "Paziņojumi", + "Albums": "Albumi", + "AddedOnValue": "Pievienots {0}", + "AddToPlaylist": "Pievienot atskaņošanas sarakstam", + "AddToPlayQueue": "Pievienot atskaņošanas rindai", + "AddToCollection": "Pievienot kolekcijai", + "Add": "Pievienot", + "Actor": "Aktieris", + "AccessRestrictedTryAgainLater": "Piekļuve pašlaik ir ierobežota. Lūdzu mēģini vēlreiz pēc brīža.", + "NewCollection": "Jauna Kolekcija", + "Never": "Nekad", + "Name": "Nosaukums", + "MySubtitles": "Mani subtitri", + "MusicVideo": "Mūzikas Video", + "OptionAllUsers": "Visi lietotāji", + "OptionAlbumArtist": "Albuma Izpildītājs", + "OptionAlbum": "Albums", + "OptionAdminUsers": "Administratori", + "OnlyImageFormats": "Tikai attēlu formāti (VOBSUB, PGS, SUB, utt.)", + "Option3D": "3D", + "OneChannel": "Viens kanāls", + "Off": "Izslēgts", + "NumLocationsValue": "{0} mapes", + "Normal": "Normāls", + "None": "Nakā", + "NoSubtitles": "Nav subtitru", + "NoSubtitleSearchResultsFound": "Nav atrasti rezultāti.", + "No": "Nr", + "Next": "Nākamais", + "News": "Ziņas", + "NewEpisodesOnly": "Tikai jaunas epizodes", + "NewEpisodes": "Jaunas epizodes", + "NewCollectionNameExample": "Piemēram: Zvaigžņu Karu Kolekcija", + "AllowMediaConversionHelp": "Atļauj vai aizliedz piekļuvi pie multivides pārveidošanas funkcijas.", + "Aired": "Raidīts", + "AdditionalNotificationServices": "Pārlūko paplašinājumu katalogu lai uzstādītu papildu paziņojumu servisus.", + "Yesterday": "Vakar", + "Yes": "Jā", + "XmlTvSportsCategoriesHelp": "Raidījumi ar šīm kategorijām tiks rādīti kā sporta raidījumi. Atdali vairākus ar '|'.", + "XmlTvNewsCategoriesHelp": "Raidījumi ar šīm kategorijām tiks rādīti kā ziņu raidījumi. Atdali vairākus ar '|'.", + "XmlTvMovieCategoriesHelp": "Raidījumi ar šīm kategorijām tiks rādīti kā filmas. Atdali vairākus ar '|'.", + "XmlTvKidsCategoriesHelp": "Raidījumi ar šīm kategorijām tiks rādīti kā raidījumi, kas paredzētas bērniem. Atdali vairākus ar '|'.", + "Writer": "Rakstnieks", + "WelcomeToProject": "Esiet sveicināts Jellyfin!", + "Wednesday": "Trešdiena", + "Watched": "Skatīts", + "ViewPlaybackInfo": "Skatīt atskaņošanas info", + "ViewArtist": "Skatīt izpildītāju", + "ViewAlbum": "Skatīt albumu", + "VideoRange": "Video platums", + "Vertical": "Vertikāls", + "ValueVideoCodec": "Video Kodeks: {0}", + "ValueTimeLimitSingleHour": "Laika limits: 1 stunda", + "ValueTimeLimitMultiHour": "Laika limits: {0} stundas", + "ValueSongCount": "{0} dziesmas", + "ValueSeriesCount": "{0} sērijas", + "ValueSeconds": "{0} sekundes", + "ValueOneSong": "1 dziesma", + "ValueOneSeries": "1 sērija", + "ValueOneMusicVideo": "1 mūzikas video", + "ValueOneMovie": "1 filma", + "ValueOneEpisode": "1 epizode", + "ValueOneAlbum": "1 albums", + "ValueMusicVideoCount": "{0} mūzikas video", + "ValueMovieCount": "{0} filmas", + "ValueMinutes": "{0} min", + "ValueEpisodeCount": "{0} epizodes", + "ValueDiscNumber": "Disks {0}", + "ValueContainer": "Konteiners: {0}", + "ValueCodec": "Kodeks: {0}", + "ValueAudioCodec": "Audio Kodeks: {0}", + "ValueAlbumCount": "{0} albumi", + "UserProfilesIntro": "Jellyfin satur atbalstu lietotāju profiliem ar granulāru kontroli pār displeja iestatījumiem, atskaņošanas statusu un vecāku pārvaldi.", + "Upload": "Augšupielādēt", + "Unrated": "Nevērtēts", + "Unplayed": "Neatskaņots", + "Unmute": "Ieslēgt skaņu", + "UninstallPluginHeader": "Noņemt Paplašinājumu", + "UninstallPluginConfirmation": "Vai tu tiešām vēlies noņemt {0}?", + "Tuesday": "Otrdiena", + "Transcoding": "Trans-kodēšana", + "Trailers": "Treileri", + "TrackCount": "{0} celiņi", + "TitlePlayback": "Atskaņošana", + "TitleHostingSettings": "Hostinga Iestatījumi", + "TitleHardwareAcceleration": "Aparatūras Paātrināšana", + "Thursday": "Ceturtdiena", + "ThemeVideos": "Tēmas video", + "ThemeSongs": "Tēmas mūzika", + "TellUsAboutYourself": "Pastāsti mums par sevi", + "TagsValue": "Tagi: {0}", + "Tags": "Tagi", + "TabUsers": "Lietotāji", + "TabTranscoding": "Trans-kodēšana", + "TabTrailers": "Treileri", + "TabSuggestions": "Ieteikumi", + "TabStreaming": "Straumēšana", + "TabSongs": "Dziesmas", + "TabShows": "Raidījumi", + "TabSettings": "Iestatījumi", + "TabServer": "Serveris", + "TabSeries": "Sērijas", + "TabResumeSettings": "Turpināt", + "TabResponses": "Atbildes", + "TabRecordings": "Ieraksti", + "TabProfiles": "Profili", + "TabProfile": "Profils", + "TabPlugins": "Paplašinājumi", + "TabPlaylists": "Atskaņošanas Saraksti", + "TabPlaylist": "Atskaņošanas Saraksts", + "TabPlayback": "Atskaņošana", + "TabPassword": "Parole", + "TabParentalControl": "Vecāku Pārvaldība", + "TabOther": "Cits", + "TabNotifications": "Paziņojumi", + "TabNfoSettings": "NFO Iestatījumi", + "TabNetworking": "Tīklošana", + "TabNetworks": "Tīkli", + "TabMyPlugins": "Mani Paplašinājumi", + "TabMusicVideos": "Mūzikas Video", + "TabMusic": "Mūzika", + "TabMovies": "Filmas", + "TabMetadata": "Metadati", + "TabLogs": "Logs", + "TabLiveTV": "Tiešraides TV", + "TabLatest": "Jaunākais", + "TabInfo": "Info", + "TabGuide": "Gids", + "TabGenres": "Žanri", + "TabFavorites": "Favorīti", + "TabEpisodes": "Epizodes", + "TabDisplay": "Displejs", + "TabDirectPlay": "Tiešā Atskaņošana", + "TabDevices": "Ierīces", + "TabContainers": "Konteineri", + "TabCollections": "Kolekcijas", + "TabCodecs": "Kodeksi", + "TabChannels": "Kanāli", + "TabCatalog": "Katalogs", + "TabArtists": "Izpildītāji", + "TabAlbums": "Albumi", + "ValueSpecialEpisodeName": "Speciālais - {0}", + "Sync": "Sinhronizācija", + "Songs": "Dziesmas", + "Shows": "Raidījumi", + "Playlists": "Atskaņošanas Saraksti", + "Photos": "Attēli", + "RepeatOne": "Atkārtot vienu", + "RepeatMode": "Atkārtošanas Režīms", + "RepeatEpisodes": "Atkārtot epizodes", + "RepeatAll": "Atkārtot visu", + "Repeat": "Atkārtot", + "RemoveFromPlaylist": "Noņemt no atskaņošanas sarakasta", + "RemoveFromCollection": "Noņemt no kolekcijas", + "RememberMe": "Atcerēties mani", + "Refresh": "Atjaunot", + "Recordings": "Ieraksti", + "RecordingCancelled": "Ieraksts atcelts.", + "RecordSeries": "Ierakstīt sēriju", + "Record": "Ierakstīt", + "RecommendationBecauseYouWatched": "Tāpēc ka tu skatījies {0}", + "RecommendationBecauseYouLike": "Tāpēc ka tev patīk {0}", + "RecentlyWatched": "Nesen skatīts", + "Quality": "Kvalitāte", + "Programs": "Programmas", + "Producer": "Producents", + "Previous": "Iepriekšējais", + "PleaseSelectTwoItems": "Izvēlies vismaz divus vienumus.", + "Played": "Atskaņots", + "PlayNext": "Atskaņot nākamp", + "PlayAllFromHere": "Atskaņot visus no šejienes", + "Play": "Atskaņot", + "PinCodeResetComplete": "Pin kods atiestatīts.", + "PictureInPicture": "Attēls attēlā", + "PasswordSaved": "Parole saglabāta.", + "People": "Cilvēki", + "OptionTvdbRating": "TVDB Reitings", + "OptionRandom": "Nejaušs", + "OptionProtocolHttp": "HTTP", + "OptionProfileVideoAudio": "Video Audio", + "OptionProfileVideo": "Video", + "OptionProfileAudio": "Audio", + "OptionPlayed": "Atskaņots", + "OptionParentalRating": "Vecāku Reitings", + "OptionOnInterval": "Pēc intervāla", + "OptionNone": "Neviens", + "OptionNew": "Jauns...", + "OptionMonday": "Pirmdien", + "OptionList": "Saraksts", + "OptionLikes": "Patīk", + "OptionIsSD": "SD", + "OptionIsHD": "HD", + "OptionHasTrailer": "Treileris", + "OptionHasSubtitles": "Subtitri", + "OptionFriday": "Piektdien", + "OptionFavorite": "Favorīti", + "OptionEveryday": "Katru dienu", + "OptionEnded": "Beidzies", + "OptionEnableAccessToAllLibraries": "Iespējot piekļuvi visām bibliotēkām", + "OptionDvd": "DVD", + "OptionDownloadMenuImage": "Izvēlne", + "OptionDownloadLogoImage": "Logo", + "OptionDownloadDiscImage": "Disks", + "OptionDownloadBoxImage": "Kaste", + "OptionDaily": "Ikdienas", + "OptionContinuing": "Turpina", + "OptionBluray": "Blu-ray", + "OptionBlockTvShows": "TV Raidījumi", + "OptionBlockTrailers": "Treileri", + "OptionBlockMusic": "Mūzika", + "OptionBlockMovies": "Filmas", + "OptionBlockBooks": "Grāmatas", + "OptionAutomatic": "Auto", + "OptionAuto": "Auto", + "OptionArtist": "Izpildītājs", + "NoPluginConfigurationMessage": "Šim paplašinājumam nav konfigurējamu iestatījumu.", + "NoCreatedLibraries": "Izskatās ka tu vēl neesi izveidojis nevienu bibliotēku. {0}Vai tu vēlies izveidot vienu tagad?{1}", + "NextUp": "Nākamais", + "Mute": "Apklusināt", + "MessageNoServersAvailable": "Automātiskā serveru meklēšana neatrada nevienu serveri.", + "MessageInvalidForgotPasswordPin": "Tika ievadīts nepareizs vai nevecojis pin kods. Lūdzu mēģini vēlreiz.", + "Menu": "Izvēlne", + "LabelTriggerType": "Trigera Veids:", + "LabelSkipIfGraphicalSubsPresent": "Izlaist ja video jau satur iegultus subtitrus", + "LabelSkin": "Izskats:", + "LabelSimultaneousConnectionLimit": "Vienlaicīgo straumju limits:", + "LabelServerHostHelp": "192.168.1.100:8096 vai https://myserver.com", + "LabelServerHost": "Resursdators:", + "LabelReleaseDate": "Izlaiduma datums:", + "LabelPrevious": "Iepriekšējais", + "LabelPreferredSubtitleLanguage": "Ieteicamā subtitru valoda:", + "LabelPreferredDisplayLanguageHelp": "Jellyfin tulkošana ir notiekošs projekts.", + "LabelPlayerDimensions": "Atskaņotāja dimensijas:", + "LabelParentalRating": "Vecāku reitings:", + "LabelMonitorUsers": "Uzraudzīt aktivitāti no:", + "LabelMinResumePercentageHelp": "Vienumi tiek uzskatīti par neatskaņotiem ja apturēti pirms šī laika.", + "LabelMinResumePercentage": "Minimālais turpināšanas procents:", + "LabelMinResumeDurationHelp": "Īsākais video garums sekundēs, kas saglabās atskaņošanas pozīciju un ļaus turpināt.", + "LabelMinResumeDuration": "Minimālais turpināšanas laiks:", + "LabelMetadataDownloadLanguage": "Ieteicamā lejupielādes valoda:", + "LabelMaxResumePercentageHelp": "Vienumi tiek uzskatīti pilnībā atskaņoti, ja tiek apturēti pēc šī laika.", + "LabelMaxResumePercentage": "Maksimālais turpināšanas procents:", + "LabelMaxParentalRating": "Maksimālais atļautais vecāku reitings:", + "LabelLoginDisclaimerHelp": "Ziņojums, kas tiks parādīts ieiešanas lapas apakšā.", + "LabelLoginDisclaimer": "Ieiešanas ziņojums:", + "LabelKodiMetadataDateFormat": "Izlaiduma datuma formāts:", + "LabelKidsCategories": "Bērnu kategorijas:", + "LabelIconMaxHeight": "Ikonas maksimālais augstums:", + "LabelHttpsPortHelp": "TCP ports, uz kura uzstādīt Jellyfin HTTPS serveri.", + "LabelH264Crf": "H264 kodēšanas CRF:", + "LabelGroupMoviesIntoCollections": "Grupēt filmas kolekcijās", + "LabelEnableRealtimeMonitor": "Iespējot reāllaika uzraudzību", + "LabelEnableDlnaServerHelp": "Ļauj UPnP ierīcēm tavā tīklā pārlūkot un atskaņot vienumus.", + "LabelEnableDlnaPlayToHelp": "Atrast ierīces lokālajā tīklā un dot iespēju tās attālināti kontrolēt.", + "LabelEnableDlnaDebugLoggingHelp": "Izveido lielas log datnes, un paredzēts tikai atkļūdošanas lietošanai.", + "LabelEnableBlastAliveMessagesHelp": "Iespējo šo ja serveri uzticami neatrod citas tīklā esošas UPnP ierīces.", + "LabelEnableAutomaticPortMapHelp": "Mēģināt automātiski kartēt publisko portu uz lokālo portu caur UPnP. Tas var nefunkcionēt uz dažiem rūteru modeļiem. Izmaiņas netiks pielietotas līdz servera restartam.", + "LabelEnableAutomaticPortMap": "Iespējot automātisko portu kartēšanu", + "LabelDynamicExternalId": "{0} Id:", + "LabelDropImageHere": "Nomet attēlu šeit, vai noklikšķini lai pārlūkotu.", + "LabelDidlMode": "DIDL režīms:", + "LabelDeathDate": "Nāves datums:", + "LabelDateTimeLocale": "Datuma un laika lokalizācija:", + "LabelCustomCertificatePathHelp": "Ceļš uz PKCS #12 datni, kas satur sertifikātu un privāto atslēgu lai iespējotu TLS atbalstu uz sava domēna.", + "FolderTypeUnset": "Jaukts Saturs", + "ErrorSavingTvProvider": "Kļūda saglabājot TV sniedzēju. Pārliecinies ka tas ir pieejams un mēģini vēlreiz.", + "ErrorMessageStartHourGreaterThanEnd": "Beigu laikam jābūt vēlākam par sākuma laiku.", + "ErrorAddingXmlTvFile": "Kļūda atverot XMLTV datni. Lūdzu pārliecinies ka datne eksistē un mēģini vēlreiz.", + "LabelCustomCssHelp": "Izmanto pats savu pielāgoto silu web interfeisam.", + "LabelCustomCss": "Pielāgots CSS:", + "LabelCustomCertificatePath": "Pielāgotā SSL sertifikāta ceļš:", + "LabelCorruptedFrames": "Bojātie kadri:", + "LabelCertificatePasswordHelp": "Ja tavam sertifikātam ir vajadzīga parole, lūdzu ievadi to šeit.", + "LabelBlockContentWithTags": "Aizliegt vienumus ar tagiem:", + "LabelBitrate": "Bitu ātrums:", + "LabelBindToLocalNetworkAddress": "Uzstādīt uz lokālās tīkla adreses:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Automātiski atjaunot metadatus no interneta:", + "LabelAuthProvider": "Autentifikācijas Nodrošinātājs:", + "LabelAudioSampleRate": "Audio izlases ātrums:", + "LabelAudioCodec": "Audio kodeks:", + "LabelAudioChannels": "Audio kanāli:", + "LabelAudioBitrate": "Audio bitu-ātrums:", + "LabelAllowServerAutoRestartHelp": "Serveris restartēties tikai brīžos, kad neviens lietotājs nav aktīvs.", + "LabelAllowServerAutoRestart": "Atļaut serverim automātiski restartēties, lai uzstādītu atjauninājumus", + "LabelAllowHWTranscoding": "Atļaut aparatūras trans-kodēšanu", + "LabelAlbumArtMaxWidthHelp": "Maksimālā albumu vāku izšķirtspēja caur upnp:albumArtURI.", + "LabelAlbumArtMaxWidth": "Albumu vāku maksimālais platums:", + "LabelAlbumArtMaxHeightHelp": "Maksimālā albumu vāku izšķirtspēja caur upnp:albumArtURI.", + "LabelAlbumArtMaxHeight": "Albumu vāku maksimālais augstums:", + "LabelAbortedByServerShutdown": "(Atcelts dēļ servera izslēgšanas)", + "ImportFavoriteChannelsHelp": "Ja iespējots, tikai kanāli, kas atzīmēti kā favorīti uztvērēja ierīcē tiks importēti.", + "HttpsRequiresCert": "Lai iespējotu drošos savienojumus, tev ir jānodrošina uzticams SSL sertifikāts, kā Let's Encrypt. Lūdzu nodrošini sertifikātu, vai atspējo drošos savienojumus.", + "HeaderTranscodingProfileHelp": "Pievieno tiešās atskaņošanas profilus, lai norādītu kurus formātus izmantot kad ir vajadzīga trans-kodēšana.", + "HeaderTaskTriggers": "Uzdevumu Trigeri", + "HeaderSelectTranscodingPathHelp": "Pārlūko vai ievadi ceļu, kurā tiks glabātas īslaicīgās trans-kodēšanas datnes. Šai mapei jābūt rakstāmai.", + "HeaderSelectTranscodingPath": "Izvēlies Trans-kodēšanas Īslaicīgo Ceļu", + "HeaderSelectServerCachePathHelp": "Pārlūko vai ievadi ceļu, kurā vēlies saglabāt servera keša datnes. Šai mapei jābūt rakstāmai.", + "HeaderSelectPath": "Izvēlies Ceļu", + "HeaderSelectMetadataPathHelp": "Pārlūko vai ievadi ceļu, kurā vēlies saglabāt metadatus. Šai mapei jābūt rakstāmai.", + "HeaderSelectMetadataPath": "Izvēlies Metadatu Ceļu", + "HeaderSelectCertificatePath": "Izvēlies Sertifikāta Ceļu", + "HeaderScenes": "Ainas", + "HeaderRunningTasks": "Ejošie Uzdevumi", + "HeaderResponseProfileHelp": "Atbilžu profili nodrošina iespējas rediģēt informāciju, kas tiek nosūtīta uz ierīci atskaņojot noteiktus medijus.", + "HeaderResponseProfile": "Atbilžu Profils", + "HeaderRemoteControl": "Tālvadība", + "HeaderRecordingPostProcessing": "Ierakstu Pēcapstrāde", + "HeaderProfileServerSettingsHelp": "Šīs vērtības kontrolē kā Jellyfin Server sevi rādīs ierīcei.", + "HeaderPreferredMetadataLanguage": "Ieteicamā Metadatu Valoda", + "HeaderPluginInstallation": "Paplašinājuma Instalācija", + "HeaderPlayOn": "Atskaņot Uz", + "HeaderParentalRatings": "Vecāku Vērtējumi", + "HeaderOtherItems": "Citi Vienumi", + "HeaderOnNow": "Tagad", + "HeaderLoginFailure": "Ieiešanas Kļūda", + "HeaderKodiMetadataHelp": "Lai iespējotu vai atspējotu NFO metadatus, rediģē bibliotēku Jellyfin bibliotēku iestatījumu metadata glabātāju sadaļā.", + "HeaderIdentifyItemHelp": "Ievadi vienu vai vairākus meklēšanas kritērijus. Noņem kritērijus lai palielinātu meklēšanas rezultātus.", + "HeaderFetchImages": "Ielādēt Attēlus:", + "HeaderFeatures": "Funkcijas", + "HeaderFeatureAccess": "Funkciju Piekļuve", + "HeaderEnabledFieldsHelp": "Atķeksē lauku lai to slēgtu un aizliegt tā satura mainīšanu.", + "HeaderEnabledFields": "Iespējotie Lauki", + "HeaderEasyPinCode": "Vieglais Pin Kods", + "HeaderDirectPlayProfileHelp": "Pievieno tiešās atskaņošanas profilus, lai norādītu kurus formātus ierīce spēj atskaņot natīvi.", + "HeaderDirectPlayProfile": "Tiešās Atskaņošanas Profils", + "HeaderDetectMyDevices": "Noteikt Manas Ierīces", + "HeaderDeleteTaskTrigger": "Dzēst Uzdevuma Trigeri", + "HeaderDeleteProvider": "Dzēst Sniedzēju", + "HeaderDefaultRecordingSettings": "Noklusējuma Ierakstīšanas Iestatījumi", + "HeaderDateIssued": "Izdošanas Datums", + "HeaderCustomDlnaProfiles": "Pielāgoti Profili", + "HeaderConfirmProfileDeletion": "Apstiprināt Profila Dzēšanu", + "HeaderChapterImages": "Nodaļu Attēli", + "HeaderCastCrew": "Lomas/Apkalpe", + "HeaderCastAndCrew": "Lomas/Apkalpe", + "HeaderAppearsOn": "Redzams", + "FFmpegSavePathNotFound": "Mēs nespējām atrast FFmpeg norādītajā ceļā. FFprobe arī ir vajadzīgs, un tam ir jāatrodas tajā pašā mapē. Šīs komponentes parasti tiek apvienotas vienā un tajā pašā lejupielādē. Lūdzu pārbaudiet ceļu un mēģiniet vēlreiz.", + "HeaderAdditionalParts": "Papildus Ceļi", + "HeaderAddUpdateImage": "Pievienot/Atjaunot Attēlu", + "HeaderAddScheduledTaskTrigger": "Pievienot Trigeri", + "GuideProviderLogin": "Ieiet", + "Ended": "Beidzies", + "EnableStreamLoopingHelp": "Iespējo šo, ja tiešsaistes straume satur tikai pāris sekunžu datus, un ir nepārtraukti jāatjauno. Iespējojot bez vajadzības var radīties problēmas.", + "EnableStreamLooping": "Automātiski atkārtot tiešsaistes straumes", + "EnablePhotosHelp": "Attēli tiks atrasti un parādīti blakus citām mediju datnēm.", + "EnableExternalVideoPlayersHelp": "Ārēja atskaņotāja izvēlne tiks parādīta, kad tiks sākta video atskaņošana.", + "EnableColorCodedBackgrounds": "Krāsu kodēti foni", + "EnableBackdropsHelp": "Attēlot fona attēlus dažu lapu fonā bibliotēkas pārlūkošanas laikā.", + "DropShadow": "Fona Ēnojums", + "DisplayMissingEpisodesWithinSeasons": "Rādīt trūkstošās epizodes sezonās", + "Disconnect": "Atvienot", + "DirectStreamHelp2": "Tieši Straumējot datni tiek izmantots ļoti maz procesora jaudas, bez video vai audio kvalitātes zudumiem.", + "DirectStreamHelp1": "Šis medijs ir saderīgs ar ierīci pēc izšķirtspējas un medija veida (H.264, AC3, utt.), bet atrodas nesaderīgā datnes konteinerī (mkv, avi, wmv, utt.). Video tiks pārpakots uz saderīgu formātu pirms tas tiks straumēts uz ierīci.", + "Descending": "Disltošs", + "Depressed": "Atspiests", + "DeleteUserConfirmation": "Vai tu tiešām vēlies izdzēst šo lietotāju?", + "DeleteUser": "Dzēst Lietotāju", + "DeleteMedia": "Dzēst mediju", + "DeleteImageConfirmation": "Vai tu tiešām vēlies izdzēst šo attēlu?", + "DeleteDeviceConfirmation": "Vai tu tiešām vēlies noņemt šo ierīci? Tā parādīsies atkārtoti nākamo reizi, kad lietotājs ieiet ar to.", + "DefaultErrorMessage": "Apstrādājot pieprasījumu notika kļūda. Pēc brītiņa lūdzu mēģini vēlreiz.", + "DeathDateValue": "Miris: {0}", + "ConfirmEndPlayerSession": "Vai jūs gribat izslēgt Jellyfin uz {0}?", + "ConfirmDeleteItems": "Dzēšot šos vienumus, tie tiks izdzēsti gan no jūsu failu sistēmas, gan mediju bibliotēkas. Vai tiešām turpināt?", + "ConfirmDeleteItem": "Dzēšot šo vienumu, tas tiks izdzēsts gan no jūsu failu sistēmas, gan mediju bibliotēkas. Vai tiešām turpināt?", + "ConfigureDateAdded": "Iestati kā pievienošanas datums tiek noteikts iekš Jellyfin Server pārvaldes paneļa zem Bibliotēkas iestatījumiem", + "Composer": "Komponists", + "ColorSpace": "Krāsu telpa", + "ColorPrimaries": "Primārās krāsas", + "CinemaModeConfigurationHelp": "Teātra režīms ienes kinoteātra pieredzi tavā dzīvojamā istabā, ar iespējām atskaņot treilerus un pielāgotus ievadus pirms galvenās filmas.", + "ChannelAccessHelp": "Izvēlies kanālus, ko koplietot ar šo lietotāju. Administratori spēs rediģēt visus kanālus izmantojot metadatu pārvaldnieku.", + "ChangingMetadataImageSettingsNewContent": "Izmaiņas metadatu vai mākslas lejupielādes iestatījumos tiks izmantotas tikai jauniem bibliotēkas vienumiem. Lai pielietotu šīs izmaiņas jau esošiem vienumiem, tev vajadzēs atjaunot šo vienumu metadatus manuāli.", + "ButtonSubmit": "Iesniegt", + "ButtonSort": "Kārtot", + "ButtonQuickStartGuide": "Pamata Lietošanas Instrukcija", + "ButtonManualLogin": "Manuālā Ieiešana", + "ButtonEditOtherUserPreferences": "Rediģē šī lietotāja profilu, attēlu un personas iestatījumus.", + "ButtonDown": "Lejup", + "ButtonArrowUp": "Augšup", + "ButtonArrowRight": "Labi", + "ButtonArrowLeft": "Kreisi", + "ButtonArrowDown": "Lejup", + "ButtonAddScheduledTaskTrigger": "Pievienot Trigeru", + "BookLibraryHelp": "Audio un teksta grāmatas tiek atbalstītas. Pārskati {0}grāmatu nosaukumu instrukciju{1}.", + "Blacklist": "Melnais saraksts", + "AuthProviderHelp": "Izvēlies Autentifikācijas Nodrošinājumu, kas tiks izmantots lai autentificētu šī lietotāja paroli.", + "AspectRatio": "Attēla Proporcijas", + "AskAdminToCreateLibrary": "Vaicājiet administratoram, lai izveidotu bibliotēku.", + "Ascending": "Augoši", + "AlwaysPlaySubtitlesHelp": "Valodas preferencei atbilstošie subtitri tiks ielādēti neatkarīgi no audio valodas.", + "AllowFfmpegThrottling": "Ierobežot Trans-kodējumus", + "AllowHWTranscodingHelp": "Atļaut uztvērējam trans-kodēt straumes tiešsaistē. Tas var atvieglot trans-kodēšanu, kas jāveic serverim.", + "AirDate": "Tiešraides datums", + "LabelIconMaxWidthHelp": "Maksimālā ikonu izšķirtspēja caur upnp:icon.", + "LabelIconMaxHeightHelp": "Maksimālā ikonu izšķirtspēja caur upnp:icon.", + "LabelHardwareAccelerationTypeHelp": "Aparatūras paātrināšanai ir vajadzīga papildus konfigurācija.", + "LabelEncoderPreset": "H264 un H265 kodēšanas noklusējumi:", + "HardwareAccelerationWarning": "Iespējojot aparatūras paātrināšanu var veidot nestabilitāti dažās vidēs. Pārliecinies ka tava operētājsistēma un video draiveri it pilnībā atjaunināti. Ja tev ir problēmas ar video atskaņošanu pēc šī iestatījuma iespējošanas, tev vajadzēs pārmainīt to atpakaļ uz Neviens.", + "HandledByProxy": "Apstrādā reversais proxy", + "LabelImageFetchersHelp": "Iespējo un sakārto savu attēlu sagādnieku prioritāti.", + "HeaderFetcherSettings": "Sagādnieku Iestatījumi", + "HeaderBranding": "Zīmols", + "HeaderBlockItemsWithNoRating": "Bloķēt vienumus, kam nav vai nav atpazīta reitinga informācija:", + "HeaderApiKeysHelp": "Ārējām lietotnēm ir vajadzīgas API atslēgas, lai sazinātos ar Jellyfin Serveri. Atslēgas tiek izdotas ieejot savā Jellyfin kontā, vai manuāli ģenerējot lietotnei atslēgu.", + "HeaderAccessScheduleHelp": "Izveido grafiku, lai ierobežotu piekļuvi noteiktās stundās.", + "HeaderAccessSchedule": "Piekļuves Grafiks", + "ExtraLarge": "Ļoti Liels", + "ErrorPleaseSelectLineup": "Lūdzu izvēlies sarakstu un mēģini vēlreiz. Ja nav pieejams neviens saraksts, pārliecinies ka tavs lietotājvārds, parole un pasta kods ir pareizi.", + "ErrorGettingTvLineups": "Notika kļūda lejupielādējot TV sarakstus. Lūdzu pārliecinies, ka tava informācija ir pareiza un mēģini vēlreiz.", + "DisplayMissingEpisodesWithinSeasonsHelp": "Tam arī jābūt iespējotam priekš TV bibliotēkām servera konfigurācijā.", + "DefaultMetadataLangaugeDescription": "Šie ir jūsu noklusējumi, kas var tikt rediģēti atkarībā no bibliotēkas.", + "AddItemToCollectionHelp": "Pievieno vienumus kolekcijām tos meklējot un izmantojot to labā taustiņa vai spiediena izvēlnes lai pievienotu tos.", + "LabelPleaseRestart": "Izmaiņas tiks pielietotas pēc manuālas web klienta pārlādes.", + "LabelPersonRole": "Loma:", + "LabelMusicStreamingTranscodingBitrateHelp": "Iestati maksimālo mūzikas straumēšanas bitu ātrumu.", + "LabelMusicStreamingTranscodingBitrate": "Mūzikas trans-kodēšanas bitu ātrums:", + "LabelModelUrl": "Modeļa URL", + "LabelModelNumber": "Modeļa numurs", + "LabelModelName": "Modeļa nosaukums", + "LabelModelDescription": "Modeļa apraksts", + "LabelMinScreenshotDownloadWidth": "Minimālais ekrānattēlu lejupielādes platums:", + "LabelMinBackdropDownloadWidth": "Minimālais fona attēla lejupielādes platums:", + "LabelKodiMetadataUser": "Saglabāt lietotāja skatīšanās informāciju uz NFO datnēm priekš:", + "LabelKodiMetadataSaveImagePathsHelp": "Tas ir ieteicams ja tev ir attēlu datņu nosaukumi, kas neatbilst Kodi vadlīnijām.", + "LabelKodiMetadataSaveImagePaths": "Saglabāt attēlu ceļus iekš nfo datnēm", + "LabelKodiMetadataEnablePathSubstitutionHelp": "Iespējot ceļu substitūciju attēlu ceļiem izmantojot serveru ceļu substitūcijas iestatījumus.", + "LabelKodiMetadataEnablePathSubstitution": "Iespējot ceļu substitūciju", + "MessageDirectoryPickerBSDInstruction": "Priekš BSD, tev var būt vajadzēs nokonfigurēt glabātuvi savā FreeNAS jail, lai atļautu Jellyfin tai piekļuvi.", + "MessageConfirmRevokeApiKey": "Vai tu tiešām vēlies atsaukt šo api atslēgu? Lietotnes savienojums ar Jellyfin Serveri tiks strauji atslēgts.", + "MessageConfirmProfileDeletion": "Vai tu tiešām vēlies izdzēst šo profilu?", + "LabelTranscodingProgress": "Trans-kodēšanas progress:", + "LabelTranscodingFramerate": "Trans-kodēšanas kadru ātrums:", + "LabelRecordingPathHelp": "Ievadi noklusējuma vietējo vietu, kur saglabāt ierakstus. Ja atstāsts tukšs, servera programmas datu mape tiks lietota tā vietā.", + "LabelPublicHttpsPortHelp": "Publiskais porta numurs, ko kartēt uz vietējo HTTPS portu.", + "LabelOriginalAspectRatio": "Oriģinālās proporcijas:", + "LabelMaxStreamingBitrateHelp": "Ievadi maksimālo bitu ātrumu straumēšanai.", + "LabelLocalHttpServerPortNumberHelp": "TCP porta numurs, kuru izmantos Jellyfin HTTP serveris.", + "MessageAreYouSureYouWishToRemoveMediaFolder": "Vai tiešām vēlies noņemt šo mediju datni?", + "MessageAreYouSureDeleteSubtitles": "Vai tiešām vēlies izdzēst šo subtitru datni?", + "MediaIsBeingConverted": "Medijs tiek pārveidots uz formātu kuru atbalsta tā atskaņojošā ierīce.", + "MediaInfoStreamTypeEmbeddedImage": "Iegults Attēls", + "MediaInfoTimestamp": "Laika zīmogs", + "MediaInfoSampleRate": "Izlases ātrums", + "MediaInfoInterlaced": "Rindpārlēkts", + "MediaInfoFramerate": "Kadru ātrums", + "MediaInfoAspectRatio": "Attēla proporcijas", + "MaxParentalRatingHelp": "Saturs ar augstāku reitingu tiks paslēpts no šī lietotāja.", + "LibraryAccessHelp": "Izvēlies bibliotēkas, ko koplietot ar šo lietotāju. Administratori spēs rediģēt visas bibliotēkas izmantojot metadatu pārvaldnieku.", + "LearnHowYouCanContribute": "Uzzini, kā tu vari dot ieguldījumu.", + "LabelUserLoginAttemptsBeforeLockout": "Neizdevušies piekļuves mēģinājumi pirms lietotājs tiek bloķēts:", + "LabelTranscodingThreadCount": "Trans-kodēšanas kodolu daudzums:", + "LabelTranscodes": "Transkodi:", + "LabelTitle": "Tituls:", + "LabelSaveLocalMetadata": "Saglabāt māksu media mapēs", + "LabelReadHowYouCanContribute": "Uzzini, kā tu vari dot ieguldījumu.", + "LabelNumberOfGuideDays": "Dienu daudzumus, kuram lejupielādēt gidu:", + "LabelLockItemToPreventChanges": "Aizslēgt šo objektu lai aizliegtu izmaiņas", + "LabelLocalHttpServerPortNumber": "Vietējais HTTP porta numurs:", + "OptionAllowManageLiveTv": "Atļaut Tiešraides TV ierakstu pārvaldīšanu", + "OptionAllowLinkSharing": "Atļaut dalīšanos sociālajos tīklos", + "OptionAllowBrowsingLiveTv": "Atļaut Tiešraides TV piekļuvi", + "MediaInfoForced": "Piespiests", + "LabelPublicHttpPortHelp": "Publiskai porta numurs, kas tiks kartēts uz vietējo HTTP portu.", + "LabelOptionalNetworkPath": "(Neobligāts) Koplietota tīkla mape:" +} diff --git a/src/strings/mr.json b/src/strings/mr.json new file mode 100644 index 0000000000..381c609a9e --- /dev/null +++ b/src/strings/mr.json @@ -0,0 +1,101 @@ +{ + "ButtonOpen": "उघडा", + "ButtonOk": "ऑन", + "ButtonOff": "ऑफ", + "ButtonNextTrack": "पुढचा ट्रॅक", + "ButtonNew": "नवीन", + "ButtonNetwork": "नेटवर्क", + "ButtonMore": "अजून", + "ButtonLearnMore": "अधिक माहिती", + "ButtonInfo": "माहिती", + "ButtonHelp": "मदत", + "ButtonGuide": "गाईड", + "ButtonGotIt": "समजले", + "ButtonForgotPassword": "पासवर्ड विसरलो", + "ButtonEditImages": "चित्र संपादित करा", + "ButtonEdit": "संपादित करा", + "ButtonDownload": "डाउनलोड करा", + "ButtonDown": "खाली", + "ButtonDeleteImage": "चित्र काढून टाका", + "ButtonDelete": "काढून टाका", + "ButtonChangeServer": "सर्व्हर बदला", + "ButtonCancel": "रद्द करा", + "ButtonBack": "मागे", + "ButtonAudioTracks": "ऑडिओ ट्रॅक", + "ButtonArrowUp": "वर", + "ButtonArrowRight": "उजवीकडे", + "ButtonArrowLeft": "डावीकडे", + "ButtonArrowDown": "खाली", + "ButtonAddUser": "प्रयोक्ता जोडा", + "ButtonAddServer": "सर्व्हर जोडा", + "ButtonAdd": "जोडा", + "Books": "पुस्तकं", + "Blacklist": "ब्लॅकलिस्ट", + "BirthPlaceValue": "जन्म ठिकाण: {0}", + "BirthLocation": "जन्मस्थान", + "BirthDateValue": "जन्म: {0}", + "Backdrops": "पार्श्वभूमी", + "Backdrop": "पार्श्वभूमी", + "Auto": "आपोआप", + "Audio": "ऑडिओ", + "AttributeNew": "नवीन", + "AspectRatio": "अ‍ॅस्पेक्ट रेशो", + "AsManyAsPossible": "जमतील तितके", + "Artists": "संगीतकार", + "Artist": "संगीतकार", + "Anytime": "कधीही", + "AnyLanguage": "कोणतीही भाषा", + "AlwaysPlaySubtitles": "नेहमीच प्ले करा", + "AllLibraries": "सर्व संग्रहालय", + "AllLanguages": "सर्व भाषा", + "AllEpisodes": "सर्व भाग", + "AllChannels": "सर्व वाहिन्या", + "All": "सर्व", + "Albums": "अल्बम", + "AlbumArtist": "अल्बम संगीतकार", + "Album": "अल्बम", + "AddedOnValue": "{0} जोडले", + "Add": "जोडा", + "Actor": "अभिनेता", + "EnableBackdrops": "पार्श्वभूमी", + "EditSubtitles": "सबटायटल संपादित करा", + "EditMetadata": "मेटाडेटा संपादित करा", + "EditImages": "चित्र संपादित करा", + "Edit": "संपादित करा", + "DrmChannelsNotImported": "डी.आर.एम. असलेल्या वाहिन्या आयात केल्या जाणार नाहीत.", + "DownloadsValue": "{0} डाउनलोड", + "Download": "डाउनलोड", + "Down": "खाली", + "DoNotRecord": "रेकॉर्ड करू नका", + "Directors": "दिग्दर्शक", + "Director": "दिग्दर्शक", + "Desktop": "डेस्कटॉप", + "DeleteImageConfirmation": "तुम्हाला नक्की हे चित्र काढून टाकायचे आहे का?", + "Delete": "काढून टाका", + "DeleteImage": "चित्र काढून टाका", + "ConfirmEndPlayerSession": "{0} येथील जेलिफिन बंद करावे का?", + "Composer": "संगीत दिग्दर्शक", + "Channels": "वाहिन्या", + "ChannelNumber": "वाहिनी क्रमांक", + "Categories": "वर्ग", + "CancelRecording": "रेकॉर्डिंग रद्द करा", + "ButtonWebsite": "संकेतस्थळ", + "ButtonViewWebsite": "संकेतस्थळ पाहा", + "ButtonUp": "वर", + "ButtonTrailer": "ट्रेलर", + "ButtonSubtitles": "सबटायटल", + "ButtonStop": "थांबा", + "ButtonStart": "सुरू करा", + "ButtonSettings": "सेटिंग्झ", + "ButtonSend": "पाठवा", + "ButtonSelectView": "दृष्य निवडा", + "ButtonSelectServer": "सर्व्हर निवडा", + "ButtonSelectDirectory": "डिरेक्टरी निवडा", + "ButtonSearch": "शोधा", + "ButtonScanAllLibraries": "सर्व संग्रहालय स्कॅन करा", + "ButtonRename": "नाव बदला", + "ButtonRemove": "काढून टाका", + "ButtonPreviousTrack": "मागचा ट्रॅक", + "ButtonPlay": "प्ले", + "ButtonPause": "पॉझ" +} diff --git a/src/strings/ms.json b/src/strings/ms.json index 9f959b9574..c377e52af1 100644 --- a/src/strings/ms.json +++ b/src/strings/ms.json @@ -35,14 +35,14 @@ "AllowOnTheFlySubtitleExtractionHelp": "Sarikata-sarikata yang sedia ada dapat diekstrak dari video-video dan dihantar ke aplikasi Jellyfin dalam teks biasa. Ini untuk menghindari video daripada transkoding. Pada sistem-sistem lain, ia dapat mengambil masa panjang dan menyebabkan video main balik terhenti semasa proses pengekstrakan. Ciri ini dapat dimatikan supaya sarikata yang sedia ada akan dibakar bersama video transkoding, jika ianya tidak disokong secara asal oleh peranti klien.", "AllowRemoteAccess": "Membenarkan persambungan jauh ke pelayan Jellyfin ini.", "AllowRemoteAccessHelp": "Jika tidak disemak, semua persambungan jauh akan disekat.", - "AllowHWTranscodingHelp": "Jika diaktifkan, penala dibolehkan untuk transkod strim dengan serta-merta. Ini dapat bantu mengurangkan transkoding yang diperlukan dari pelayan Jellyfin.", + "AllowHWTranscodingHelp": "Benarkan penala untuk transkod strim serta-merta. Ini mungkin dapat bantu kurangkan kadar transkod yang diperlukan dari pelayan.", "AlwaysPlaySubtitles": "Sentiasa main sarikata", "AlwaysPlaySubtitlesHelp": "Sarikata sepadan dengan bahasa yang dipilih akan masih dimuatkan tanpa mengira bahasa audio.", "AnyLanguage": "Mana-mana bahasa", "Anytime": "Pada bila masa saja", "AroundTime": "Sekitar {0}", "Art": "Seni", - "Artists": "Artis-artis", + "Artists": "Artis", "AsManyAsPossible": "Sebanyak mungkin", "Ascending": "Susunan menaik", "AspectRatio": "Nisbah aspek", diff --git a/src/strings/nb.json b/src/strings/nb.json index 0ad9459aca..0a616ae2e1 100644 --- a/src/strings/nb.json +++ b/src/strings/nb.json @@ -115,7 +115,7 @@ "ColorSpace": "Fargeutvalg", "ColorTransfer": "Overføring av farger", "Composer": "Komponist", - "ConfigureDateAdded": "Konfigurer hvordan lagt til-dato bestemmes på Jellyfin-serveren sitt dashbord under instillinger for Bibliotek", + "ConfigureDateAdded": "Konfigurer hvordan \"Dato lagt til\" bestemmes på Jellyfin-serveren sitt dashbord under instillinger for Bibliotek", "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?", @@ -189,9 +189,9 @@ "GuestStar": "Gjesteskuespiller", "GuideProviderSelectListings": "Velg oppføringer", "H264CrfHelp": "Constant Rate Factor (CRF) er standard kvalitetsinnstilling for x264-koderen. Du kan stille inn verdier mellom 0 og 51, hvor lavere verdier vil resultere i bedre kvalitet (på bekostning av høyere fil-størrelse). Fornuftige verdier ligger mellom 18 og 28. Standard for x264 er 23, så du kan bruke det som et utgangspunkt.", - "H264EncodingPresetHelp": "Velg en raskere verdi for å forbedre ytelsen, eller en lavere verdi for å forbedre kvaliteten.", + "EncoderPresetHelp": "Velg en raskere verdi for å forbedre ytelsen, eller en lavere verdi for å forbedre kvaliteten.", "HDPrograms": "HD-programmer", - "HardwareAccelerationWarning": "Aktivering av maskinvareakselerasjon kan føre til ustabilitet i enkelte miljøer. Sørg for at operativsystemet og skjermdriverne dine er fullt oppdatert. Hvis du har problemer med å spille videoer etter å ha aktivert dette, må du endre innstillingen tilbake til Auto.", + "HardwareAccelerationWarning": "Aktivering av maskinvareakselerasjon kan føre til ustabilitet i enkelte miljøer. Sørg for at operativsystemet og skjermdriverne dine er fullt oppdatert. Hvis du har problemer med å spille videoer etter å ha aktivert dette, må du deaktivere innstillingen igjen.", "HeaderAccessSchedule": "Tidsplan for tilgang", "HeaderAccessScheduleHelp": "Lag en tidsplan for tilgang for å begrense tilgangen til visse tider.", "HeaderActiveDevices": "Aktive enheter", @@ -382,7 +382,7 @@ "Images": "Bilder", "ImportFavoriteChannelsHelp": "Hvis aktivert, vil kun kanaler som er markert som favoritt på tuneren bli importert.", "ImportMissingEpisodesHelp": "Hvis aktivert, vil informasjon om manglende episoder importeres til Jellyfin-databasen og de vil vises under sesonger og serier. Dette kan føre til at skanning av biblioteket tar betydelig lengre tid.", - "InstallingPackage": "Installerer {0}", + "InstallingPackage": "Installerer {0} (versjon {1})", "InstantMix": "Direktemiks", "ItemCount": "{0} elementer", "Items": "Elementer", @@ -434,9 +434,9 @@ "LabelCustomCssHelp": "Bruk tilpasset CSS-kode for å endre stil på web-grensesnittet.", "LabelCustomDeviceDisplayName": "Visningsnavn:", "LabelCustomDeviceDisplayNameHelp": "Oppgi et egendefinert visningsnavn eller la det være tomt for å bruke navnet som enheten rapporterer.", - "LabelCustomRating": "Egen anmeldelse:", + "LabelCustomRating": "Egen aldersgrense:", "LabelDateAdded": "Dato lagt til:", - "LabelDateAddedBehavior": "Dato lagt til-atferd for nytt innhold:", + "LabelDateAddedBehavior": "Hvordan bestemme \"Dato lagt til\" for nytt innhold:", "LabelDateAddedBehaviorHelp": "Hvis en metadataverdi finnes, vil den alltid bli brukt fremfor noen av disse valgene.", "LabelDay": "Dag:", "LabelDeathDate": "Dødsdato:", @@ -457,7 +457,7 @@ "LabelEmbedAlbumArtDidl": "Bygg inn albumbilder i DIDL", "LabelEmbedAlbumArtDidlHelp": "Noen enheter foretrekker denne metoden for å motta albumomslag. Andre vil kunne få problemer med avspilling hvis dette alternativet er aktivert.", "LabelEnableAutomaticPortMap": "Aktiver automatisk portmapping", - "LabelEnableAutomaticPortMapHelp": "Forsøk å automatisk koble den eksterne porten til den lokale porten via UPnP. Dette fungerer ikke med alle rutere.", + "LabelEnableAutomaticPortMapHelp": "Forsøk å automatisk koble den eksterne porten til den lokale porten via UPnP. Dette fungerer ikke med alle rutere. Endringer trer ikke kraft før serveren startes på nytt.", "LabelEnableBlastAliveMessages": "Kringkast keepalive-meldinger", "LabelEnableBlastAliveMessagesHelp": "Aktiver hvis serveren ikke blir konsekvent oppdaget av andre UPnP-enheter på nettverket ditt.", "LabelEnableDlnaClientDiscoveryInterval": "Oppdateringsintervall for klient (i sekunder)", @@ -487,9 +487,9 @@ "LabelGroupMoviesIntoCollections": "Gruppér filmer i samlinger", "LabelGroupMoviesIntoCollectionsHelp": "Ved visning av filmlister vil filmer som tilhører en samling bli vist som ett gruppeelement.", "LabelH264Crf": "CRF-verdi for H264-koding:", - "LabelH264EncodingPreset": "Forhåndsinnstilling for H264-koding:", + "LabelEncoderPreset": "Forhåndsinnstilling for H264-koding:", "LabelHardwareAccelerationType": "Maskinvareakselerasjon:", - "LabelHardwareAccelerationTypeHelp": "Dette er en eksperimentell funksjon som bare er tilgjengelig på støttede systemer.", + "LabelHardwareAccelerationTypeHelp": "Maskinvareakselerasjon krever ytterligere konfigurasjon.", "LabelHomeScreenSectionValue": "Hjemskjermseksjon {0}:", "LabelHttpsPort": "Lokal HTTPS-port:", "LabelHttpsPortHelp": "TCP-portnummeret som Jellyfin sin HTTPS-server skal benytte.", @@ -501,7 +501,7 @@ "LabelImageFetchersHelp": "Aktiver og ranger dine foretrukne kilder for omslagsbilder i prioritert rekkefølge.", "LabelImageType": "Bildetype:", "LabelImportOnlyFavoriteChannels": "Begrens til kanaler som er merket som favoritt", - "LabelInNetworkSignInWithEasyPassword": "Tillat PIN-kode-innlogging på det lokale nettverket", + "LabelInNetworkSignInWithEasyPassword": "Tillat innlogging med PIN-kode på det lokale nettverket", "LabelInNetworkSignInWithEasyPasswordHelp": "Bruk den enkle PIN-koden for å logge inn på klienter som befinner seg i hjemmenettverket. Det vanlige passordet ditt vil kun være nødvendig ved pålogging fra eksternt nettverk. Hvis PIN-koden er tom, trenger du ikke passord i hjemmenettverket.", "LabelKeepUpTo": "Bevar opptil:", "LabelKidsCategories": "Barnekategorier:", @@ -713,7 +713,7 @@ "MessageCreateAccountAt": "Opprett en konto hos {0}", "MessageDeleteTaskTrigger": "Er du sikker på at du vil slette denne oppgaveutløseren?", "MessageDirectoryPickerBSDInstruction": "På BSD-systemer må du kanskje endre lagringsinnstillinger i FreeNAS Jail slik at Jellyfin har tilgang dit.", - "MessageDirectoryPickerInstruction": "Nettverksplasseringer kan skrives inn manuelt i tilfelle Nettverk-knappen ikke klarer å lokalisere enhetene dine. For eksempel {0} eller {1}.", + "MessageDirectoryPickerInstruction": "Nettverksbaner kan skrives inn manuelt i tilfelle søke-knappen ikke klarer å lokalisere enhetene dine. For eksempel {0} eller {1}.", "MessageDirectoryPickerLinuxInstruction": "På Linux-systemer med Arch Linux, CentOS, Debian, Fedora, openSUSE eller Ubuntu må du minimum gi tjenestebrukeren lesetilgang til lagringsplassene dine.", "MessageDownloadQueued": "Nedlasting lagt i kø.", "MessageEnablingOptionLongerScans": "Aktivering av dette alternativet kan føre til at skanning av biblioteket tar betydelig lenger tid.", @@ -783,7 +783,7 @@ "OptionAllowRemoteControlOthers": "Tillat fjernstyring av andre brukere", "OptionAllowRemoteSharedDevices": "Tillat fjernstyring av delte enheter", "OptionAllowRemoteSharedDevicesHelp": "DLNA-enheter betraktes som delte inntil en bruker begynner å styre dem.", - "OptionAllowUserToManageServer": "TIllatt denne brukeren å administrere serveren", + "OptionAllowUserToManageServer": "Tillatt denne brukeren å administrere serveren", "OptionAllowVideoPlaybackRemuxing": "Tillat avspilling av video som krever konvertering uten omkoding", "OptionAllowVideoPlaybackTranscoding": "Tillat filmavspilling som krever omkoding", "OptionAscending": "Økende", @@ -822,7 +822,6 @@ "OptionEnableAccessFromAllDevices": "Gi tilgang fra alle enheter", "OptionEnableAccessToAllChannels": "Gi tilgang til alle kanaler", "OptionEnableAccessToAllLibraries": "Gi tilgang til alle bibliotek", - "OptionEnableAutomaticServerUpdates": "Aktiver automatiske serveroppdateringer", "OptionEnableExternalContentInSuggestions": "Aktiver eksternt innhold i forslag", "OptionEnableExternalContentInSuggestionsHelp": "Tillat at Internett-trailere og programmer på direkte-TV inkluderes i foreslått innhold.", "OptionEnableForAllTuners": "Aktiver for alle mottakerenheter", @@ -1130,9 +1129,9 @@ "AllowOnTheFlySubtitleExtractionHelp": "Integrerte undertekster kan hentes ut fra videoer og bli levert til klienter i klartekst for å unngå omkoding av video. På noen systemer kan dette ta lang tid og føre til opphold i avspillingen samtidig som prosessen pågår. Deaktiver innstillingen for å brenne inn underteksten i videoen ved hjelp av omkoding når undertekstformatet ikke er støttet av klienten.", "AllowOnTheFlySubtitleExtraction": "Tillat at undertekster hentes ut fortløpende", "AllLanguages": "Alle språk", - "AllComplexFormats": "Alle avanserte formater (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Alle avanserte formater (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AccessRestrictedTryAgainLater": "Tilgang er for øyeblikket begrenset. Vennligst prøv igjen senere.", - "BurnSubtitlesHelp": "Angir om serveren skal brenne inn teksting når videoer konverteres, basert på tekstformatet. Ytelsen på serveren vil forbedres dersom tekstingen ikke brennes inn. Velg Automatisk for å brenne inn bildebaserte formater (VOBSUB, PGS, SUB/IDX, osv.) og enkelte ASS/SSA-undertekster.", + "BurnSubtitlesHelp": "Angir om serveren skal brenne inn teksting når videoer konverteres, basert på tekstformatet. Ytelsen på serveren vil forbedres dersom tekstingen ikke brennes inn. Velg Automatisk for å brenne inn bildebaserte formater (VOBSUB, PGS, SUB, IDX) og enkelte ASS eller SSA-undertekster.", "General": "Generelt", "ChangingMetadataImageSettingsNewContent": "Endringer gjort i innstillinger for metadata eller omslagsbilder vil kun gjelde nytt innhold i biblioteket ditt. For å endre eksisterende innhold, må du oppdatere dets metadata manuelt.", "DefaultSubtitlesHelp": "Undertekster lastes inn basert på flaggene \"standard\" og \"tvungen\" i videoens integrerte metadata. Språkpreferanser tas høyde for dersom flere valg er tilgjengelig.", @@ -1160,7 +1159,6 @@ "MediaInfoStreamTypeVideo": "Video", "OptionDownloadBannerImage": "Banner", "CopyStreamURLSuccess": "URLen ble kopiert.", - "DirectorValue": "Regissør: {0}", "OptionThumb": "Miniatyrbilde", "LabelInternetQuality": "Internettkvalitet:", "SubtitleAppearanceSettingsDisclaimer": "Disse innstillingene vil ikke påvirke grafiske undertekster (PGS, DVD, osv.) eller ASS/SSA-teksting som inkluderer sin egen formatering.", @@ -1181,7 +1179,7 @@ "MediaInfoSampleRate": "Samplingsfrekvens", "MediaInfoStreamTypeData": "Data", "Option3D": "3D", - "LabelVideo": "Video:", + "LabelVideo": "Video", "OptionAlbum": "Album", "OptionAlbumArtist": "Albumartist", "Filters": "Filtre", @@ -1220,12 +1218,12 @@ "Unmute": "Skru på lyd", "OptionIsHD": "HD", "ButtonAddImage": "Legg til bilde", - "DisplayModeHelp": "Velg hvilken slags skjerm du bruker Jellyfin på.", + "DisplayModeHelp": "Velg hvilket brukergrensesnitt oppsett du vil ha.", "DownloadsValue": "{0} nedlastninger", "EnableNextVideoInfoOverlayHelp": "Vis informasjon om den neste videoen i spillelisten ved slutten av en video.", "ExtractChapterImagesHelp": "Uthenting av kapittelbilder vil gjøre det mulig for klienter å vise bilder i menyer for å velge kapitel. Denne prosessen kan være treg, ressurskrevende, og kan kreve flere gigabyte med lagringsplass. Prosessen kjører når videoer oppdages, samt som en daglig planlagt hendelse. Tidsplanen kan endres i innstillinger for planlagte hendelser. Det anbefales ikke at denne prosessen kjøres når det er mange aktive brukere innlogget.", "Extras": "Ekstramateriale", - "HeaderKodiMetadataHelp": "For å aktivere eller deaktivere NFO-metadata, gå til bibliotekoppsettet i Jellyfin og finn valgene for metadatalagring.", + "HeaderKodiMetadataHelp": "For å aktivere eller deaktivere NFO-metadata, gå til bibliotekoppsettet i Jellyfin og finn valgene for lagring av metadata.", "OptionArtist": "Artist", "HeaderPhotoAlbums": "Fotoalbum", "HeaderRestartingServer": "Serveren starter på nytt", @@ -1268,7 +1266,7 @@ "LabelMatchType": "Matchtype:", "OptionPosterCard": "Plakatkort", "Uniform": "Jevn", - "DirectorsValue": "Regissører: {0}", + "Directors": "Regissører", "Disabled": "Deaktivert", "Disc": "Plate", "Display": "Vis", @@ -1284,8 +1282,7 @@ "FetchingData": "Henter ytterligere data", "Folders": "Mapper", "FormatValue": "Format: {0}", - "GenreValue": "Sjanger: {0}", - "GenresValue": "Sjangre: {0}", + "Genre": "Sjanger", "GroupBySeries": "Grupper etter serie", "GroupVersions": "Grupper etter versjon", "Guide": "Guide", @@ -1316,7 +1313,7 @@ "Horizontal": "Horisontal", "HttpsRequiresCert": "For å bruke sikker tilkobling må du legge inn et klarert SSL-sertifikat, for eksempel fra Let's Encrypt. Du må enten legge inn et sertifikat, eller deaktivere sikker tilkobling.", "LabelAlbumArtPN": "Albumomslag PN:", - "LabelAudio": "Lyd:", + "LabelAudio": "Lyd", "LabelAuthProvider": "Autentiserings-metode:", "LabelBitrate": "Bithastighet:", "LabelBurnSubtitles": "Brenn inn undertekst:", @@ -1345,7 +1342,7 @@ "LabelSpecialSeasonsDisplayName": "Visningsnavn for spesialsesong:", "LabelStatus": "Status:", "LabelSubtitleDownloaders": "Kilder for undertekst:", - "LabelSubtitles": "Undertekster:", + "LabelSubtitles": "Undertekster", "LabelTVHomeScreen": "Hjemskjerm for TV-modus:", "LabelTag": "Tagg:", "LabelTextBackgroundColor": "Tekstbagrunnsfarge:", @@ -1362,7 +1359,7 @@ "DashboardArchitecture": "Arkitektur: {0}", "LabelVideoBitrate": "Bithastighet på video:", "LabelVideoCodec": "Videokodek:", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "LabelXDlnaCap": "X-DLNA-begrensning:", "LabelXDlnaDoc": "X-DLNA-doc:", "LabelYear": "År:", @@ -1452,6 +1449,36 @@ "OptionResElement": "res element", "OptionRandom": "Tilfeldig", "HeaderFavoritePeople": "Favorittpersoner", - "Raised": "Hevet", - "ButtonSplit": "Del opp" + "Raised": "Opphøyet", + "ButtonSplit": "Del opp", + "SelectAdminUsername": "Vennligst velg et brukernavn for administrator kontoen. ", + "HeaderNavigation": "Navigering", + "MessageConfirmAppExit": "Vil du avslutte?", + "EnableFastImageFadeInHelp": "Bruk rask inntoning av animasjon for lastede bilder", + "EnableFastImageFadeIn": "Rask bilde inntoning", + "CopyStreamURLError": "Det var en feil under kopiering av URL'en.", + "LabelVideoResolution": "Oppløsning på video:", + "LabelPlayerDimensions": "Dimensjoner på avspiller:", + "LabelCorruptedFrames": "Korrupte bilder:", + "LabelStreamType": "Type strøm:", + "LabelDroppedFrames": "Fortapte bilder:", + "OptionForceRemoteSourceTranscoding": "Tvunget omkoding av eksterne media-kilder (som Direkte-TV)", + "NoCreatedLibraries": "Det virker som at du ikke har opprettet noen biblioteker ennå. {0}Vil du opprette et nå?{1}", + "AskAdminToCreateLibrary": "Spør en administrator om å lage et bibliotek.", + "PlaybackErrorNoCompatibleStream": "Det oppstod et problem med klientprofilering, og serveren sender ikke et kompatibelt medieformat.", + "AllowFfmpegThrottlingHelp": "Når en omkoding eller ompakking kommer langt nok foran den nåværende avspillingsposisjonen stoppes prosessen slik at den bruker mindre ressurser. Dette er mest nyttig når du sjeldent bytter posisjon i videoen. Slå av dette hvis du opplever problemer med avspilling.", + "AllowFfmpegThrottling": "Begrens hastighet på omkoding", + "Episode": "Episode", + "ClientSettings": "Klientinstillinger", + "BoxSet": "Samleboks", + "Artist": "Artist", + "AlbumArtist": "Albumartist", + "Album": "Album", + "LabelLibraryPageSizeHelp": "Velger hvor mange elementer som skal bli vist på en bibliotek side. Velg 0 for å deaktivere.", + "LabelLibraryPageSize": "Biblioteks side størrelse:", + "LabelDeinterlaceMethod": "Deinterlacing metode:", + "HeaderFavoritePlaylists": "Favorittspillelister", + "DeinterlaceMethodHelp": "Velg deinterlacing metoden som skal bli brukt når man transkoder interlaced innhold.", + "ButtonTogglePlaylist": "Spilleliste", + "ButtonToggleContextMenu": "Mer" } diff --git a/src/strings/nl.json b/src/strings/nl.json index 8e5c9714a4..a3c3a84f13 100644 --- a/src/strings/nl.json +++ b/src/strings/nl.json @@ -14,7 +14,7 @@ "Alerts": "Meldingen", "All": "Alle", "AllChannels": "Alle kanalen", - "AllComplexFormats": "Alle complexe formaten (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Alle Complexe Formaten (ASS, SSA, VOBSUB, PGS, SUB, IDX, etc.)", "AllEpisodes": "Alle afleveringen", "AllLanguages": "Alle talen", "AllLibraries": "Alle bibliotheken", @@ -26,7 +26,7 @@ "AllowRemoteAccess": "Externe verbindingen met deze Jellyfin Server toestaan.", "AllowRemoteAccessHelp": "Indien niet aangevinkt worden alle externe verbindingen geblokkeerd.", "AllowedRemoteAddressesHelp": "Komma-gescheiden lijst van IP-adressen of IP/netmask adressen voor netwerken die op afstand verbinding mogen maken. Indien blanco, worden alle externe adressen toegestaan.", - "AlwaysPlaySubtitles": "Altijd ondertitels weergeven", + "AlwaysPlaySubtitles": "Altijd afspelen", "AlwaysPlaySubtitlesHelp": "Ondertitels die met de taalvoorkeur overeenkomen worden weergegeven, ongeacht de audiotaal.", "AnyLanguage": "Elke taal", "Anytime": "Op elk moment", @@ -49,7 +49,7 @@ "BoxRear": "Hoes (achterkant)", "Browse": "Bladeren", "BrowsePluginCatalogMessage": "Bekijk de Plugin catalogus voor beschikbare Plug-ins.", - "BurnSubtitlesHelp": "Bepaalt of de server ondertitels moet inbranden wanneer video's op basis van het soort ondertitels geconverteerd moeten worden. Het inbranden van ondertitels heeft een negatief effect op de server performance. Selecteer Automatisch om op afbeelding gebaseerde formaten (VOBSUB, PGS, SUB/IDX etc.) en bepaalde ASS/SSA ondertitels in te branden.", + "BurnSubtitlesHelp": "Bepaalt of de server ondertitels moet branden bij het transcoderen van video's. Als u dit vermijd, worden de prestaties aanzienlijk verbeterd. Selecteer Auto om op afbeeldingen gebaseerde formaten (VOBSUB, PGS, SUB/IDX etc.) en bepaalde ASS/SSA ondertitels te branden.", "ButtonAdd": "Toevoegen", "ButtonAddMediaLibrary": "Voeg Media Bibliotheek toe", "ButtonAddScheduledTaskTrigger": "Trigger Toevoegen", @@ -168,8 +168,7 @@ "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}", + "Directors": "Regisseurs", "Disabled": "Uitgeschakeld", "Disc": "Disk", "Disconnect": "Loskoppelen", @@ -179,7 +178,7 @@ "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 de server configuratie.", - "DisplayModeHelp": "Selecteer het scherm type waar u Jellyfin op draait", + "DisplayModeHelp": "Selecteer het schermtype waar Jellyfin op draait.", "DoNotRecord": "Niet opnemen", "Down": "Omlaag", "Download": "Downloaden", @@ -196,10 +195,10 @@ "EnableColorCodedBackgrounds": "Kleurgecodeerde achtergronden", "EnableDisplayMirroring": "Beeld spiegelen", "EnableExternalVideoPlayers": "Externe video spelers", - "EnableExternalVideoPlayersHelp": "Een menu voor externe spelers zal worden getoond bij het afspelen van video's", + "EnableExternalVideoPlayersHelp": "Een menu voor externe spelers wordt getoond bij het afspelen van video's.", "EnableHardwareEncoding": "Activeer hardwaredecodering", "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", + "EnableNextVideoInfoOverlayHelp": "Toon informatie over de volgende video in de afspeellijst aan het einde van de video.", "EnablePhotos": "Foto's weergeven", "EnablePhotosHelp": "Afbeeldingen worden herkend en weergegeven naast andere mediabestanden.", "EnableStreamLooping": "Livestreams automatisch herhalen", @@ -252,10 +251,10 @@ "GuideProviderLogin": "Log in", "GuideProviderSelectListings": "Selecteer lijst", "H264CrfHelp": "De Constant Rate Factor (CRF) is de standaard kwaliteit instelling voor de x264-encoder. U kunt de waarden tussen 0 en 51, in voorkomend lagere waarden zou resulteren in een betere kwaliteit (ten koste van hogere bestandsgrootte). aanbevolen zijn waarden tussen de 18 en 28. De standaard voor de x264 is 23, zodat u deze kunt gebruiken als uitgangspunt.", - "H264EncodingPresetHelp": "Kies een hogere waarde om de prestaties, of een tragere waarde om de kwaliteit te verbeteren.", + "EncoderPresetHelp": "Kies een hogere waarde om de prestaties, of een tragere waarde om de kwaliteit te verbeteren.", "HDPrograms": "HD Programma's", "HandledByProxy": "Behandeld door reverse proxy", - "HardwareAccelerationWarning": "Hardwareversnelling inschakelen kan instabiliteit veroorzaken in sommige omgevingen. Zorg ervoor dat uw besturingssysteem en videostuurprogramma's volledig up-to-date zijn. Als u problemen ondervindt bij het afspelen van video, nadat u dit hebt ingeschakeld, moet u de instelling terugzetten naar Auto.", + "HardwareAccelerationWarning": "Hardwareversnelling inschakelen kan instabiliteit veroorzaken in sommige omgevingen. Zorg ervoor dat uw besturingssysteem en videostuurprogramma's volledig up-to-date zijn. Als u problemen ondervindt bij het afspelen van video, nadat u dit hebt ingeschakeld, moet u de instelling terugzetten naar geen.", "HeaderAccessSchedule": "Schema Toegang", "HeaderAccessScheduleHelp": "Maak een toegangsschema om de toegang tot bepaalde tijden te beperken.", "HeaderActiveDevices": "Actieve apparaten", @@ -279,7 +278,7 @@ "HeaderAudioBooks": "Luisterboeken", "HeaderAudioSettings": "Audio Instellingen", "HeaderAutomaticUpdates": "Automatische updates", - "HeaderBlockItemsWithNoRating": "Blokkeer items met geen of niet herkende keurinformatie.", + "HeaderBlockItemsWithNoRating": "Blokkeer items met geen of niet herkende beoordelingsinformatie:", "HeaderBooks": "Boeken", "HeaderBranding": "Huisstijl", "HeaderCancelRecording": "Opname Annuleren", @@ -412,7 +411,7 @@ "HeaderSelectTranscodingPath": "Selecteer Tijdelijke Transcodeer Pad", "HeaderSelectTranscodingPathHelp": "Bladeren of voer het pad in om te gebruiken voor het transcoderen van tijdelijke bestanden. De map moet beschrijfbaar zijn.", "HeaderSendMessage": "Stuur bericht", - "HeaderSeries": "Series:", + "HeaderSeries": "Series", "HeaderSeriesOptions": "Series Opties", "HeaderSeriesStatus": "Seriestatus", "HeaderServerSettings": "Server Instellingen", @@ -462,9 +461,9 @@ "Images": "Afbeeldingen", "ImportFavoriteChannelsHelp": "Bij inschakelen zullen alleen kanalen geïmporteerd worden die op de tuner als favoriet aangemerkt zijn.", "ImportMissingEpisodesHelp": "Indien ingeschakeld, wordt informatie over ontbrekende afleveringen in uw Jellyfin de database geïmporteerd en weergegeven in de seizoenen en series. Dit kan aanzienlijk langere bibliotheekscans veroorzaken.", - "InstallingPackage": "Installeren van {0}", + "InstallingPackage": "Installeren van {0} (versie {1})", "Kids": "Kinderen", - "Label3DFormat": "3D formaat", + "Label3DFormat": "3D formaat:", "LabelAbortedByServerShutdown": "(Afgebroken door afsluiten van de server)", "LabelAccessDay": "Dag van de week:", "LabelAccessEnd": "Eind tijd:", @@ -492,7 +491,7 @@ "LabelArtists": "Artiest:", "LabelArtistsHelp": "Scheidt meerdere met een ;", "LabelAudioLanguagePreference": "Voorkeurs audiotaal:", - "LabelAutomaticallyRefreshInternetMetadataEvery": "Vernieuw metagegevens automatisch van het internet", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Vernieuw metagegevens automatisch van het internet:", "LabelBindToLocalNetworkAddress": "Binden aan het lokale netwerk adres:", "LabelBindToLocalNetworkAddressHelp": "Optioneel. Overrule het lokale IP-adres om aan de http-server te binden. Indien leeg gelaten, zal de server binden aan alle beschikbare adressen. Het veranderen van deze waarde vereist herstarten van Jellyfin Server.", "LabelBirthDate": "Geboortedatum:", @@ -507,7 +506,7 @@ "LabelCertificatePassword": "Certificaat paswoord:", "LabelCertificatePasswordHelp": "Als je certificaat een paswoord vereist, vul het dan hier in alstublieft.", "LabelChannels": "Kanalen:", - "LabelCollection": "Collectie", + "LabelCollection": "Collectie:", "LabelCommunityRating": "Beoordeling gemeenschap:", "LabelContentType": "Inhoud type:", "LabelCountry": "Land:", @@ -548,7 +547,7 @@ "LabelEmbedAlbumArtDidl": "Insluiten van albumhoezen in Didl", "LabelEmbedAlbumArtDidlHelp": "Sommige apparaten prefereren deze methode voor het verkrijgen van albumhoezen. Anderen kunnen falen om af te spelen met deze optie ingeschakeld.", "LabelEnableAutomaticPortMap": "Schakel automatisch poort vertalen in", - "LabelEnableAutomaticPortMapHelp": "Probeer om de publieke poort automatisch te vertalen naar de lokale poort via UPnP. Dit werkt niet op alle routers.", + "LabelEnableAutomaticPortMapHelp": "Poging om de publieke poort automatisch om te zetten naar een lokale poort via UPnP. Dit werkt niet op alle routers. De wijzigingen worden pas actief na een herstart van de server.", "LabelEnableBlastAliveMessages": "Alive berichten zenden", "LabelEnableBlastAliveMessagesHelp": "Zet dit aan als de server niet betrouwbaar door andere UPnP-apparaten op uw netwerk wordt gedetecteerd.", "LabelEnableDlnaClientDiscoveryInterval": "Interval voor het zoeken naar clients (seconden)", @@ -564,7 +563,7 @@ "LabelEnableRealtimeMonitorHelp": "Wijzigingen aan bestanden worden op ondersteunde bestandssystemen direct verwerkt.", "LabelEnableSingleImageInDidlLimit": "Beperk tot één enkele ingesloten afbeelding", "LabelEnableSingleImageInDidlLimitHelp": "Sommige apparaten zullen niet goed weergeven als er meerdere afbeeldingen ingesloten zijn in Didl.", - "LabelEndDate": "Eind datum|", + "LabelEndDate": "Eind datum:", "LabelEpisodeNumber": "Afleveringsnummer:", "LabelEvent": "Gebeurtenis:", "LabelEveryXMinutes": "Iedere:", @@ -580,9 +579,9 @@ "LabelServerNameHelp": "Deze naam wordt gebruikt om de server te identificeren, standaard is deze de server zijn computer naam.", "LabelGroupMoviesIntoCollections": "Groepeer films in collecties", "LabelGroupMoviesIntoCollectionsHelp": "Bij de weergave van film lijsten, zullen films die tot een collectie behoren worden weergegeven als een gegroepeerd object.", - "LabelH264EncodingPreset": "H264 codering preset:", + "LabelEncoderPreset": "H264 codering preset:", "LabelHardwareAccelerationType": "Hardware acceleratie:", - "LabelHardwareAccelerationTypeHelp": "Dit is een experimentele functie die alleen beschikbaar is op ondersteunde systemen.", + "LabelHardwareAccelerationTypeHelp": "Hardwarematige versnelling vereist extra configuratie.", "LabelHomeNetworkQuality": "Thuisnetwerk kwaliteit:", "LabelHomeScreenSectionValue": "Beginscherm sectie {0}:", "LabelHttpsPort": "Lokale HTTPS poort nummer:", @@ -674,7 +673,7 @@ "LabelParentNumber": "Bovenliggend nummer:", "LabelParentalRating": "Kijkwijzer classificatie:", "LabelPassword": "Wachtwoord:", - "LabelPasswordConfirm": "Wachtworod (Bevestig)", + "LabelPasswordConfirm": "Wachtwoord (Bevestig):", "LabelPasswordRecoveryPinCode": "Pincode:", "LabelPath": "Pad:", "LabelPersonRole": "Rol:", @@ -682,17 +681,17 @@ "LabelPlaceOfBirth": "Geboorteplaats:", "LabelPlayDefaultAudioTrack": "Standaard audio spoor afspelen ongeacht de taal", "LabelPlaylist": "Afspeellijst:", - "LabelPostProcessor": "Nabewerkings toepassing:", - "LabelPostProcessorArguments": "Nabewerkings command line argumenten:", + "LabelPostProcessor": "Nabewerkings- toepassing:", + "LabelPostProcessorArguments": "Nabewerkings command lijn argumenten:", "LabelPostProcessorArgumentsHelp": "Gebruik {path} als het pad naar het opnamebestand.", - "LabelPreferredDisplayLanguage": "Voorkeurs weergavetaal:", + "LabelPreferredDisplayLanguage": "Voorkeur weergavetaal:", "LabelPreferredDisplayLanguageHelp": "Vertaling van Jellyfin is een voortdurend project.", - "LabelPreferredSubtitleLanguage": "Voorkeurstaal ondertitels:", + "LabelPreferredSubtitleLanguage": "Voorkeurstaal ondertiteling:", "LabelPrevious": "Vorige", "LabelProfileAudioCodecs": "Geluidscodecs:", - "LabelProfileCodecsHelp": "Gescheiden door een komma. Deze kan leeg gelaten worden om te laten gelden voor alle codecs.", - "LabelProfileContainersHelp": "Gescheiden door een komma. Deze kan leeg gelaten worden om te laten gelden voor alle containers.", - "LabelProtocol": "Protokol:", + "LabelProfileCodecsHelp": "Gescheiden door een komma. Dit kan leeg worden gelaten om te laten gelden voor alle codecs.", + "LabelProfileContainersHelp": "Gescheiden door een komma. Dit kan leeg worden gelaten om te laten gelden voor alle containers.", + "LabelProtocol": "Protocol:", "LabelProtocolInfoHelp": "De waarde die wordt gebruikt bij het reageren op GetProtocolInfo verzoeken van het apparaat.", "LabelPublicHttpPort": "Publieke HTTP poort nummer:", "LabelPublicHttpPortHelp": "Het publieke poortnummer dat moet worden toegewezen aan de lokale HTTP poort.", @@ -703,12 +702,12 @@ "LabelRecord": "Opnemen:", "LabelRecordingPath": "Standaard opname pad:", "LabelRecordingPathHelp": "Geef de standaard locatie op om opnamen op te slaan. Indien leeg gelaten, zal de map van de server-programma gegevens worden gebruikt.", - "LabelRefreshMode": "Vernieuw-modus", + "LabelRefreshMode": "Ververs-modus:", "LabelReleaseDate": "Uitgave datum:", "LabelRemoteClientBitrateLimit": "Internet streaming bitrate limiet (Mbps):", - "LabelRemoteClientBitrateLimitHelp": "Een optionele bitrate limiet per stream voor alle apparaten buiten het netwerk. Dit is handig om te voorkomen dat apparaten een hogere bitrate vragen dan je internetverbinding aan kan. Dit kan een verhoogde belasting van de CPU in je server veroorzaken om om videos direct te transcoderen naar een lagere bitrate.", + "LabelRemoteClientBitrateLimitHelp": "Een optionele bitrate per stream limiet voor alle apparaten buiten het netwerk. Dit is handig om te voorkomen dat apparaten een hogere bitrate vragen dan je internetverbinding aan kan. Dit kan een verhoogde belasting van de CPU in je server veroorzaken om videos direct te transcoderen naar een lagere bitrate.", "LabelRuntimeMinutes": "Speelduur (minuten):", - "LabelSaveLocalMetadata": "Afbeeldingen opslaan in de mediamappen", + "LabelSaveLocalMetadata": "Afbeeldingen opslaan in mediamappen", "LabelSaveLocalMetadataHelp": "Door afbeeldingen op te slaan in de mediamappen kunnen ze makkelijker worden aangepast.", "LabelScheduledTaskLastRan": "Laatste keer {0}, duur {1}.", "LabelScreensaver": "Schermbeveiliging:", @@ -723,31 +722,31 @@ "LabelSeriesRecordingPath": "Serieopname pad (optioneel):", "LabelServerHost": "Server:", "LabelServerHostHelp": "192.168.1.100:8096 of https://mijnserver.nl", - "LabelSimultaneousConnectionLimit": "Gelijktijdige streams limiet:", - "LabelSkipBackLength": "Terugspoellengte", - "LabelSkipForwardLength": "Vooruitspoellengte", + "LabelSimultaneousConnectionLimit": "Gelijktijdige stream limiet:", + "LabelSkipBackLength": "Terugspoellengte:", + "LabelSkipForwardLength": "Vooruitspoellengte:", "LabelSkipIfAudioTrackPresent": "Overslaan als het standaard geluidsspoor overeenkomt met de taal van de download", - "LabelSkipIfAudioTrackPresentHelp": "Vink dit uit om ervoor te zorgen dat alle video's ondertiteings krijgen, ongeacht de geluidstaal.", + "LabelSkipIfAudioTrackPresentHelp": "Vink dit uit om ervoor te zorgen dat alle video's ondertitelingen krijgen, ongeacht de geluidstaal.", "LabelSkipIfGraphicalSubsPresent": "Overslaan als de video al ingesloten ondertiteling heeft", "LabelSkipIfGraphicalSubsPresentHelp": "Tekstversies van ondertiteling opslaan zal video's efficiënter overbrengen en de kans op transcodering van video's verkleinen.", "LabelSonyAggregationFlags": "Sony aggregatie vlaggen:", "LabelSonyAggregationFlagsHelp": "Bepaalt de inhoud van het aggregationFlags element in de urn: schemas-sonycom av namespace.", "LabelSortBy": "Sorteren op:", - "LabelSortOrder": "Sorteervolgorde:", + "LabelSortOrder": "Sorteer volgorde:", "LabelSortTitle": "Sorteer titel:", "LabelSoundEffects": "Geluidseffecten:", "LabelSource": "Bron:", - "LabelSpecialSeasonsDisplayName": "De weergavenaam van de speciale seizoen:", + "LabelSpecialSeasonsDisplayName": "De weergavenaam van een speciaal seizoen:", "LabelSportsCategories": "Sport categorieën:", "LabelStartWhenPossible": "Start indien mogelijk:", "LabelStopWhenPossible": "Stop indien mogelijk:", "LabelStopping": "Stoppen", - "LabelSubtitleDownloaders": "Ondertiteldownloaders:", + "LabelSubtitleDownloaders": "Ondertiteling downloaders:", "LabelSubtitleFormatHelp": "Voorbeeld: srt", - "LabelSubtitlePlaybackMode": "Ondertitel mode:", - "LabelSubtitles": "Ondertitels:", + "LabelSubtitlePlaybackMode": "Ondertitel modus:", + "LabelSubtitles": "Ondertiteling", "LabelSupportedMediaTypes": "Ondersteunde Media Types:", - "LabelTVHomeScreen": "TV mode begin scherm", + "LabelTVHomeScreen": "TV mode begin scherm:", "LabelTextBackgroundColor": "Tekst achtergrond kleur:", "LabelTextColor": "Tekst kleur:", "LabelTextSize": "Tekst grootte:", @@ -757,9 +756,9 @@ "LabelTitle": "Titel:", "LabelTrackNumber": "Tracknummer:", "LabelTranscodingAudioCodec": "Geluidscodec:", - "LabelTranscodingTempPathHelp": "Specificeer een eigen pad voor de transcode bestanden die geleverd worden aan cliënten. Laat leeg om het server standaard te gebruiken.", - "LabelTranscodingThreadCount": "Aantal transcodeer threads:", - "LabelTranscodingThreadCountHelp": "Selecteer het maximale aantal threads die gebruikt mogen worden om te transcoderen. Bij een lager aantal zal het CPU gebruik lager zijn, maar kan de afspeelkwaliteit minder zijn.", + "LabelTranscodingTempPathHelp": "Specificeer een eigen pad voor de transcode bestanden die geleverd worden aan gebruikers. Laat leeg om de server standaard te gebruiken.", + "LabelTranscodingThreadCount": "Aantal transcodeer draden:", + "LabelTranscodingThreadCountHelp": "Selecteer het maximale aantal draden die gebruikt mogen worden om te kunnen transcoderen. Bij een lager aantal zal het processorgebruik lager zijn, maar kan de afspeelkwaliteit minder zijn voor een vloeiende ervaring.", "LabelTunerIpAddress": "Tuner IP adres:", "LabelTunerType": "Soort Tuner:", "LabelTypeText": "Tekst", @@ -767,8 +766,8 @@ "LabelUser": "Gebruiker:", "LabelUserAgent": "User-agent:", "LabelUserLibrary": "Gebruikers Bibliotheek:", - "LabelUserLibraryHelp": "Selecteer welke gebruikers bibliotheek weergegeven moet worden op het apparaat. Laat leeg standaardinstelling te gebruiken.", - "LabelUserRemoteClientBitrateLimitHelp": "Schrijf de standaard globale waarde gedefineerd in de server afspeel instellingen.", + "LabelUserLibraryHelp": "Selecteer welke gebruikers bibliotheek weergegeven moeten worden op het apparaat. Laat leeg om de standaardinstelling te gebruiken.", + "LabelUserRemoteClientBitrateLimitHelp": "Schrijf de standaard globale waarde gedefinieerd in de server afspeel instellingen.", "LabelUsername": "Gebruikersnaam:", "LabelVaapiDevice": "VA API Apparaat:", "LabelVaapiDeviceHelp": "Dit is de render knooppunt dat wordt gebruikt voor hardwareversnelling.", @@ -793,11 +792,11 @@ "List": "Lijst", "LiveBroadcasts": "Live uitzendingen", "ManageLibrary": "Bibliotheek beheren", - "ManageRecording": "Beheren opnames", + "ManageRecording": "Beheer opnames", "MapChannels": "Map Kanalen", - "MarkPlayed": "Markeren als Afgespeeld", - "MarkUnplayed": "Markeren als Niet Afgespeeld", - "MaxParentalRatingHelp": "Media met een hogere classificatie wordt niet weergegeven", + "MarkPlayed": "Markeren als afgespeeld", + "MarkUnplayed": "Markeren als niet afgespeeld", + "MaxParentalRatingHelp": "Media met een hogere classificatie wordt niet weergegeven voor deze gebruiker.", "MediaInfoAnamorphic": "Anamorf", "MediaInfoAspectRatio": "Beeld verhouding", "MediaInfoBitDepth": "Bitdiepte", @@ -812,48 +811,48 @@ "MediaInfoPixelFormat": "Pixel formaat", "MediaInfoProfile": "Profiel", "MediaInfoResolution": "Resolutie", - "MediaInfoSampleRate": "Samplesnelheid", + "MediaInfoSampleRate": "Bemonsteringsfrequentie", "MediaInfoSize": "Grootte", "MediaInfoTimestamp": "Tijdstempel", - "MediaIsBeingConverted": "De media wordt geconverteerd naar een formaat dat compatible is met het apparaat dat wordt gebruikt om de media af te spelen.", - "MessageAlreadyInstalled": "Deze versie is al geïnstalleerd", - "MessageAreYouSureDeleteSubtitles": "Weet u zeker dat u dit ondertitelbestand wilt verwijderen?", + "MediaIsBeingConverted": "De media wordt geconverteerd naar een formaat dat leesbaar is met het apparaat dat wordt gebruikt om de media af te spelen.", + "MessageAlreadyInstalled": "Deze versie is al geïnstalleerd.", + "MessageAreYouSureDeleteSubtitles": "Weet u zeker dat u dit ondertitelingsbestand wilt verwijderen?", "MessageAreYouSureYouWishToRemoveMediaFolder": "Weet u zeker dat u deze media map wilt verwijderen?", "MessageConfirmDeleteGuideProvider": "Weet u zeker dat u deze gidsprovider wilt verwijderen?", "MessageConfirmDeleteTunerDevice": "Weet u zeker dat u dit apparaat wilt verwijderen?", "MessageConfirmProfileDeletion": "Weet u zeker dat u dit profiel wilt verwijderen?", - "MessageConfirmRecordingCancellation": "Opnemen annuleren?", + "MessageConfirmRecordingCancellation": "Opname annuleren?", "MessageConfirmRemoveMediaLocation": "Weet u zeker dat u deze locatie wilt verwijderen?", "MessageConfirmRestart": "Weet u zeker dat u Jellyfin Server wilt herstarten?", - "MessageConfirmRevokeApiKey": "Weet u zeker dat u deze api key in wilt trekken? De verbinding met Jellyfin Server zal direct verbroken worden.", + "MessageConfirmRevokeApiKey": "Weet u zeker dat u deze api sleutel in wilt trekken? De verbinding met Jellyfin Server zal direct verbroken worden.", "MessageConfirmShutdown": "Weet u zeker dat u de server wilt afsluiten?", "MessageContactAdminToResetPassword": "Neem contact op met de server beheerder om uw wachtwoord te resetten.", "MessageCreateAccountAt": "Maak een account bij {0}", - "MessageDeleteTaskTrigger": "Weet u zeker dat u deze taak trigger wilt verwijderen?", + "MessageDeleteTaskTrigger": "Weet u zeker dat u deze signaal taak wilt verwijderen?", "MessageDirectoryPickerBSDInstruction": "Voor BSD kan het noodzakelijk zijn opslag op uw FreeNAS Jail te configureren voordat Jellyfin het kan benaderen.", - "MessageDirectoryPickerInstruction": "Netwerk paden kunnen handmatig worden ingevoerd in het geval de Netwerk knop faalt om uw apparatuur te lokaliseren . Bijvoorbeeld: {0} of {1}.", + "MessageDirectoryPickerInstruction": "Netwerk paden kunnen handmatig worden ingevoerd in het geval de Netwerk knop faalt om uw apparatuur te lokaliseren. Bijvoorbeeld: {0} of {1}.", "MessageDirectoryPickerLinuxInstruction": "Voor Linux op Arch Linux, CentOS, Debian, Fedora, openSUSE, of Ubuntu, moet u de service-gebruiker ten minste leestoegang tot uw opslaglocaties verlenen.", "MessageDownloadQueued": "Download in de wachtrij geplaatst.", - "MessageEnablingOptionLongerScans": "Inschakelen van deze optie kan leiden tot langere doorlooptijd van bibliotheek scans.", + "MessageEnablingOptionLongerScans": "Het inschakelen van deze optie kan leiden tot langere doorlooptijd van bibliotheek scans.", "MessageFileReadError": "Er is een fout opgetreden bij het lezen van het bestand. Probeer het opnieuw.", - "MessageForgotPasswordFileCreated": "Het volgende bestand met instructies hoe nu verder te gaan is gemaakt:", + "MessageForgotPasswordFileCreated": "Het volgende bestand is gecreëerd op uw server en bevat instructies om verder te gaan:", "MessageForgotPasswordInNetworkRequired": "Probeer de wachtwoord herstel procedure opnieuw vanuit uw thuisnetwerk.", "MessageInstallPluginFromApp": "Deze plugin moet geïnstalleerd worden vanuit de app waarin u het wilt gebruiken.", "MessageInvalidForgotPasswordPin": "Er is een ongeldige of verlopen pincode ingegeven. Probeer opnieuw.", - "MessageInvalidUser": "Foutieve gebruikersnaam of wachtwoord. Probeer opnieuw.", + "MessageInvalidUser": "Incorrecte gebruikersnaam of wachtwoord. Probeer opnieuw.", "MessageItemSaved": "Item opgeslagen.", - "MessageItemsAdded": "Items toegevoegd", + "MessageItemsAdded": "Items toegevoegd.", "MessageLeaveEmptyToInherit": "Leeg laten om instellingen van bovenliggend item of de algemene waarde over te nemen.", "MessageNoAvailablePlugins": "Geen beschikbare Plugins.", "MessageNoMovieSuggestionsAvailable": "Er zijn momenteel geen film suggesties beschikbaar. Begin met het bekijken en waardeer uw films, kom daarna terug om uw aanbevelingen te bekijken.", - "MessageNoPluginsInstalled": "U heeft geen Plugins geïnstalleerd.", - "MessageNoTrailersFound": "Geen trailers gevonden. Installeer het Trailers kanaal en verbeter uw film ervaring door middel van een bibliotheek met internet trailers.", + "MessageNoPluginsInstalled": "U heeft geen plugins geïnstalleerd.", + "MessageNoTrailersFound": "Geen trailers gevonden. Installeer het Trailers kanaal om uw film ervaring te verbeteren door middel van het toevoegen van een bibliotheek met internet trailers.", "MessageNothingHere": "Lijst is leeg.", - "MessagePasswordResetForUsers": "De volgende gebruikers hebben hun wachtwoord laten resetten. Zij kunnen nu inloggen met de pin codes die gebruikt werden om de reset te voltooien.", + "MessagePasswordResetForUsers": "De volgende gebruikers hebben hun wachtwoord laten herstellen. Zij kunnen nu inloggen met de pin codes die gebruikt werden om de herstel te voltooien.", "MessagePlayAccessRestricted": "Afspelen hiervan is op dit moment niet toegestaan. Neem contact op met uw server beheerder voor meer informatie.", "MessagePleaseEnsureInternetMetadata": "Zorg ervoor dat het downloaden van internet-metadata is ingeschakeld.", "MessagePleaseWait": "Even geduld. Dit kan even duren.", - "MessagePluginConfigurationRequiresLocalAccess": "Meld svp. op de lokale server aan om deze plugin te configureren.", + "MessagePluginConfigurationRequiresLocalAccess": "Om deze plugin te configuren moet u zich aanmelden direct op de lokale server.", "MessagePluginInstallDisclaimer": "Plugins ontwikkeld door leden van de Jellyfin gemeenschap zijn een geweldige manier om uw Jellyfin ervaring met extra functies en voordelen te verbeteren. Alvorens te installeren, dient u zich bewust te zijn van de gevolgen die zij kunnen hebben op uw Jellyfin Server, zoals langere bibliotheek scans, extra achtergrondinformatie verwerking, en een verminderde stabiliteit van het systeem.", "MessageReenableUser": "Zie hieronder hoe opnieuw in te schakelen", "MessageSettingsSaved": "Instellingen opgeslagen.", @@ -883,13 +882,13 @@ "NewEpisodesOnly": "Alleen nieuwe afleveringen", "News": "Nieuws", "Next": "Volgende", - "NextUp": "Volgende", + "NextUp": "Hierna", "No": "Nee", "NoNewDevicesFound": "Er zijn geen nieuwe apparaten gevonden. Sluit dit melding en voer handmatig de apparaat gegevens in om een nieuwe tuner toe te voegen.", "NoNextUpItemsMessage": "Niets gevonden. Start met kijken!", "NoPluginConfigurationMessage": "Deze plugin heeft geen instellingen te configureren.", "NoSubtitleSearchResultsFound": "Geen resultaten gevonden.", - "NoSubtitles": "Geen ondertitels", + "NoSubtitles": "Geen ondertiteling", "NoSubtitlesHelp": "Ondertitels worden niet standaard weergegeven. Deze kunnen tijdens het afspelen handmatig worden ingeschakeld.", "None": "Geen", "Normal": "Normaal", @@ -897,14 +896,14 @@ "OneChannel": "Eén kanaal", "OnlyForcedSubtitles": "Alleen geforceerde ondertitels", "OnlyForcedSubtitlesHelp": "Alleen als geforceerd gemarkeerde ondertitels worden geladen.", - "OnlyImageFormats": "Alleen image formaten (VOBSUP, PGS, SUB, etc.)", + "OnlyImageFormats": "Alleen beeld formaten (VOBSUP, PGS, SUB, etc.)", "OptionAdminUsers": "Beheerders", "OptionAlbumArtist": "Albumartiest", "OptionAllUsers": "Alle gebruikers", "OptionAllowAudioPlaybackTranscoding": "Afspelen van geluid via transcoding toestaan", "OptionAllowBrowsingLiveTv": "Live TV toegang toestaan", "OptionAllowContentDownloading": "Media downloaden en synchroniseren toestaan", - "OptionAllowLinkSharing": "Sta social media delen toe", + "OptionAllowLinkSharing": "Sta het delen op social media toe", "OptionAllowLinkSharingHelp": "Alleen webpagina's met media-informatie worden gedeeld. Media-bestanden worden nooit publiekelijk gedeeld. Gedeelde items zijn beperkt in tijd en verlopen na {0} dagen.", "OptionAllowManageLiveTv": "Live TV opname beheer toestaan", "OptionAllowMediaPlayback": "Media afspelen toestaan", @@ -915,7 +914,7 @@ "OptionAllowSyncTranscoding": "Het downloaden en synchroniseren van media via transcoding toestaan", "OptionAllowUserToManageServer": "Deze gebruiker kan de server beheren", "OptionAllowVideoPlaybackRemuxing": "Sta afspelen toe van video die conversie vereist zonder re-encoding", - "OptionAllowVideoPlaybackTranscoding": "Afspelen van video via transcoding toestaan", + "OptionAllowVideoPlaybackTranscoding": "Afspelen van video die transcoderen vereisen toestaan", "OptionArtist": "Artiest", "OptionAscending": "Oplopend", "OptionAutomatic": "Automatisch", @@ -928,8 +927,8 @@ "OptionBlockMusic": "Muziek", "OptionBlockTvShows": "TV Series", "OptionBluray": "Blu-ray", - "OptionCommunityRating": "Gemeenschaps Waardering", - "OptionContinuing": "Wordt vervolgd...", + "OptionCommunityRating": "Algemene Waardering", + "OptionContinuing": "Wordt vervolgd", "OptionCriticRating": "Kritieken", "OptionCustomUsers": "Aangepast", "OptionDaily": "Dagelijks", @@ -938,7 +937,7 @@ "OptionDateAddedImportTime": "Gebruik scan datum", "OptionDatePlayed": "Datum afgespeeld", "OptionDescending": "Aflopend", - "OptionDisableUser": "Dit account uitschakelen", + "OptionDisableUser": "Deze gebruiker uitschakelen", "OptionDisableUserHelp": "Indien uitgeschakeld zal de server geen verbindingen van deze gebruiker toestaan. Bestaande verbindingen zullen abrupt worden beëindigd.", "OptionDislikes": "Niet leuk", "OptionDisplayFolderView": "Toon een mappenweergave als u gewoon Mediamappen wilt weergeven", @@ -953,15 +952,14 @@ "OptionEnableAccessFromAllDevices": "Toegang vanaf alle apparaten toestaan", "OptionEnableAccessToAllChannels": "Toegang tot alle kanalen inschakelen", "OptionEnableAccessToAllLibraries": "Toegang tot alle bibliotheken inschakelen", - "OptionEnableAutomaticServerUpdates": "Schakel automatische server updates in", "OptionEnableExternalContentInSuggestions": "Inschakelen externe inhoud in suggesties", "OptionEnableExternalContentInSuggestionsHelp": "Laat internet trailers en live-tv-programma's op te nemen binnen de voorgestelde inhoud.", "OptionEnableForAllTuners": "Inschakelen voor alle tuners", "OptionEnableM2tsMode": "M2ts-modus inschakelen", - "OptionEnableM2tsModeHelp": "m2ts-modus bij het encoderen naar mpegts inschakelen", + "OptionEnableM2tsModeHelp": "M2ts-modus bij het encoderen naar mpegts inschakelen.", "OptionEnded": "Gestopt", "OptionEquals": "Is gelijk aan", - "OptionEstimateContentLength": "Lengte schatten van de inhoud bij het transcoderen", + "OptionEstimateContentLength": "Lengte inschatten van de inhoud bij het transcoderen", "OptionEveryday": "Elke dag", "OptionExternallyDownloaded": "Externe download", "OptionExtractChapterImage": "Inschakelen uitpakken van hoofdstuk afbeeldingen", @@ -969,10 +967,10 @@ "OptionFriday": "Vrijdag", "OptionHasSpecialFeatures": "Extra's", "OptionHasSubtitles": "Ondertiteling", - "OptionHasThemeSong": "Herkenningsmelodie", + "OptionHasThemeSong": "Thema Lied", "OptionHasThemeVideo": "Thema Video", "OptionHideUser": "Verberg deze gebruiker op de aanmeldschermen", - "OptionHideUserFromLoginHelp": "Handig voor pivé of verborgen beheer accounts. De gebruiker zal handmatig m.b.v. gebruikersnaam en wachtwoord aan moeten melden.", + "OptionHideUserFromLoginHelp": "Handig voor pivé of verborgen beheer accounts. De gebruiker zal handmatig moeten inloggen met een gebruikersnaam en wachtwoord.", "OptionHlsSegmentedSubtitles": "HLS gesegmenteerde ondertiteling", "OptionHomeVideos": "Foto's", "OptionIgnoreTranscodeByteRangeRequests": "Transcodeer byte range-aanvragen negeren", @@ -1022,9 +1020,9 @@ "OptionWeekly": "Wekelijks", "OriginalAirDateValue": "Originele uitzenddatum: {0}", "Overview": "Overzicht", - "PackageInstallCancelled": "{0} installatie geannuleerd.", - "PackageInstallCompleted": "{0} installatie voltooid.", - "PackageInstallFailed": "{0} installatie is mislukt.", + "PackageInstallCancelled": "{0} (versie {1}) installatie geannuleerd.", + "PackageInstallCompleted": "{0} (versie {1}) installatie voltooid.", + "PackageInstallFailed": "{0} (versie {1}) installatie is mislukt.", "ParentalRating": "Kijkwijzer classificatie", "PasswordMatchError": "Wachtwoord en wachtwoord bevestiging moeten hetzelfde zijn.", "PasswordResetComplete": "Het wachtwoord is opnieuw ingesteld.", @@ -1066,7 +1064,7 @@ "Raised": "Verhoogd", "Rate": "Waardeer", "RecentlyWatched": "Onlangs bekeken", - "RecommendationBecauseYouLike": "Omdat u {0} leuk vond.", + "RecommendationBecauseYouLike": "Omdat u {0} leuk vond", "RecommendationBecauseYouWatched": "Omdat u keek naar {0}", "RecommendationDirectedBy": "Geregisseerd door {0}", "RecommendationStarring": "In de hoofdrollen {0}", @@ -1074,12 +1072,12 @@ "RecordSeries": "Series Opnemen", "RecordingCancelled": "Opname geannuleerd.", "RecordingPathChangeMessage": "Bij het wijzigen van uw opnamemap zullen bestaande opnamen niet migreren van de oude locatie naar de nieuwe. U moet deze desgewenst handmatig verplaatsen.", - "RecordingScheduled": "Opname schema", + "RecordingScheduled": "Opname schema.", "Recordings": "Opnames", "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", + "RefreshQueued": "Verversen wachtrij.", "ReleaseDate": "Uitgave datum", "RememberMe": "Onthoud mij", "RemoveFromCollection": "Verwijder uit collectie", @@ -1087,7 +1085,7 @@ "Repeat": "Herhaling", "RepeatAll": "Alle herhalen", "RepeatEpisodes": "Herhaal afleveringen", - "RepeatMode": "Herhaal mode", + "RepeatMode": "Herhaal modus", "RepeatOne": "Eén herhalen", "ReplaceAllMetadata": "Alle metadata vervangen", "ReplaceExistingImages": "Bestaande afbeeldingen vervangen", @@ -1134,7 +1132,7 @@ "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", + "SmallCaps": "Kleine letters", "Smaller": "Kleiner", "Smart": "Slim", "SmartSubtitlesHelp": "Ondertitels worden weergegeven in de voorkeurstaal als de audio in een andere taal zijn.", @@ -1203,7 +1201,7 @@ "ThemeSongs": "Themamuziek", "ThemeVideos": "Themavideo's", "TheseSettingsAffectSubtitlesOnThisDevice": "Deze instellingen betreffen ondertitels op dit apparaat", - "ThisWizardWillGuideYou": "Deze wizard helpt u door het setup-proces. Om te beginnen selecteert u eerst de gewenste taal.", + "ThisWizardWillGuideYou": "Deze helper helpt u door het opzet proces heen. Om te beginnen selecteert u eerst de gewenste taal.", "Thumb": "Miniatuur", "Thursday": "Donderdag", "TitleHardwareAcceleration": "Hardware versnelling", @@ -1251,7 +1249,7 @@ "XmlTvKidsCategoriesHelp": "Programma's met deze categorieën wordt weergegeven als programma's voor kinderen. Scheid meerdere met '|'.", "XmlTvMovieCategoriesHelp": "Programma's met deze categorieën wordt weergegeven als films. Scheid meerdere met '|'.", "XmlTvNewsCategoriesHelp": "Programma's met deze categorieën wordt weergegeven als nieuwsprogramma's. Scheid meerdere met '|'.", - "XmlTvPathHelp": "Een pad naar een XML-TV-bestand. Jellyfin zal dit bestand regelmatig lezen en controleren voor updates. U bent verantwoordelijk voor het maken en bijwerken van het bestand.", + "XmlTvPathHelp": "Een pad naar een XML-TV-bestand. Jellyfin zal dit bestand regelmatig lezen en controleren voor updates. U bent verantwoordelijk voor het maken en bijwerken van dit bestand.", "XmlTvSportsCategoriesHelp": "Programma's met deze categorieën wordt weergegeven als sportprogramma's. Scheid meerdere met '|'.", "Yes": "Ja", "Yesterday": "Gisteren", @@ -1270,12 +1268,11 @@ "Desktop": "Bureaublad", "DownloadsValue": "{0} downloads", "Filters": "Filters", - "GenreValue": "Genre: {0}", + "Genre": "Genre", "Genres": "Genres", - "GenresValue": "Genres: {0}", "HeaderAlbums": "Albums", - "HeaderCastAndCrew": "Cast & Crew", - "HeaderCastCrew": "Cast & Crew", + "HeaderCastAndCrew": "Acteurs en medewerkers", + "HeaderCastCrew": "Acteurs & medewerkers", "Art": "Afbeeldingen", "HeaderLiveTV": "Live TV", "HeaderDetails": "Details", @@ -1293,7 +1290,7 @@ "HeaderSync": "Synchronisatie", "HeaderTV": "TV", "HeaderTopPlugins": "Top Plugins", - "AuthProviderHelp": "Selecteer een Authenticatie Provider om het wachtwoord van deze gebruiker te verifiëren", + "AuthProviderHelp": "Selecteer een Authenticatie Provider om het wachtwoord van deze gebruiker te verifiëren.", "HeaderFavoriteMovies": "Favoriete Films", "HeaderFavoriteShows": "Favoriete shows", "HeaderFavoriteEpisodes": "Favoriete afleveringen", @@ -1301,7 +1298,7 @@ "HeaderFavoriteArtists": "Favoriete artiesten", "HeaderFavoriteSongs": "Favoriete nummers", "HeaderFavoriteVideos": "Favoriete Films", - "HeaderInstantMix": "Instant Mix", + "HeaderInstantMix": "Directe Mix", "HeaderItems": "Items", "HeaderJellyfinServer": "Jellyfin Server", "HeaderLiveTv": "Live TV", @@ -1313,7 +1310,7 @@ "ItemCount": "{0} items", "Items": "Items", "LabelAlbum": "Album:", - "LabelAudio": "Audio:", + "LabelAudio": "Audio", "LabelAuthProvider": "Authenticatie Aanbieder:", "LabelCache": "Cache:", "LabelDidlMode": "DIDL mode:", @@ -1325,23 +1322,23 @@ "LabelProfileCodecs": "Codecs:", "LabelProfileContainer": "Container:", "LabelProfileVideoCodecs": "Video codecs:", - "LabelProtocolInfo": "Protocool info:", + "LabelProtocolInfo": "Protocol info:", "LabelServerName": "Server naam:", - "LabelSkin": "Skin:", + "LabelSkin": "Uiterlijk:", "ButtonAddImage": "Voeg afbeelding toe", "LabelSize": "Grootte:", - "CopyStreamURLSuccess": "URL gekopieerd", - "CopyStreamURL": "Kopieer stream URL ", + "CopyStreamURLSuccess": "URL succesvol gekopieerd.", + "CopyStreamURL": "Kopieer Stream URL", "TabLiveTV": "Live TV", "ValueAlbumCount": "{0} albums", "FetchingData": "Meer data op aan het halen", "HeaderFavoriteBooks": "Favoriete Boeken", - "LabelUserLoginAttemptsBeforeLockout": "Mislukte login pogingen voordat de gebruiker buitengesloten wordt:", + "LabelUserLoginAttemptsBeforeLockout": "Mislukte aanmeld pogingen voordat de gebruiker buitengesloten wordt:", "OptionHasTrailer": "Trailer", "OptionMax": "Max", "LabelBaseUrl": "Basis URL:", - "LabelTranscodingProgress": "Transcoding voortgang:", - "LabelTriggerType": "Trigger Type:", + "LabelTranscodingProgress": "Transcoderen voortgang:", + "LabelTriggerType": "Signaal Type:", "LaunchWebAppOnStartup": "Lanceer de web interface wanneer de server start", "MediaInfoBitrate": "Bitrate", "MediaInfoInterlaced": "Interlaced", @@ -1361,13 +1358,13 @@ "SubtitleOffset": "Ondertiteling Compensatie", "LabelXDlnaDoc": "X-DLNA doc:", "LiveTV": "Live TV", - "LabelTag": "Tag:", + "LabelTag": "Label:", "Live": "Live", "OptionDvd": "DVD", "OptionResElement": "res element", "TV": "TV", "HeaderHome": "Thuis", - "MediaInfoStreamTypeEmbeddedImage": "Embedded Afbeelding", + "MediaInfoStreamTypeEmbeddedImage": "Ingeladen Afbeelding", "LabelTypeMetadataDownloaders": "{0} metadata downloaders:", "OptionLoginAttemptsBeforeLockout": "Bepaald hoeveel foutieve login pogingen plaats kunnen vinden voor dat de gebruiker buitengesloten wordt.", "Premiere": "Première", @@ -1375,7 +1372,7 @@ "LabelAudioSampleRate": "Audio sample rate:", "OptionIsHD": "HD", "OptionIsSD": "SD", - "OptionSpecialEpisode": "Specials", + "OptionSpecialEpisode": "Extra's", "TabContainers": "Containers", "TabDashboard": "Dashboard", "TabNetworking": "Netwerken", @@ -1390,7 +1387,7 @@ "OptionThumbCard": "Miniatuur kaart", "PlaybackData": "Afspeel Data", "PasswordResetProviderHelp": "Kies een wachtwoord reset provider om te gebruiken wanneer deze gebruiker een wachtwoord reset aanvraagt", - "Screenshots": "Screenshots", + "Screenshots": "Schermafdruk", "Series": "Series", "TabAlbums": "Albums", "TabGenres": "Genres", @@ -1404,7 +1401,7 @@ "MediaInfoCodec": "Codec", "Menu": "Menu", "OptionThumb": "Miniatuur", - "LabelTranscodingFramerate": "Transcoding framerate:", + "LabelTranscodingFramerate": "Transcoderen beeldverversing:", "LabelType": "Type:", "HeaderFavoritePeople": "Favoriete Mensen", "LabelAudioBitrate": "Audio bitrate:", @@ -1416,13 +1413,13 @@ "LabelLineup": "Lineup:", "LabelPlayer": "Speler:", "LabelPlayMethod": "Afspeel methode:", - "LabelPleaseRestart": "Verandering zullen toegepast worden na het handmatig herladen van de web cliënt.", + "LabelPleaseRestart": "De wijzigingen zullen worden toegepast na het handmatig herladen van de web cliënt.", "LabelStatus": "Status:", - "LabelTagline": "Tagline:", + "LabelTagline": "Label lijn:", "LabelTranscodingContainer": "Container:", - "LabelTranscodePath": "Transcode pad:", - "LabelTranscodes": "Transcodes:", - "DashboardOperatingSystem": "Besturingsysteem: {0}", + "LabelTranscodePath": "Transcodeer pad:", + "LabelTranscodes": "Transcoderen:", + "DashboardOperatingSystem": "Besturingssysteem: {0}", "LabelWeb": "Web:", "LaunchWebAppOnStartupHelp": "Open de web cliënt in uw standaard browser wanneer de server voor de eerste keer start. Dit zal niet voorkomen tijdens gebruik van de server herstart functie.", "LeaveBlankToNotSetAPassword": "U kunt dit veld leeg laten om geen wachtwoord in te stellen.", @@ -1432,7 +1429,7 @@ "LabelXDlnaCap": "X-DLNA cap:", "DashboardVersionNumber": "Versie: {0}", "DashboardArchitecture": "Architectuur: {0}", - "LabelVideo": "Video:", + "LabelVideo": "Video", "MediaInfoStreamTypeAudio": "Audio", "MediaInfoStreamTypeData": "Data", "MediaInfoStreamTypeSubtitle": "Ondertiteling", @@ -1441,17 +1438,17 @@ "Logo": "Logo", "MediaInfoCodecTag": "Codec tag", "MediaInfoContainer": "Container", - "MediaInfoFramerate": "Framerate", - "MediaInfoRefFrames": "Ref frames", + "MediaInfoFramerate": "Beeldverversing", + "MediaInfoRefFrames": "Ref beeld", "MediaInfoSoftware": "Software", - "MessageImageFileTypeAllowed": "Alleen JPEG en PNG bestanden zijn ondersteund.", - "MessageImageTypeNotSelected": "Selecteer alstublieft een afbeelding type van het drop-down menu.", + "MessageImageFileTypeAllowed": "Alleen JPEG en PNG bestanden worden ondersteund.", + "MessageImageTypeNotSelected": "Selecteer een afbeelding type van het menu alstublieft .", "MessageNoCollectionsAvailable": "Collecties staan u toe om te genieten van gepersonaliseerde groeperingen van Films, Series en Albums. Klik de + knop om te beginnen met het maken van collecties.", - "MessageNoServersAvailable": "Geen servers zijn gevonden doormiddel van het automatisch server ontdekken.", + "MessageNoServersAvailable": "Geen servers zijn gevonden door middel van het automatisch ontdekken van een server.", "Metadata": "Metadata", "MetadataManager": "Metadata Beheerder", "MusicAlbum": "Muziek Album", - "NumLocationsValue": "{0} folders", + "NumLocationsValue": "{0} mappen", "OptionBanner": "Banner", "OptionBlockTrailers": "Trailers", "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)", @@ -1464,5 +1461,60 @@ "TabStreaming": "Streamen", "TabTrailers": "Trailers", "OptionAuto": "Auto", - "OptionProfileVideo": "Video" + "OptionProfileVideo": "Video", + "AlbumArtist": "Album Artiest", + "Album": "Album", + "DeinterlaceMethodHelp": "Selecteer de deinterlacingmethode die u wilt gebruiken bij het transcoderen van geïnterlinieerde inhoud.", + "CopyStreamURLError": "Er trad een fout op tijdens het kopieren van de URL.", + "ClientSettings": "Client instellingen", + "ButtonSplit": "Splitsen", + "BoxSet": "Box Set", + "AskAdminToCreateLibrary": "Vraag een beheerder om een bibliotheek te maken.", + "Artist": "Artiest", + "AllowFfmpegThrottlingHelp": "Wanneer een transcode of remux ver genoeg voorloopt op de huidige afspeelpositie, pauzeer het proces, zodat het minder middelen verbruikt. Dit is vooral handig wanneer u kijkt zonder vaak te zoeken. Schakel dit uit als u afspeelproblemen ondervindt.", + "AllowFfmpegThrottling": "Throttle Transcodes", + "EnableFastImageFadeInHelp": "Schakel snellere vervagings-animatie in voor ingeladen afbeeldingen", + "EnableFastImageFadeIn": "Snelle afbeeldingsvervaging", + "LabelPlayerDimensions": "Afspeellengte:", + "LabelLibraryPageSizeHelp": "Kies het aantal artikelen dat wordt weergegeven op een bibliotheekpagina. Kies 0 om dit te verbergen.", + "LabelLibraryPageSize": "Bibliotheekpagina grootte:", + "LabelDroppedFrames": "Vervallen beelden:", + "LabelDeinterlaceMethod": "Deinterlacing methode:", + "LabelCorruptedFrames": "Corrupte beelden:", + "HeaderNavigation": "Navigeren", + "Episode": "Aflevering", + "Season": "Seizoen", + "ReleaseGroup": "Uitgave groep", + "PreferEmbeddedEpisodeInfosOverFileNames": "Verkies ingeladen afleveringsinformatie boven bestandsnaam", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Dit gebruikt de afleveringsinformatie van de ingeladen metadata als deze aanwezig is.", + "PlaybackErrorNoCompatibleStream": "Deze machine is niet leesbaar met de media en de server verstuurd geen leesbare media formaten.", + "Person": "Persoon", + "OtherArtist": "Andere Artiesten", + "OptionForceRemoteSourceTranscoding": "Forceer het transcoderen van op afstand bediende media bronnen (zoals LiveTV)", + "NoCreatedLibraries": "Het lijkt erop dat er geen bibliotheek is gecreëerd. {0}Wilt u er nu een aanmaken?{1}", + "Movie": "Film", + "MessageUnauthorizedUser": "U bent niet gemachtigd om toegang tot de server te krijgen op dit moment. Neem contact op met de server beheerder voor meer informatie.", + "MessageConfirmAppExit": "Wilt u afsluiten?", + "LabelVideoResolution": "Video resolutie:", + "LabelStreamType": "Stream type:", + "UnsupportedPlayback": "Jellyfin kan DRM beschermde inhoud niet ontsleutelen. Alle inhoud zal geprobeerd worden om te ontsleutelen inclusief beschermde titels. Sommige bestanden kunnen volledig zwart zijn vanwege de versleuteling of andere niet ondersteunde functies, zoals interactieve titels.", + "OnApplicationStartup": "Op het opstarten van de applicatie", + "EveryXHours": "Elke {0} uren", + "EveryHour": "Elk uur", + "EveryXMinutes": "Elke {0} minuten", + "OnWakeFromSleep": "Op het wakker worden vanuit slaapstand", + "WeeklyAt": "{0}s op {1}", + "DailyAt": "Dagelijks op {0}", + "LastSeen": "Laatst bekeken {0}", + "PersonRole": "als {0}", + "ListPaging": "{0}-{1} van de {2}", + "WriteAccessRequired": "De Jellyfin Server vereist schrijftoegang tot deze map. Zorg evoor dat Jellyfin schrijftoegang tot de map heeft en probeer opnieuw.", + "PathNotFound": "Het pad kan niet gevonden worden. Zorg ervoor dat het pad correct is en probeer opnieuw.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Nummer", + "SelectAdminUsername": "Selecteer een gebruikersnaam voor het beheerder account.", + "HeaderFavoritePlaylists": "Favoriete afspeellijsten", + "ButtonTogglePlaylist": "Afspeellijst", + "ButtonToggleContextMenu": "Meer" } diff --git a/src/strings/pl.json b/src/strings/pl.json index 15603fc139..1cea825bf8 100644 --- a/src/strings/pl.json +++ b/src/strings/pl.json @@ -54,7 +54,7 @@ "BoxRear": "Pudełko (tył)", "Browse": "Przeglądaj", "BrowsePluginCatalogMessage": "Przejrzyj nasz katalog wtyczek żeby zobaczyć dostępne wtyczki.", - "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.", + "BurnSubtitlesHelp": "Określa czy serwer powinien wypalać napisy podczas konwersji wideo, w zależności od formatu napisów. Unikanie wypalania napisów znacząco poprawia wydajność serwera. Wybierz Automatycznie, w celu wypalania zarówno napisów w formatach graficznych (np. VOBSUB, PGS, SUB/IDX), jak i pewnych napisów ASS lub SSA.", "ButtonAdd": "Dodaj", "ButtonAddMediaLibrary": "Dodaj media do biblioteki", "ButtonAddScheduledTaskTrigger": "Dodaj wyzwalacz", @@ -180,8 +180,7 @@ "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}", + "Directors": "Reżyserzy", "Disabled": "Nieaktywne", "Disc": "Dysk", "Disconnect": "Rozłącz", @@ -191,7 +190,7 @@ "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.", - "DisplayModeHelp": "Określa typ urządzenia, na którym uruchomiono Jellyfin.", + "DisplayModeHelp": "Wybierz styl układu interfejsu.", "DoNotRecord": "Nie nagrywaj", "Down": "W dół", "Download": "Pobierz", @@ -258,9 +257,8 @@ "Friday": "Piątek", "Fullscreen": "Pełny ekran", "General": "Ogólne", - "GenreValue": "Gatunek: {0}", + "Genre": "Gatunek", "Genres": "Gatunki", - "GenresValue": "Gatunki: {0}", "GroupBySeries": "Grupuj po serialach", "GroupVersions": "Wersje grup", "GuestStar": "Gość specjalny", @@ -268,10 +266,10 @@ "GuideProviderLogin": "Logowanie", "GuideProviderSelectListings": "Pokazuj oferty", "H264CrfHelp": "Constant Rate Factor (CRF) to domyślna jakość kodowania x264. Możesz ją ustawić w zakresie 0-51, gdzie niższe wartości zwiększają jakość (kosztem większego rozmiaru pliku). Rozsądne wartości to zakres 18-28. Domyślnie jest to wartość 23 - możesz jej użyć jako wartości początkowej.", - "H264EncodingPresetHelp": "Wybierz wartość faster, żeby zwiększyć wydajność, albo slower, żeby zwiększyć jakość.", + "EncoderPresetHelp": "Wybierz wartość faster, żeby zwiększyć wydajność, albo slower, żeby zwiększyć jakość.", "HDPrograms": "Programy w jakości HD", "HandledByProxy": "Obsługiwane przez usługę pośredniczącą", - "HardwareAccelerationWarning": "Aktywacja akceleracji sprzętowej może powodować niestabilność na niektórych środowiskach. Upewnij się, że system operacyjny i sterowniki karty graficznej są aktualne. Jeżeli masz problemy z odtwarzaniem wideo po aktywacji, przywróć to ustawienie do wartości Automatycznie.", + "HardwareAccelerationWarning": "Aktywacja akceleracji sprzętowej może powodować niestabilność na niektórych środowiskach. Upewnij się, że system operacyjny i sterowniki karty graficznej są aktualne. Jeżeli masz problemy z odtwarzaniem wideo po aktywacji, przywróć to ustawienie do wartości Brak.", "HeaderAccessSchedule": "Harmonogram dostępu", "HeaderAccessScheduleHelp": "Utwórz dostęp do harmonogramu aby ograniczyć go do określonych godzin.", "HeaderActiveDevices": "Aktywne urządzenia", @@ -492,7 +490,7 @@ "Images": "Obrazy", "ImportFavoriteChannelsHelp": "Jeśli aktywne, tylko kanały oznaczone jako ulubione na tunerze, będą importowane.", "ImportMissingEpisodesHelp": "W przypadku aktywacji tej opcji, informacje o brakujących odcinkach zostaną zaimportowane do bazy Jellyfin i będą wyświetlane na listach sezonów i seriali. Może to jednak znacznie wydłużyć czas skanowania biblioteki.", - "InstallingPackage": "Instalowanie {0}", + "InstallingPackage": "Instalowanie {0} (wersja {1})", "InstantMix": "Szybki remiks", "ItemCount": "{0} pozycje", "Items": "Pozycje", @@ -525,7 +523,7 @@ "LabelAppNameExample": "Przykład: Sickbeard, Sonarr", "LabelArtists": "Wykonawcy:", "LabelArtistsHelp": "Oddzielaj używając ;", - "LabelAudio": "Dźwięk:", + "LabelAudio": "Dźwięk", "LabelAudioLanguagePreference": "Preferowany język ścieżki dźwiękowej:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Odświeżaj automatycznie metadane z Internetu:", "LabelBindToLocalNetworkAddress": "Przypisz do lokalnego adresu sieciowego:", @@ -585,7 +583,7 @@ "LabelEmbedAlbumArtDidl": "Wbudowana okładka albumu w Didl", "LabelEmbedAlbumArtDidlHelp": "Niektóre urządzenia wybierają tę metodę uzyskiwania okładki albumu. Inne mogą nie odtwarzać gdy ta opcja jest włączona.", "LabelEnableAutomaticPortMap": "Mapuj porty automatycznie", - "LabelEnableAutomaticPortMapHelp": "Umożliwia automatyczne mapowanie publicznego numeru portu z lokalnym numerem portu za pomocą UPnP. Ta opcja może nie działać z niektórymi modelami ruterów.", + "LabelEnableAutomaticPortMapHelp": "Umożliwia automatyczne mapowanie publicznego numeru portu z lokalnym numerem portu za pomocą UPnP. Ta opcja może nie działać z niektórymi modelami ruterów. Zmiany zaczną działać po ponownym uruchomieniu serwera.", "LabelEnableBlastAliveMessages": "Przesyłaj komunikaty o dostępności", "LabelEnableBlastAliveMessagesHelp": "Aktywuj tę funkcję, jeśli serwer nie jest odpowiednio wykrywany przez inne urządzenia UPnP w twojej sieci.", "LabelEnableDlnaClientDiscoveryInterval": "Częstotliwość wykrywania klientów (sekundy)", @@ -617,9 +615,9 @@ "LabelGroupMoviesIntoCollections": "Grupuj filmy w kolekcje", "LabelGroupMoviesIntoCollectionsHelp": "Podczas wyświetlania listy filmów, filmy należące do kolekcji będą wyświetlone jako jedna zgrupowana pozycja.", "LabelH264Crf": "CRF kodowania H264:", - "LabelH264EncodingPreset": "Szablon kodowania H264:", + "LabelEncoderPreset": "Szablon kodowania H264:", "LabelHardwareAccelerationType": "Akceleracja sprzętowa:", - "LabelHardwareAccelerationTypeHelp": "Jest to funkcja eksperymentalna dostępna tylko w obsługiwanych systemach.", + "LabelHardwareAccelerationTypeHelp": "Akceleracja sprzętowa wymaga dodatkowej konfiguracji.", "LabelHomeNetworkQuality": "Jakość dla sieci lokalnej:", "LabelHomeScreenSectionValue": "Sekcja ekranu startowego {0}:", "LabelHttpsPort": "Lokalny numer portu HTTPS:", @@ -791,7 +789,7 @@ "LabelSubtitleDownloaders": "Dostawcy napisów:", "LabelSubtitleFormatHelp": "Przykład: srt", "LabelSubtitlePlaybackMode": "Tryb napisów:", - "LabelSubtitles": "Napisy:", + "LabelSubtitles": "Napisy", "LabelSupportedMediaTypes": "Obsługiwane typy mediów:", "LabelTVHomeScreen": "Ekran startowy trybu telewizyjnego:", "LabelTag": "Znacznik:", @@ -829,7 +827,7 @@ "LabelVersion": "Wersja:", "LabelVersionInstalled": "Zainstalowano {0}", "LabelVersionNumber": "Wersja {0}", - "LabelVideo": "Wideo:", + "LabelVideo": "Wideo", "LabelXDlnaCapHelp": "Określa zawartość elementu X_DLNACAP w przestrzeni nazw urn:schemas-dlna-org:device-1-0.", "LabelXDlnaDocHelp": "Określa zawartość elementu X_DLNADOC w przestrzeni nazw urn:schemas-dlna-org:device-1-0.", "LabelYear": "Rok:", @@ -955,16 +953,16 @@ "NoNextUpItemsMessage": "Nie znaleziono niczego. Zacznij oglądać swoje seriale!", "NoPluginConfigurationMessage": "Ta wtyczka nie ma żadnych ustawień.", "NoSubtitleSearchResultsFound": "Brak wyników wyszukiwania.", - "NoSubtitles": "Brak napisów", + "NoSubtitles": "Brak", "NoSubtitlesHelp": "Domyślnie napisy nie będą wczytywane. Można je ciągle włączyć ręcznie podczas odtwarzania.", "None": "Brak", "Normal": "Normalny", "NumLocationsValue": "{0} foldery", "Off": "Wyłączone", "OneChannel": "Jeden kanał", - "OnlyForcedSubtitles": "Tylko wymuszone napisy", + "OnlyForcedSubtitles": "Tylko wymuszone", "OnlyForcedSubtitlesHelp": "Tylko napisy oznaczone jako wymuszone będą wczytywane.", - "OnlyImageFormats": "Tylko formaty graficzne (VOBSUB, PGS, SUB, itp.)", + "OnlyImageFormats": "Tylko Formaty Graficzne (VOBSUB, PGS, SUB)", "OptionAdminUsers": "Administratorzy", "OptionAlbumArtist": "Wykonawca albumu", "OptionAllUsers": "Wszyscy użytkownicy", @@ -1026,7 +1024,6 @@ "OptionEnableAccessFromAllDevices": "Udostępniaj na wszystkich urządzeniach", "OptionEnableAccessToAllChannels": "Udostępniaj wszystkie kanały", "OptionEnableAccessToAllLibraries": "Udostępniaj wszystkie biblioteki", - "OptionEnableAutomaticServerUpdates": "Aktualizuj serwer automatycznie", "OptionEnableExternalContentInSuggestions": "Dodawaj zewnętrzną zawartość do polecanych", "OptionEnableExternalContentInSuggestionsHelp": "Umożliwia dodawanie zwiastunów i programów telewizyjnych do polecanej zawartości.", "OptionEnableForAllTuners": "Aktywuj dla wszystkich tunerów", @@ -1103,7 +1100,7 @@ "OptionWeekly": "Cotygodniowo", "OriginalAirDateValue": "Data pierwszej emisji: {0}", "Overview": "Opis", - "PackageInstallCancelled": "Instalacja {0} anulowana.", + "PackageInstallCancelled": "Instalacja {0} (wersja {1}) anulowana.", "PackageInstallCompleted": "Instalacja {0} zakończona.", "PackageInstallFailed": "Instalacja {0} nieudana.", "ParentalRating": "Kategoria wiekowa", @@ -1274,7 +1271,7 @@ "TabPassword": "Hasło", "TabPlayback": "Odtwarzanie", "TabPlaylist": "Lista odtwarzania", - "TabPlaylists": "Lista odtwarzania", + "TabPlaylists": "Listy odtwarzania", "TabPlugins": "Wtyczki", "TabProfile": "Profil", "TabProfiles": "Profile", @@ -1453,5 +1450,38 @@ "LabelAudioBitDepth": "Głębia bitowa audio:", "HeaderFavoritePeople": "Ulubieni ludzie", "FetchingData": "Pobieranie dodatkowych danych", - "ButtonSplit": "Rozdziel" + "ButtonSplit": "Rozdziel", + "SelectAdminUsername": "Podaj nazwę użytkownika dla konta administratora.", + "MessageConfirmAppExit": "Czy chcesz wyjść?", + "HeaderNavigation": "Nawigacja", + "LabelPlayerDimensions": "Rozmiar odtwarzacza:", + "LabelDroppedFrames": "Upuszczone klatki:", + "LabelCorruptedFrames": "Uszkodzone klatki:", + "CopyStreamURLError": "Wystąpił błąd podczas kopiowania adresu URL.", + "AskAdminToCreateLibrary": "Poproś administratora o stworzenie biblioteki.", + "AllowFfmpegThrottlingHelp": "Kiedy transkodowanie lub remuxowanie dotrze wystarczająco daleko od aktualnej pozycji odtwarzania, zatrzymaj proces aby zużywać mniej zasobów. Jest to najbardziej użyteczne podczas oglądania bez częstego przeskakiwania. Wyłącz jeśli zaobserwujesz problemy z odtwarzaniem.", + "AllowFfmpegThrottling": "Ograniczaj transkodowanie", + "PlaybackErrorNoCompatibleStream": "Wystąpił problem ze sprofilowaniem klienta i serwer nie wysyła kompatybilnego formatu mediów.", + "OptionForceRemoteSourceTranscoding": "Wymuś transkodowanie zewnętrznych źródeł mediów (jak telewizja na żywo)", + "NoCreatedLibraries": "Wygląda na to, że nie utworzyłeś jeszcze żadnych bibliotek. {0}Czy chcesz utworzyć jedną teraz?{1}", + "LabelVideoResolution": "Rozdzielczość wideo:", + "LabelStreamType": "Typ transmisji:", + "EnableFastImageFadeInHelp": "Włącz szybszą animację pojawiania się dla załadowanych obrazów", + "EnableFastImageFadeIn": "Szybkie pojawianie się obrazów", + "Artist": "Artysta", + "AlbumArtist": "Album artysty", + "Album": "Album", + "Person": "Osoba", + "OtherArtist": "Inny artysta", + "Movie": "Film", + "MessageUnauthorizedUser": "Nie masz dostępu do zasobów serwera. Skontaktuj się z administratorem sieci, aby uzyskać więcej informacji.", + "LabelLibraryPageSizeHelp": "Ustaw liczbę pozycji pokazywanych na stronie biblioteki. Ustaw 0, aby wyłączyć podział na strony.", + "LabelLibraryPageSize": "Rozmiar strony biblioteki:", + "LabelDeinterlaceMethod": "Metoda usuwania przeplotu:", + "HeaderFavoritePlaylists": "Ulubione Playlisty", + "Episode": "Odcinek", + "DeinterlaceMethodHelp": "Wybierz metodę usuwania przeplotu używaną podczas transkodowania.", + "ClientSettings": "Ustawienia klienta", + "ButtonTogglePlaylist": "Playlista", + "ButtonToggleContextMenu": "Więcej" } diff --git a/src/strings/pt-br.json b/src/strings/pt-br.json index f3d3562691..37772d654b 100644 --- a/src/strings/pt-br.json +++ b/src/strings/pt-br.json @@ -44,13 +44,13 @@ "BirthDateValue": "Nascimento: {0}", "BirthLocation": "Local de nascimento", "BirthPlaceValue": "Local de nascimento: {0}", - "BookLibraryHelp": "Livros de áudio e texto são suportados. Verifique o {0}guia de nomes de livros{1}.", + "BookLibraryHelp": "Livros de áudio e texto são suportados. Revise o {0}Guia de Nomes de Livros no Jellyfin{1}.", "Books": "Livros", "Box": "Caixa", "BoxRear": "Caixa (traseira)", "Browse": "Navegar", "BrowsePluginCatalogMessage": "Navegue pelo nosso catálogo de plugins para ver os plugins disponíveis.", - "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 formatos de legenda baseados em imagem baseado nos formatos (ex. VOBSUB, PGS, SUB/IDX, etc.) e algumas legendas ASS/SSA.", + "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 legendas baseados em imagem dos tipos (ex. VOBSUB, PGS, SUB/IDX, etc.) e algumas legendas ASS/SSA.", "ButtonAdd": "Adicionar", "ButtonAddMediaLibrary": "Adicionar Biblioteca de Mídia", "ButtonAddScheduledTaskTrigger": "Adicionar Disparador", @@ -172,8 +172,7 @@ "DirectStreamHelp2": "O streaming direto de um arquivo usa baixo processamento sem perda de qualidade de vídeo.", "DirectStreaming": "Streaming Direto", "Director": "Diretor", - "DirectorValue": "Diretor: {0}", - "DirectorsValue": "Diretores: {0}", + "Directors": "Diretores", "Disabled": "Desativado", "Disc": "Disco", "Disconnect": "Desconectar", @@ -183,7 +182,7 @@ "DisplayInOtherHomeScreenSections": "Exibir nas seções da tela inicial como mídia recente e continuar assistindo", "DisplayMissingEpisodesWithinSeasons": "Exibir episódios em falta nas temporadas", "DisplayMissingEpisodesWithinSeasonsHelp": "Isto também deve ser ativado para as bibliotecas de TV na configuração do servidor.", - "DisplayModeHelp": "Seleciona o tipo de tela para executar o Jellyfin.", + "DisplayModeHelp": "Selecione o estilo de layout que deseje para a interface.", "DoNotRecord": "Não gravar", "Down": "Baixo", "DrmChannelsNotImported": "Canais com DRM não serão importados.", @@ -219,7 +218,7 @@ "ErrorAddingTunerDevice": "Ocorreu um erro ao adicionar o sintonizador. Por favor, verifique se está acessível e tente novamente.", "ErrorAddingXmlTvFile": "Ocorreu um erro ao acessar o arquivo XmlTV. Por favor, verifique se o arquivo existe e tente novamente.", "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.", - "ErrorGettingTvLineups": "Ocorreu um erro ao baixar a programação da TV. Por favor, verifique se sua informação está correta e tente novamente.", + "ErrorGettingTvLineups": "Ocorreu um erro ao fazer download da programação de TV. Por favor, certifique-se que sua informação esteja correta e tente novamente.", "ErrorMessageStartHourGreaterThanEnd": "A hora final deve ser maior que a hora inicial.", "ErrorPleaseSelectLineup": "Por favor, selecione a programação e tente novamente. Se não houver programações disponíveis, verifique se o seu nome de usuário, senha e código postal estão corretos.", "ErrorSavingTvProvider": "Um erro ocorreu ao salvar o provedor de TV. Por favor, verifique se está acessível e tente novamente.", @@ -248,16 +247,15 @@ "Friday": "Sexta-feira", "Fullscreen": "Tela cheia", "General": "Geral", - "GenreValue": "Gênero: {0}", + "Genre": "Gênero", "Genres": "Gêneros", - "GenresValue": "Gêneros: {0}", "GroupBySeries": "Agrupar por séries", "GroupVersions": "Agrupar versões", "GuestStar": "Convidado especial", "Guide": "Guia", "GuideProviderSelectListings": "Selecionar Listas", "H264CrfHelp": "O CRF (Constant Rate Factor) é a configuração padrão de qualidade para o codificador x264. Você pode definir valores entre 0 e 51, onde valores menores resultarão em melhor qualidade (ao custo de arquivos maiores). Valores saudáveis estão entre 18 e 28. O padrão para o x264 é 23, então você pode usar isso como um ponto de partida.", - "H264EncodingPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho ou um valor mais lento para melhorar a qualidade.", + "EncoderPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho ou um valor mais lento para melhorar a qualidade.", "HDPrograms": "Programas em HD", "HandledByProxy": "Tratado pelo proxy reverso", "HardwareAccelerationWarning": "Ativar a aceleração de hardware pode causar instabilidade em alguns sistemas. Verifique se seu sistema operacional e drivers de vídeo estão atualizados. Se tiver dificuldades em reproduzir vídeo depois de ativar, retorne a configuração para automático.", @@ -476,7 +474,7 @@ "Images": "Imagens", "ImportFavoriteChannelsHelp": "Se ativado, apenas canais que estão marcados como favoritos no sintonizador serão importados.", "ImportMissingEpisodesHelp": "Se ativado, as informações dos episódios que faltam serão importadas para seu banco de dados do Jellyfin e exibidas dentro das temporadas e séries. Isto pode causar lentidão no rastreamento da biblioteca.", - "InstallingPackage": "Instalando {0}", + "InstallingPackage": "Instalando {0} (versão{1})", "InstantMix": "Mix instântaneo", "ItemCount": "{0} itens", "Items": "itens", @@ -508,7 +506,7 @@ "LabelAppNameExample": "Exemplo: Sickbeard, Sonarr", "LabelArtists": "Artistas:", "LabelArtistsHelp": "Separa vários usando ;", - "LabelAudio": "Áudio:", + "LabelAudio": "Áudio", "LabelAudioLanguagePreference": "Idioma preferido de áudio:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Atualizar automaticamente os metadados da internet:", "LabelBindToLocalNetworkAddress": "Vincular a um endereço de rede local:", @@ -568,7 +566,7 @@ "LabelEmbedAlbumArtDidl": "Arte do álbum incorporada no Didl", "LabelEmbedAlbumArtDidlHelp": "Alguns dispositivos preferem este método para obter a arte do álbum. Outros podem falhar ao reproduzir com esta opção ativada.", "LabelEnableAutomaticPortMap": "Ativar mapeamento automático de portas", - "LabelEnableAutomaticPortMapHelp": "Tentativa de mapear automaticamente a porta pública para a porta local através de UPnP. Isto poderá não funcionar em alguns modelos de roteadores.", + "LabelEnableAutomaticPortMapHelp": "Tentar mapear automaticamente a porta pública para a porta local através de UPnP. Pode não funcionar em alguns modelos de roteadores. As mudanças não serão aplicadas até a reinicialização do servidor.", "LabelEnableBlastAliveMessages": "Mensagens ao vivo", "LabelEnableBlastAliveMessagesHelp": "Ative esta função se o servidor não for detectado por outros dispositivos UPnP em sua rede.", "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para descoberta do cliente (segundos)", @@ -601,9 +599,9 @@ "LabelGroupMoviesIntoCollections": "Agrupar filmes em coletâneas", "LabelGroupMoviesIntoCollectionsHelp": "Ao exibir listas de filmes, filmes que pertençam a uma coletânea serão exibidos como um único item agrupado.", "LabelH264Crf": "CRF de codificação H264:", - "LabelH264EncodingPreset": "Preset de codificação H264:", + "LabelEncoderPreset": "Preset de codificação H264:", "LabelHardwareAccelerationType": "Aceleração de hardware:", - "LabelHardwareAccelerationTypeHelp": "Esta é uma função experimental disponível apenas em sistemas suportados.", + "LabelHardwareAccelerationTypeHelp": "Aceleração por hardware requer configurações adicionais.", "LabelHomeNetworkQuality": "Qualidade da rede local:", "LabelHomeScreenSectionValue": "Seção {0} da tela inicial:", "LabelHttpsPort": "Número da porta local de HTTPS:", @@ -628,7 +626,7 @@ "LabelKodiMetadataEnablePathSubstitution": "Ativar substituição de local", "LabelKodiMetadataEnablePathSubstitutionHelp": "Ativa a substituição do local das imagens usando as configurações de substituição de local do servidor.", "LabelKodiMetadataSaveImagePaths": "Salvar o local das imagens dentro dos arquivos nfo", - "LabelKodiMetadataSaveImagePathsHelp": "Isto é recomendado se os nomes dos arquivos de imagem não estão de acordo com as recomendações do Kodi.", + "LabelKodiMetadataSaveImagePathsHelp": "Isto é recomendado se os nomes dos arquivos de imagem não estão de acordo com as exigências do Kodi.", "LabelKodiMetadataUser": "Salvar informações do que o usuário assiste aos NFO's para:", "LabelKodiMetadataUserHelp": "Salva os dados para arquivos NFO para que outras aplicações possam usar.", "LabelLanNetworks": "Redes LAN:", @@ -639,7 +637,7 @@ "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", "LabelLoginDisclaimer": "Aviso legal no login:", "LabelLoginDisclaimerHelp": "Um aviso será exibido na parte inferior da página de login.", - "LabelManufacturer": "Fabricante", + "LabelManufacturer": "Fabricante:", "LabelManufacturerUrl": "URL do fabricante", "LabelMatchType": "Tipo de correspondência:", "LabelMaxBackdropsPerItem": "Número máximo de imagens de fundo por item:", @@ -664,7 +662,7 @@ "LabelMethod": "Método:", "LabelMinBackdropDownloadWidth": "Tamanho mínimo da imagem de fundo para download:", "LabelMinResumeDuration": "Duração mínima para retomar:", - "LabelMinResumeDurationHelp": "A menor duração de vídeo em segundos que salvará o local de reprodução e permitirá que retome.", + "LabelMinResumeDurationHelp": "Tempo mínimo do vídeo em segundos que permitirá continuar a reprodução a partir do ponto que parou.", "LabelMinResumePercentage": "Porcentagem mínima para retomar:", "LabelMinResumePercentageHelp": "Títulos são considerados como não reproduzidos se parados antes deste tempo.", "LabelMinScreenshotDownloadWidth": "Tamanho mínimo da captura de tela para download:", @@ -678,7 +676,7 @@ "LabelMoviePrefixHelp": "Se os títulos dos filmes devem ter um prefixo, digite-o aqui para que o servidor possa usá-lo corretamente.", "LabelMovieRecordingPath": "Local de gravação de filme (opcional):", "LabelMusicStreamingTranscodingBitrate": "Bitrate da transcodificação de músicas:", - "LabelMusicStreamingTranscodingBitrateHelp": "Define o bitrate máximo do streaming de músicas", + "LabelMusicStreamingTranscodingBitrateHelp": "Especifique uma taxa de bits máxima ao transmitir músicas.", "LabelName": "Nome:", "LabelNewName": "Novo nome:", "LabelNewPassword": "Nova senha:", @@ -690,7 +688,7 @@ "LabelNumberOfGuideDays": "Número de dias de dados do guia para baixar:", "LabelNumberOfGuideDaysHelp": "Baixar mais dias do guia da TV permite agendar com maior antecedência e visualizar mais listas, mas também levará mais tempo para baixar. Se selecionar Automático, será escolhido o período baseado no número de canais.", "LabelOptionalNetworkPath": "(Opcional) Pasta compartilhada em rede:", - "LabelOptionalNetworkPathHelp": "Se esta pasta estiver compartilhada em sua rede, fornecendo o local do compartilhamento em rede permitirá que os apps Jellyfin em outros dispositivos acessem arquivos de mídia diretamente.", + "LabelOptionalNetworkPathHelp": "Se esta pasta estiver compartilhada em sua rede, informar o caminho do compartilhamento permitirá que os apps Jellyfin em outros dispositivos acessem arquivos de mídia diretamente.", "LabelOriginalAspectRatio": "Proporção original da tela:", "LabelOriginalTitle": "Título original:", "LabelOverview": "Sinopse:", @@ -727,7 +725,7 @@ "LabelReasonForTranscoding": "Motivo da transcodificação:", "LabelRecord": "Gravar:", "LabelRecordingPath": "Local de gravação padrão:", - "LabelRecordingPathHelp": "Define o local padrão para salvar as gravações. Se deixar em branco, a pasta de dados do programa do servidor será usada.", + "LabelRecordingPathHelp": "Define o local padrão para salvar as gravações. Se deixar não preenchido, a pasta de dados do programa do servidor será usada.", "LabelRefreshMode": "Modo de atualização:", "LabelReleaseDate": "Data do lançamento:", "LabelRemoteClientBitrateLimit": "Limite do bitrate para streaming da internet (Mbps):", @@ -770,7 +768,7 @@ "LabelSubtitleDownloaders": "Downloaders de legendas:", "LabelSubtitleFormatHelp": "Exemplo: srt", "LabelSubtitlePlaybackMode": "Modo de legenda:", - "LabelSubtitles": "Legendas:", + "LabelSubtitles": "Legendas", "LabelSupportedMediaTypes": "Tipos de Mídia Suportados:", "LabelTVHomeScreen": "Tela inicial do modo TV:", "LabelTagline": "Slogan:", @@ -806,7 +804,7 @@ "LabelVersion": "Versão:", "LabelVersionInstalled": "{0} instalado", "LabelVersionNumber": "Versão {0}", - "LabelVideo": "Vídeo:", + "LabelVideo": "Vídeo", "LabelXDlnaCapHelp": "Determina o conteúdo do elemento X_DLNACAP no namespace urn:schemas-dlna-org:device-1-0.", "LabelXDlnaDocHelp": "Determina o conteúdo do elemento X_DLNADOC no namespace urn:schemas-dlna-org:device-1-0.", "LabelYear": "Ano:", @@ -814,7 +812,7 @@ "LabelYoureDone": "Pronto!", "LabelZipCode": "CEP:", "LabelffmpegPath": "Local do FFmpeg:", - "LabelffmpegPathHelp": "O local para o arquivo de aplicação ffmpeg, ou pasta contendo ffmpeg.", + "LabelffmpegPathHelp": "O local para o programa ffmpeg, ou pasta contendo ffmpeg.", "LanNetworksHelp": "Lista separada por vírgula de endereços IP ou entradas IP/máscara de rede para redes que serão consideradas como redes locais ao forçar restrições de banda. Se definida, todos os outros endereços IP serão considerados como estando em uma rede externa e estarão sujeitos a restrições de banda externa. Se deixada em branco, apenas a sub-rede do servidor é considerada como rede local.", "Large": "Grande", "LatestFromLibrary": "Recentes {0}", @@ -869,7 +867,7 @@ "MessageDeleteTaskTrigger": "Deseja realmente excluir este disparador de tarefa?", "MessageDirectoryPickerBSDInstruction": "Para BSD, você precisará configurar o armazenamento dentro de seu Jail do FreeNAS para permitir que o Jellyfin tenha acesso a ele.", "MessageDirectoryPickerInstruction": "Os locais de rede podem ser inseridos manualmente caso o botão de rede falhe em localizar seus dispositivos. Por exemplo, {0} ou {1}.", - "MessageDirectoryPickerLinuxInstruction": "Para Linux no Arch Linux, CentOS, Debian, Fedora, openSUSE ou Ubuntu, você deve permitir que o usuário do serviço tenha ao menos acesso de leitura ao seu armazenamento.", + "MessageDirectoryPickerLinuxInstruction": "Sistemas operacionais Arch Linux, CentOS, Debian, Fedora, openSUSE ou Ubuntu, devem permitir que a conta de serviço tenha ao menos acesso de leitura nos locais de armazenamento.", "MessageDownloadQueued": "Download enfileirado.", "MessageEnablingOptionLongerScans": "Ativar esta opção pode resultar em rastreamentos de biblioteca significativamente mais demorados.", "MessageFileReadError": "Ocorreu um erro ao ler o arquivo. Por favor, tente novamente.", @@ -900,7 +898,7 @@ "MessageYouHaveVersionInstalled": "Você possui a versão {0} instalada.", "Metadata": "Metadados", "MetadataManager": "Gerenciador de Metadados", - "MetadataSettingChangeHelp": "Alterar as configurações dos metadados afetará o novo conteúdo que será adicionado. Para atualizar o conteúdo existente, abra a tela de detalhes e clique no botão de atualizar ou atualize usando o gerenciador de metadados.", + "MetadataSettingChangeHelp": "Alterar as configurações dos metadados afetará o novo conteúdo que será adicionado. Para atualizar o conteúdo existente, abra a tela de detalhes e clique no botão de atualizar, ou atualize usando o gerenciador de metadados.", "MinutesAfter": "minutos após", "MinutesBefore": "minutos antes", "Mobile": "Celular", @@ -926,9 +924,9 @@ "No": "Não", "NoNewDevicesFound": "Nenhum novo dispositivo encontrado. Para adicionar um novo sintonizador, feche esta mensagem e digite as informações do dispositivo manualmente.", "NoNextUpItemsMessage": "Nada encontrado. Comece a assistir suas séries!", - "NoPluginConfigurationMessage": "Este plugin não tem configurações disponíveis.", + "NoPluginConfigurationMessage": "Este plugin não permite alterar configurações.", "NoSubtitleSearchResultsFound": "Nenhum resultado encontrado.", - "NoSubtitles": "Nenhuma legenda", + "NoSubtitles": "Não há legendas", "NoSubtitlesHelp": "Legendas não serão carregadas por padrão. Elas podem ser carregadas manualmente durante a reprodução.", "None": "Nenhum(a)", "NumLocationsValue": "{0} pastas", @@ -951,10 +949,10 @@ "OptionAllowMediaPlaybackTranscodingHelp": "Restringir o acesso à transcodificação pode ocasionar falhas na reprodução nos apps do Jellyfin devido a formatos de mídias não suportados.", "OptionAllowRemoteControlOthers": "Permitir controle remoto de outros usuários", "OptionAllowRemoteSharedDevices": "Permitir controle remoto de dispositivos compartilhados", - "OptionAllowRemoteSharedDevicesHelp": "Dispositivos DLNA são considerados compartilhados até que um usuário comece a controlá-los.", + "OptionAllowRemoteSharedDevicesHelp": "Dispositivos DLNA são autorizados até que um usuário altere as permissões.", "OptionAllowSyncTranscoding": "Permitir download e sincronização de mídia que necessite de transcodificação", "OptionAllowUserToManageServer": "Permitir este usuário administrar o servidor", - "OptionAllowVideoPlaybackRemuxing": "Permitir reprodução de vídeos que requeiram conversão sem re-encodação", + "OptionAllowVideoPlaybackRemuxing": "Permitir reprodução de vídeos que requerem conversão sem recodificar", "OptionAllowVideoPlaybackTranscoding": "Permitir reprodução de vídeo que necessite de transcodificação", "OptionArtist": "Artista", "OptionAscending": "Crescente", @@ -978,15 +976,15 @@ "OptionDescending": "Decrescente", "OptionDisableUser": "Desativar este usuário", "OptionDisableUserHelp": "Se desativado, o servidor não permitirá nenhuma conexão deste usuário. Conexões existentes serão encerradas imediatamente.", - "OptionDislikes": "Não Curtidos", - "OptionDisplayFolderView": "Exibe uma visualização de pasta para exibir pastas de mídias", - "OptionDisplayFolderViewHelp": "Exibe pastas ao lado de suas outras biblioteca de mídia. Isto pode ser útil se quiser uma visualização por pasta.", + "OptionDislikes": "Não gostei", + "OptionDisplayFolderView": "Exibe visualização em pastas para exibir pastas de mídias", + "OptionDisplayFolderViewHelp": "Exibição em pastas ao lado das biblioteca de mídia. Isto pode ser útil para visualizar por pastas.", "OptionDownloadArtImage": "Arte", "OptionDownloadBackImage": "Traseira", "OptionDownloadBoxImage": "Caixa", "OptionDownloadDiscImage": "Disco", "OptionDownloadImagesInAdvance": "Fazer download de imagens antecipadamente", - "OptionDownloadImagesInAdvanceHelp": "Por padrão, a maioria das imagens são baixadas só quando um app Jellyfin solicita. Ativando esta opção, baixará todas as imagens antecipadamente, assim que novas mídias são importadas. Isto pode ocasionar um tempo maior para escanear a biblioteca.", + "OptionDownloadImagesInAdvanceHelp": "Por padrão, a maioria das imagens são baixadas somente quando um app Jellyfin solicita. Ativar esta opção, baixará todas as imagens antecipadamente, ao importar novas mídias. Isto pode ocasionar um tempo maior para escanear a biblioteca.", "OptionDownloadPrimaryImage": "Principal", "OptionDownloadThumbImage": "Miniatura", "OptionDvd": "DVD", @@ -994,7 +992,6 @@ "OptionEnableAccessFromAllDevices": "Ativar o acesso de todos os dispositivos", "OptionEnableAccessToAllChannels": "Ativar o acesso a todos os canais", "OptionEnableAccessToAllLibraries": "Ativar o acesso a todas as bibliotecas", - "OptionEnableAutomaticServerUpdates": "Ativar as atualizações automáticas do servidor", "OptionEnableExternalContentInSuggestions": "Ativar conteúdo externo nas sugestões", "OptionEnableExternalContentInSuggestionsHelp": "Permitir que trailers da internet e programas de TV ao vivo sejam incluídos em conteúdos sugeridos.", "OptionEnableForAllTuners": "Ativar para todos os sintonizadores", @@ -1033,7 +1030,7 @@ "OptionPlainStorageFoldersHelp": "Se ativado, todas as pastas são representadas no DIDL como \"object.container.storageFolder\" ao invés de um tipo mais específico como, por exemplo, \"object.container.person.musicArtist\".", "OptionPlainVideoItems": "Exibir todos os vídeos como itens de vídeo", "OptionPlainVideoItemsHelp": "Se ativado, todos os vídeos são representados no DIDL como \"object.item.videoItem\" ao invés de um tipo mais específico como, por exemplo, \"object.item.videoItem.movie\".", - "OptionPlayCount": "Número de Reproduções", + "OptionPlayCount": "Contagem de Reproduções", "OptionPlayed": "Reproduzido", "OptionPremiereDate": "Data da Estréia", "OptionProfileAudio": "Áudio", @@ -1042,7 +1039,7 @@ "OptionProfileVideoAudio": "Áudio do Vídeo", "OptionReleaseDate": "Data de Lançamento", "OptionReportByteRangeSeekingWhenTranscoding": "Reportar que o servidor suporta busca de byte quando transcodificar", - "OptionReportByteRangeSeekingWhenTranscodingHelp": "Isto é necessário para alguns dispositivos que não buscam o tempo muito bem.", + "OptionReportByteRangeSeekingWhenTranscodingHelp": "Isto é necessário para avançar ou retroceder o tempo em alguns dispositivos.", "OptionRequirePerfectSubtitleMatch": "Fazer download apenas de legendas que correspondam exatamente aos meus arquivos de vídeo", "OptionRequirePerfectSubtitleMatchHelp": "Ao solicitar uma combinação perfeita, filtrará as legendas para incluir somente aquelas que foram testadas e verificadas com o arquivo de vídeo. Ao desmarcar isto, aumentará a quantidade de legendas baixadas, mas aumentará as chances de ter legendas que não estejam sincronizadas.", "OptionResElement": "elemento res", @@ -1066,9 +1063,9 @@ "OptionWeekly": "Semanal", "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.", + "PackageInstallCancelled": "Instalação da versão {0} cancelada.", + "PackageInstallCompleted": "Instalação da versão {0} concluída.", + "PackageInstallFailed": "A Instalação da versão {0} falhou.", "ParentalRating": "Classificação etária", "PasswordMatchError": "A senha e a confirmação da senha devem ser iguais.", "PasswordResetComplete": "A senha foi redefinida.", @@ -1268,7 +1265,7 @@ "Up": "Para cima", "Upload": "Carregar", "UserAgentHelp": "Fornece um cabeçalho HTTP personalizado para o user-agent.", - "UserProfilesIntro": "O Jellyfin inclui suporte para perfis de usuários com configurações precisas de exibição, estado de reprodução e controle dos pais.", + "UserProfilesIntro": "O Jellyfin inclui suporte para perfis de usuário com configurações de exibição granular, estado de reprodução e controle dos pais.", "ValueAlbumCount": "{0} álbuns", "ValueAudioCodec": "Codec de Áudio: {0}", "ValueConditions": "Condições: {0}", @@ -1351,12 +1348,12 @@ "HeaderFavoriteAlbums": "Álbuns Favoritos", "HeaderFavoriteArtists": "Artistas Favoritos", "HeaderFavoriteSongs": "Músicas Favoritas", - "HeaderFavoriteVideos": "Vídeos Favoritos", + "HeaderFavoriteVideos": "Videos favoritos", "HeaderHome": "Inicio", - "HeaderRestartingServer": "Reiniciando Servidor", - "LabelAuthProvider": "Provedor de Autenticação:", + "HeaderRestartingServer": "Reiniciando servidor", + "LabelAuthProvider": "Provedor de autenticação:", "LabelServerName": "Nome do servidor:", - "LabelTranscodePath": "Local de transcodificação:", + "LabelTranscodePath": "Pasta de transcodificação:", "LabelTranscodes": "Transcodificação:", "LabelUserLoginAttemptsBeforeLockout": "Tentativas de login com falha antes que o usuário seja bloqueado:", "DashboardVersionNumber": "Versão: {0}", @@ -1364,7 +1361,7 @@ "DashboardOperatingSystem": "Sistema Operacional: {0}", "DashboardArchitecture": "Arquitetura: {0}", "LabelPasswordResetProvider": "Provedor para Redefinir a Senha:", - "LabelWeb": "Web: ", + "LabelWeb": "Web:", "OptionBluray": "Blu-ray", "LabelProfileContainer": "Formato:", "LabelTranscodingContainer": "Formato:", @@ -1395,7 +1392,7 @@ "OptionIsSD": "SD", "OptionList": "Lista", "OptionLoginAttemptsBeforeLockout": "Determinar quantas tentativas de logins incorretas podem ser feitas antes de ocorrer o bloqueio.", - "OptionLoginAttemptsBeforeLockoutHelp": "Um valor de zero significa herdar o padrão de três tentativas para usuários normais e cinco para administradores. Configurar para -1 desativará o recurso.", + "OptionLoginAttemptsBeforeLockoutHelp": "O valor zero significa herdar o padrão de três tentativas para usuários normais e cinco para administradores. Configurar para -1 desativará o recurso.", "OptionPoster": "Poster", "OptionPosterCard": "Cartaz", "OptionProtocolHls": "Streaming ao Vivo por HTTP", @@ -1452,5 +1449,62 @@ "MusicLibraryHelp": "Verifique o {0}guia de nomes de músicas{1}.", "ButtonAddImage": "Adicionar Imagem", "HeaderFavoritePeople": "Pessoas Favoritas", - "OptionRandom": "Aleatório" + "OptionRandom": "Aleatório", + "SelectAdminUsername": "Por favor selecione um nome de usuário para a conta de administrador.", + "OptionForceRemoteSourceTranscoding": "Forçar transcodificação em fontes de mídia remotas (como LiveTV)", + "NoCreatedLibraries": "Parece que você ainda não criou nenhuma biblioteca. {0}Gostaria de criar uma agora?{1}", + "MessageConfirmAppExit": "Você quer sair?", + "LabelVideoResolution": "Resolução de vídeo:", + "LabelStreamType": "Tipo de stream:", + "EnableFastImageFadeIn": "Fade-in rápido da imagem", + "LabelPlayerDimensions": "Dimensões do player:", + "LabelCorruptedFrames": "Quadros corrompidos:", + "HeaderNavigation": "Navegação", + "CopyStreamURLError": "Houve um erro ao copiar a URL.", + "ButtonSplit": "Dividir", + "AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.", + "AllowFfmpegThrottling": "Transcodes do Acelerador", + "PlaybackErrorNoCompatibleStream": "Este cliente não é compatível com a media e o servidor não está enviando um formato de mídia compatível.", + "EnableFastImageFadeInHelp": "Habilitar animações rápidas de aparecimento para imagens carregadas", + "LabelDroppedFrames": "Quadros caídos:", + "AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux estiver suficientemente avançada da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais proveitoso para quando não há avanço ou retrocesso do vídeo com frequência. Desative se tiver problemas de reprodução.", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferir informações dos episódios incorporadas nos arquivos ao invés dos nomes", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Esta opção habilita as informações dos episódios incorporadas nos metadados dos arquivos(se estiverem disponíveis).", + "ClientSettings": "Configurações do cliente", + "OnApplicationStartup": "Na inicialização do aplicativo", + "EveryXHours": "A cada {0} horas", + "EveryHour": "A cada hora", + "EveryXMinutes": "A cada {0} minutos", + "OnWakeFromSleep": "Ao acordar da suspensão", + "WeeklyAt": "{0} às {1}", + "DailyAt": "Diariamente à {0}", + "LastSeen": "Visto pela última vez {0}", + "PersonRole": "como {0}", + "ListPaging": "{0}-{1} de {2}", + "WriteAccessRequired": "O servidor Jellyfin necessita de acesso de escrita para essa pasta. Garanta o acesso e tente novamente.", + "PathNotFound": "O caminho não pôde ser encontrado. Por favor certifique-se da validade e tente novamente.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Trilha", + "Season": "Temporada", + "ReleaseGroup": "Grupo de Lançamento", + "Person": "Pessoa", + "OtherArtist": "Outro Artista", + "Movie": "Filme", + "LabelLibraryPageSizeHelp": "Selecione a quantidade de itens a aparecer na página da biblioteca. Coloque 0 para desabilitar a paginação.", + "LabelLibraryPageSize": "Tamanho da página da biblioteca:", + "LabelDeinterlaceMethod": "Método de desentrelaçamento:", + "Episode": "Episódio", + "DeinterlaceMethodHelp": "Selecione o método de desentrelaçamento a ser usado ao transcodificar o conteúdo entrelaçado.", + "BoxSet": "Coleção", + "Artist": "Artista", + "AlbumArtist": "Artista do Album", + "Album": "Album", + "UnsupportedPlayback": "O Jellyfin não pode descriptografar conteúdo protegido por DRM, porém mesmo assim fará uma tentativa para todo tipo de conteúdo, incluindo títulos protegidos. A imagem de alguns arquivos pode aparecer completamente preta devido a criptografia ou outros recursos não suportados, como títulos interativos.", + "MessageUnauthorizedUser": "Você não está autorizado a acessar o servidor neste momento. Por favor, contate o administrador do servidor para mais informações.", + "ButtonTogglePlaylist": "Playlist", + "ButtonToggleContextMenu": "Mais", + "Filter": "Filtro", + "New": "Novo", + "HeaderFavoritePlaylists": "Playlists Favoritas" } diff --git a/src/strings/pt-pt.json b/src/strings/pt-pt.json index 54d4a6e78f..981b7a7b41 100644 --- a/src/strings/pt-pt.json +++ b/src/strings/pt-pt.json @@ -134,8 +134,8 @@ "HeaderConfirmProfileDeletion": "Confirmar Remoção do Perfil", "HeaderConfirmRevokeApiKey": "Revogar Chave da API", "HeaderConnectToServer": "Ligar ao Servidor", - "HeaderContainerProfile": "Perfil do Container", - "HeaderContainerProfileHelp": "Perfis do Container indicam as limitações de um dispositivo ao reproduzir formatos específicos. Se uma limitação ocorre, o ficheiro multimédia será transcodificado, mesmo se o formato estiver configurado para reprodução direta.", + "HeaderContainerProfile": "Perfil do Contentor", + "HeaderContainerProfileHelp": "Perfis do contentor indicam as limitações de um dispositivo ao reproduzir formatos específicos. Se uma limitação ocorre, o ficheiro multimédia será transcodificado, mesmo se o formato estiver configurado para reprodução direta.", "HeaderContinueWatching": "Continuar a Ver", "HeaderCustomDlnaProfiles": "Perfis Personalizados", "HeaderDateIssued": "Data da Emissão", @@ -184,7 +184,7 @@ "HeaderMediaFolders": "Pastas Multimédia", "HeaderMediaInfo": "Informações Multimédia", "HeaderMetadataSettings": "Configurações de Metadados", - "HeaderMusicVideos": "Vídeos de Música", + "HeaderMusicVideos": "Videoclips", "HeaderMyMedia": "O Meu Conteúdo", "HeaderNewApiKey": "Nova Chave da API", "HeaderNextUp": "A Seguir", @@ -351,7 +351,7 @@ "LabelGroupMoviesIntoCollections": "Agrupar filmes em coleções", "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma coleção serão mostrados como um único item agrupado.", "LabelHardwareAccelerationType": "Aceleração por hardware:", - "LabelHardwareAccelerationTypeHelp": "Esta funcionalidade é experimental e está disponível apenas em sistemas suportados.", + "LabelHardwareAccelerationTypeHelp": "Aceleração via hardware requer configurações adicionais.", "LabelHttpsPort": "Número do porto HTTPS local:", "LabelHttpsPortHelp": "Número do porto TCP em que o servidor HTTPS do Jellyfin ficará à escuta.", "LabelIconMaxHeight": "Altura máxima do ícone:", @@ -367,7 +367,7 @@ "LabelKodiMetadataDateFormatHelp": "Todas as datas presentes em ficheiros NFO serão analisadas utilizando este formato.", "LabelKodiMetadataEnableExtraThumbs": "Copiar o parâmetro extrafanart para extrathumbs", "LabelKodiMetadataEnableExtraThumbsHelp": "Ao transferir imagens, estas podem ser guardadas como extrafanart e extrathumbs para uma maior compatibilidade com os temas Kodi.", - "LabelKodiMetadataEnablePathSubstitution": "Ativar substituição de local", + "LabelKodiMetadataEnablePathSubstitution": "Ativar substituição de localização", "LabelKodiMetadataEnablePathSubstitutionHelp": "Ativa a substituição da localização das imagens usando as opções de substituição de localização no servidor.", "LabelKodiMetadataSaveImagePaths": "Guardar a localização de imagens em ficheiros nfo", "LabelKodiMetadataSaveImagePathsHelp": "Esta opção é recomendada se existirem nomes de imagens que não estejam de acordo com as recomendações do Kodi.", @@ -430,7 +430,7 @@ "LabelProfileAudioCodecs": "Codecs do áudio:", "LabelProfileCodecsHelp": "Separados por vírgula. Pode ser deixado em branco para usar com todos os codecs.", "LabelProfileContainer": "Contentor:", - "LabelProfileContainersHelp": "Separados por vírgula. Pode ser deixado em branco para usar com todos os containers.", + "LabelProfileContainersHelp": "Separados por vírgula. Pode ser deixado em branco para ser aplicado a todos os containers.", "LabelProfileVideoCodecs": "Codecs do vídeo:", "LabelProtocol": "Protocolo:", "LabelProtocolInfo": "Informação do protocolo:", @@ -444,8 +444,8 @@ "LabelReleaseDate": "Data de lançamento:", "LabelRemoteClientBitrateLimit": "Taxa de bits máxima para transmissão para a Internet (Mbps):", "LabelRuntimeMinutes": "Duração (minutos):", - "LabelSaveLocalMetadata": "Guardar imagens e metadados nas pastas multimédia", - "LabelSaveLocalMetadataHelp": "Guardar imagens e metadados diretamente nas pastas multimédia, vai colocá-los num local de fácil acesso para poderem ser editados facilmente.", + "LabelSaveLocalMetadata": "Guardar capas de álbum nas pastas multimédia", + "LabelSaveLocalMetadataHelp": "Guardar capas de álbum diretamente nas pastas multimédia, vai colocá-las num local de fácil acesso para edição.", "LabelScheduledTaskLastRan": "Última execução há {0}. Tempo de execução {1}.", "LabelSeasonNumber": "Número da temporada:", "LabelSelectUsers": "Selecionar utilizadores:", @@ -577,11 +577,10 @@ "OptionDownloadPrimaryImage": "Principal", "OptionDownloadThumbImage": "Miniatura", "OptionDvd": "DVD", - "OptionEmbedSubtitles": "Incorporar no recipiente", + "OptionEmbedSubtitles": "Incorporar no contentor", "OptionEnableAccessFromAllDevices": "Ativar acesso de todos os dispositivos", "OptionEnableAccessToAllChannels": "Permitir acesso a todos os canais", "OptionEnableAccessToAllLibraries": "Permitir acesso a todas as bibliotecas", - "OptionEnableAutomaticServerUpdates": "Ativar as atualizações automáticas do servidor", "OptionEnableM2tsMode": "Ativar modo M2ts", "OptionEnableM2tsModeHelp": "Ativar o modo m2ts durante a transcodificação para mpegts.", "OptionEnded": "Terminado", @@ -671,7 +670,7 @@ "Save": "Guardar", "ScanLibrary": "Analisar biblioteca", "Search": "Busca", - "SearchForCollectionInternetMetadata": "Procurar na Internet por imagens e metadados", + "SearchForCollectionInternetMetadata": "Procurar na Internet por capas de álbum e metadados", "SearchForSubtitles": "Procurar Legendas", "SendMessage": "Enviar mensagem", "Series": "Séries", @@ -769,7 +768,7 @@ "AllowMediaConversion": "Permitir conversão multimédia", "AllowMediaConversionHelp": "Permitir ou negar acesso à funcionalidade de conversão multimédia.", "AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real", - "AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes para evitar transcodificação. Em certos dispositivos, é uma operação demorada e pode causar paragens de reprodução durante o processo de extração. Desative esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.", + "AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes para evitar transcodificação. Em certos dispositivos, esta poderá ser uma operação demorada e pode causar paragens de reprodução durante o processo de extração. Desative esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.", "AllowRemoteAccess": "Permitir ligações remotas a este Jellyfin Server.", "AllowRemoteAccessHelp": "Se inativo, todas as ligações remotas serão bloqueadas.", "AllowedRemoteAddressesHelp": "Lista de IP ou IP/Máscara, separados por vírgulas, com permissão para se ligar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.", @@ -781,7 +780,7 @@ "AspectRatio": "Proporção", "AuthProviderHelp": "Selecione um mecanismo de autenticação a ser utilizado para validar as credenciais deste utilizador.", "Auto": "Automático", - "AutoBasedOnLanguageSetting": "Auomático (baseado no idioma definido)", + "AutoBasedOnLanguageSetting": "Automático (baseado no idioma definido)", "BirthDateValue": "Nascimento: {0}", "BirthPlaceValue": "Local de nascimento: {0}", "Blacklist": "Lista Negra", @@ -869,13 +868,12 @@ "HeaderAddToPlaylist": "Adicionar à Lista de Reprodução", "HandledByProxy": "Gerido pelo proxy inverso", "HDPrograms": "Programas HD", - "H264EncodingPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", + "EncoderPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", "Guide": "Programação", "GuestStar": "Estrela convidada", "GroupVersions": "Agrupar versões", "GroupBySeries": "Agrupar por série", - "GenresValue": "Géneros: {0}", - "GenreValue": "Género: {0}", + "Genre": "Género", "General": "Geral", "FormatValue": "Formato: {0}", "FolderTypeUnset": "Conteúdo Misto", @@ -934,7 +932,7 @@ "OptionProtocolHls": "Emissão HTTP em direto", "LabelHomeScreenSectionValue": "Secção {0} do Painel Principal:", "LabelHomeNetworkQuality": "Qualidade da rede interna:", - "LabelH264EncodingPreset": "Preset para codificação H264:", + "LabelEncoderPreset": "Preset para codificação H264:", "LabelH264Crf": "CRF para codificação H264:", "LabelFont": "Tipo de Letra:", "LabelFileOrUrl": "Ficheiro ou URL:", @@ -957,7 +955,7 @@ "LabelBindToLocalNetworkAddress": "Endereço local para colocar o servidor à escuta:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Atualizar metadados automaticamente a partir da Internet:", "LabelAuthProvider": "Provedor de autenticação:", - "LabelAudio": "Áudio:", + "LabelAudio": "Áudio", "LabelAllowedRemoteAddressesMode": "Tipo de filtro de IP remoto:", "LabelAllowedRemoteAddresses": "Filtro de IP remoto:", "LabelAllowHWTranscoding": "Permitir transcodificação por hardware", @@ -1003,7 +1001,7 @@ "RequiredForAllRemoteConnections": "Necessário para todas as ligações externas", "ReplaceAllMetadata": "Substituir todos os metadados", "RepeatOne": "Repetir este", - "RepeatMode": "Modo de repetição", + "RepeatMode": "Modo de Repetição", "ServerRestartNeededAfterPluginInstall": "O Servidor Jellyfin necessitará de reiniciar depois de instalar uma extensão.", "NoPluginConfigurationMessage": "Esta extensão não é configurável.", "MessagePluginInstallDisclaimer": "As extensões desenvolvidas pela comunidade Jellyfin são uma ótima forma de melhorar a experiência de utilização do Jellyfin, adicionando novas funcionalidades e benefícios. Antes de proceder à instalação, tenha em atenção que estas podem alterar determinados comportamentos no Servidor Jellyfin e provocar efeitos como tempos de atualização da Biblioteca mais longos, processamento adicional em segundo plano e estabilidade do sistema reduzida.", @@ -1078,8 +1076,7 @@ "News": "Notícias", "Programs": "Programas", "HeaderMovies": "Filmes", - "DirectorsValue": "Realização: {0}", - "DirectorValue": "Realizador: {0}", + "Directors": "Realização", "ButtonOff": "Desligado", "ButtonAddImage": "Adicionar Imagem", "LabelOriginalTitle": "Título original:", @@ -1181,17 +1178,17 @@ "MediaInfoLevel": "Nível", "Banner": "Insígnia", "Desktop": "Desktop", - "DetectingDevices": "Procurando dispositivos", - "CopyStreamURL": "Copiar URL da corrente", + "DetectingDevices": "A procurar dispositivos", + "CopyStreamURL": "Copiar URL da transmissão", "Disc": "Disco", - "EnableBackdrops": "Pano de fundo", - "HeaderRestartingServer": "Reiniciando o servidor", + "EnableBackdrops": "Imagens de Fundo", + "HeaderRestartingServer": "A reiniciar o Servidor", "HeaderTags": "Etiquetas", "LabelLogs": "Registos:", "LabelSortTitle": "Título para ordenação:", - "HeaderFavoritePeople": "Pessoas favoritas", + "HeaderFavoritePeople": "Pessoas Favoritas", "HeaderFetcherSettings": "Definições do fornecedor", - "HeaderKodiMetadataHelp": "Para activar ou desactiver metadados NFO, use a secção de metadados disponível na página de configurações da biblioteca.", + "HeaderKodiMetadataHelp": "Para ativar ou desativar metadados NFO, utilize a secção de metadados disponível na página de configurações da biblioteca.", "HeaderTypeImageFetchers": "{0} fornecedores de imagens", "LabelImageFetchersHelp": "Active e ordene os fornecedores de imagens por ordem de preferência.", "LabelKodiMetadataUserHelp": "Autorizar que outras aplicações usem dados de visualização gaurdados em ficheiros NFO.", @@ -1202,17 +1199,17 @@ "Home": "Início", "GuideProviderLogin": "Iniciar Sessão", "HeaderSubtitleDownloads": "Transferir legendas", - "LabelRecord": "Registo/Guardar", + "LabelRecord": "Gravação:", "LabelSkin": "Máscara:", - "LabelMetadataDownloadersHelp": "Active e ordene os seus provedores de metadados por ordem de preferência. Provedores com menos prioriadade só serão usados para completar informação em falta.", - "LabelMetadataReadersHelp": "Ordene as suas fontes preferidas de metadados por ordem de preferência. O primeiro ficheiro encontrado será utilizado.", + "LabelMetadataDownloadersHelp": "Ative e ordene os seus provedores de metadados por ordem de preferência. Provedores com menos prioridade só serão usados para completar informação em falta.", + "LabelMetadataReadersHelp": "Ordene as suas fontes de metadados por ordem de preferência. O primeiro ficheiro encontrado será utilizado.", "LabelMetadataReaders": "Provedores de metadados:", "LabelPasswordResetProvider": "Provedor de redefinição da palavra-passe:", "LabelSortOrder": "Sequência de ordenação:", "LabelKodiMetadataUser": "Guardar dados de visualização em ficheiros NFO:", "HeaderCastAndCrew": "Elenco e Equipa", - "HeaderAdmin": "Administrar", - "HeaderAppearsOn": "Present em", + "HeaderAdmin": "Gerir o Servidor", + "HeaderAppearsOn": "Presente em", "LabelSortBy": "Ordenar por:", "LabelSpecialSeasonsDisplayName": "Nome da temporada especial:", "StopRecording": "Parar gravação", @@ -1268,7 +1265,7 @@ "ValueSeconds": "{0} segundos", "ValueOneSong": "1 música", "ValueOneSeries": "1 série", - "ValueOneMusicVideo": "1 vídeo de música", + "ValueOneMusicVideo": "1 videoclip", "ValueOneMovie": "1 filme", "ValueOneEpisode": "1 episódio", "Yesterday": "Ontem", @@ -1309,7 +1306,7 @@ "LabelWeb": "Web:", "LabelVideoCodec": "Codec de vídeo:", "LabelVideoBitrate": "Taxa de bits de vídeo:", - "LabelVideo": "Vídeo:", + "LabelVideo": "Vídeo", "DashboardArchitecture": "Arquitetura: {0}", "DashboardOperatingSystem": "Sistema Operativo: {0}", "DashboardServerName": "Servidor: {0}", @@ -1323,7 +1320,139 @@ "LabelTextColor": "Côr do texto:", "LabelTextBackgroundColor": "Côr de fundo do texto:", "LabelTag": "Etiqueta:", - "LabelSubtitles": "Legendas:", + "LabelSubtitles": "Legendas", "LabelSportsCategories": "Categorias de Desporto:", - "FetchingData": "A transferir informação adicional" + "FetchingData": "A transferir informação adicional", + "List": "lista", + "LaunchWebAppOnStartup": "Iniciar a interface web ao iniciar o servidor", + "No": "Não", + "OptionRegex": "Expressão Regular", + "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)", + "NoSubtitles": " Sem legendas", + "NoSubtitleSearchResultsFound": "Sem resultados.", + "NoNewDevicesFound": "Não foi encontrado nenhum dispositivo novo. Para adicionar um novo sintonizador, feche este diálogo e introduza manualmente as informações do dispositivo.", + "NextUp": "A Seguir", + "Next": "Próximo", + "NewEpisodesOnly": "Apenas novos episódios", + "NewEpisodes": "Novos episódios", + "Never": "Nunca", + "Name": "Nome", + "MusicVideo": "Videoclip", + "MusicArtist": "Artista de Música", + "MusicAlbum": " Álbum de Música", + "MoreMediaInfo": "Informações", + "MediaInfoBitrate": "Taxa de Bits", + "LabelUserAgent": "User-Agent:", + "MediaInfoAnamorphic": "Anamórfico", + "LabelTranscodes": "Transcodificação:", + "Whitelist": "Lista branca", + "VideoRange": "Alcance video", + "ValueOneAlbum": "1 álbum", + "ValueMusicVideoCount": "{0} videoclips", + "ValueMovieCount": "{0} filmes", + "ValueMinutes": "{0} min", + "ValueEpisodeCount": "{0} episódios", + "ValueDiscNumber": "Disco {0}", + "ValueContainer": "Contentor: {0}", + "ValueCodec": "Codec: {0}", + "ValueAlbumCount": "{0} álbuns", + "Upload": "Carregar", + "Up": "Cima", + "Unrated": "Sem avaliação", + "Transcoding": "Transcodificação", + "Trailers": "Trailers", + "TitleHostingSettings": "Configurações de Hospedagem", + "Thumb": "Miniatura", + "ThemeVideos": "Vídeos de tema", + "ThemeSongs": "Músicas de tema", + "TagsValue": "Etiquetas: {0}", + "Tags": "Etiquetas", + "TabTrailers": "Trailers", + "TabResumeSettings": "Retomar", + "TabLogs": "Logs", + "TabInfo": "Info", + "TabCodecs": "Codecs", + "Suggestions": "Sugestões", + "SortName": "Ordenar nome", + "SortByValue": "Ordenar por {0}", + "Sort": "Ordenar", + "Smart": "Inteligente", + "Smaller": "Menor", + "Small": "Pequeno", + "ShowTitle": "Mostrar título", + "ShowIndicatorsFor": "Mostrar indicadores para:", + "ServerNameIsShuttingDown": "Jellyfin Server - {0} está a desligar.", + "ServerNameIsRestarting": "Jellyfin Server - {0} está a reiniciar.", + "SeriesYearToPresent": "{0} - Presente", + "SeriesSettings": "Configuração de série", + "SeriesCancelled": "Série cancelada.", + "SelectAdminUsername": "Por favor selecione um nome de utilizador para a conta de administração.", + "RepeatEpisodes": "Repetir episódios", + "RepeatAll": "Repetir tudo", + "RemoveFromCollection": "Remover da coleção", + "RememberMe": "Lembrar-me", + "ReleaseDate": "Data de lançamento", + "RefreshQueued": "Recarregar na fila.", + "RefreshMetadata": "Recarregar metadados", + "RecentlyWatched": "Vistos recentemente", + "Rate": "Avaliação", + "QueueAllFromHere": "Fila a partir daqui", + "Quality": "Qualidade", + "ProductionLocations": "Localizações de produção", + "Primary": "Primário", + "Previous": "Anterior", + "Premieres": "Estreias", + "Premiere": "Estreia", + "PreferredNotRequired": "Prefiro, mas não obrigatório", + "PreferEmbeddedTitlesOverFileNames": "Preferir títulos embutidos a nomes de ficheiro", + "PictureInPicture": "Imagem em imagem", + "OptionThumbCard": "Miniatura cartão", + "OptionThumb": "Miniatura", + "OptionPosterCard": "Poster cartão", + "OptionPoster": "Poster", + "OptionDownloadBannerImage": "Cartaz", + "OptionDisplayFolderView": "Mostre em vista de pasta para ver pastas de mídia", + "OptionBanner": "Cartaz", + "NewCollectionHelp": "Coleções permitem criar grupos personalizados de filmes e outros tipos de conteúdo.", + "MusicLibraryHelp": "Reveja o {0}guia de nomeação de música{1}.", + "MovieLibraryHelp": "Reveja o {0} guia de nomeação de filmes {1}.", + "MessageConfirmAppExit": "Quer sair?", + "MediaInfoRefFrames": "Ref quadros", + "MediaInfoLayout": "Disposição", + "MediaInfoDefault": "Padrão", + "MediaInfoBitDepth": "Bit profundidade", + "Logo": "Logotipo", + "LinksValue": "Ligações: {0}", + "Like": "Gosto", + "LaunchWebAppOnStartupHelp": "Abra o cliente web no ser browser padrão quando o servidor iniciar. Isto não acontecerá usando uma função de reiniciar de servidor.", + "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaCap": "X-DLNA cap:", + "LabelVaapiDeviceHelp": "Este é o nó de renderização usado para aceleração de hardware.", + "LabelVaapiDevice": "Dispositivo VAAPI:", + "LabelTypeMetadataDownloaders": "{0} transferências de metadados:", + "LabelTheme": "Tema:", + "LabelTVHomeScreen": "TV modo ecrã de casa:", + "LabelSubtitleDownloaders": "Transferência de legendas:", + "LabelParentNumber": "Número fonte:", + "LabelMetadataSavers": "Formatos de Gravação de Metadados:", + "LabelAudioBitDepth": "Áudio bit quantidade:", + "HeaderNavigation": "Navegação", + "EnableStreamLooping": "Auto-cíclico de streams ao vivo", + "Down": "Baixo", + "CopyStreamURLError": "Ocorreu um erro a copiar o URL.", + "ButtonSplit": "Dividir", + "NoCreatedLibraries": "Parece que ainda não foi criada nenhuma biblioteca por enquanto. {0} Gostaria de criar uma biblioteca agora? {1}", + "AskAdminToCreateLibrary": "Pergunte a um administrador para criar uma biblioteca.", + "LabelVideoResolution": "Resolução de vídeo:", + "LabelPlayerDimensions": "Dimensões de leitor:", + "OptionLoginAttemptsBeforeLockoutHelp": "O valor zero significa herdar a definição por defeito de três tentativas para utilizadores comuns e cinco para administradores. Definir este campo como -1 desativa esta funcionalidade.", + "OptionDisplayFolderViewHelp": "Mostrar pastas juntamente com outras bibliotecas multimédia. Pode ser útil caso pretenda ter uma vista simples das pastas.", + "OptionForceRemoteSourceTranscoding": "Forçar transcodificação de fontes remotas de multimédia (LiveTV, por exemplo)", + "LabelStreamType": "Tipo de transmissão:", + "LabelDroppedFrames": "Fotogramas descartados:", + "LabelCorruptedFrames": "Fotogramas corrompidos:", + "AllowFfmpegThrottlingHelp": "Suspende o processo de transcodificação assim que este avance o suficiente após o ponto de reprodução atual, para poupança de recursos. Esta funcionalidade é mais útil quando a reprodução é maioritariamente contínua, sem avançar ou recuar manualmente. Desative esta opção caso haja problemas de reprodução.", + "AllowFfmpegThrottling": "Reduzir Taxa de Transcodificação", + "PreferEmbeddedTitlesOverFileNamesHelp": "Determina o título a apresentar por defeito quando não é possível carregar metadados locais nem da Internet.", + "OptionSaveMetadataAsHiddenHelp": "Alterar esta definição apenas afetará metadados guardados futuramente. Ficheiros existentes serão atualizados assim que forem alterados pelo Servidor Jellyfin." } diff --git a/src/strings/pt.json b/src/strings/pt.json index abf208a766..4bf5591347 100644 --- a/src/strings/pt.json +++ b/src/strings/pt.json @@ -18,7 +18,7 @@ "ValueVideoCodec": "Codec de Vídeo: {0}", "ValueTimeLimitSingleHour": "Limite de tempo: 1 hora", "ValueTimeLimitMultiHour": "Limite de tempo: {0} horas", - "ValueSpecialEpisodeName": "Especial - {0}", + "ValueSpecialEpisodeName": "Episódio Especial - {0}", "ValueConditions": "Condições: {0}", "ValueAudioCodec": "Codec de Áudio: {0}", "UserProfilesIntro": "O Jellyfin suporta perfis de utilizadores, permitindo que cada utilizador tenha as suas configurações de visualização, estado da reprodução e controlos parentais.", @@ -113,7 +113,7 @@ "Screenshot": "Captura de Ecrã", "Schedule": "Agendamentos", "ScanForNewAndUpdatedFiles": "Procurar ficheiros novos ou actualizados", - "SaveSubtitlesIntoMediaFoldersHelp": "Guardar ficheiros de legendas junto aos ficheiros vídeo facilita a gestão.", + "SaveSubtitlesIntoMediaFoldersHelp": "Salvar arquivos de legendas junto aos arquivos vídeo facilita o gerenciamento.", "SaveSubtitlesIntoMediaFolders": "Guardar legendas nas pastas multimédia", "Save": "Guardar", "Saturday": "Sábado", @@ -270,7 +270,7 @@ "LabelNewPassword": "Nova palavra-passe:", "LabelNewName": "Novo nome:", "LabelName": "Nome:", - "LabelMusicStreamingTranscodingBitrateHelp": "Defina a taxa máxima de transmissão de música", + "LabelMusicStreamingTranscodingBitrateHelp": "Especifique uma taxa de bits máxima ao transmitir músicas.", "LabelMusicStreamingTranscodingBitrate": "Taxa de transcodificação de música:", "LabelMovieRecordingPath": "Caminho para gravação de filmes (opcional):", "LabelMoviePrefixHelp": "Se aplicar um prefixo aos títulos dos filmes, introduza-o aqui para que o servidor consiga tratá-los corretamente.", @@ -307,7 +307,7 @@ "LabelMaxBackdropsPerItem": "Número máximo de imagens de fundo por item:", "LabelMatchType": "Tipo de correspondência:", "LabelManufacturerUrl": "URL do Fabricante", - "LabelManufacturer": "Fabricante", + "LabelManufacturer": "Fabricante:", "LabelLoginDisclaimerHelp": "Este aviso será mostrado na parte inferior da página de login.", "LabelLoginDisclaimer": "Aviso legal de login:", "LabelLockItemToPreventChanges": "Bloquear este item para evitar alterações futuras", @@ -340,9 +340,9 @@ "LabelHttpsPort": "Número da porta HTTPS local:", "LabelHomeScreenSectionValue": "Secção {0} do Painel Principal:", "LabelHomeNetworkQuality": "Qualidade da rede interna:", - "LabelHardwareAccelerationTypeHelp": "Esta funcionalidade é experimental e está disponível apenas em sistemas suportados.", + "LabelHardwareAccelerationTypeHelp": "A aceleração de hardware requer configuração adicional.", "LabelHardwareAccelerationType": "Aceleração por hardware:", - "LabelH264EncodingPreset": "Predefinição para codificação H264:", + "LabelEncoderPreset": "Predefinição para codificação H264:", "LabelH264Crf": "CRF para codificação H264:", "LabelGroupMoviesIntoCollectionsHelp": "Ao mostrar listas de filmes, filmes que pertençam a uma colecção serão mostrados como um único item agrupado.", "LabelGroupMoviesIntoCollections": "Agrupar filmes em colecções", @@ -377,7 +377,7 @@ "LabelEnableDlnaClientDiscoveryInterval": "Intervalo para descoberta de clientes (segundos)", "LabelEnableBlastAliveMessagesHelp": "Activar esta opção se o servidor não for convenientemente detectado por outros dispositivos UPnP na rede.", "LabelEnableBlastAliveMessages": "Enviar mensagens de reconhecimento", - "LabelEnableAutomaticPortMapHelp": "Tenta correponder automaticamente a porta pública para a porta local através de UPnP. Isto poderá não funcionar em alguns modelos de routers.", + "LabelEnableAutomaticPortMapHelp": "Tenta corresponder automaticamente a porta pública para a porta local através de UPnP. Isto poderá não funcionar em alguns modelos de roteadores. As alterações não serão até reinicialização do servidor.", "LabelEnableAutomaticPortMap": "Activar a correspondência automática de portas", "LabelEmbedAlbumArtDidlHelp": "Alguns dispositivos preferem este método para obter a capa do álbum. Outros pode não ser capazes de reproduzir com esta opção activada.", "LabelEmbedAlbumArtDidl": "Incorporar a capa do álbum no DIDL", @@ -404,12 +404,12 @@ "LabelDeathDate": "Data de falecimento:", "LabelRefreshMode": "Mode de actualização:", "LabelRecord": "Registo:", - "LabelPasswordResetProvider": "Provedor de actualização de palavra-passe", + "LabelPasswordResetProvider": "Provedor de redefinição de senha:", "LabelMetadataSaversHelp": "Escolha os formato em que deseja guardar os seus metadados.", "LabelMetadataReadersHelp": "Ordene as fontes locais de metadados por ordem de prioridade. O primeiro ficheiro a ser encontrado será lido.", "LabelMetadataReaders": "Leirores de metadados", "LabelMetadataDownloadersHelp": "Active e ordene os seus pesquisadores de metadados por ordem de prioridade. Pesquisadores com menor prioridade só serão utilizados para completar informação em falta.", - "LabelLogs": "Registos", + "LabelLogs": "Histórico:", "LabelKodiMetadataUserHelp": "Guardar dados de utilização em NFO para que outras aplicações os utilizem.", "LabelKodiMetadataUser": "Guardar dados de utilização em NFO para:", "LabelImageFetchersHelp": "Activar e ordenar os pesquisadores de imagens por ordem de preferência.", @@ -450,7 +450,7 @@ "LabelAudioCodec": "Codec de áudio:", "LabelAudioChannels": "Canais de áudio:", "LabelAudioBitrate": "Taxa de bits de áudio:", - "LabelAudio": "Áudio:", + "LabelAudio": "Áudio", "LabelArtistsHelp": "Separe múltiplos com ;", "LabelArtists": "Artistas:", "LabelAppNameExample": "Exemplo: Sickbeard, NzbDrone", @@ -595,7 +595,7 @@ "HeaderMedia": "Multimédia", "HeaderLiveTvTunerSetup": "Configurar Sintonizador de TV", "HeaderLiveTv": "TV ao Vivo", - "HeaderLiveTV": "TV ao Vivo", + "HeaderLiveTV": "TV em Directo", "HeaderLibrarySettings": "Configurações da Biblioteca", "HeaderLibraryOrder": "Ordenação da Biblioteca", "HeaderLibraryFolders": "Pastas Multimédia", @@ -891,7 +891,7 @@ "EditImages": "Editar imagens", "Edit": "Editar", "EasyPasswordHelp": "O código PIN é utilizado para acesso off-line em clientes suportados e pode ser usado para um acesso fácil dentro da rede.", - "DropShadow": "Sombreado", + "DropShadow": "sombra projetada", "DrmChannelsNotImported": "Canais com proteção DRM não serão importados.", "DownloadsValue": "{0} transferências", "Download": "Transferir", @@ -906,8 +906,7 @@ "Disconnect": "Desligar", "Disc": "Disco", "Disabled": "Desactivado", - "DirectorsValue": "Realização: {0}", - "DirectorValue": "Realizador: {0}", + "Directors": "Realização", "Director": "Realizador", "DirectStreaming": "Reprodução directa", "DirectStreamHelp2": "A reprodução directa de um ficheiro requer pouco processamento e não implica perda de qualidade num vídeo.", @@ -915,7 +914,7 @@ "DirectPlaying": "Reprodução directa", "DeviceAccessHelp": "Apenas se aplica a dispositivos que podem ser identificados como únicos e que não impedem o acesso ao navegador. Filtrar o acesso a dispositivos a um utilizador, impede-o de utilizar novos dispositivos, até estes serem aprovados aqui.", "DetectingDevices": "Procurando dispositivos", - "Desktop": "Desktop", + "Desktop": "Área de Trabalho", "Descending": "Descendente", "Depressed": "Baixo relevo", "DeleteUserConfirmation": "Tem a certeza que deseja apagar este utilizador?", @@ -1053,7 +1052,6 @@ "OptionEnableM2tsModeHelp": "Activar o modo m2ts ao codificar para mpegts.", "OptionEnableM2tsMode": "Activar modo M2ts", "OptionEnableExternalContentInSuggestionsHelp": "Permitir que trailers da Internet e programas de TV em Directo sejam incluídos no conteúdo sugerido.", - "OptionEnableAutomaticServerUpdates": "Activar actualizações automáticas do servidor", "OptionEnableAccessToAllLibraries": "Permitir acesso a todas as bibliotecas", "OptionEnableAccessFromAllDevices": "Activar acesso de todos os dispositivos", "OptionEmbedSubtitles": "Incorporar no contentor", @@ -1093,7 +1091,7 @@ "AuthProviderHelp": "Seleccione um mecanismo de autenticação a ser utilizado para validar as credenciais deste utilizador.", "Audio": "Áudio", "AttributeNew": "Novo", - "AspectRatio": "Formato", + "AspectRatio": "Proporção da tela", "Ascending": "Crescente", "Art": "Capa", "AroundTime": "Por volta das {0}", @@ -1101,12 +1099,12 @@ "AnyLanguage": "Qualquer idioma", "Artists": "Artistas", "AsManyAsPossible": "Tantos quanto possível", - "AllowedRemoteAddressesHelp": "Lista de endereços IP ou IP/Máscara, separados por vírgulas, com permissão para se ligar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.", - "AllowRemoteAccessHelp": "Se esta opção não for seleccionada, todas as ligações remotas serão bloqueadas.", + "AllowedRemoteAddressesHelp": "Lista separada por vírgula de endereços IP ou entradas de máscara de IP/rede para redes que terão permissão para se conectar remotamente. Se deixado em branco, todos os endereços remotos serão permitidos.", + "AllowRemoteAccessHelp": "Se desmarcada, todas as conexões remotas serão bloqueadas.", "AllowRemoteAccess": "Permitir ligações remotas a este Servidor Jellyfin.", "AllowOnTheFlySubtitleExtractionHelp": "Legendas integradas podem ser extraídas do vídeo e enviadas como texto simples para os clientes para evitar transcodificação. Em certos dispositivos, é uma operação demorada e pode causar paragens de reprodução durante o processo de extracção. Desactive esta opção para que as legendas sejam integradas no vídeo durante a conversão para um formato suportado pelo dispositivo de destino.", - "AllowOnTheFlySubtitleExtraction": "Permitir a extracção de legendas em tempo real", - "AllowHWTranscodingHelp": "Permitir o sintonizador converter emissões em tempo real. Poderá reduzir a necessidade do servidor converter o conteúdo.", + "AllowOnTheFlySubtitleExtraction": "Permitir a extração de legendas em tempo real", + "AllowHWTranscodingHelp": "Permita que o sintonizador transcodifique os fluxos em tempo real. Isso pode ajudar a reduzir a transcodificação exigida pelo servidor.", "AllLibraries": "Todas as bibliotecas", "AllLanguages": "Todos os idiomas", "AllEpisodes": "Todos os episódios", @@ -1121,21 +1119,21 @@ "AddedOnValue": "{0} foi adicionado", "AddToPlaylist": "Adicionar à lista de reprodução", "AddToPlayQueue": "Adicionar à fila de reprodução", - "AddToCollection": "Adicionar à colecção", - "AddItemToCollectionHelp": "Adicione itens às colecções pesquisando-os e utilizando o respetivo menu de toque ou clique direito para os adicionar a uma colecção.", + "AddToCollection": "Adicionar à coleção", + "AddItemToCollectionHelp": "Adicione itens às coleções pesquisando-os e utilizando o respetivo menu de toque ou clique direito para os adicionar a uma coleção.", "Add": "Adicionar", - "Actor": "Actor", - "AccessRestrictedTryAgainLater": "O acesso está actualmente restrito. Por favor, tente mais tarde.", + "Actor": "Ator", + "AccessRestrictedTryAgainLater": "O acesso está atualmente restrito. Por favor, tente mais tarde.", "Absolute": "Absoluto", - "AlwaysPlaySubtitlesHelp": "Legendas correspondentes à língua preferida serão sempre carregadas, independentemente do idioma do áudio.", - "SearchForMissingMetadata": "Procurar metadados em falta", + "AlwaysPlaySubtitlesHelp": "As legendas correspondentes à preferência de idioma serão carregadas, independentemente do idioma do áudio.", + "SearchForMissingMetadata": "Procurar metadados ausentes", "ScanLibrary": "Analisar biblioteca", "HeaderDeleteItem": "Remover item", "HeaderDeleteDevice": "Apagar Dispositivo", "HeaderDefaultRecordingSettings": "Definições de Gravação por Omissão", "HeaderDateIssued": "Data da Emissão", "HeaderCustomDlnaProfiles": "Perfis Personalizados", - "HeaderContinueWatching": "Continuar a Ver", + "HeaderContinueWatching": "Continuar a Assistir", "HeaderContinueListening": "Continuar a Ouvir", "HeaderContainerProfileHelp": "Os Perfis do Contentor indicam as limitações de um dispositivo ao reproduzir formatos específicos. Se hourver alguma limitação, o ficheiro multimédia será transcodificado, mesmo se o formato estiver configurado para reprodução directa.", "HeaderContainerProfile": "Perfil do Contentor", @@ -1177,27 +1175,26 @@ "HeaderActiveDevices": "Dispositivos Activos", "HeaderAccessScheduleHelp": "Crie uma restrição horária de acesso para limitar o acesso ao Jellyfin a determinadas horas.", "HeaderAccessSchedule": "Restrição Horária de Acesso", - "HardwareAccelerationWarning": "Activar a aceleração por hardware pode causar instabilidade em alguns ambientes. Garanta que o sistema operativo e os controladores da placa gráfica estão completamente actualizados. Se tiver dificuldades em reproduzir vídeo depois de alterar esta opção, pode ser necessário repôr \\\"Auto\\\".", + "HardwareAccelerationWarning": "A ativação da aceleração de hardware pode causar instabilidade em alguns ambientes. Verifique se o sistema operacional e os drivers de vídeo estão totalmente atualizados. Se você tiver dificuldade em reproduzir o vídeo depois de ativar isso, precisará alterar a configuração novamente para Nenhum.", "HandledByProxy": "Gerido pelo proxy inverso", "HDPrograms": "Programas HD", - "H264EncodingPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", + "EncoderPresetHelp": "Escolha um valor mais rápido para melhorar o desempenho, ou um valor mais lento para melhorar a qualidade.", "H264CrfHelp": "O parâmetro \\\"Constant Rate Factor (CRF)\\\" define o nível de qualidade usadoi por omissão pelo codificador x264. Os valores variam entre 0 e 51, em que valores mais baixos resultam em maior qualidade (com o custo de ficheiros maiores). Valores entre 18 e 28 são habitualmente considerados aceitáveis. O valor por omissão é 23, sendo um bom ponto de partida para ajustes.", "GuideProviderSelectListings": "Seleccionar Listas", "Guide": "Programação", "GuestStar": "Estrela convidada", "GroupVersions": "Agrupar versões", "GroupBySeries": "Agrupar por série", - "GenresValue": "Géneros: {0}", "ErrorAddingListingsToSchedulesDirect": "Ocorreu um erro ao adicionar o alinhamento à sua conta Schedules Direct. As contas Schedules Direct permitem apenas um número limitado de alinhamentos. Poderá ser necessário iniciar sessão na sua conta e remover outras listagens antes de prosseguir.", "Ended": "Terminado", "DefaultMetadataLangaugeDescription": "Estes são os valores por omissão que podem ser individualizados para cada uma das bibliotecas.", "Genres": "Géneros", - "GenreValue": "Género: {0}", + "Genre": "Género", "General": "Geral", "Fullscreen": "Ecrã inteiro", "Friday": "Sexta", "FormatValue": "Formato: {0}", - "Folders": "Pastas", + "Folders": "Directórios", "FolderTypeUnset": "Conteúdo Misto", "FolderTypeTvShows": "Programas TV", "FolderTypeMusicVideos": "Videoclips", @@ -1208,5 +1205,194 @@ "OptionDownloadDiscImage": "Disco", "FetchingData": "Buscando Dados Adicionais", "EnableStreamLooping": "Habilitar loop do streaming", - "Down": "Baixar" + "Down": "Baixar", + "HeaderTags": "Tags", + "HeaderNavigation": "Navegar", + "CopyStreamURLError": "Ocorreu um erro ao copiar o URL.", + "ButtonSplit": "Dividir", + "AskAdminToCreateLibrary": "Peça a um administrador para criar uma biblioteca.", + "AllowFfmpegThrottling": "Transcodificação com falhas", + "DashboardOperatingSystem": "Sistema Operativo", + "LabelUserLoginAttemptsBeforeLockout": "Número de tentativas de login falhadas antes do bloqueio do utilizador:", + "LabelTrackNumber": "Número da faixa:", + "LabelSportsCategories": "Categorias de Desportos:", + "Yesterday": "Ontem", + "MusicVideo": "Vídeo de música", + "MusicLibraryHelp": "Reveja o {0} guia de nomes de músicas {1}.", + "MusicArtist": "Artista musical", + "MusicAlbum": "Álbum de música", + "MovieLibraryHelp": "Reveja o {0} guia de nomeação de filmes {1}.", + "MoveRight": "Mover para a direita", + "MoveLeft": "Mova à esquerda", + "MoreMediaInfo": "Informações sobre mídia", + "MoreFromValue": "Mais de {0}", + "MediaInfoRefFrames": "Quadros de referência", + "MediaInfoContainer": "Recipiente", + "MediaInfoAnamorphic": "Anamórfico", + "LabelVideoResolution": "Resolução do vídeo:", + "LabelTypeMetadataDownloaders": "{0} download de metadados:", + "LabelTranscodePath": "Caminho da transcodificação:", + "OnlyImageFormats": "Somente formatos de imagem (VOBSUB, PGS, SUB)", + "OnlyForcedSubtitlesHelp": "Apenas as legendas marcadas como forçadas serão carregadas.", + "OnlyForcedSubtitles": "Somente legendas forçadas", + "Off": "Desligar", + "NumLocationsValue": "{0} pastas", + "Normal": "Normal", + "None": "Nenhum", + "NoSubtitlesHelp": "As legendas não serão carregadas por padrão. Eles ainda podem ser ativados manualmente durante a reprodução.", + "NoSubtitles": "Sem legendas", + "NoSubtitleSearchResultsFound": "Nenhum resultado encontrado.", + "NoNewDevicesFound": "Não foram encontrados novos dispositivos. Para adicionar um novo sintonizador, feche esta caixa de diálogo e insira as informações do dispositivo manualmente.", + "NoCreatedLibraries": "Parece que você ainda não criou nenhuma biblioteca. {0} Deseja criar um agora? {1}", + "No": "Não", + "Mobile": "Celular", + "MetadataSettingChangeHelp": "A alteração das configurações de metadados afetará o novo conteúdo adicionado a partir de agora. Para atualizar o conteúdo existente, abra a tela de detalhes e clique no botão Atualizar ou execute atualizações em massa usando o gerenciador de metadados.", + "MetadataManager": "Gestor de metadados", + "Metadata": "Metadados", + "MessageYouHaveVersionInstalled": "Você possui a versão {0} atualmente instalada.", + "MessageUnsetContentHelp": "O conteúdo será exibido como pastas simples. Para obter melhores resultados, use o gerenciador de metadados para definir os tipos de conteúdo das subpastas.", + "MessageSettingsSaved": "Configurações salvas.", + "MessagePleaseWait": "Por favor, espere. Isso pode levar um minuto.", + "MessagePlayAccessRestricted": "A reprodução deste conteúdo está atualmente restrita. Entre em contato com o administrador do servidor para obter mais informações.", + "MessageNoServersAvailable": "Nenhum servidor foi encontrado usando a descoberta automática de servidores.", + "MessageNoCollectionsAvailable": "As coleções permitem que você desfrute de agrupamentos personalizados de filmes, séries e álbuns. Clique no botão + para começar a criar coleções.", + "MessageConfirmAppExit": "Você quer sair?", + "MediaInfoLayout": "Layout", + "MediaInfoLanguage": "Língua", + "MediaInfoInterlaced": "Entrelaçada", + "MediaInfoFramerate": "Taxa de quadros", + "MediaInfoForced": "Forçar", + "MediaInfoExternal": "Externo", + "MediaInfoDefault": "Padrão", + "MediaInfoCodecTag": "Codec tag", + "MediaInfoCodec": "Codec", + "MediaInfoBitrate": "Taxa de bits", + "MediaInfoBitDepth": "Profundidade de bits", + "MediaInfoAspectRatio": "Proporção da tela", + "ManageRecording": "Gerenciar gravações", + "Logo": "Logo", + "List": "Lista", + "LinksValue": "Links: {0}", + "Like": "Gostei", + "LeaveBlankToNotSetAPassword": "Você pode deixar esse campo em branco para definir nenhuma senha.", + "LearnHowYouCanContribute": "Aprenda como você pode contribuir.", + "LaunchWebAppOnStartupHelp": "Abra o cliente da web no seu navegador da web padrão quando o servidor iniciar. Isso não ocorrerá ao usar a função de reinicialização do servidor.", + "LaunchWebAppOnStartup": "Inicie a interface da web ao iniciar o servidor", + "Large": "Amplo", + "LanNetworksHelp": "Lista separada por vírgula de endereços IP ou entradas de máscara de rede/IP para redes que serão consideradas na rede local ao impor restrições de largura de banda. Se definido, todos os outros endereços IP serão considerados na rede externa e estarão sujeitos às restrições de largura de banda externa. Se deixado em branco, apenas a sub-rede do servidor é considerada na rede local.", + "LabelffmpegPathHelp": "O caminho para o arquivo do aplicativo ffmpeg ou pasta que contém o ffmpeg.", + "LabelffmpegPath": "FFmpeg caminho:", + "LabelYear": "Ano:", + "LabelXDlnaDoc": "X-DLNA doc:", + "LabelXDlnaCap": "X-DLNA cap:", + "LabelWeb": "Web:", + "LabelVideoCodec": "Vídeo: codec:", + "LabelVideoBitrate": "Vídeo taxa de bits:", + "LabelVideo": "Vídeo:", + "DashboardArchitecture": "Arquitetura: {0}", + "DashboardServerName": "Servidor: {0}", + "DashboardVersionNumber": "Versão: {0}", + "LabelVersion": "Versão:", + "LabelVaapiDeviceHelp": "Este é o nó de renderização usado para aceleração de hardware.", + "LabelVaapiDevice": "VA API Dispositivo:", + "LabelUserAgent": "Agente de usuário:", + "LabelTranscodes": "Transcodificação:", + "LabelTranscodingFramerate": "Transcodificação frame por segundo:", + "LabelTranscodingProgress": "Progresso da transcodificação:", + "LabelTitle": "Título:", + "LabelTheme": "Tema:", + "LabelTextColor": "Cor do texto:", + "LabelTextBackgroundColor": "Cor do plano de fundo do texto:", + "LabelTag": "Tag:", + "LabelTVHomeScreen": "Tela inicial do modo TV:", + "LabelSubtitles": "Legendas:", + "LabelSubtitleDownloaders": "Downloaders de legendas:", + "LabelStreamType": "Tipo de fluxo:", + "LabelSpecialSeasonsDisplayName": "Nome de exibição da temporada especial:", + "LabelSoundEffects": "Efeitos sonoros:", + "LabelSortTitle": "Classificar título:", + "LabelSortOrder": "Ordem de classificação:", + "LabelSortBy": "Ordenar por:", + "LabelSkin": "Pele:", + "EnableFastImageFadeInHelp": "Habilite uma animação mais rápida para imagens carregadas", + "EnableFastImageFadeIn": "Efeito de imagem fade-in rápido", + "LabelRemoteClientBitrateLimitHelp": "Um limite opcional de taxa de bits por fluxo para todos os dispositivos fora da rede. Isso é útil para impedir que os dispositivos solicitem uma taxa de bits mais alta do que a sua conexão à Internet pode suportar. Isso pode resultar no aumento da carga da CPU no servidor para transcodificar vídeos em tempo real para uma taxa de bits mais baixa.", + "LabelPlayerDimensions": "Dimensões do reprodutor:", + "LabelParentNumber": "Número pai:", + "LabelMetadataSavers": "Economizadores de metadados:", + "LabelDroppedFrames": "Quadros caídos:", + "LabelCorruptedFrames": "Quadros corrompidos:", + "LabelAudioBitDepth": "Profundidade do bit de áudio:", + "ClientSettings": "Configurações do Cliente", + "AllowFfmpegThrottlingHelp": "Quando uma transcodificação ou remux se aproximar da posição atual de reprodução, pause o processo para que consuma menos recursos. Isso é mais útil ao assistir sem procurar com frequência. Desative isso se você tiver problemas de reprodução.", + "MySubtitles": "Minhas legendas", + "Name": "Nome", + "Never": "Nunca", + "Artist": "Artista", + "LabelDeinterlaceMethod": "Método de desentrelaçamento:", + "DeinterlaceMethodHelp": "Selecione o método de desentrelaçamento para converter conteúdo entrelaçado.", + "Movie": "Filme", + "LabelLibraryPageSize": "Tamanho da página da biblioteca:", + "Album": "Álbum", + "LabelLibraryPageSizeHelp": "Escolher a quantidade itens a exibir numa página de biblioteca. Escolha \"0\" para desabilitar a exibição em páginas.", + "Episode": "Episódio", + "OptionRequirePerfectSubtitleMatch": "Baixar apenas legendas que correspondem corretamente aos arquivos de vídeo", + "OptionRandom": "Aleatório", + "OptionPoster": "Encarte", + "OptionLoginAttemptsBeforeLockout": "Determinar a quantidade de tentativas de login incorretas até que ocorra bloqueio.", + "OptionList": "Listar", + "OptionIsSD": "Definição padrão", + "OptionIsHD": "Alta definição", + "OptionHomeVideos": "Fotos", + "OptionHasTrailer": "Trailer", + "OptionEnableExternalContentInSuggestions": "Habilitar sugestão de conteúdo externo", + "OptionDownloadMenuImage": "Menu", + "OptionDownloadLogoImage": "Logotipo", + "OptionDownloadBannerImage": "Encarte", + "OptionDisplayFolderViewHelp": "Exiba pastas ao lado de outras bibliotecas de mídia. Isso pode ser útil se você quiser ter uma visualização simples de pastas.", + "OptionDisplayFolderView": "Exibir uma exibição de pasta para mostrar pastas de mídia simples", + "OptionBluray": "Bluray", + "OptionBanner": "Poster", + "OptionAuto": "Automático", + "OptionAllowVideoPlaybackRemuxing": "Permitir execução de vídeo que requer conversão sem recodificar", + "OptionAllowLinkSharingHelp": "Somente páginas da web que contêm informações sobre mídia são compartilhadas. Os arquivos de mídia nunca são compartilhados publicamente. O tempo de compartilhamento é limitado e expira após {0} dias.", + "Option3D": "3D", + "NextUp": "Próximo", + "Next": "Próximo", + "NewEpisodesOnly": "apenas novos episódios", + "NewEpisodes": "Novos episódios", + "NewCollectionHelp": "Coleções permitem criar agrupamentos personalizados de filmes ou de outros conteúdos da biblioteca.", + "BoxSet": "Coleção", + "AlbumArtist": "Álbum do Artista", + "Quality": "Qualidade", + "Previous": "Anterior", + "PreferredNotRequired": "Preferível, mas não obrigatório", + "PictureInPicture": "vídeo destacado", + "OptionThumb": "Miniatura", + "OptionRequirePerfectSubtitleMatchHelp": "Solicitar a \"correspondência perfeita\" filtrará as legendas incluindo apenas aquelas que foram testadas com o arquivo de vídeo. Desmarcar isto aumentará a probabilidade de baixar legendas, mas poderá obter legendas incorretas ou não sincronizadas.", + "StopRecording": "Parar gravação", + "ShowYear": "Exibir ano", + "ShowTitle": "Exibir título", + "SettingsWarning": "Mudar estes valores pode causar instabilidade ou falhas de conexão. Se tiver problemas, recomendamos restaurar os valores originais.", + "ServerNameIsShuttingDown": "Servidor Jellyfin - {0} está desligando.", + "ServerNameIsRestarting": "Servidor Jellyfin - {0} está reiniciando.", + "SeriesYearToPresent": "{0} - Atualmente", + "SeriesCancelled": "Série cancelada.", + "SelectAdminUsername": "Por favor, selecione um usuário para a conta de administrador.", + "Season": "Temporada", + "RepeatEpisodes": "Repetir episódios", + "RepeatAll": "Repetir todos", + "RemoveFromCollection": "Remover da coleção", + "RememberMe": "Lembrar-me", + "ReleaseDate": "Data do lançamento", + "RefreshMetadata": "Atualizar metadados", + "RecentlyWatched": "Visto recentemente", + "OptionEnableForAllTuners": "Ativar para todos os dispositivos sintonizadores", + "OptionCaptionInfoExSamsung": "Informações da legenda (Samsung)", + "OptionBlockTrailers": "trechos de um filme", + "OptionAutomaticallyGroupSeriesHelp": "Se ativada, as séries espalhadas por várias pastas nesta biblioteca serão automaticamente mescladas em uma única série.", + "OptionAutomaticallyGroupSeries": "Mesclar automaticamente séries que estão espalhadas por várias pastas", + "OptionAllowSyncTranscoding": "Permitir download e sincronização de mídia que requeiram transcodificação", + "OptionForceRemoteSourceTranscoding": "Forçar a transcodificação de fontes de mídia remota (como LiveTV)", + "MessageUnauthorizedUser": "Você não está autorizado a acessar o servidor no momento. Entre em contato com o administrador do servidor para obter mais informações." } diff --git a/src/strings/ro.json b/src/strings/ro.json index 8951df4505..de53cabc68 100644 --- a/src/strings/ro.json +++ b/src/strings/ro.json @@ -66,16 +66,16 @@ "LabelAllowServerAutoRestart": "Permite serverului să se repornească automat pentru a aplica actualizările", "LabelAllowServerAutoRestartHelp": "Serverul se va reporni doar în timp ce nu are nici o sarcină, când nu este nici un utilizator conectat.", "LabelArtists": "Artisti:", - "LabelArtistsHelp": "Folosire separata multipla ;", + "LabelArtistsHelp": "Separare multiplă utilizând ;", "LabelAudioLanguagePreference": "Preferințe de limbă pentru audio:", - "LabelCachePath": "Cale pentru cache:", - "LabelCachePathHelp": "Specificați o locație specială pentru fișierele de cache, precum imagini etc. Lasați gol pentru a folosi setarea implicită.", - "LabelContentType": "Tip continut:", - "LabelCountry": "Tara:", + "LabelCachePath": "Cale pentru depozit:", + "LabelCachePathHelp": "Specificați o locație specială pentru fișierele de tip depozit, precum imagini etc. Lasați gol pentru a folosi setarea implicită.", + "LabelContentType": "Tip conținut:", + "LabelCountry": "Țara:", "LabelCurrentPassword": "Parola curentă:", "LabelCustomCertificatePath": "Calea către certificatul personalizat:", "LabelCustomCertificatePathHelp": "Furnizați propriul fișier care conține un certificat SSL in format .pfx.", - "LabelDisplayMissingEpisodesWithinSeasons": "Afișeaza episoadele lipsă din seriale", + "LabelDisplayMissingEpisodesWithinSeasons": "Afișeaza episoadele lipsă din sezon", "LabelFinish": "Termină", "LabelLanguage": "Limba:", "LabelMaxBackdropsPerItem": "Numărul maxim de fundaluri pentru fiecare element:", @@ -102,20 +102,20 @@ "LabelSeriesRecordingPath": "Calea pentru înregistrări seriale (opțional):", "LabelStopWhenPossible": "Oprește când este posibil:", "LabelTimeLimitHours": "Limită de timp(ore):", - "LabelTranscodingTempPathHelp": "Acest director conține fișierele de lucru folosite de convertor. Specificați o cale specială sau lasați gol pentru a folosi pe cea implicită în directorul de lucru al serverului.", + "LabelTranscodingTempPathHelp": "Specificați o cale specială pentru fișierele transcodate trimise clienților. Lasați gol pentru a folosi pe cea implicită în directorul de lucru al serverului.", "LabelTriggerType": "Tip Declanșator:", "LabelUser": "Utilizator:", "LabelYourFirstName": "Numele tău:", "LabelYoureDone": "Ești Gata!", - "LibraryAccessHelp": "Selectează dosarele media partajate cu acest utilizator. Administratorii vor avea posibilitatea sa modifice toate dosarele utilizând managerul de metadata.", - "MaxParentalRatingHelp": "Conținutul cu un o limită de vârstă mai mare va fi ascuns pentru acest utilizator.", + "LibraryAccessHelp": "Selectează biblioteciile media partajate cu acest utilizator. Administratorii vor avea posibilitatea să modifice toate dosarele utilizând managerul de metadata.", + "MaxParentalRatingHelp": "Conținutul cu o limită de vârstă mai mare va fi ascuns pentru acest utilizator.", "MessageEnablingOptionLongerScans": "Activând această opțiune poate rezulta în scanări ale bilbiotecilor semnificativ mai îndelungate.", "MessageNothingHere": "Nimic aici.", - "MessagePleaseEnsureInternetMetadata": "Vă rugăm să vă asigurați că descarcarea de metadata din internet este activată.", + "MessagePleaseEnsureInternetMetadata": "Vă rugăm să vă asigurați că descărcarea de metadate din internet este activată.", "MinutesAfter": "minute după", "MinutesBefore": "minute înainte", "Monday": "Luni", - "MoreUsersCanBeAddedLater": "Mai mulți utilizatori pot fi adăugați mai târziu în Tabloul de Bord.", + "MoreUsersCanBeAddedLater": "Mai mulți utilizatori pot fi adăugați mai târziu din Tabloul de Bord.", "NewCollectionNameExample": "Exemplu: Star Wars Collection", "NoNextUpItemsMessage": "Nu s-a gasit nimic. Începe să vizionezi seriale!", "OptionAllowBrowsingLiveTv": "Permite accessul la Live TV", @@ -127,8 +127,8 @@ "OptionAllowRemoteSharedDevices": "Permite controlul la distanță a dispozitivelor partajate", "OptionAllowRemoteSharedDevicesHelp": "Dispozitivele DLNA sunt considerate partajate până ce un utilizator începe să le controleze.", "OptionAllowUserToManageServer": "Permite acestui utilizator să administreze serverul", - "OptionAscending": "Crescător", - "OptionAutomatic": "Automat", + "OptionAscending": "Ascendent", + "OptionAutomatic": "Auto", "OptionCommunityRating": "Rating Comunitate", "OptionContinuing": "Continuă", "OptionCriticRating": "Rating Critic", @@ -178,10 +178,10 @@ "OptionUnplayed": "Nerulat", "OptionWednesday": "Miercuri", "ParentalRating": "Parental Rating", - "Saturday": "Sambata", + "Saturday": "Sâmbătă", "Save": "Salveaza", "SearchForCollectionInternetMetadata": "Căutare pe internet pentru postere și metadate", - "Sunday": "Duminica", + "Sunday": "Duminică", "TabAccess": "Acces", "TabAdvanced": "Avansat", "TabAlbumArtists": "Albume Artiști", @@ -217,11 +217,11 @@ "TellUsAboutYourself": "Spune-ne despre tine", "ThisWizardWillGuideYou": "Acest asistent vă va ghida prin procesul de configurare. Pentru a începe, vă rugăm să selectați limba preferată.", "Thursday": "Joi", - "Tuesday": "Marti", - "UserProfilesIntro": "Jellyfin include sprijin pentru profile de utilizator, permițând fiecărui utilizator să își facă propriile setări de afișare, playstate și control parental.", + "Tuesday": "Marți", + "UserProfilesIntro": "Jellyfin include suport pentru profile de utilizator cu setări de afișare granulare, starea redării și control parental.", "Wednesday": "Miercuri", "WelcomeToProject": "Bine ați venit la Jellyfin!", - "WizardCompleted": "Asta e tot ce avem nevoie pentru moment. Jellyfin a început colectarea de informații despre biblioteca media. Verifică unele din aplicațiile noastre, și apoi faceți clic pe Finalizare pentru a vizualiza Tabloul de bord al Serverului .", + "WizardCompleted": "Asta este tot ce avem nevoie pentru moment. Jellyfin a început colectarea de informații despre biblioteca media. Verifică unele din aplicațiile noastre, și apoi faceți clic pe Finalizare pentru a vizualiza Tabloul de bord.", "AllowOnTheFlySubtitleExtraction": "Permite extragerea subtitrărilor în timp real", "AllowMediaConversionHelp": "Permite sau interzice accesul la funcția de conversie media.", "AllowMediaConversion": "Permite coversia media", @@ -229,7 +229,7 @@ "AllLibraries": "Toate librăriile", "AllLanguages": "Toate limbile", "AllEpisodes": "Toate episoadele", - "AllComplexFormats": "Toate formatele complexe (ASS, SSA, VOBSUB, PGS, SUB/IDX, etc.)", + "AllComplexFormats": "Toate formatele complexe (ASS, SSA, VOBSUB, PGS, SUB, IDX)", "AllChannels": "Toate canalele", "Alerts": "Alerte", "Albums": "Albume", @@ -243,7 +243,7 @@ "AddToPlayQueue": "Adaugă la coada de redare", "AddItemToCollectionHelp": "Adaugă obiectele la colecții căutând-le și folosind meniul de click-dreapta sau apasare pentru a le adăuga la colecție.", "Add": "Adaugă", - "Actor": "Actor", + "Actor": "Artist", "AccessRestrictedTryAgainLater": "Accesul este restricționat. Te rugăm să încerci mai târziu.", "AllowedRemoteAddressesHelp": "Listă separată prin virgulă de adrese IP sau IP/netmask pentru rețelele care for permise din conexiuni externe. Dacă este lăsat gol, toate adresele externe vor fi permise.", "ButtonStop": "Stop", @@ -251,15 +251,15 @@ "Collections": "Colecții", "AllowRemoteAccess": "Permite conexiuni externe către serverul Jellyfin.", "AllowRemoteAccessHelp": "Dacă este nebifat, toate conexiunile externe vor fi blocate.", - "AlwaysPlaySubtitles": "Întotdeauna folosește subtitrări", - "AnyLanguage": "Orice limbă", + "AlwaysPlaySubtitles": "Întotdeauna arată", + "AnyLanguage": "Orice Limbă", "Anytime": "Oricând", "Art": "Artă", "AlwaysPlaySubtitlesHelp": "Subtitrările care se potrivesc cu preferințele limbii utilizate vor fi încărcate indiferent de limba audio.", "AroundTime": "Împrejur {0}", "AsManyAsPossible": "Cât mai mulți cu putință", "Ascending": "Ascendent", - "AspectRatio": "Aspect", + "AspectRatio": "Raportul aspectului", "AuthProviderHelp": "Selectează un Furnizor de Autentificare de folosit pentru autentificarea parolei acestui utilizator.", "Auto": "Auto", "AutoBasedOnLanguageSetting": "Auto (bazat pe setările limbii)", @@ -284,11 +284,11 @@ "Disc": "Placă", "CopyStreamURL": "Copiază Stream URL", "CriticRating": "Evaluare critici", - "Desktop": "Desktop", + "Desktop": "Birou", "Director": "Regizor", "AllowOnTheFlySubtitleExtractionHelp": "Subtitrările încorporate pot fi extrase din video și transmise către client în mod text pentru a preveni transcodarea videoului. Pe unele sisteme acest lucru poate dura mult timp și poate cauza oprirea redării video în timpul procesului de extragere. Dezactivează opțiunea pentru a avea subtitrările încorporate incluse în videoul transcodat atunci când nu sunt nativ suportate de către dispozitivul client.", "BirthLocation": "Locul nașterii", - "BurnSubtitlesHelp": "Determină dacă serverul ar trebui să includă subtitrări când face conversia video depinzând de formatul subtitrărilor. Evitând includerea subtitrărilor va îmbunătăți performanța serverului. Selectează Auto pentru includerea formaturilor bazate pe imagini (VOBSUB, PGS, SUB/IDX, etc) și anumitor subtitrări ASS/SSA.", + "BurnSubtitlesHelp": "Determină dacă serverul ar trebui să includă subtitrări când face transcodarea video. Evitând acest lucru va îmbunătăți performanța serverului. Selectează Auto pentru includerea formaturilor bazate pe imagini (VOBSUB, PGS, SUB, IDX) și anumitor subtitrări ASS sau SSA.", "ButtonPreviousTrack": "Calea anterioară", "ButtonRevoke": "Revocă", "ButtonSettings": "Setări", @@ -382,8 +382,7 @@ "ConfirmDeletion": "Confirmă ștergerea", "DeleteDeviceConfirmation": "Sigur doriți să ștergeți acest dispozitiv? Acesta va reapărea data viitoare când un utilizator se conectează cu acesta.", "DeleteUser": "Șterge utilizator", - "DirectorValue": "Regizor: {0}", - "DirectorsValue": "Regizori: {0}", + "Directors": "Regizori", "Disabled": "Dezactivat", "Disconnect": "Deconectare", "Dislike": "Neplăcut", @@ -412,7 +411,7 @@ "HDPrograms": "Programe HD", "HandledByProxy": "Gestionat de proxy invers", "HeaderApiKeys": "Chei API", - "HeaderApp": "App", + "HeaderApp": "Aplicație", "HeaderCastCrew": "Distribuție și echipă", "HeaderConfirmPluginInstallation": "Confirmați instalarea plugin-ului", "HeaderDeleteItems": "Ștergeți Elemente", @@ -429,7 +428,7 @@ "HeaderError": "Eroare", "HeaderExternalIds": "ID-uri Externe:", "HeaderFavoriteBooks": "Cărți Favorite", - "HeaderBranding": "Branding", + "HeaderBranding": "Marca", "HeaderApiKeysHelp": "Aplicațiile externe trebuie să aibă o cheie API pentru a comunica cu Jellyfin Server. Cheile sunt emise prin conectarea cu un cont Jellyfin sau prin acordarea manuală a unei chei aplicației.", "Sync": "Sincronizare", "ErrorAddingXmlTvFile": "A apărut o eroare la accesarea fișierului XMLTV. Vă rugăm să vă asigurați că fișierul există și încercați din nou.", @@ -511,8 +510,8 @@ "GroupVersions": "Grup versiuni", "GuestStar": "Vedeta invitata", "GuideProviderSelectListings": "Selectați Listări", - "H264EncodingPresetHelp": "Alegeți o valoare mai rapidă pentru a îmbunătăți performanța sau o valoare mai lentă pentru a îmbunătăți calitatea.", - "HardwareAccelerationWarning": "Activarea accelerării hardware poate provoca instabilitate în anumite medii. Asigurați-vă că sistemul de operare și driverele video sunt complet actualizate. Dacă întâmpinați dificultăți pentru a reda video după activarea acestei opțiuni, va trebui să schimbați setarea la Auto.", + "EncoderPresetHelp": "Alegeți o valoare mai rapidă pentru a îmbunătăți performanța sau o valoare mai lentă pentru a îmbunătăți calitatea.", + "HardwareAccelerationWarning": "Activarea accelerării hardware poate provoca instabilitate în anumite medii. Asigurați-vă că sistemul de operare și driverele video sunt complet actualizate. Dacă întâmpinați dificultăți pentru a reda video după activarea acestei opțiuni, va trebui să schimbați setarea la Nimic.", "HeaderAccessSchedule": "Program de Acces", "HeaderAccessScheduleHelp": "Creați un program de acces pentru a limita accesul la anumite ore.", "HeaderActiveDevices": "Dispozitive active", @@ -545,8 +544,7 @@ "EveryNDays": "La fiecare {0} zile", "Extras": "Extra", "Genres": "Genuri", - "GenreValue": "Gen: {0}", - "GenresValue": "Genuri: {0}", + "Genre": "Gen", "Guide": "Ghid", "HeaderCancelRecording": "Anulați înregistrarea", "HeaderCancelSeries": "Anulați seriile", @@ -590,7 +588,7 @@ "DisplayInOtherHomeScreenSections": "Afișați în secțiuni ecranul principal, cum ar fi cele mai noi suporturi și continuați să vizionați", "DisplayMissingEpisodesWithinSeasons": "Afișați episoade lipsă din sezoane", "DisplayMissingEpisodesWithinSeasonsHelp": "Acesta trebuie de asemenea activat pentru bibliotecile TV din configurația serverului.", - "DisplayModeHelp": "Selectați tipul de ecran pe care executați Jellyfin.", + "DisplayModeHelp": "Selectați stilul schemei pe care îl doriți pentru interfață.", "Download": "Descarcă", "DrmChannelsNotImported": "Canalele cu DRM nu vor fi importate.", "DropShadow": "Umbra", @@ -636,5 +634,876 @@ "HeaderSettings": "Setări", "HeaderShutdown": "Opriți Alimentarea", "HeaderSortBy": "Sortează după", - "HeaderSortOrder": "Ordinea de sortare" + "HeaderSortOrder": "Ordinea de sortare", + "LabelTranscodingThreadCount": "Numărul de threaduri ale transcodării:", + "LabelTranscodingProgress": "Progresul transcodării:", + "LabelTranscodingFramerate": "Rata de cadru a transcodării:", + "LabelTranscodes": "Transcodează:", + "LabelTranscodePath": "Cale transcodare:", + "LabelTranscodingContainer": "Container :", + "LabelTranscodingAudioCodec": "Codec audio:", + "LabelTrackNumber": "Număr melodie:", + "LabelTitle": "Titlu:", + "LabelTime": "Ora:", + "LabelTheme": "Tema:", + "LabelTextSize": "Mărimea textului:", + "LabelTextColor": "Culoarea textului:", + "LabelTextBackgroundColor": "Culoarea fundalului textului:", + "LabelTagline": "Sloganul:", + "LabelTag": "Etichetă:", + "LabelTVHomeScreen": "Ecran de pornire în modul TV:", + "LabelSupportedMediaTypes": "Tipuri media suportate:", + "LabelSubtitles": "Subtitrări", + "LabelSubtitlePlaybackMode": "Mod subtitrare:", + "LabelSubtitleFormatHelp": "Exemplu: srt", + "LabelSubtitleDownloaders": "Descărcare subtitrări:", + "LabelStopping": "Oprire", + "LabelStatus": "Stare:", + "LabelStartWhenPossible": "Demarează când este posibil:", + "LabelSportsCategories": "Categorii sportive:", + "LabelSpecialSeasonsDisplayName": "Denumirea afișării sezonului special:", + "LabelSource": "Sursă:", + "LabelSoundEffects": "Efecte audio:", + "LabelSortTitle": "Sortează titlu:", + "LabelSortOrder": "Ordinea de sortare:", + "LabelSortBy": "Sortează după:", + "LabelSonyAggregationFlagsHelp": "Determină conținutul elementului aggregationFlags din urn:schemas-sonycom:av spațiu de nume.", + "LabelSonyAggregationFlags": "Etichete de agregare Sony:", + "LabelSkipIfGraphicalSubsPresentHelp": "Păstrarea versiunilor în text a subtitrărilor va duce la o livrare mai eficientă și va scădea probabilitatea de transcodare video.", + "LabelSkipIfGraphicalSubsPresent": "Ignoră dacă videoul deja conține o subtitrare inclusă", + "LabelSkipIfAudioTrackPresentHelp": "Debifează acest lucru pentru a te asigura că toate videoclipurile au subtitrări, indiferent de limbajul audio.", + "LabelSkipIfAudioTrackPresent": "Ignoră dacă pista audio implicită se potrivește cu limba de descărcare", + "LabelSkipForwardLength": "Durata salt înainte:", + "LabelSkipBackLength": "Durata salt înapoi:", + "LabelSkin": "Tema:", + "LabelSize": "Mărime:", + "LabelSimultaneousConnectionLimit": "Limita streamului simultan:", + "LabelServerName": "Numele serverului:", + "LabelServerHostHelp": "192.168.1.100:8096 sau https://myserver.com", + "LabelServerHost": "Gazdă:", + "LabelSerialNumber": "Număr de serie", + "LabelSendNotificationToUsers": "Trimite notificarea către:", + "LabelSelectVersionToInstall": "Alegeți versiunea pentru instalare:", + "LabelSelectFolderGroupsHelp": "Dosarele care nu sunt bifate vor fi afișate de singure în propria vizualizare.", + "LabelSelectFolderGroups": "Grupați automat conținutul din următoarele foldere în vizualizări, cum ar fi Filme, Muzică și TV:", + "LabelSecureConnectionsMode": "Mod de conectare securizat:", + "LabelSeasonNumber": "Numărul sezonului:", + "LabelScreensaver": "Protector de ecran:", + "LabelScheduledTaskLastRan": "Ultima redare{0}, cu durata {1}.", + "LabelRuntimeMinutes": "Timp de redare (minute):", + "LabelRemoteClientBitrateLimitHelp": "O limită de biți per-stream opțională pentru toate dispozitivele din rețea. Acest lucru este util pentru a împiedica dispozitivele să solicite un bitrate mai mare decât poate gestiona conexiunea dvs. de internet. Acest lucru poate duce la creșterea încărcării procesorului pe serverul dvs. pentru a transcoda videoclipurile din zbor la un bitrate mai mic.", + "LabelRemoteClientBitrateLimit": "Limită de biți pentru streaming pe Internet (Mbps):", + "LabelReleaseDate": "Data lansării:", + "LabelRefreshMode": "Mod reîmprospătare:", + "LabelRecord": "Înregistrare:", + "LabelReasonForTranscoding": "Motiv pentru transcodare:", + "LabelReadHowYouCanContribute": "Aflați cum puteți contribui.", + "LabelPublicHttpsPortHelp": "Numărul de port public care ar trebui mapat în portul HTTPS local.", + "LabelPublicHttpsPort": "Portul HTTPS public:", + "LabelPublicHttpPortHelp": "Numărul de port public care ar trebui mapat în portul HTTP local.", + "LabelPublicHttpPort": "Portul HTTP public:", + "LabelProtocolInfoHelp": "Valoarea care va fi utilizată la răspunsul la solicitările GetProtocolInfo de pe dispozitiv.", + "LabelProtocolInfo": "Informații protocol:", + "LabelProtocol": "Protocol:", + "LabelProfileVideoCodecs": "Codecuri video:", + "LabelProfileContainersHelp": "Separat prin virgulă. Poate fi lăsat gol pentru a se aplica tuturor containerelor.", + "LabelProfileContainer": "Container :", + "LabelProfileCodecsHelp": "Separat prin virgulă. Poate fi lăsat gol pentru a se aplica tuturor codecurilor.", + "LabelProfileCodecs": "Codecuri:", + "LabelProfileAudioCodecs": "Codecuri audio:", + "LabelPreferredSubtitleLanguage": "Limba subtitrare preferată:", + "LabelPreferredDisplayLanguageHelp": "Traducerea Jellyfin este un proiect în derulare.", + "LabelPreferredDisplayLanguage": "Limba de afișare preferată:", + "LabelPostProcessorArgumentsHelp": "Utilizați {path} ca și cale către fișierul de înregistrare.", + "LabelPostProcessorArguments": "Argumentele liniei de comandă post-procesare:", + "LabelPostProcessor": "Aplicație post-procesare:", + "LabelPleaseRestart": "Modificările vor avea efect după încărcarea manuală a clientului web.", + "LabelPlayMethod": "Metoda de redare:", + "LabelPlaylist": "Listă de redare:", + "LabelPlayer": "Soft redare:", + "LabelPlayDefaultAudioTrack": "Redați calea audio implicită indiferent de limbă", + "LabelPlaceOfBirth": "Locul nașterii:", + "LabelPersonRoleHelp": "Exemplu: Șofer mașină de înghețată", + "LabelPersonRole": "Rol:", + "LabelPath": "Cale:", + "LabelPasswordRecoveryPinCode": "Cod PIN:", + "LabelPasswordResetProvider": "Furnizor de resetare a parolei:", + "LabelPasswordConfirm": "Parolă (confirmare):", + "LabelParentalRating": "Evaluarea parentală:", + "LabelParentNumber": "Numărul părintelui:", + "LabelOverview": "Prezentare generală:", + "LabelOriginalTitle": "Titlu original:", + "LabelOriginalAspectRatio": "Raport aspect original:", + "LabelOptionalNetworkPathHelp": "Dacă acest folder este partajat în rețeaua dvs., furnizarea căii de partajare a rețelei poate permite aplicațiilor Jellyfin de pe alte dispozitive să acceseze fișiere media direct.", + "LabelOptionalNetworkPath": "(Optional) Dosar partajat în rețea:", + "LabelNumber": "Număr:", + "LabelNotificationEnabled": "Activează această notificare", + "LabelNewsCategories": "Categoriile știrilor:", + "LabelNewName": "Nume nou:", + "LabelMusicStreamingTranscodingBitrateHelp": "Specificați un bitrate maxim atunci când transmiteți muzică.", + "LabelMusicStreamingTranscodingBitrate": "Bitrate pentru transcodarea audio:", + "LabelMoviePrefixHelp": "Dacă un prefix este aplicat titlurilor de filme, introduceți-l aici, astfel încât serverul să se poată gestiona corect.", + "LabelMoviePrefix": "Prefixul filmului:", + "LabelMovieCategories": "Categoriile filmului:", + "LabelMonitorUsers": "Monitorizați activitatea de la:", + "LabelModelUrl": "URL-ul modelului", + "LabelModelNumber": "Numărul modelului", + "LabelModelName": "Numele modelului", + "LabelModelDescription": "Descrierea modelului", + "LabelMinScreenshotDownloadWidth": "Lățimea minimă a descărcării capturii de ecran:", + "LabelMinResumePercentageHelp": "Titlurile se presupun neredate dacă sunt oprite înainte de această durată.", + "LabelMinResumePercentage": "Procentajul minim al reluării:", + "LabelMinResumeDurationHelp": "Cea mai scurtă lungime video în secunde, care va salva locația de redare și vă va permite să reluați.", + "LabelMinResumeDuration": "Durata minimă a reluării:", + "LabelMethod": "Metoda:", + "LabelMetadataSaversHelp": "Alegeți formatele de fișiere pentru a vă salva metadatele.", + "LabelMetadataSavers": "Salvări de metadate:", + "LabelMetadataReadersHelp": "Clasificați sursele preferate de metadate locale în ordinea priorității. Primul fișier găsit va fi citit.", + "LabelMetadataReaders": "Cititori de metadate:", + "LabelMetadataDownloadersHelp": "Activați și clasificați colectorii de metadate preferați în ordinea priorității. Colectorii cu prioritate inferioară vor fi folosiți numai pentru a completa informațiile care lipsesc.", + "LabelMetadata": "Metadate:", + "LabelMessageTitle": "Titlul mesajului:", + "LabelMessageText": "Textul mesajului:", + "LabelMaxStreamingBitrateHelp": "Specificați un bitrate maxim atunci când faceți streaming.", + "LabelMaxStreamingBitrate": "Calitate maximă pentru streaming:", + "LabelMaxResumePercentageHelp": "Titlurile sunt considerate complet redate dacă sunt oprite după acest timp.", + "LabelMaxResumePercentage": "Procentul maxim de reluare:", + "LabelMaxChromecastBitrate": "Calitatea streamului Chromecast:", + "LabelMatchType": "Tip de potrivire:", + "LabelManufacturerUrl": "URL Producător", + "LabelManufacturer": "Producător:", + "LabelLogs": "Loguri:", + "LabelLoginDisclaimerHelp": "Un mesaj care va fi afișat în partea de jos a paginii de conectare.", + "LabelLoginDisclaimer": "Act de renunțare la autentificare:", + "LabelLockItemToPreventChanges": "Blocați acest element pentru a preveni modificările viitoare", + "LabelLocalHttpServerPortNumberHelp": "Portul TCP pe care serverul HTTP Jellyfin ar trebui să îl utilizeze.", + "LabelLocalHttpServerPortNumber": "Portul local HTTP:", + "LabelLineup": "Echipa:", + "LabelLanNetworks": "Rețele LAN:", + "LabelKodiMetadataUserHelp": "Salvați datele de vizionare în fișierele NFO pentru alte aplicații de utilizat.", + "LabelKodiMetadataUser": "Salvați datele de vizionare ale utilizatorului în fișierele NFO pentru:", + "LabelKodiMetadataSaveImagePathsHelp": "Acest lucru este recomandat dacă aveți nume de fișiere imagine care nu sunt conforme cu ghidurile Kodi.", + "LabelKodiMetadataSaveImagePaths": "Salvați căile de imagine în fișierele nfo", + "LabelKodiMetadataEnablePathSubstitutionHelp": "Permite substituirea căilor pentru căile de imagine utilizând setările de substituire ale căilor serverului.", + "LabelKodiMetadataEnablePathSubstitution": "Activați substituirea căilor", + "LabelKodiMetadataEnableExtraThumbsHelp": "Atunci când descărcați imagini, acestea pot fi salvate atât în extrafanart cât și în extrathumbs pentru o compatibilitate maximă cu tema Kodi.", + "LabelKodiMetadataEnableExtraThumbs": "Copiați extrafanart în câmpul extrathumbs", + "LabelKodiMetadataDateFormatHelp": "Toate datele din fișierele NFO vor fi analizate folosind acest format.", + "LabelKodiMetadataDateFormat": "Formatul datei de lansare:", + "LabelKidsCategories": "Categorii pentru copii:", + "LabelKeepUpTo": "Păstrați până la:", + "LabelInternetQuality": "Calitatea internetului:", + "LabelInNetworkSignInWithEasyPasswordHelp": "Utilizați codul Easy PIN pentru a vă conecta la clienții din rețeaua dvs. locală. Parola dvs. obișnuită va fi necesară numai acasă. Dacă codul Easy PIN este lăsat gol, nu veți avea nevoie de o parolă în rețeaua de domiciliu.", + "LabelInNetworkSignInWithEasyPassword": "Activați conectarea în rețea cu codul Easy PIN", + "LabelImportOnlyFavoriteChannels": "Limitați la canalele marcate drept preferate", + "LabelImageType": "Tipul imaginii:", + "LabelImageFetchersHelp": "Activați și clasificați colectorul de imagini preferat în ordinea priorității.", + "LabelIdentificationFieldHelp": "Un substring cu majuscule, minuscule sau expresie regex.", + "LabelIconMaxWidthHelp": "Rezoluția maximă a pictogramelor expuse via upnp:icon.", + "LabelIconMaxWidth": "Lățimea maximă a pictogramei:", + "LabelIconMaxHeightHelp": "Rezoluția maximă a pictogramelor expuse via upnp:icon.", + "LabelIconMaxHeight": "Înălțimea maximă a pictogramei:", + "LabelHttpsPortHelp": "Portul TCP pe care serverul HTTPS Jellyfin ar trebui sa îl utilizeze.", + "LabelHttpsPort": "Portul local HTTPS:", + "LabelHomeScreenSectionValue": "Secțiunea ecranului de pornire {0}:", + "LabelHomeNetworkQuality": "Calitatea pe rețeaua de domiciliu:", + "LabelHardwareAccelerationTypeHelp": "Accelerarea hardware necesită configurare suplimentară.", + "LabelHardwareAccelerationType": "Accelerare hardware:", + "LabelEncoderPreset": "H264 encoding presetat:", + "LabelH264Crf": "CRF codare H264:", + "LabelGroupMoviesIntoCollectionsHelp": "La afișarea listelor de filme, filmele aparținând unei colecții vor fi afișate ca un articol grupat.", + "LabelGroupMoviesIntoCollections": "Grupează filmele în colecții", + "LabelServerNameHelp": "Acest nume va fi utilizat pentru a identifica serverul și va fi implicit la numele computerului serverului.", + "LabelFriendlyName": "Nume prietenos:", + "LabelFormat": "Format:", + "LabelForgotPasswordUsernameHelp": "Introduceți numele dvs. de utilizator, dacă vă amintiți.", + "LabelFont": "Font:", + "LabelFolder": "Dosar:", + "LabelFileOrUrl": "Fișier sau URL:", + "LabelFailed": "Eșuat", + "LabelExtractChaptersDuringLibraryScanHelp": "Generați imagini de capitol atunci când videoclipurile sunt importate în timpul scanării bibliotecii. În caz contrar, acestea vor fi extrase în timpul sarcinii programate de extragere a imaginilor capitolului, permițând scanarea bibliotecă obișnuită să se completeze mai rapid.", + "LabelExtractChaptersDuringLibraryScan": "Extrageți imagini de capitol în timpul scanării bibliotecii", + "LabelBaseUrlHelp": "Puteți adăuga aici un subdirector personalizat pentru a accesa serverul de pe o adresă URL mai unică.", + "LabelBaseUrl": "Adresa URL de bază:", + "LabelEveryXMinutes": "La fiecare:", + "LabelEvent": "Eveniment:", + "LabelEpisodeNumber": "Numărul episodului:", + "LabelEndDate": "Data de încheiere:", + "LabelEnableSingleImageInDidlLimitHelp": "Unele dispozitive nu vor reda corect dacă mai multe imagini sunt încorporate în Didl.", + "LabelEnableSingleImageInDidlLimit": "Limitați la o singură imagine încorporată", + "LabelEnableRealtimeMonitorHelp": "Modificările la fișiere vor fi procesate imediat, pe sistemele de fișiere acceptate.", + "LabelEnableRealtimeMonitor": "Activați monitorizarea în timp real", + "LabelEnableHardwareDecodingFor": "Activați decodarea hardware pentru:", + "LabelEnableDlnaServerHelp": "Permite dispozitivelor UPnP din rețeaua dvs. să răsfoiască și să redea conținut.", + "LabelEnableDlnaServer": "Activați serverul DLNA", + "LabelEnableDlnaPlayToHelp": "Detectează dispozitivele din rețeaua dvs. și oferă posibilitatea de a le controla de la distanță.", + "LabelEnableDlnaPlayTo": "Activează DLNA Play To", + "LabelEnableDlnaDebugLoggingHelp": "Creați fișiere de jurnal mari și trebuie utilizate numai în funcție de necesități pentru rezolvarea problemelor.", + "LabelEnableDlnaDebugLogging": "Activați jurnalul de depanare DLNA", + "LabelEnableDlnaClientDiscoveryIntervalHelp": "Determină durata în secunde între căutările SSDP efectuate de Jellyfin.", + "LabelEnableDlnaClientDiscoveryInterval": "Interval de descoperire a clientului (secunde)", + "LabelEnableBlastAliveMessagesHelp": "Activați acest lucru dacă serverul nu este detectat în mod fiabil de alte dispozitive UPnP din rețeaua dvs.", + "LabelEnableBlastAliveMessages": "Trimitere mesaje de disponibilitate", + "LabelEnableAutomaticPortMapHelp": "Încercați să mapați automat portul public către portul local prin UPnP. Este posibil să nu funcționeze cu unele modele de router. Modificările nu se vor aplica decât după repornirea serverului.", + "LabelEnableAutomaticPortMap": "Activați maparea automată a porturilor", + "LabelEmbedAlbumArtDidlHelp": "Unele dispozitive preferă această metodă pentru obținerea artei albumelor. Alții pot să nu redea cu această opțiune activată.", + "LabelEmbedAlbumArtDidl": "Încorporați arta albumului în Didl", + "LabelEasyPinCode": "Codul Easy PIN:", + "LabelDynamicExternalId": "{0} Id:", + "LabelDropShadow": "Umbra:", + "LabelDropImageHere": "Adaugă imaginea aici, sau clic pentru a căuta.", + "LabelDownloadLanguages": "Descarcă limbile:", + "LabelDownMixAudioScaleHelp": "Amplificarea audio când se mixează descendent. Lipsa unei valori va utiliza volumul original.", + "LabelDownMixAudioScale": "Amplificarea audio când se mixează descendent:", + "LabelDisplaySpecialsWithinSeasons": "Afișați episoadele speciale în sezoanele în care au fost difuzate", + "LabelDisplayOrder": "Ordinea afișării:", + "LabelDisplayName": "Numele afisat:", + "LabelDisplayMode": "Modul de afișare:", + "LabelDisplayLanguageHelp": "Traducerea Jellyfin este un proiect în derulare.", + "LabelDisplayLanguage": "Limba afișată:", + "LabelDiscNumber": "Numărul discului:", + "LabelDidlMode": "Modul DIDL:", + "LabelDeviceDescription": "Descrierea dispozitivului", + "LabelDefaultUserHelp": "Stabilește ce bibliotecă de utilizator ar trebui să fie afișată pe dispozitivele conectate. Aceasta poate fi rescrisă pentru fiecare dispozitiv folosind profiluri.", + "LabelDefaultUser": "Utilizator implicit:", + "LabelDefaultScreen": "Ecran implicit:", + "LabelDeathDate": "Data decedării:", + "LabelDay": "Ziua:", + "LabelDateTimeLocale": "Ora locală a datei:", + "LabelDateAddedBehaviorHelp": "Dacă există o valoare de metadate, aceasta va fi întotdeauna folosită înainte de oricare dintre aceste opțiuni.", + "LabelDateAddedBehavior": "Comportamentul datei adăugării pentru conținut nou:", + "LabelDateAdded": "Data adăugării:", + "LabelDashboardTheme": "Tema tabloul de bord al serverului:", + "LabelCustomRating": "Evaluare personalizată:", + "LabelCustomDeviceDisplayNameHelp": "Furnizați un nume de afișare personalizat sau lăsați gol pentru a utiliza numele raportat de dispozitiv.", + "LabelCustomDeviceDisplayName": "Numele afisat:", + "LabelCustomCssHelp": "Aplicați propriul stil personalizat pe interfața web.", + "LabelCustomCss": "CSS personalizat:", + "LabelCriticRating": "Evaluare critic:", + "LabelCommunityRating": "Evaluare comunitate:", + "LabelCollection": "Colecție:", + "LabelChannels": "Canale:", + "LabelCertificatePasswordHelp": "Dacă certificatul dvs. necesită o parolă, vă rugăm să o introduceți aici.", + "LabelCertificatePassword": "Parola certificatului:", + "LabelCancelled": "Anulat", + "LabelCache": "Depozit:", + "LabelBurnSubtitles": "Imprimă subtitrările:", + "LabelBlockContentWithTags": "Blochează articolele cu etichetele:", + "LabelBlastMessageIntervalHelp": "Determină durata în secunde între transmiterea mesajele de viață.", + "LabelBlastMessageInterval": "Interval transmitere mesaj viu (secunde)", + "LabelBitrate": "Rată de biți:", + "LabelBirthYear": "Anul nașterii:", + "LabelBirthDate": "Data nașterii:", + "LabelBindToLocalNetworkAddressHelp": "Opțional. Rescrie adresa IP locală pentru a o utiliza serverul http. Dacă este lăsat gol, serverul se va lega la toate adresele disponibile. Modificarea acestei valori necesită repornirea Jellyfin Server.", + "LabelBindToLocalNetworkAddress": "Utilizează adresa de rețea locală:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Actualizați automat metadatele de pe internet:", + "LabelAuthProvider": "Furnizor de autentificare:", + "LabelAudioSampleRate": "Rata eșantionului audio:", + "LabelAudioCodec": "Codec audio:", + "LabelAudioChannels": "Canale audio:", + "LabelAudioBitrate": "Rata de biți audio:", + "LabelAudioBitDepth": "Adâncimea bitului audio:", + "LabelAudio": "Audio", + "LabelAppNameExample": "Exemplu: Sickbeard, Sonarr", + "LabelAppName": "Nume app", + "LabelAllowedRemoteAddressesMode": "Modul de filtrare a adresei IP de la distanță:", + "LabelAllowedRemoteAddresses": "Filtrul de adrese IP de la distanță:", + "LabelAllowHWTranscoding": "Permite transcodare hardware", + "LabelAll": "Tot", + "LabelAlbumArtists": "Artiști album:", + "LabelAlbumArtPN": "Artă album PN:", + "LabelAlbumArtMaxWidthHelp": "Rezoluție maximă a artei albumului expusă via upnp:albumArtURI.", + "LabelAlbumArtMaxWidth": "Artă album lățime maximă:", + "LabelAlbumArtMaxHeightHelp": "Rezoluție maximă a artei albumului expusă via upnp:albumArtURI.", + "LabelAlbumArtMaxHeight": "Artă album înălțime maximă:", + "LabelAlbumArtHelp": "PN utilizat pentru art albumelor, în atributul dlna:profileID pe upnp:albumArtURI. Unele dispozitive necesită o valoare specifică, indiferent de dimensiunea imaginii.", + "LabelAlbum": "Album:", + "LabelAirsBeforeSeason": "Emis după sezonul:", + "LabelAirsBeforeEpisode": "Emis înaintea episodului:", + "LabelAirsAfterSeason": "Emis după sezonul:", + "LabelAirTime": "Ora de emisie:", + "LabelAirDays": "Zile de emisie:", + "LabelAccessStart": "Ora demarării:", + "LabelAccessEnd": "Ora terminării:", + "LabelAccessDay": "Ziua săptămânii:", + "LabelAbortedByServerShutdown": "(Anulat prin închiderea serverului)", + "Label3DFormat": "Format 3D:", + "Kids": "Copii", + "Items": "Articole", + "ItemCount": "{0} articole", + "InstantMix": "Mix instant", + "InstallingPackage": "Instalare {0} (versiune {1})", + "ImportFavoriteChannelsHelp": "Dacă este activat, vor fi importate numai canalele marcate ca preferate pe dispozitivul tuner.", + "Images": "Imagini", + "Identify": "Identifică", + "HttpsRequiresCert": "Pentru a activa conexiunile securizate, va trebui să furnizați un certificat SSL de încredere, cum ar fi Let's Encrypt. Vă rugăm să furnizați un certificat sau să dezactivați conexiunile securizate.", + "Horizontal": "Orizontal", + "Home": "Acasă", + "HideWatchedContentFromLatestMedia": "Ascunde conținutul vizionat din cele mai recente media", + "Hide": "Ascunde", + "HeadersFolders": "Dosare", + "HeaderYears": "Ani", + "HeaderXmlSettings": "XML setări", + "HeaderXmlDocumentAttributes": "XML Document Atribute", + "HeaderXmlDocumentAttribute": "XML Document Atribut", + "HeaderVideos": "Videoclipuri", + "HeaderVideoTypes": "Tipuri video", + "HeaderVideoType": "Tipul video", + "HeaderVideoQuality": "Calitatea Video", + "HeaderUser": "Utilizator", + "HeaderUploadImage": "Încarcă imagine", + "HeaderUpcomingOnTV": "În curând la TV", + "HeaderTypeText": "Introduceți text", + "HeaderTypeImageFetchers": "{0} Aportor de imagine", + "HeaderTuners": "Tunere", + "HeaderTunerDevices": "Dispozitive tuner", + "HeaderTranscodingProfileHelp": "Adăugați profiluri de transcodare pentru a indica ce formate trebuiesc utilizate atunci când este necesară transcodarea.", + "HeaderTranscodingProfile": "Profilul transcodării", + "HeaderTracks": "Piese", + "HeaderThisUserIsCurrentlyDisabled": "Acest utilizator este momentan dezactivat", + "HeaderTags": "Etichete", + "HeaderSystemDlnaProfiles": "Profile de sistem", + "HeaderSubtitleProfilesHelp": "Profilele subtitrării descriu formatul subtitrării compatibil cu dispozitivul.", + "HeaderSubtitleProfiles": "Profilele subtitrării", + "HeaderSubtitleProfile": "Profilul subtitrării", + "HeaderSubtitleDownloads": "Descărcări subtitrare", + "HeaderSubtitleAppearance": "Aspectul Subtitrării", + "HeaderStopRecording": "Oprește Inregistrarea", + "HeaderStatus": "Stare", + "HeaderStartNow": "Pornește Acum", + "HeaderSpecialFeatures": "Caracteristici Speciale", + "HeaderSpecialEpisodeInfo": "Informații Episod Special", + "ButtonSplit": "Împarte", + "OptionCustomUsers": "Personalizat", + "OptionCaptionInfoExSamsung": "Informații pentru legendă ex: (Samsung)", + "OptionBluray": "BluRay", + "OptionBlockTvShows": "Seriale TV", + "OptionBlockTrailers": "Trailere", + "OptionBlockMusic": "Muzică", + "OptionBlockMovies": "Filme", + "OptionBlockLiveTvChannels": "Canale Live TV", + "OptionBlockChannelContent": "Conținut canal Internet", + "OptionBlockBooks": "Cărți", + "OptionBanner": "Steag", + "OptionAutomaticallyGroupSeriesHelp": "Dacă este activat, seriile distribuite pe mai multe foldere din această bibliotecă vor fi comasate automat într-o singură serie.", + "OptionAutomaticallyGroupSeries": "Fuzionează automat seriile care sunt răspândite pe mai multe foldere", + "OptionAuto": "Auto", + "OptionArtist": "Artist", + "OptionAllowVideoPlaybackTranscoding": "Permiteți redarea video care necesită transcodare", + "OptionAllowVideoPlaybackRemuxing": "Permiteți redarea video care necesită conversie fără re-codificare", + "OptionAllowSyncTranscoding": "Permiteți descărcarea și sincronizarea media care necesită transcodare", + "OptionAllowMediaPlaybackTranscodingHelp": "Restrângerea accesului la transcodare poate provoca defecțiuni de redare în aplicațiile Jellyfin din cauza formatelor media neacceptate.", + "OptionAllowContentDownloading": "Permiteți descărcarea și sincronizarea media", + "OptionAllowAudioPlaybackTranscoding": "Permiteți redarea audio care necesită transcodare", + "OptionAllUsers": "Toți utilizatorii", + "OptionAlbumArtist": "Artistul albumului", + "OptionAlbum": "Album", + "OptionAdminUsers": "Administratorii", + "Option3D": "3D", + "OnlyImageFormats": "Numai formate de imagine (VOBSUB, PGS, SUB)", + "OnlyForcedSubtitlesHelp": "Se vor încărca doar subtitrările marcate drept forțate.", + "OnlyForcedSubtitles": "Numai forțate", + "OneChannel": "Un canal", + "Off": "Oprit", + "NumLocationsValue": "{0} dosare", + "Normal": "Normal", + "None": "Nici unul", + "NoSubtitlesHelp": "Subtitrările nu vor fi încărcate în mod implicit. Acestea pot fi însă activate manual în timpul redării.", + "NoSubtitles": "Fără", + "NoSubtitleSearchResultsFound": "Nici un rezultat găsit.", + "NoPluginConfigurationMessage": "Acest plugin nu are setări de configurat.", + "NoNewDevicesFound": "Nu s-au găsit dispozitive noi. Pentru a adăuga un nou tuner, închideți acest dialog și introduceți informațiile dispozitivului manual.", + "No": "Nu", + "NextUp": "Urmează", + "Next": "Următorul", + "News": "Știri", + "NewEpisodesOnly": "Doar episoade noi", + "NewEpisodes": "Episoade noi", + "NewCollectionHelp": "Colecțiile vă permit să creați grupări personalizate de filme și alte tipuri de conținut.", + "NewCollection": "Colecție nouă", + "Never": "Niciodată", + "Name": "Nume", + "MySubtitles": "Subtitrările mele", + "Mute": "Mut", + "MusicVideo": "Videoclip muzical", + "MusicLibraryHelp": "Consultați {0} ghidul de denumire a muzicii {1}.", + "MusicArtist": "Artist muzical", + "MusicAlbum": "Album muzical", + "MovieLibraryHelp": "Examinați {0} ghidul de denumire al filmelor {1}.", + "MoveRight": "Mută la dreapta", + "MoveLeft": "Mută la stânga", + "MoreMediaInfo": "Informații media", + "MoreFromValue": "Mai multe din {0}", + "Mobile": "Mobil", + "MetadataSettingChangeHelp": "Modificarea setărilor de metadate va afecta conținutul nou adăugat de acum înainte. Pentru a reîmprospăta conținutul existent, deschideți ecranul de detalii și faceți clic pe butonul de actualizare sau efectuați actualizări în vrac folosind managerul de metadate.", + "MetadataManager": "Manager metadata", + "Metadata": "Metadată", + "MessageYouHaveVersionInstalled": "În prezent, aveți versiunea {0} instalată.", + "MessageUnsetContentHelp": "Conținutul va fi afișat ca foldere simple. Pentru cele mai bune rezultate, utilizați managerul de metadate pentru a seta tipurile de conținut ale sub-foldererelor.", + "MessageUnableToConnectToServer": "Nu putem să ne conectăm la serverul selectat în acest moment. Vă rugăm să vă asigurați că funcționează și încercați din nou.", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Următoarele locații media vor fi eliminate din biblioteca dvs.:", + "MessageSettingsSaved": "Setări salvate.", + "MessageReenableUser": "Consultați mai jos pentru a reactiva", + "MessagePluginInstallDisclaimer": "Pluginurile create de membrii comunității Jellyfin sunt o modalitate excelentă de a vă îmbunătăți experiența Jellyfin cu funcții și beneficii suplimentare. Înainte de instalare, vă rugăm să fiți conștienți de efectele pe care le pot avea asupra serverului dvs. Jellyfin, cum ar fi scanările de bibliotecă mai lungi, procesarea suplimentară a fundalului și scăderea stabilității sistemului.", + "MessagePluginConfigurationRequiresLocalAccess": "Pentru a configura acest plugin, vă rugăm să vă conectați direct la serverul dvs. local.", + "MessagePleaseWait": "Te rog așteaptă. Poate dura un minut.", + "MessagePlayAccessRestricted": "Redarea acestui conținut este în prezent restricționată. Vă rugăm să contactați administratorul serverului pentru mai multe informații.", + "MessagePasswordResetForUsers": "Următorii utilizatori au resetat parolele. Acum se pot conecta cu codurile pin care au fost utilizate pentru a efectua resetarea.", + "MessageNoTrailersFound": "Nu s-au găsit trailere. Instalați canalul Trailer pentru a îmbunătăți experiența dvs. de film adăugând o bibliotecă de trailere din internet.", + "MessageNoServersAvailable": "Nu au fost găsite servere folosind descoperirea automată de servere.", + "MessageNoPluginsInstalled": "Nu aveți plugin-uri instalate.", + "MessageNoMovieSuggestionsAvailable": "În prezent, nu există sugestii de film. Începeți să vizionați și să evaluați filmele, apoi reveniți pentru a vedea recomandările dvs.", + "MessageNoCollectionsAvailable": "Colecțiile vă permit să vă bucurați de grupări personalizate de filme, serii și albume. Faceți clic pe butonul + pentru a începe să creați colecții.", + "MessageNoAvailablePlugins": "Nu există plugin-uri disponibile.", + "MessageLeaveEmptyToInherit": "Lăsați gol pentru a moșteni setările de la un element părinte sau valoarea implicită globală.", + "MessageItemsAdded": "Articole adăugate.", + "MessageItemSaved": "Articol salvat.", + "MessageInvalidUser": "Nume de utilizator sau parola incorecte. Vă rugăm să încercați din nou.", + "MessageInvalidForgotPasswordPin": "A fost introdus un cod PIN nevalid sau expirat. Vă rugăm să încercați din nou.", + "MessageInstallPluginFromApp": "Acest plugin trebuie instalat din aplicația în care intenționați să îl utilizați.", + "MessageImageTypeNotSelected": "Vă rugăm să selectați un tip de imagine din meniul derulant.", + "MessageImageFileTypeAllowed": "Sunt acceptate numai fișierele JPEG și PNG.", + "MessageForgotPasswordInNetworkRequired": "Încercați din nou în rețeaua de domiciliu pentru a iniția procesul de resetare a parolei.", + "MessageForgotPasswordFileCreated": "Următorul fișier a fost creat pe serverul dvs. și conține instrucțiuni despre cum să procedați:", + "MessageFileReadError": "S-a întâmpinat o eroare în timpul citirii fișierului. Vă rugăm să încercați din nou.", + "MessageDownloadQueued": "Descărcare adăugata în coadă.", + "MessageDirectoryPickerLinuxInstruction": "Pentru Linux pe Arch Linux, CentOS, Debian, Fedora, openSUSE sau Ubuntu, trebuie să acordați utilizatorului serverului Jellyfin cel puțin permisiunea de citire la locațiile de stocare.", + "MessageDirectoryPickerInstruction": "Căile de rețea pot fi introduse manual în cazul în care butonul Network nu reușește să localizeze dispozitivele. De exemplu, {0} sau {1}.", + "MessageDirectoryPickerBSDInstruction": "Pentru BSD, poate fi necesar să configurați stocarea în FreeNAS jail pentru a permite serverului Jellyfin să o acceseze.", + "MessageDeleteTaskTrigger": "Sigur doriți să ștergeți acest declanșator de activitate?", + "MessageCreateAccountAt": "Crează un cont la {0}", + "MessageContactAdminToResetPassword": "Vă rugăm să contactați administratorul de sistem pentru a vă reseta parola.", + "MessageConfirmShutdown": "Sigur doriți să opriți serverul?", + "MessageConfirmRevokeApiKey": "Sigur doriți să revocați această cheie API? Conexiunea aplicației la Jellyfin Server va fi terminată brusc.", + "MessageConfirmRestart": "Sigur doriți să redemarați serverul Jellyfin?", + "MessageConfirmRemoveMediaLocation": "Sigur doriți să eliminați această locație?", + "MessageConfirmRecordingCancellation": "Anulați înregistrarea?", + "MessageConfirmProfileDeletion": "Sigur doriți să ștergeți acest profil?", + "MessageConfirmDeleteTunerDevice": "Sigur doriți să ștergeți acest dispozitiv?", + "MessageConfirmDeleteGuideProvider": "Sigur doriți să eliminați acest furnizor de ghid?", + "MessageAreYouSureYouWishToRemoveMediaFolder": "Sigur doriți să eliminați acest dosar media?", + "MessageAreYouSureDeleteSubtitles": "Sigur doriți să ștergeți acest fișier de subtitrare?", + "MessageAlreadyInstalled": "Această versiune este deja instalată.", + "Menu": "Meniu", + "MediaIsBeingConverted": "Fișierul media este transformat într-un format compatibil cu dispozitivul folosit pentru redare.", + "MediaInfoStreamTypeVideo": "Video", + "MediaInfoStreamTypeSubtitle": "Subtitrare", + "MediaInfoStreamTypeEmbeddedImage": "Imaginea încorporată", + "MediaInfoStreamTypeData": "Date", + "MediaInfoStreamTypeAudio": "Audio", + "MediaInfoSoftware": "Software", + "MediaInfoTimestamp": "Data și ora", + "MediaInfoSize": "Mărime", + "MediaInfoSampleRate": "Rata monstrei", + "MediaInfoResolution": "Rezoluție", + "MediaInfoRefFrames": "Frame-uri referință", + "MediaInfoProfile": "Profil", + "MediaInfoPixelFormat": "Format pixel", + "MediaInfoPath": "Cale", + "MediaInfoLevel": "Nivel", + "MediaInfoLayout": "Amplasare", + "MediaInfoLanguage": "Limba", + "MediaInfoInterlaced": "Întrețesut", + "MediaInfoFramerate": "Rata frame-urilor", + "MediaInfoForced": "Forțat", + "MediaInfoExternal": "Extern", + "MediaInfoDefault": "Implicit", + "MediaInfoContainer": "Recipient", + "MediaInfoCodecTag": "Etichetă codec", + "MediaInfoCodec": "Codec", + "MediaInfoChannels": "Canale", + "MediaInfoBitrate": "Rata de biți", + "MediaInfoBitDepth": "Număr de biți", + "MediaInfoAspectRatio": "Raportul aspectului", + "MediaInfoAnamorphic": "Anamorfic", + "MarkUnplayed": "Marchează ca nevizionat", + "MarkPlayed": "Marchează ca vizionat", + "MapChannels": "Mapează canalele", + "ManageRecording": "Gestionează înregistrarea", + "ManageLibrary": "Gestionează biblioteca", + "Logo": "Siglă", + "LiveTV": "TV în Direct", + "LiveBroadcasts": "Emisie în direct", + "Live": "În direct", + "List": "Listă", + "LinksValue": "Linkuri: {0}", + "Like": "Îmi place", + "LeaveBlankToNotSetAPassword": "Puteți lăsa acest câmp necompletat pentru a nu seta o parolă.", + "LearnHowYouCanContribute": "Aflați cum puteți contribui.", + "LaunchWebAppOnStartupHelp": "Deschideți clientul web în browserul dvs. implicit la pornirea inițială a serverului. Acest lucru nu se va produce atunci când se utilizează funcția serverului de repornire.", + "LaunchWebAppOnStartup": "Lansați interfața web la pornirea serverului", + "LatestFromLibrary": "Ultimele {0}", + "Large": "Mare", + "LanNetworksHelp": "Lista separată de virgule a adreselor IP sau a intrărilor de tip IP/mască de rețea pentru rețelele care vor fi luate în considerare în rețeaua locală atunci când se aplică restricțiile de lățime de bandă. Dacă este setat, toate celelalte adrese IP vor fi considerate a fi în rețeaua externă și vor fi supuse restricțiilor de lățime de bandă externe. Dacă este lăsat necompletat, numai subnetul serverului este considerat a fi în rețeaua locală.", + "LabelffmpegPathHelp": "Calea către executabilul ffmpeg, sau dosarul care conține ffmpeg.", + "LabelffmpegPath": "Calea către FFmpeg:", + "LabelZipCode": "Cod poștal:", + "LabelYear": "Anul:", + "LabelXDlnaDocHelp": "Determină conținutul elementului X_DLNADOC din domeniul urn:schemas-dlna-org:device-1-0.", + "LabelXDlnaDoc": "Documentație X-DLNA:", + "LabelXDlnaCapHelp": "Determină conținutul elementului X_DLNACAP din domeniul urn:schemas-dlna-org:device-1-0.", + "LabelXDlnaCap": "Limită X-DLNA:", + "LabelWeb": "Web:", + "LabelVideoCodec": "Codec video:", + "LabelVideoBitrate": "Rata de biți a video-ului:", + "LabelVideo": "Video", + "DashboardArchitecture": "Arhitectură: {0}", + "DashboardOperatingSystem": "Sistem de operare: {0}", + "DashboardServerName": "Server: {0}", + "DashboardVersionNumber": "Versiune: {0}", + "LabelVersionInstalled": "{0} instalat", + "LabelVersion": "Versiune:", + "LabelValue": "Valoare:", + "LabelVaapiDeviceHelp": "Acesta este nodul de execuție folosit pentru accelerarea hardware.", + "LabelVaapiDevice": "Dispozitiv VA API:", + "LabelUsername": "Utilizator:", + "LabelUserRemoteClientBitrateLimitHelp": "Înlocuiți valoarea globală setată în configurările de redare ale serverului.", + "LabelUserLoginAttemptsBeforeLockout": "Încercări de autentificare eșuate înainte ca utilizatorul să fie blocat:", + "LabelUserLibraryHelp": "Selectați ce bibliotecă de utilizator să se afișeze pe dispozitiv. Lăsați gol pentru a moșteni setarea implicită.", + "LabelUserLibrary": "Bibliotecă utilizator:", + "LabelUserAgent": "Agent utilizator:", + "LabelUseNotificationServices": "Utilizează următoarele servicii:", + "LabelTypeText": "Text", + "LabelTypeMetadataDownloaders": "{0} colectori metadate:", + "LabelType": "Tip:", + "LabelTunerType": "Tip tuner:", + "LabelTunerIpAddress": "Adresă IP Tuner:", + "LabelTranscodingVideoCodec": "Codec video:", + "LabelTranscodingThreadCountHelp": "Selectați numărul maxim de fire de execuție de utilizat la transcodare. Reducerea numărului de fire de execuție va scădea utilizarea procesorului, dar este posibil să nu se convertească suficient de repede pentru o experiență de redare lină.", + "Suggestions": "Recomandări", + "Subtitles": "Subtitrări", + "SubtitleOffset": "Decalaj subtitrare", + "SubtitleDownloadersHelp": "Activați și clasificați descărcătorii de subtitrare preferați în ordinea priorității.", + "SubtitleAppearanceSettingsDisclaimer": "Aceste setări nu se vor aplica subtitrărilor grafice (PGS, DVD etc.) sau subtitrărilor ASS / SSA care încorporează propriile lor stiluri.", + "SubtitleAppearanceSettingsAlsoPassedToCastDevices": "Aceste setări se aplică și oricărei redări Chromecast pornite de acest dispozitiv.", + "Studios": "Studiouri", + "StopRecording": "Oprește înregistrarea", + "Sports": "Sporturi", + "SortName": "Sortare nume", + "SortChannelsBy": "Ordonează canalele după:", + "SortByValue": "Sortează după {0}", + "Sort": "Sortează", + "SmartSubtitlesHelp": "Subtitrările care corespund preferinței limbii vor fi încărcate atunci când audioul este într-o limbă străină.", + "Smart": "Inteligent", + "Smaller": "Mai mic", + "SmallCaps": "Litere mici", + "Small": "Mic", + "SkipEpisodesAlreadyInMyLibraryHelp": "Episoadele vor fi comparate folosind numerele de sezon și episod, atunci când sunt disponibile.", + "SkipEpisodesAlreadyInMyLibrary": "Nu înregistrați episoadele care sunt deja în biblioteca mea", + "SimultaneousConnectionLimitHelp": "Numărul maxim de fluxuri simultane permise. Introduceți 0 pentru fără limită.", + "Shuffle": "Amestecă", + "ShowYear": "Arată anul", + "ShowTitle": "Arată titlul", + "ShowIndicatorsFor": "Afișați indicatori pentru:", + "ShowAdvancedSettings": "Afișați setări avansate", + "Share": "Distribuie", + "SettingsWarning": "Modificarea acestor valori poate provoca instabilități sau eșecuri de conectivitate. Dacă întâmpinați probleme, vă recomandăm să le schimbați înapoi cu cele din modul implicit.", + "SettingsSaved": "Setări salvate.", + "Settings": "Setări", + "ServerUpdateNeeded": "Acest Jellyfin Server trebuie actualizat. Pentru a descărca cea mai recentă versiune, accesați {0}", + "ServerRestartNeededAfterPluginInstall": "Jellyfin Server va trebui să fie repornit după instalarea unui plugin.", + "ServerNameIsShuttingDown": "Jellyfin Server - {0} se oprește.", + "ServerNameIsRestarting": "Jellyfin Server - {0} se repornește.", + "SeriesYearToPresent": "{0} - Prezent", + "SeriesSettings": "Setările serialului", + "SeriesRecordingScheduled": "Înregistrarea serialului programată.", + "SeriesDisplayOrderHelp": "Aranjați episoadele după data de emisie, lansare DVD sau numerotarea absolută.", + "SeriesCancelled": "Serial anulat.", + "Series": "Serial", + "SendMessage": "Trimite mesaj", + "SelectAdminUsername": "Vă rugăm să selectați un nume de utilizator pentru contul de admin.", + "SearchResults": "Rezultatele căutării", + "SearchForSubtitles": "Căutați subtitrări", + "SearchForMissingMetadata": "Căutați metadate lipsă", + "Search": "Caută", + "Screenshots": "Capturi de ecran", + "Screenshot": "Captură de ecran", + "Schedule": "Program", + "ScanLibrary": "Scanează biblioteca", + "ScanForNewAndUpdatedFiles": "Căutați fișiere noi și actualizate", + "SaveSubtitlesIntoMediaFoldersHelp": "Stocarea subtitrărilor lângă fișierele video le va permite să fie gestionate mai ușor.", + "SaveSubtitlesIntoMediaFolders": "Salvați subtitrările în dosarele media", + "Runtime": "Timpul de rulare", + "RunAtStartup": "Rulați la pornire", + "Rewind": "Derulează", + "ResumeAt": "Reluați de la {0}", + "RestartPleaseWaitMessage": "Vă rugăm să așteptați cât Jellyfin Server se închide și repornește. Acest lucru poate dura un minut sau două.", + "RequiredForAllRemoteConnections": "Obligatoriu pentru toate conexiunile distante", + "ReplaceExistingImages": "Înlocuiți toate imaginile", + "ReplaceAllMetadata": "Înlocuiți toate metadatele", + "RepeatOne": "Repetă una singură", + "RepeatMode": "Modul de repetare", + "RepeatEpisodes": "Repetă episoadele", + "RepeatAll": "Repetă tot", + "Repeat": "Repetă", + "RemoveFromPlaylist": "Scoateți din lista de redare", + "RemoveFromCollection": "Scoateți din colecție", + "RememberMe": "Ține-mă minte", + "ReleaseDate": "Data lansării", + "RefreshQueued": "Actualizare adăugată în coadă.", + "RefreshMetadata": "Actualizați metadatele", + "RefreshDialogHelp": "Metadatele sunt actualizate pe baza setărilor și a serviciilor de internet care sunt activate în tabloul de bord Jellyfin Server.", + "Refresh": "Reîmprospătează", + "Recordings": "Înregistrări", + "RecordingScheduled": "Înregistrare programată.", + "RecordingPathChangeMessage": "Modificarea dosarului dvs. de înregistrare nu va migra înregistrările existente din vechea locație la cea nouă. Dacă doriți, trebuie să le mutați manual.", + "RecordingCancelled": "Înregistrare anulată.", + "RecordSeries": "Înregistrează serialele", + "Record": "Înregistrează", + "RecommendationStarring": "În rol principal {0}", + "RecommendationDirectedBy": "Regizat de {0}", + "RecommendationBecauseYouWatched": "Pentru că ai vizionat {0}", + "RecommendationBecauseYouLike": "Pentru că vă place {0}", + "RecentlyWatched": "Vizionate recent", + "Rate": "Evaluare", + "Raised": "Ridicat", + "QueueAllFromHere": "Formează o coadă de aici", + "Quality": "Calitatea", + "Programs": "Programe", + "ProductionLocations": "Locații de producție", + "Producer": "Producător", + "Primary": "Primar", + "Previous": "Anteriorul", + "Premieres": "Premiere", + "Premiere": "Premieră", + "PreferredNotRequired": "Preferat, dar nu este necesar", + "PreferEmbeddedTitlesOverFileNamesHelp": "Aceasta determină titlul afișat implicit atunci când nu sunt disponibile metadate din internet sau metadate locale.", + "PreferEmbeddedTitlesOverFileNames": "Preferă titlurile incluse decât numele fișierelor", + "PluginInstalledMessage": "Pluginul a fost instalat cu succes. Jellyfin Server va trebui să fie repornit pentru ca modificările să intre în vigoare.", + "PleaseSelectTwoItems": "Vă rugăm să selectați cel puțin două elemente.", + "PleaseRestartServerName": "Vă rugăm să reporniți Jellyfin Server - {0}.", + "PleaseEnterNameOrId": "Vă rugăm să introduceți un nume sau un ID extern.", + "PleaseConfirmPluginInstallation": "Faceți clic pe OK pentru a confirma că ați citit mai sus și doriți să continuați cu instalarea pluginului.", + "PleaseAddAtLeastOneFolder": "Vă rugăm să adăugați cel puțin un dosar la această bibliotecă făcând clic pe butonul Adăugare.", + "Played": "Rulat", + "PlayNextEpisodeAutomatically": "Ruleză următorul episod automat", + "PlayNext": "Rulează următorul", + "PlayFromBeginning": "Rulează de la început", + "PlayCount": "Număr de rulări", + "PlaybackData": "Date de redare", + "PlayAllFromHere": "Rulează totul de aici", + "Play": "Rulează", + "PlaceFavoriteChannelsAtBeginning": "Plasați canalele preferate la început", + "PinCodeResetConfirmation": "Sigur doriți să resetați codul PIN?", + "PinCodeResetComplete": "Codul PIN a fost resetat.", + "PictureInPicture": "Imagine în imagine", + "PerfectMatch": "Potrivire perfectă", + "People": "Oameni", + "PasswordSaved": "Parolă salvată.", + "PasswordResetProviderHelp": "Alegeți un furnizor de resetare a parolei pentru a fi utilizat atunci când acest utilizator solicită o resetare a parolei", + "PasswordResetHeader": "Resetează parola", + "PasswordResetConfirmation": "Sigur doriți să resetați parola?", + "PasswordResetComplete": "Parola a fost resetată.", + "PasswordMatchError": "Confirmarea parolei și parola trebuie să corespundă.", + "PackageInstallFailed": "{0} (versiune{1}) instalare eșuată.", + "PackageInstallCompleted": "{0} (versiune {1}) instalare efectuată.", + "PackageInstallCancelled": "{0} (versiune {1}) instalarea a fost anulată.", + "Overview": "Prezentare generală", + "OriginalAirDateValue": "Data inițială de emisie: {0}", + "OptionWeekly": "Săptămânal", + "OptionWeekends": "Sfârşit de săptămână", + "OptionWeekdays": "Zile de lucru", + "OptionWakeFromSleep": "Trezește din suspendare", + "OptionUnairedEpisode": "Episoade netransmise", + "OptionTvdbRating": "Evaluare TVDB", + "OptionThumbCard": "Card în miniatură", + "OptionThumb": "Miniatură", + "OptionSubstring": "Subșir", + "OptionSpecialEpisode": "Speciale", + "OptionSaveMetadataAsHiddenHelp": "Modificarea acestui lucru se va aplica la noi metadate salvate de acum înainte. Fișierele de metadate existente vor fi actualizate data viitoare când sunt salvate de Jellyfin Server.", + "OptionSaveMetadataAsHidden": "Salvați metadata și imaginile ca fișiere ascunse", + "OptionResElement": "element res", + "OptionRequirePerfectSubtitleMatchHelp": "Cerând o potrivire perfectă va filtra subtitrările pentru a le include doar pe cele care au fost testate și verificate cu fișierul dvs. video exact. Debifând acest lucru, va crește probabilitatea descărcării subtitrărilor, dar va crește șansele de a avea decalaje sau de a greși textul de subtitrare.", + "OptionRequirePerfectSubtitleMatch": "Descărcați doar subtitrări care se potrivesc perfect pentru fișierele mele video", + "OptionReportByteRangeSeekingWhenTranscodingHelp": "Acest lucru este necesar pentru unele dispozitive care nu caută foarte bine în timp.", + "OptionReportByteRangeSeekingWhenTranscoding": "Raportați că serverul acceptă căutarea în octeți la transcodare", + "OptionRegex": "Expresie regulată", + "OptionRandom": "Aleator", + "OptionProtocolHttp": "HTTP", + "OptionProtocolHls": "Transmitere în direct HTTP", + "OptionProfileVideoAudio": "Audioul videoclipului", + "OptionProfileVideo": "Video", + "OptionProfilePhoto": "Fotografie", + "OptionProfileAudio": "Audio", + "OptionPosterCard": "Carte de afiș", + "OptionPoster": "Afiș", + "OptionPlainVideoItemsHelp": "Dacă este activat, toate videoclipurile sunt reprezentate în DIDL ca „object.item.videoItem” în loc de un tip mai specific, cum ar fi „object.item.videoItem.movie”.", + "OptionPlainVideoItems": "Afișați toate videoclipurile ca elemente video simple", + "OptionPlainStorageFoldersHelp": "Dacă este activat, toate folderele sunt reprezentate în DIDL ca „object.container.storageFolder” în loc de un tip mai specific, cum ar fi „object.container.person.musicArtist”.", + "OptionPlainStorageFolders": "Afișați toate dosarele ca dosare simple de stocare", + "OptionOnInterval": "La un interval", + "OptionOnAppStartup": "La pornirea aplicației", + "OptionNone": "Nici unul", + "OptionNew": "Nou...", + "OptionMissingEpisode": "Episoade lipsă", + "OptionMax": "Max", + "OptionLoginAttemptsBeforeLockoutHelp": "O valoare zero înseamnă că va moșteni valoarea implicită de trei încercări pentru utilizatorii normali și cinci pentru administratori. Setarea acestei opțiuni la -1 va dezactiva funcția.", + "OptionLoginAttemptsBeforeLockout": "Determină câte încercări de conectare incorecte pot fi făcute înainte de blocare.", + "OptionList": "Listă", + "OptionIsSD": "SD", + "OptionIsHD": "HD", + "OptionIgnoreTranscodeByteRangeRequestsHelp": "Dacă sunt activate, aceste solicitări vor fi respectate, dar vor ignora antetul intervalului de octeți.", + "OptionIgnoreTranscodeByteRangeRequests": "Ignorați solicitările pentru transcodarea intervalului de octeți", + "OptionHomeVideos": "Fotografii", + "OptionHlsSegmentedSubtitles": "Subtitrare segmentată HLS", + "OptionHasTrailer": "Trailer", + "OptionExtractChapterImage": "Activați extragerea imaginii pentru capitole", + "OptionExternallyDownloaded": "Descărcare externă", + "OptionEveryday": "Zilnic", + "OptionEstimateContentLength": "Lungimea conținutului estimată la transcodare", + "OptionEquals": "Egal", + "OptionEnableM2tsModeHelp": "Activați modul m2ts atunci când face encoding la mpegts.", + "OptionEnableM2tsMode": "Activați modul M2ts", + "OptionEnableForAllTuners": "Activare pentru toate dispozitivele tuner", + "OptionEnableExternalContentInSuggestionsHelp": "Permiteți trailerelor din internet și programelor TV în direct să fie incluse în conținutul sugerat.", + "OptionEnableExternalContentInSuggestions": "Activați conținut extern în sugestii", + "OptionEmbedSubtitles": "Inclus în container", + "OptionDownloadLogoImage": "Siglă", + "OptionDownloadImagesInAdvanceHelp": "În mod implicit, majoritatea imaginilor sunt descărcate numai la cererea unei aplicații din Jellyfin. Activați această opțiune pentru a descărca în prealabil toate imaginile, în timp ce fișierele media noi sunt importate. Acest lucru poate provoca scanări ale bibliotecii semnificativ mai lungi.", + "OptionDownloadImagesInAdvance": "Descărcați imaginile în avans", + "OptionDownloadDiscImage": "Placă", + "OptionDisplayFolderViewHelp": "Afișați dosarele alături de celelalte biblioteci media. Acest lucru poate fi util dacă doriți să aveți o vizualizare direct în dosar.", + "OptionDisplayFolderView": "Afișați o vizualizare de dosar pentru a afișa dosarele media simple", + "OptionDateAddedImportTime": "Utilizați data scanării în bibliotecă", + "OptionDateAddedFileTime": "Utilizați data creării fișierelor", + "Yesterday": "Ieri", + "Yes": "Da", + "XmlTvSportsCategoriesHelp": "Programele cu aceste categorii vor fi afișate ca programe sportive. Separați multiple categorii utilizând „|”.", + "XmlTvPathHelp": "O cale către un fișier XMLTV. Jellyfin va citi acest fișier și îl va verifica periodic pentru actualizări. Sunteți responsabil pentru crearea și actualizarea fișierului.", + "XmlTvNewsCategoriesHelp": "Programele cu aceste categorii vor fi afișate ca programe de știri. Separați multiple categorii utilizând „|”.", + "XmlTvMovieCategoriesHelp": "Programele cu aceste categorii vor fi afișate ca filme. Separați multiple categorii utilizând „|”.", + "XmlTvKidsCategoriesHelp": "Programele cu aceste categorii vor fi afișate ca programe pentru copii. Separați multiple categorii utilizând „|”.", + "XmlDocumentAttributeListHelp": "Aceste atribute sunt aplicate elementului rădăcină al fiecărui răspuns XML.", + "Writer": "Scriitor", + "Whitelist": "Listă agreată", + "Watched": "Vizionat", + "ViewPlaybackInfo": "Vizualizați informațiile despre redare", + "ViewArtist": "Vezi artist", + "ViewAlbum": "Vizualizați albumul", + "VideoRange": "Interval video", + "Vertical": "Vertical", + "ValueVideoCodec": "Codec Video: {0}", + "ValueTimeLimitSingleHour": "Limită de timp: 1 oră", + "ValueTimeLimitMultiHour": "Limită de timp: {0} ore", + "ValueSongCount": "{0} melodii", + "ValueSeriesCount": "{0} seriale", + "ValueSeconds": "{0} secunde", + "ValueOneSong": "1 melodie", + "ValueOneSeries": "1 serial", + "ValueOneMusicVideo": "1 videoclip muzical", + "ValueOneMovie": "1 film", + "ValueOneEpisode": "1 episod", + "ValueOneAlbum": "1 album", + "ValueMusicVideoCount": "{0} videoclipuri muzicale", + "ValueMovieCount": "{0} filme", + "ValueMinutes": "{0} min", + "ValueEpisodeCount": "{0} episoade", + "ValueDiscNumber": "Disc {0}", + "ValueContainer": "Containere: {0}", + "ValueConditions": "Condiții: {0}", + "ValueCodec": "Codec: {0}", + "ValueAudioCodec": "Codec Audio: {0}", + "ValueAlbumCount": "{0} albume", + "UserAgentHelp": "Furnizați un antet HTTP personalizat de utilizator.", + "Upload": "Încarcă", + "Up": "Sus", + "Unrated": "Neevaluat", + "Unplayed": "Nerulat", + "Unmute": "Activați sunetul", + "UninstallPluginHeader": "Dezinstalați pluginul", + "UninstallPluginConfirmation": "Sigur doriți să dezinstalați {0}?", + "Uniform": "Constant", + "TvLibraryHelp": "Examinați {0}ghidul de denumire TV{1}.", + "Transcoding": "Conversie", + "Trailers": "Trailere", + "TrackCount": "{0} piese", + "TitlePlayback": "Redare", + "TitleHostingSettings": "Setări de găzduire", + "TitleHardwareAcceleration": "Accelerare Hardware", + "Thumb": "Miniatură", + "TheseSettingsAffectSubtitlesOnThisDevice": "Aceste setări afectează subtitrările de pe acest dispozitiv", + "ThemeVideos": "Videoclipurile temei", + "ThemeSongs": "Melodiile temei", + "TagsValue": "Etichete: {0}", + "Tags": "Etichete", + "TabUsers": "Utilizatori", + "TabStreaming": "Transmitere", + "TabServer": "Server", + "TabScheduledTasks": "Task-uri programate", + "TabResumeSettings": "Continuă", + "TabResponses": "Răspunsuri", + "TabPlugins": "Pluginuri", + "TabPlaylists": "Liste redare", + "TabPlayback": "Redare", + "TabParentalControl": "Control Parental", + "TabNfoSettings": "Setări NFO", + "TabNetworking": "Rețele", + "TabMetadata": "Metadată", + "TabLogs": "Jurnal", + "TabLiveTV": "TV în Direct", + "TabInfo": "Info", + "TabDisplay": "Afișare", + "TabDirectPlay": "Redare directă", + "TabDevices": "Dispozitive", + "TabDashboard": "Tablou de bord", + "TabContainers": "Containere", + "TabCodecs": "Codecuri", + "TabCatalog": "Registru", + "TV": "TV", + "SystemDlnaProfilesHelp": "Profilele de sistem pot fi numai citite. Modificările aduse unui profil de sistem vor fi salvate într-un nou profil personalizat.", + "HeaderNavigation": "Navigare", + "MessageConfirmAppExit": "Vrei să ieși?", + "CopyStreamURLError": "A apărut o eroare la copierea adresei URL.", + "EnableFastImageFadeInHelp": "Activați animația mai rapidă de tranziție pentru imaginile încărcate", + "EnableFastImageFadeIn": "Tranziție a imaginii rapidă", + "LabelVideoResolution": "Rezoluția video:", + "LabelStreamType": "Tipul streamului:", + "LabelPlayerDimensions": "Dimensiunile soft redare:", + "LabelDroppedFrames": "Cadre abandonate:", + "LabelCorruptedFrames": "Cadre corupte:", + "OptionForceRemoteSourceTranscoding": "Forțați transcodarea surselor media distante (cum ar fi LiveTV)", + "NoCreatedLibraries": "Se pare că nu ați creat încă biblioteci. {0} Doriți să creați una acum? {1}", + "AskAdminToCreateLibrary": "Cereți unui administrator să creeze o bibliotecă.", + "PlaybackErrorNoCompatibleStream": "Clientul nu este compatibil cu formatul media, iar serverul nu trimite un format media compatibil.", + "AllowFfmpegThrottlingHelp": "Când un transcod sau un remux se află destul de departe înainte de poziția actuală de redare, întrerupeți procesul, astfel încât să consume mai puține resurse. Acest lucru este cel mai util când priviți fără a derula des. Dezactivați acestă opțiune dacă întâmpinați probleme de redare.", + "AllowFfmpegThrottling": "Accelerare Transcod-uri", + "Track": "Cale", + "Season": "Sezon", + "ReleaseGroup": "Gruparea lansării", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferați informația despre episod încorporată în fișier decât numele fișierelor", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Aceasta folosește informația despre episod din metadatele încorporate, dacă sunt disponibile.", + "Person": "Persoană", + "OtherArtist": "Alt artist", + "Movie": "Film", + "Episode": "Episod", + "ClientSettings": "Setări pentru client", + "BoxSet": "Set de colecție", + "Artist": "Artist", + "AlbumArtist": "Artistul albumului", + "Album": "Album", + "OnApplicationStartup": "La pornirea aplicației", + "EveryXHours": "La fiecare {0} ore", + "EveryHour": "În fiecare oră", + "EveryXMinutes": "La fiecare {0} minute", + "OnWakeFromSleep": "La trezire din somn", + "WeeklyAt": "{0} la {1}", + "DailyAt": "Zilnic la {0}", + "LastSeen": "Văzut ultima dată {0}", + "PersonRole": "ca {0}", + "ListPaging": "{0}-{1} din {2}", + "WriteAccessRequired": "Jellyfin Server necesită acces de scriere la acest folder. Vă rugăm să vă asigurați accesul la scriere și încercați din nou.", + "PathNotFound": "Calea nu a fost găsită. Vă rugăm să vă asigurați de validitatea căii și încercați din nou.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelDeinterlaceMethod": "Metoda de intercalare:", + "DeinterlaceMethodHelp": "Selectați metoda de intercalat pe care să o utilizați la transcodarea conținutului intercalat.", + "UnsupportedPlayback": "Jellyfin nu poate decripta conținut protejat de DRM, dar tot conținutul va fi încercat indiferent de titlurile protejate. Unele fișiere pot părea complet negre din cauza criptării sau a altor funcții neacceptate, cum ar fi titluri interactive.", + "LabelLibraryPageSizeHelp": "Setează cantitatea de elemente de afișat pe o pagină a bibliotecii. Setați la 0 pentru a dezactiva paginarea.", + "LabelLibraryPageSize": "Mărimea paginii Bibliotecă:", + "MessageUnauthorizedUser": "Nu sunteți autorizat să accesați serverul în acest moment. Vă rugăm să contactați administratorul serverului pentru mai multe informații.", + "ButtonTogglePlaylist": "Listă de redare", + "ButtonToggleContextMenu": "Mai mult", + "Filter": "Filtru", + "New": "Nou", + "HeaderFavoritePlaylists": "Listă Favorită" } diff --git a/src/strings/ru.json b/src/strings/ru.json index 4e612aa5bd..9fc2a00df6 100644 --- a/src/strings/ru.json +++ b/src/strings/ru.json @@ -3,19 +3,19 @@ "AccessRestrictedTryAgainLater": "В настоящее время доступ запрещён. Повторите попытку позже.", "Actor": "Актёр", "Add": "Добавить", - "AddItemToCollectionHelp": "Добавляйте элементы в коллекции проведя их поиск, и с помощью правого щелчка по ним или по касанию меню, чтобы присоединить ко коллекции.", + "AddItemToCollectionHelp": "Добавляйте элементы в коллекции, выполняя их поиск, и с помощью правой кнопки мыши или касания меню присоедините их к коллекции.", "AddToCollection": "Добавить в коллекцию", "AddToPlayQueue": "Добавить в очередь воспроизведения", "AddToPlaylist": "Добавить в плей-лист", "AddedOnValue": "Добавлено {0}", - "AdditionalNotificationServices": "Просмотрите каталог плагинов, чтобы установить дополнительные услуги для уведомлений.", + "AdditionalNotificationServices": "Просмотрите каталог плагинов, чтобы установить дополнительные сервисы уведомлений.", "AirDate": "Дата эфира", "Aired": "Эфирный", "Albums": "Альбомы", "Alerts": "Оповещения", "All": "Все", "AllChannels": "Все каналы", - "AllComplexFormats": "Все комлексные форматы (ASS, SSA, VOBSUB, PGS, SUB/IDX и т.д.)", + "AllComplexFormats": "Все комплексные форматы (ASS, SSA, VOBSUB, PGS, SUB и IDX)", "AllEpisodes": "Все эпизоды", "AllLanguages": "Все языки", "AllLibraries": "Все медиатеки", @@ -23,11 +23,11 @@ "AllowMediaConversion": "Разрешить преобразование медиаданных", "AllowMediaConversionHelp": "Предоставить или запретить доступ к компоненте преобразования медиаданных.", "AllowOnTheFlySubtitleExtraction": "Разрешить динамическое извлечение субтитров", - "AllowOnTheFlySubtitleExtractionHelp": "Внедрённые субтитры возможно извлекать из видео и доставлять клиентам в виде обычного текста, в целях предотвращения перекодировки видео. На некоторых системах это может занять продолжительное время и вызывать задержки воспроизведения видео в процессе извлечения. Отключите это, для прошивки внедрённых субтитров во время перекодировки видео, при отсутствии встроенной поддержки их в клиентском устройстве.", - "AllowRemoteAccess": "Разрешение удалённого доступа к данному серверу Jellyfin Server.", + "AllowOnTheFlySubtitleExtractionHelp": "Встроенные субтитры могут быть извлечены из видео и доставлены клиентам в виде обычного текста, в целях предотвращения перекодировки видео. На некоторых системах это может занять продолжительное время и вызвать задержки воспроизведения видео в процессе извлечения. Отключите этот параметр, чтобы встроенные субтитры записывались при перекодировании видео, если они изначально не поддерживаются клиентским устройством.", + "AllowRemoteAccess": "Разрешить удалённый доступ к данному серверу Jellyfin Server.", "AllowRemoteAccessHelp": "Если флажок снят, то все удалённые подключения будут заблокированы.", - "AllowedRemoteAddressesHelp": "Список разделённых запятыми IP-адресов или записей IP/netmask для сетей, которым разрешено удалённое соединение. Если не заполнять, то будут использованы все внешние адреса.", - "AlwaysPlaySubtitles": "Всегда воспроизводить с субтитрами", + "AllowedRemoteAddressesHelp": "Список разделённых запятыми IP-адресов или записей IP/netmask сетей, которым разрешено удалённое соединение. Если оставить это поле пустым, то будут разрешены все удаленные адреса.", + "AlwaysPlaySubtitles": "Воспроизводить всегда", "AlwaysPlaySubtitlesHelp": "Субтитры, соответствующие настройке языка, будут загружаться независимо от языка аудио.", "AnyLanguage": "Любой язык", "Anytime": "В любое время", @@ -36,25 +36,25 @@ "Artists": "Исполнители", "AsManyAsPossible": "Как можно больше", "Ascending": "По возрастанию", - "AspectRatio": "Соот-ие сторон", + "AspectRatio": "Соотношение сторон", "AttributeNew": "Новинка", "Audio": "Аудио", "Auto": "Авто", "AutoBasedOnLanguageSetting": "Авто (на основе настройки языка)", - "Backdrop": "Задник", - "Backdrops": "Задники", + "Backdrop": "Фон", + "Backdrops": "Фоны", "Banner": "Баннер", "BirthDateValue": "Дата рождения: {0}", "BirthLocation": "Место рождения", "BirthPlaceValue": "Место рождения: {0}", "Blacklist": "Чёрный список", - "BookLibraryHelp": "Поддерживаются аудио и текстовые книги. Просмотрите {0}руководство по именованию книг{1}.", + "BookLibraryHelp": "Поддерживаются аудио и текстовые книги. Просмотрите {0}руководство по именованию книг{1}.", "Books": "Книги", "Box": "Коробка", - "BoxRear": "Спинка коробки", + "BoxRear": "Коробка (задняя часть)", "Browse": "Навигация", "BrowsePluginCatalogMessage": "Просмотрите каталог плагинов, чтобы ознакомиться с имеющимися плагинами.", - "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при преобразовании видео в зависимости от формата субтитров. Избегание внедрения субтитров улучшит производительность сервера. Выберите «Авто» для записи основанных на графике форматов (VOBSUB, PGS, SUB/IDX и т.п.) и некоторых субтитров ASS/SSA.", + "BurnSubtitlesHelp": "Определяется, должен ли сервер внедрять субтитры при перекодировании. Избежание этого значительно улучшит производительность. Выберите «Авто» для записи основанных на графике форматов (VOBSUB, PGS, SUB и IDX) и некоторых субтитров ASS или SSA.", "ButtonAdd": "Добавить", "ButtonAddMediaLibrary": "Добавить медиатеку", "ButtonAddScheduledTaskTrigger": "Добавить триггер", @@ -70,12 +70,12 @@ "ButtonChangeServer": "Сменить сервер", "ButtonConnect": "Подсоединиться", "ButtonDelete": "Удалить", - "ButtonDeleteImage": "Удалить рисунок", + "ButtonDeleteImage": "Удалить изображение", "ButtonDown": "Вниз", "ButtonDownload": "Загрузить", "ButtonEdit": "Править", - "ButtonEditImages": "Править рисунки", - "ButtonEditOtherUserPreferences": "Править профиль, рисунок и личные настройки этого пользователя.", + "ButtonEditImages": "Править изображения", + "ButtonEditOtherUserPreferences": "Править профиль, изображение и персональные настройки этого пользователя.", "ButtonFilter": "Фильтр", "ButtonForgotPassword": "Напомнить пароль", "ButtonFullscreen": "Полный экран", @@ -83,21 +83,21 @@ "ButtonGuide": "Телегид", "ButtonHelp": "Справка", "ButtonHome": "Главное", - "ButtonInfo": "Инфо...", + "ButtonInfo": "Инфо", "ButtonLearnMore": "Подробнее", "ButtonLibraryAccess": "Доступ к медиатеке", "ButtonManualLogin": "Войти вручную", "ButtonMore": "Ещё", "ButtonNetwork": "Сеть", "ButtonNew": "Новое", - "ButtonNextTrack": "След. дорожка", + "ButtonNextTrack": "Следующая дорожка", "ButtonOff": "Откл", "ButtonOk": "Ок", "ButtonOpen": "Открыть", - "ButtonParentalControl": "Управлять содержанием", + "ButtonParentalControl": "Родительский контроль", "ButtonPause": "Пауза", - "ButtonPlay": "Воспр.", - "ButtonPreviousTrack": "Пред. дорожка", + "ButtonPlay": "Воспроизведение", + "ButtonPreviousTrack": "Предыдущая дорожка", "ButtonProfile": "Профиль", "ButtonQuickStartGuide": "Руководство по запуску", "ButtonRefresh": "Обновить", @@ -127,6 +127,8 @@ "ButtonStop": "Остановить", "ButtonSubmit": "Подтвердить", "ButtonSubtitles": "Субтитры", + "ButtonToggleContextMenu": "Ещё", + "ButtonTogglePlaylist": "Плей-лист", "ButtonTrailer": "Трейлер", "ButtonUninstall": "Удалить", "ButtonUp": "Вверх", @@ -147,27 +149,27 @@ "CommunityRating": "Общественная оценка", "Composer": "Композитор", "ConfigureDateAdded": "Как конфигурировать дату добавления определяется в Панели Jellyfin Server в параметрах Медиатеки", - "ConfirmDeleteImage": "Удалить рисунок?", + "ConfirmDeleteImage": "Удалить изображение?", "ConfirmDeleteItem": "При удалении данного элемента, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?", "ConfirmDeleteItems": "При удалении данных элементов, он удалится и из файловой системы, и из медиатеки. Вы действительно хотите продолжить?", "ConfirmDeletion": "Подтверждение удаления", "ConfirmEndPlayerSession": "Вы хотите завершить работу Jellyfin на {0}?", - "Connect": "Подсоединиться", + "Connect": "Соединиться", "ContinueWatching": "Продолжение просмотра", "Continuing": "Продолжающееся", "CriticRating": "Оценка критиков", "CustomDlnaProfilesHelp": "Создайте настраиваемый профиль, назначаемый для нового устройства или переопределите системный профиль.", "DateAdded": "Дата добавления", "DatePlayed": "Дата воспроизведения", - "DeathDateValue": "Кончина: {0}", - "Default": "Умолчание", + "DeathDateValue": "Дата смерти: {0}", + "Default": "По умолчанию", "DefaultErrorMessage": "Произошла ошибка при обработке запроса. Повторите попытку позже.", "DefaultMetadataLangaugeDescription": "Они являются значениями по умолчанию и могут быть подстроены индивидуально для каждой медиатеки.", "DefaultSubtitlesHelp": "Загрузки субтитров определяются флагами \"По умолчанию\" и \"Форсированные\" во внедрённых метаданных. Языковые настройки учитываются при наличии нескольких опций.", "Delete": "Удалить", "DeleteDeviceConfirmation": "Вы действительно хотите удалить данное устройство? Оно появится снова в следующий раз, когда пользователь войдёт с него.", - "DeleteImage": "Удалить рисунок", - "DeleteImageConfirmation": "Вы действительно хотите удалить данный рисунок?", + "DeleteImage": "Удалить изображение", + "DeleteImageConfirmation": "Вы действительно хотите удалить данное изображение?", "DeleteMedia": "Удалить медиаданные", "DeleteUser": "Удалить пользователя", "DeleteUserConfirmation": "Вы действительно хотите удалить этого пользователя?", @@ -181,8 +183,7 @@ "DirectStreamHelp2": "При прямой трансляции файла расходуется очень мало вычислительной мощности без потери качества видео.", "DirectStreaming": "Транслируется напрямую", "Director": "Режиссёр", - "DirectorValue": "Режиссёр: {0}", - "DirectorsValue": "Режиссёры: {0}", + "Directors": "Режиссёры", "Disabled": "Отключено", "Disc": "Диск", "Disconnect": "Разъединиться", @@ -192,7 +193,7 @@ "DisplayInOtherHomeScreenSections": "Показывать в разделах главного экрана (нпр., новейшие медиаданные, продолжение просмотра и т.п.)", "DisplayMissingEpisodesWithinSeasons": "Отображать отсутствующие эпизоды в пределах сезонов", "DisplayMissingEpisodesWithinSeasonsHelp": "Это также должно быть включено для ТВ-медиатек в конфигурации сервера.", - "DisplayModeHelp": "Выберите тип экрана, где запущен Jellyfin.", + "DisplayModeHelp": "Выберите желательный стиль разметки для интерфейса.", "DoNotRecord": "Не записывать", "Down": "Вниз", "Download": "Загрузить", @@ -201,11 +202,11 @@ "DropShadow": "Теневая", "EasyPasswordHelp": "Простой PIN-код используется для автономного доступа на поддерживаемых клиентах и может также использоваться для удобного внутрисетевого входа.", "Edit": "Правка", - "EditImages": "Править рисунки", + "EditImages": "Править изображения", "EditMetadata": "Править метаданные", "EditSubtitles": "Править субтитры", - "EnableBackdrops": "Задники", - "EnableBackdropsHelp": "Задники будут отображаются фоном на некоторых страницах при просмотре медиатеки.", + "EnableBackdrops": "Фоны", + "EnableBackdropsHelp": "Фоны будут отображаются на заднем плане на некоторых страницах при просмотре медиатеки.", "EnableCinemaMode": "Режим кинозала", "EnableColorCodedBackgrounds": "Обозначеннные цветом фоны", "EnableDisplayMirroring": "Дублирование отображения", @@ -215,8 +216,8 @@ "EnableNextVideoInfoOverlay": "Показывать сведения о следующем видео во время воспроизведения", "EnableNextVideoInfoOverlayHelp": "В конце видео отображать информацию о последующем видео в текущем плей-листе.", "EnablePhotos": "Отображать фотографии", - "EnablePhotosHelp": "Рисунки будут обнаруживаться и отображаться наряду с другими медиафайлами.", - "EnableStreamLooping": "Автоциклирование трансляций", + "EnablePhotosHelp": "Изображения будут обнаруживаться и отображаться наряду с другими медиафайлами.", + "EnableStreamLooping": "Зацикливание трансляций", "EnableStreamLoopingHelp": "Включайте, если трансляции содержат данные только на несколько секунд и необходимо непрерывно их запрашивать. Включение этого без необходимости может породить проблемы.", "EnableThemeSongs": "Тематические композиции", "EnableThemeSongsHelp": "Воспроизведение тематических композиций в фоновом режиме при навигации по медиатеке.", @@ -237,7 +238,7 @@ "EveryNDays": "Каждые {0} дней", "ExitFullscreen": "Выход с полного экрана", "ExtraLarge": "Очень крупный", - "ExtractChapterImagesHelp": "Извлечение рисунков сцен предоставляет возможности клиентам для отображения графических меню выбора сцены. Данный процесс может быть медленным, потребляет ресурсы, и могут понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", + "ExtractChapterImagesHelp": "Извлечение изображений сцен предоставляет возможности клиентам для отображения графических меню выбора сцены. Данный процесс может быть медленным, потребляет ресурсы, и могут понадобиться несколько гигабайт пространства. Он работает при обнаружении видеофайлов, а также, как задача, назначенная на ночь. Расписание возможно перенастроить в области Назначенных задач. Не рекомендуется запускать данную задачу в часы пик.", "Extras": "Допматериалы", "FFmpegSavePathNotFound": "Мы не смогли обнаружить FFmpeg по введённому вами пути. FFprobe также необходим и должен быть в той же самой папке. Эти компоненты обычно поставляются вместе в одном загрузочном пакете. Проверьте путь и повторите попытку.", "FastForward": "Быстро вперёд", @@ -260,20 +261,19 @@ "Friday": "пятница", "Fullscreen": "Полный экран", "General": "Общие", - "GenreValue": "Жанр: {0}", + "Genre": "Жанр", "Genres": "Жанры", - "GenresValue": "Жанры: {0}", "GroupBySeries": "Группирование по сериалам", "GroupVersions": "Сгруппировать версии", - "GuestStar": "Пригл. актёр", + "GuestStar": "Приглашенный актёр", "Guide": "Телегид", "GuideProviderLogin": "Вход", "GuideProviderSelectListings": "Выбор перечней", - "H264CrfHelp": "Постоянное значение оценки (Constant Rate Factor, CRF) - параметр качества по умолчанию для кодёра x264. Возможно задавать значения от 0 до 51, где меньшие значения привели бы к улучшению качества (за счёт бо́льших размеров файлов). Разумными являются значения от 18 до 28. Стандартно для x264 - 23, так что вы можете использовать это в качестве отправной точки.", - "H264EncodingPresetHelp": "Выберите значение быстрее для улучшения производительности, или значение медленнее для улучшения качества.", + "H264CrfHelp": "Постоянное значение оценки (Constant Rate Factor, CRF) - параметр качества по умолчанию для кодёра x264. Возможно задавать значения от 0 до 51, где меньшие значения привели бы к улучшению качества (за счёт увеличения размеров файлов). Приемлемыми являются значения от 18 до 28. Стандартно для x264 - 23, так что вы можете использовать это в качестве отправной точки.", + "EncoderPresetHelp": "Выберите значение быстрее для улучшения производительности, или значение медленнее для улучшения качества.", "HDPrograms": "HD-передачи", "HandledByProxy": "Обрабатывается обратным прокси", - "HardwareAccelerationWarning": "Включение аппаратного ускорения может привести к нестабильности в некоторых средах. Убедитесь в том, что ваша операционная система и видеодрайверы полностью актуализированы. Если имеются проблемы с воспроизведением видео после включения этого, необходимо сменить параметр назад на Авто.", + "HardwareAccelerationWarning": "Включение аппаратного ускорения может привести к нестабильности в некоторых средах. Убедитесь в том, что ваша операционная система и видеодрайверы полностью актуализированы. Если имеются проблемы с воспроизведением видео после включения этого, необходимо сменить параметр назад на Ничего.", "HeaderAccessSchedule": "Расписание доступа", "HeaderAccessScheduleHelp": "Создайте расписание доступа, чтобы лимитировать доступ определёнными часами.", "HeaderActiveDevices": "Активные устройства", @@ -282,7 +282,7 @@ "HeaderAddScheduledTaskTrigger": "Добавление триггера", "HeaderAddToCollection": "Добавить в коллекцию", "HeaderAddToPlaylist": "Добавление в плей-лист", - "HeaderAddUpdateImage": "Добавление/Обновление рисунка", + "HeaderAddUpdateImage": "Добавление/Обновление изображения", "HeaderAddUser": "Добавить пользователя", "HeaderAdditionalParts": "Дополнительные части", "HeaderAdmin": "Администрирование", @@ -307,7 +307,7 @@ "HeaderCastCrew": "Снимались и снимали", "HeaderChannelAccess": "Доступ ко каналам", "HeaderChannels": "Каналы", - "HeaderChapterImages": "Рисунки сцен", + "HeaderChapterImages": "Изображения сцен", "HeaderCodecProfile": "Профиль кодеков", "HeaderCodecProfileHelp": "Профили кодеков обозначают ограничения устройства при воспроизведении с определёнными кодеками. Если применяется ограничение, то медиаданные перекодируются, даже если кодек настроен для прямого воспроизведения.", "HeaderConfigureRemoteAccess": "Конфигурирование удалённого доступа", @@ -337,7 +337,7 @@ "HeaderDisplay": "Отображение", "HeaderDownloadSync": "Загрузка и синхро", "HeaderEasyPinCode": "Простой PIN-код", - "HeaderEditImages": "Править рисунки", + "HeaderEditImages": "Править изображения", "HeaderEnabledFields": "Включённые поля", "HeaderEnabledFieldsHelp": "Снимите флажок, чтобы зафиксировать поле и защитить его данные от изменнений.", "HeaderEpisodes": "Эпизоды", @@ -345,7 +345,7 @@ "HeaderExternalIds": "Внешние идентификаторы:", "HeaderFeatureAccess": "Доступ к компонентам", "HeaderFeatures": "Материалы", - "HeaderFetchImages": "Отборка рисунков:", + "HeaderFetchImages": "Отборка изображений:", "HeaderFetcherSettings": "Параметры отборщика", "HeaderFilters": "Фильтры", "HeaderForKids": "Детям", @@ -358,8 +358,8 @@ "HeaderIdentificationCriteriaHelp": "Введите хотя бы одно условие распознания.", "HeaderIdentificationHeader": "Заголовок для распознания", "HeaderIdentifyItemHelp": "Введите одно или несколько условий поиска. Изымите условие, чтобы прирастить найденные результаты.", - "HeaderImageOptions": "Опции рисунка", - "HeaderImageSettings": "Параметры рисунков", + "HeaderImageOptions": "Параметры изображения", + "HeaderImageSettings": "Настройки изображения", "HeaderInstall": "Установка", "HeaderInstantMix": "Автомикс", "HeaderItems": "Элементы", @@ -406,7 +406,7 @@ "HeaderPeople": "Люди", "HeaderPhotoAlbums": "Фотоальбомы", "HeaderPinCodeReset": "Сброс PIN-кода", - "HeaderPlayAll": "Воспр. все", + "HeaderPlayAll": "Воспроизвести все", "HeaderPlayOn": "Воспроизведение", "HeaderPlayback": "Воспроизведение медиаданных", "HeaderPlaybackError": "Ошибка воспроизведения", @@ -469,10 +469,10 @@ "HeaderTranscodingProfileHelp": "Добавьте профили перекодировки, чтобы указать, какие форматы следует использовать, когда требуется перекодировка.", "HeaderTunerDevices": "Тюнерные устройства", "HeaderTuners": "Тюнеры", - "HeaderTypeImageFetchers": "{0} отборщики рисунков", + "HeaderTypeImageFetchers": "{0} отборщики изображений", "HeaderTypeText": "Ввод текста", "HeaderUpcomingOnTV": "Ожидаемое на ТВ", - "HeaderUploadImage": "Выкладка рисунка", + "HeaderUploadImage": "Загрузка изображения", "HeaderUser": "Пользователь", "HeaderUsers": "Пользователи", "HeaderVideoQuality": "Качество видео", @@ -491,10 +491,10 @@ "Horizontal": "Горизонтально", "HttpsRequiresCert": "Чтобы включить HTTPS для внешних подключений, вам нужно будет предоставить доверенный SSL-cертификат, например, Let's Encrypt. Предоставьте сертификат или отключите защищенные соединения.", "Identify": "Распознать", - "Images": "Рисунки", + "Images": "Изображения", "ImportFavoriteChannelsHelp": "При включении, будут импортированы только каналы, которые обозначены как избранное на тюнерном устройстве.", "ImportMissingEpisodesHelp": "При включении, информация об отсутствующих эпизодах будет импортирована в вашу базу данных Jellyfin и отображаться в пределах сезонов и сериалов. Это может увеличить время сканирования медиатеки.", - "InstallingPackage": "Устанавливается {0}", + "InstallingPackage": "Устанавливается {0} (версия {1})", "InstantMix": "Автомикс", "ItemCount": "{0} элемент(а/ов)", "Items": "Элементы", @@ -510,7 +510,7 @@ "LabelAirsBeforeEpisode": "Эпизод airs_before:", "LabelAirsBeforeSeason": "Сезон airs_before:", "LabelAlbum": "Альбом:", - "LabelAlbumArtHelp": "PN используемое для альбомных обложек, внутри атрибута dlna:profileID при upnp:albumArtURI. Некоторым устройствам требуется специфическое значение, вне зависимости от размера рисунка.", + "LabelAlbumArtHelp": "PN используемое для альбомных обложек, внутри атрибута dlna:profileID при upnp:albumArtURI. Некоторым устройствам требуется специфическое значение, вне зависимости от размера изображения.", "LabelAlbumArtMaxHeight": "Макс. высота облома альбома:", "LabelAlbumArtMaxHeightHelp": "Максимальное разрешение обложек альбома, представляемых с помощью upnp:albumArtURI.", "LabelAlbumArtMaxWidth": "Макс. ширина обложки альбома:", @@ -527,7 +527,7 @@ "LabelAppNameExample": "Пример: Sickbeard, Sonarr", "LabelArtists": "Исполнители:", "LabelArtistsHelp": "Для разделения используйте точку с запятой ;", - "LabelAudio": "Аудио:", + "LabelAudio": "Аудио", "LabelAudioLanguagePreference": "Выбор языка аудио:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Автоматически обновлять метаданные из Интернета:", "LabelBindToLocalNetworkAddress": "Привязка к адресу в локальной сети:", @@ -540,7 +540,7 @@ "LabelBurnSubtitles": "Внедрение субтитров:", "LabelCache": "Кэш:", "LabelCachePath": "Путь к кешу:", - "LabelCachePathHelp": "Укажите произвольное расположение для файлов серверного кэша, например, рисунков. Оставьте поле незаполненным, чтобы использовать значение по умолчанию.", + "LabelCachePathHelp": "Укажите произвольное расположение для файлов серверного кэша, например, изображений. Оставьте поле незаполненным, чтобы использовать значение по умолчанию.", "LabelCancelled": "Отменено", "LabelCertificatePassword": "Пароль сертификата:", "LabelCertificatePasswordHelp": "Если для вашего сертификата требуется пароль, то введите его здесь.", @@ -581,13 +581,13 @@ "LabelDownMixAudioScale": "Коэффициент усиления при понижающем микшировании:", "LabelDownMixAudioScaleHelp": "Коэффициент компенсирующего усиления звука при понижающем до стерео микшировании. Значение 1 сохраняет исходный уровень.", "LabelDownloadLanguages": "Загружаемые языки:", - "LabelDropImageHere": "Перетащите рисунок сюда или щёлкните для навигации.", + "LabelDropImageHere": "Перетащите изображение сюда или щёлкните для навигации.", "LabelDropShadow": "Окантовка:", "LabelEasyPinCode": "Простой PIN-код:", "LabelEmbedAlbumArtDidl": "Внедрять альбомные обложки в DIDL", "LabelEmbedAlbumArtDidlHelp": "Для некоторых устройств данный метод получения альбомных обложек является предпочтительным. Остальные могут быть не в состоянии воспроизводить, при включении данной опции.", "LabelEnableAutomaticPortMap": "Включить автоматическое сопоставление портов", - "LabelEnableAutomaticPortMapHelp": "Попытаться автоматически сопоставить публичный порт с локальным портом с помощью UPnP. Это может не сработать с некоторыми моделями маршрутизаторов.", + "LabelEnableAutomaticPortMapHelp": "Попытаться автоматически сопоставить публичный порт с локальным портом с помощью UPnP. Это может не работать с некоторыми моделями маршрутизаторов. Изменения не применяются до перезапуска сервера.", "LabelEnableBlastAliveMessages": "Бомбардировать сообщениями проверки активности", "LabelEnableBlastAliveMessagesHelp": "Включите, если сервер надёжно не обнаруживается иными UPnP устройствами в своей сети.", "LabelEnableDlnaClientDiscoveryInterval": "Интервал обнаружения клиентов", @@ -601,14 +601,14 @@ "LabelEnableHardwareDecodingFor": "Включить аппаратное декодирование для:", "LabelEnableRealtimeMonitor": "Включить отслеживание в реальном времени", "LabelEnableRealtimeMonitorHelp": "В поддерживаемых файловых системах правки файлов будут обрабатываться незамедлительно.", - "LabelEnableSingleImageInDidlLimit": "Лимитировать до единственного внедрённого рисунка", - "LabelEnableSingleImageInDidlLimitHelp": "На некоторых устройствах не отрисовывается нормально, если внедрены несколько рисунков внутри DIDL.", + "LabelEnableSingleImageInDidlLimit": "Ограничить единственным встроенным изображением", + "LabelEnableSingleImageInDidlLimitHelp": "На некоторых устройствах не отрисовывается нормально, если встроено несколько изображений внутри DIDL.", "LabelEndDate": "Конечная дата:", "LabelEpisodeNumber": "Номер эпизода:", "LabelEvent": "Событие:", "LabelEveryXMinutes": "Каждые:", - "LabelExtractChaptersDuringLibraryScan": "Извлекать рисунки сцен в процессе сканирования медиатеки", - "LabelExtractChaptersDuringLibraryScanHelp": "Генерируются рисунки сцен при импорте видео в процессе сканирования медиатеки. В противном случае, они будут извлечены в процессе назначенной задачи «Рисунки сцен», позволяя регулярному сканированию медиатеки завершаться быстрее.", + "LabelExtractChaptersDuringLibraryScan": "Извлекать изображения сцен в процессе сканирования медиатеки", + "LabelExtractChaptersDuringLibraryScanHelp": "Генерируются изображения сцен при импорте видео в процессе сканирования медиатеки. В противном случае, они будут извлечены в процессе назначенной задачи «Изображения сцен», позволяя регулярному сканированию медиатеки завершаться быстрее.", "LabelFailed": "Неудачно", "LabelFileOrUrl": "Файл или URL:", "LabelFinish": "Завершить", @@ -620,9 +620,9 @@ "LabelGroupMoviesIntoCollections": "Группировать фильмы внутрь коллекций", "LabelGroupMoviesIntoCollectionsHelp": "При отображении списка фильмов, элементы, принадлежащие к одной коллекции будут отображаться как единый сгруппированный элемент.", "LabelH264Crf": "Значение CRF H264-кодирования:", - "LabelH264EncodingPreset": "Предустановка H264-кодирования:", + "LabelEncoderPreset": "Предустановка H264-кодирования:", "LabelHardwareAccelerationType": "Аппаратное ускорение:", - "LabelHardwareAccelerationTypeHelp": "Это экспериментальная функция, имеющаяся только на поддерживаемых системах.", + "LabelHardwareAccelerationTypeHelp": "Аппаратное ускорение требует дополнительной конфигурации.", "LabelHomeNetworkQuality": "Качество в домашней сети:", "LabelHomeScreenSectionValue": "Главная страница - раздел {0}:", "LabelHttpsPort": "Номер локального HTTPS-порта:", @@ -632,8 +632,8 @@ "LabelIconMaxWidth": "Макс. ширина значка:", "LabelIconMaxWidthHelp": "Максимальное разрешение значков представляемых с помощью upnp:icon.", "LabelIdentificationFieldHelp": "Подстрока без учёта регистра, либо регулярное выражение.", - "LabelImageFetchersHelp": "Включите и ранжируйте предпочитаемые отборщики рисунков в порядке приоритета.", - "LabelImageType": "Тип рисунка:", + "LabelImageFetchersHelp": "Включите и ранжируйте предпочитаемые отборщики изображений в порядке приоритета.", + "LabelImageType": "Тип изображения:", "LabelImportOnlyFavoriteChannels": "Ограничиваться каналами обозначенными как избранное", "LabelInNetworkSignInWithEasyPassword": "Включить внутрисетевой вход со своим простым PIN-кодом", "LabelInNetworkSignInWithEasyPasswordHelp": "Используется простой PIN-код для входа в клиенты внутри своей локальной сети. Ваш обычный пароль будет необходим только вне дома. Если PIN-код не заполнен, то внутри своей домашней сети не потребуется пароль.", @@ -643,11 +643,11 @@ "LabelKodiMetadataDateFormat": "Формат даты выпуска:", "LabelKodiMetadataDateFormatHelp": "Все даты в пределах NFO-файлов будут разбираться по данному формату.", "LabelKodiMetadataEnableExtraThumbs": "Копировать extrafanart в поле extrathumbs", - "LabelKodiMetadataEnableExtraThumbsHelp": "При загрузке рисунков, их возможно сохранять внутрь extrafanart и extrathumbs для максимальной совместимости с оболочкой Kodi.", + "LabelKodiMetadataEnableExtraThumbsHelp": "Загружаемые изображения могут быть сохранены внутри полей extrafanart и extrathumbs для максимальной совместимости с оболочкой Kodi.", "LabelKodiMetadataEnablePathSubstitution": "Включить подстановки путей", - "LabelKodiMetadataEnablePathSubstitutionHelp": "Включаются подстановки путей к рисункам с помощью параметров подстановки путей сервера.", - "LabelKodiMetadataSaveImagePaths": "Сохранять пути рисунков в пределах NFO-файлов", - "LabelKodiMetadataSaveImagePathsHelp": "Рекомендуется, если имена файлов рисунков не соответствуют руководящим принципам Kodi.", + "LabelKodiMetadataEnablePathSubstitutionHelp": "Включаются подстановки путей к изображениям с помощью параметров подстановки путей сервера.", + "LabelKodiMetadataSaveImagePaths": "Сохранять пути изображений в пределах NFO-файлов", + "LabelKodiMetadataSaveImagePathsHelp": "Рекомендуется, если имена файлов изображений не соответствуют руководящим принципам Kodi.", "LabelKodiMetadataUser": "Сохранение в NFO-файле данных о просмотре пользователем:", "LabelKodiMetadataUserHelp": "Сохраняет данные о просмотрах в NFO-файлах для использования в других приложениях.", "LabelLanNetworks": "Домашние сети:", @@ -662,7 +662,7 @@ "LabelManufacturer": "Производитель:", "LabelManufacturerUrl": "URL производителя", "LabelMatchType": "Тип соответствия:", - "LabelMaxBackdropsPerItem": "Макс. число задников на элемент:", + "LabelMaxBackdropsPerItem": "Максимальное число фонов на элемент:", "LabelMaxChromecastBitrate": "Качество трансляции Chromecast:", "LabelMaxParentalRating": "Макс. допустимая возрастная категория:", "LabelMaxResumePercentage": "Макс. доля для возобновления, %:", @@ -682,12 +682,12 @@ "LabelMetadataSavers": "Хранители метаданных:", "LabelMetadataSaversHelp": "Выберите форматы файлов, куда будут сохраняться метаданные.", "LabelMethod": "Метод:", - "LabelMinBackdropDownloadWidth": "Мин. ширина загружаемого задника:", - "LabelMinResumeDuration": "Мин. длительность для возобновления:", + "LabelMinBackdropDownloadWidth": "Минимальная ширина загружаемого фона:", + "LabelMinResumeDuration": "Минимальная длительность для возобновления:", "LabelMinResumeDurationHelp": "Наименьшая длительность видео в секундах, при которой сохраняется позиция воспроизведения и позволяется возобновление.", - "LabelMinResumePercentage": "Мин. доля для возобновления, %:", + "LabelMinResumePercentage": "Минимальная доля для возобновления, %:", "LabelMinResumePercentageHelp": "Произведения предполагаются не воспроизведёнными, при остановке до данного момента.", - "LabelMinScreenshotDownloadWidth": "Мин. ширина загружаемого снимка экрана:", + "LabelMinScreenshotDownloadWidth": "Минимальная ширина загружаемого снимка экрана:", "LabelModelDescription": "Описание модели", "LabelModelName": "Наименование модели", "LabelModelNumber": "Номер модели", @@ -711,7 +711,7 @@ "LabelNumberOfGuideDaysHelp": "Больше дней загрузки данных телегида обеспечивает возможность заблаговременно назначать расписание и просматривать больше перечней, однако это займёт больше времени для загрузки. При значении «Авто» выбор определяется числом каналов.", "LabelOptionalNetworkPath": "(Необязательно) Общедоступная сетевая папка:", "LabelOptionalNetworkPathHelp": "Если данная папка общедоступна в своей сети, предоставление пути к сетевой папке может позволить Jellyfin-приложениям на других устройствах получить прямой доступ к медиафайлам.", - "LabelOriginalAspectRatio": "Исходное соот-ие сторон:", + "LabelOriginalAspectRatio": "Исходное соотношение сторон:", "LabelOriginalTitle": "Оригинальное название:", "LabelOverview": "Обзор:", "LabelParentNumber": "Родительский номер:", @@ -794,7 +794,7 @@ "LabelSubtitleDownloaders": "Загрузчики субтитров:", "LabelSubtitleFormatHelp": "Пример: srt", "LabelSubtitlePlaybackMode": "Режим субтитров:", - "LabelSubtitles": "Субтитры:", + "LabelSubtitles": "Субтитры", "LabelSupportedMediaTypes": "Поддерживаемые типы медиаданных:", "LabelTVHomeScreen": "Главная страница ТВ-режима:", "LabelTag": "Тег:", @@ -832,10 +832,10 @@ "LabelVersion": "Версия:", "LabelVersionInstalled": "Установлена: {0}", "LabelVersionNumber": "Версия {0}", - "LabelVideo": "Видео:", + "LabelVideo": "Видео", "LabelXDlnaCap": "Свойства X-Dlna:", "LabelXDlnaCapHelp": "Определяется содержание из элемента X_DLNACAP во пространстве имён urn:schemas-dlna-org:device-1-0.", - "LabelXDlnaDoc": "Схема X-Dlna:", + "LabelXDlnaDoc": "Схема X-DLNA:", "LabelXDlnaDocHelp": "Определяется содержание из элемента X_DLNADOC во пространстве имён urn:schemas-dlna-org:device-1-0.", "LabelYear": "Год:", "LabelYourFirstName": "Ваше имя:", @@ -858,18 +858,18 @@ "ManageLibrary": "Управление медиатекой", "ManageRecording": "Управлять записью", "MapChannels": "Сопоставить каналы", - "MarkPlayed": "Отметить как воспр-ое", - "MarkUnplayed": "Отметить как невоспр-ое", + "MarkPlayed": "Отметить как воспроизведенное", + "MarkUnplayed": "Отметить как невоспроизведенное", "MaxParentalRatingHelp": "Содержание с более высокой возр. категорией будет скрыто от этого пользователя.", "MediaInfoAnamorphic": "Анаморфность", - "MediaInfoAspectRatio": "Соот-ие сторон", + "MediaInfoAspectRatio": "Соотношение сторон", "MediaInfoBitDepth": "Глубина цвета", "MediaInfoBitrate": "Поток. ск-ть", "MediaInfoChannels": "Каналы", "MediaInfoCodec": "Кодек", "MediaInfoCodecTag": "Тег кодека", "MediaInfoContainer": "Контейнер", - "MediaInfoDefault": "Умолчание", + "MediaInfoDefault": "По умолчанию", "MediaInfoExternal": "Внешние", "MediaInfoForced": "Форсир-ые", "MediaInfoFramerate": "Ч-та кадров", @@ -882,7 +882,7 @@ "MediaInfoProfile": "Профиль", "MediaInfoRefFrames": "Опорные кадры", "MediaInfoResolution": "Разрешение", - "MediaInfoSampleRate": "Ч-та дискр-ии", + "MediaInfoSampleRate": "Частота дискретизации", "MediaInfoSize": "Размер", "MediaInfoTimestamp": "Метка времени", "MediaIsBeingConverted": "Медиаданные преобразуются в формат, совместимый с устройством, которое воспроизводит эти медиаданные.", @@ -890,6 +890,7 @@ "MessageAlreadyInstalled": "Данная версия уже установлена.", "MessageAreYouSureDeleteSubtitles": "Вы действительно хотите удалить данный файл субитров?", "MessageAreYouSureYouWishToRemoveMediaFolder": "Вы действительно хотите изъять данную медиапапку?", + "MessageConfirmAppExit": "Вы хотите выйти?", "MessageConfirmDeleteGuideProvider": "Вы действительно хотите удалить данного поставщика телегида?", "MessageConfirmDeleteTunerDevice": "Вы действительно хотите удалить данное устройство?", "MessageConfirmProfileDeletion": "Вы действительно хотите удалить данный профиль?", @@ -962,16 +963,16 @@ "NoNextUpItemsMessage": "Ничего не найдено. Начните смотреть свои ТВ-передачи!", "NoPluginConfigurationMessage": "В данном плагине нет параметров конфигурирования.", "NoSubtitleSearchResultsFound": "Результатов не найдено.", - "NoSubtitles": "Без субтитров", + "NoSubtitles": "Ничего", "NoSubtitlesHelp": "По умолчанию, субтитры не будут загружаться. Они могут быть все ещё включены вручную во время воспроизведения.", "None": "Ничего", "Normal": "Обычный", "NumLocationsValue": "{0} пап(ки/ок)", "Off": "Выкл", "OneChannel": "Один канал", - "OnlyForcedSubtitles": "Только форсированные субтитры", + "OnlyForcedSubtitles": "Только форсированные", "OnlyForcedSubtitlesHelp": "Загружены будут только форсированные субтитры.", - "OnlyImageFormats": "Только графические форматы (VOBSUB, PGS, SUB и т.д.)", + "OnlyImageFormats": "Только графические форматы (VOBSUB, PGS и SUB)", "OptionAdminUsers": "Администраторы", "OptionAlbum": "Альбом", "OptionAlbumArtist": "Исп. альбома", @@ -1004,7 +1005,7 @@ "OptionBlockMusic": "Музыка", "OptionBlockTrailers": "Трейлеры", "OptionBlockTvShows": "ТВ-передачи", - "OptionBluray": "BluRay", + "OptionBluray": "Blu-ray", "OptionCommunityRating": "Пользовательский рейтинг", "OptionContinuing": "Продолжающееся", "OptionCriticRating": "Оценка критиков", @@ -1021,12 +1022,12 @@ "OptionDisplayFolderView": "Отображать аспект Папки для просмотра обычных медиапапок", "OptionDisplayFolderViewHelp": "Отображение аспекта \"Папки\" рядом с другими вашими медиатеками. Это может быть полезно, если вы хотите вид обычных папок.", "OptionDownloadArtImage": "Виньетка", - "OptionDownloadBackImage": "Задник", + "OptionDownloadBackImage": "Фон", "OptionDownloadBannerImage": "Баннер", "OptionDownloadBoxImage": "DVD-бокс", "OptionDownloadDiscImage": "Диск", - "OptionDownloadImagesInAdvance": "Загружать рисунки заблаговременно", - "OptionDownloadImagesInAdvanceHelp": "По умолчанию, большинство рисунков загружаются только при запросе от Jellyfin-приложения. Включите данную опцию, чтобы загружать все рисунки заблаговременно, при импорте новых медиаданных. Это может привести к существенно длительным сканированиям медиатеки.", + "OptionDownloadImagesInAdvance": "Загружать изображения заблаговременно", + "OptionDownloadImagesInAdvanceHelp": "По умолчанию, большинство изображений загружаются только при запросе от Jellyfin-приложения. Включите данную опцию, чтобы загружать все изображения заблаговременно, при импорте новых медиаданных. Это может привести к существенно длительным сканированиям медиатеки.", "OptionDownloadLogoImage": "Логотип", "OptionDownloadMenuImage": "Меню", "OptionDownloadPrimaryImage": "Основной", @@ -1036,7 +1037,6 @@ "OptionEnableAccessFromAllDevices": "Включить доступ со всех устройств", "OptionEnableAccessToAllChannels": "Включить доступ ко всем каналам", "OptionEnableAccessToAllLibraries": "Включить доступ ко всем медиатекам", - "OptionEnableAutomaticServerUpdates": "Включить автоматические обновления сервера", "OptionEnableExternalContentInSuggestions": "Включать внешнее содержание в предложения", "OptionEnableExternalContentInSuggestionsHelp": "Разрешить охват интернет-трейлеров и эфирных передач в предлагаемом содержании.", "OptionEnableForAllTuners": "Включить для всех тюнерных устройств", @@ -1047,7 +1047,7 @@ "OptionEstimateContentLength": "Рассчитывать длину содержимого при перекодировке", "OptionEveryday": "Ежедневно", "OptionExternallyDownloaded": "Внешние загружаемые", - "OptionExtractChapterImage": "Включить извлечение рисунков сцен", + "OptionExtractChapterImage": "Включить извлечение изображений сцен", "OptionFavorite": "Избранное", "OptionFriday": "пятница", "OptionHasSpecialFeatures": "Доп. материалы", @@ -1094,7 +1094,7 @@ "OptionResumable": "Возможно возобновление", "OptionRuntime": "Длительность", "OptionSaturday": "суббота", - "OptionSaveMetadataAsHidden": "Сохранять метаданные и рисунки в виде скрытых файлов", + "OptionSaveMetadataAsHidden": "Сохранять метаданные и изображения в виде скрытых файлов", "OptionSaveMetadataAsHiddenHelp": "Это изменение будет применено к новым метаданным сохраняемым в будущем. Существующие файлы метаданных будут обновлены в следующий раз, когда они будут сохраняться на Jellyfin Server.", "OptionSpecialEpisode": "Спецэпизоды", "OptionSubstring": "Подстрока", @@ -1112,10 +1112,10 @@ "OptionWeekly": "Еженедельно", "OriginalAirDateValue": "Дата исходного эфира: {0}", "Overview": "Обзор", - "PackageInstallCancelled": "Установка {0} отменена.", - "PackageInstallCompleted": "Установка {0} завершена.", - "PackageInstallFailed": "Установка {0} неудачна.", - "ParentalRating": "Возр. кат-ия", + "PackageInstallCancelled": "Установка {0} (версия {1}) отменена.", + "PackageInstallCompleted": "Установка {0} (версия {1}) завершена.", + "PackageInstallFailed": "Установка {0} (версия {1}) неудачна.", + "ParentalRating": "Возрастная категория", "PasswordMatchError": "Пароль и подтверждение пароля должны совпадать.", "PasswordResetComplete": "Пароль был сброшен.", "PasswordResetConfirmation": "Вы действительно хотите сбросить пароль?", @@ -1128,10 +1128,10 @@ "PinCodeResetComplete": "PIN-код был сброшен.", "PinCodeResetConfirmation": "Вы действительно хотите сбросить PIN-код?", "PlaceFavoriteChannelsAtBeginning": "Разместить избранные каналы в начале", - "Play": "Воспр.", - "PlayAllFromHere": "Воспр. все отсюда", + "Play": "Воспроизведение", + "PlayAllFromHere": "Воспроизвести все отсюда", "PlayCount": "Кол. воспроизведений", - "PlayFromBeginning": "Воспр. с начала", + "PlayFromBeginning": "Воспроизвести с начала", "PlayNext": "Воспроизвести следующее", "PlayNextEpisodeAutomatically": "Воспроизводить последующий эпизод автоматически", "Played": "Воспроизведено", @@ -1181,7 +1181,7 @@ "RepeatMode": "Режим повтора", "RepeatOne": "Повторить раз", "ReplaceAllMetadata": "Замена всех метаданных", - "ReplaceExistingImages": "Замена имеющихся рисунков", + "ReplaceExistingImages": "Замена имеющихся изображений", "RequiredForAllRemoteConnections": "Требуется для всех внешних подключений", "RestartPleaseWaitMessage": "Подождите, пока Jellyfin Server выключится и перезапустится. Это может занять минуту или две.", "ResumeAt": "Возобновить с {0}", @@ -1219,10 +1219,12 @@ "Share": "Поделиться", "ShowAdvancedSettings": "Показать расширенные параметры", "ShowIndicatorsFor": "Показывать метки для:", - "ShowTitle": "Название передачи", - "ShowYear": "Год передачи", + "ShowTitle": "Отображать название", + "ShowYear": "Отображать год", "Shows": "Передачи", "Shuffle": "Перемешать", + "New": "Новинка", + "Filter": "Фильтр", "SimultaneousConnectionLimitHelp": "Максимальное количество разрешённых одновременных потоков. Введите 0, чтобы снять ограничения.", "SkipEpisodesAlreadyInMyLibrary": "Не записывать эпизоды, которые уже находятся в моей медиатеке", "SkipEpisodesAlreadyInMyLibraryHelp": "Эпизоды будут сравниваться с помощью номеров сезонов и эпизодов, когда они имеются.", @@ -1245,7 +1247,7 @@ "Subtitles": "Субтитры", "Suggestions": "Предлагаемое", "Sunday": "воскресенье", - "Sync": "Синхро", + "Sync": "Синхронизация", "SystemDlnaProfilesHelp": "Системные профили доступны только для чтения. Правки системного профиля будут сохранены в новом настраиваемом профиле.", "TV": "ТВ", "TabAccess": "Доступ", @@ -1260,7 +1262,7 @@ "TabContainers": "Контейнеры", "TabDashboard": "Панель", "TabDevices": "Устройства", - "TabDirectPlay": "Прямое воспр-ие", + "TabDirectPlay": "Прямое воспроизведение", "TabDisplay": "Отображение", "TabEpisodes": "Эпизоды", "TabFavorites": "Избранное", @@ -1348,7 +1350,7 @@ "ValueSeconds": "{0} сек", "ValueSeriesCount": "{0} сериал(а/ов)", "ValueSongCount": "{0} композици(и/й)", - "ValueSpecialEpisodeName": "Спецэпизод - {0}", + "ValueSpecialEpisodeName": "Специальный эпизод - {0}", "ValueTimeLimitMultiHour": "Временной лимит: {0} час(а/ов)", "ValueTimeLimitSingleHour": "Временной лимит: 1 час", "ValueVideoCodec": "Видео кодек: {0}", @@ -1375,7 +1377,7 @@ "LabelDynamicExternalId": "{0} Ид:", "LeaveBlankToNotSetAPassword": "Оставьте пустым, чтобы не назначать пароль.", "MessageImageFileTypeAllowed": "Поддерживаются только файлы JPEG и PNG.", - "MessageImageTypeNotSelected": "Выберите тип рисунка из выпадающего меню.", + "MessageImageTypeNotSelected": "Выберите тип изображения из выпадающего меню.", "OptionResElement": "res-элемент", "AuthProviderHelp": "Выберите поставщика аутентификации, который будет использоваться для аутентификации пароля этого пользователя.", "HeaderFavoriteMovies": "Избранные фильмы", @@ -1397,13 +1399,13 @@ "DashboardServerName": "Сервер: {0}", "DashboardOperatingSystem": "Операционная система: {0}", "DashboardArchitecture": "Архитектура: {0}", - "LabelWeb": "Веб: ", + "LabelWeb": "Веб:", "LaunchWebAppOnStartup": "Запустить веб-интерфейс при запуске Jellyfin Server", "LaunchWebAppOnStartupHelp": "Открывается веб-клиент в браузере по умолчанию при начальном запуске сервера. Это не произойдет при использовании функции перезапуска сервера.", "MediaInfoSoftware": "ПО", "MediaInfoStreamTypeAudio": "Аудио", "MediaInfoStreamTypeData": "Данные", - "MediaInfoStreamTypeEmbeddedImage": "Внедрённый рисунок", + "MediaInfoStreamTypeEmbeddedImage": "Встроенное изображение", "MediaInfoStreamTypeSubtitle": "Субтитры", "MediaInfoStreamTypeVideo": "Видео", "MessageNoCollectionsAvailable": "Коллекции позволяют вам наслаждаться персонализированными группами фильмов, сериалов и альбомов. Нажмите кнопку +, чтобы начать создавать коллекции.", @@ -1421,14 +1423,14 @@ "OptionLoginAttemptsBeforeLockoutHelp": "При значении 0 наследуются по умолчанию три попытки для обычных пользователей и пять для администратора. При установке этого значения в -1 функция отключается.", "OptionPoster": "Постер", "OptionPosterCard": "Постер-карта", - "OptionThumb": "Бегунок", - "OptionThumbCard": "Бегунок-карта", + "OptionThumb": "Эскиз", + "OptionThumbCard": "Эскиз-карта", "PasswordResetProviderHelp": "Выберите поставщика сброса пароля, который будет использоваться, когда этот пользователь запрашивает сброс пароля", "PlaybackData": "Данные воспроизведения", "SubtitleOffset": "Сдвиг субтитров", "TabNetworking": "Работа в сети", "LabelBaseUrlHelp": "Здесь вы можете добавить пользовательский подкаталог для доступа к серверу с более уникального URL.", - "LabelPlayer": "Игрок:", + "LabelPlayer": "Проигрыватель:", "MoreMediaInfo": "О медиаданных", "LabelVideoCodec": "Видео кодек:", "LabelVideoBitrate": "Потоковая скорость аудио:", @@ -1438,8 +1440,8 @@ "LabelPlayMethod": "Метод воспроизведения:", "LabelFolder": "Папка:", "LabelBaseUrl": "Базовый URL:", - "LabelBitrate": "Поток. ск-ть:", - "LabelAudioSampleRate": "Ч-та дискр-ии аудио:", + "LabelBitrate": "Битрейт:", + "LabelAudioSampleRate": "Частота дискретизации аудио:", "LabelAudioCodec": "Аудио кодек:", "LabelAudioChannels": "Аудио каналы:", "LabelAudioBitrate": "Потоковая скорость аудио:", @@ -1447,11 +1449,62 @@ "HeaderFavoriteBooks": "Избранные книги", "CopyStreamURL": "Копировать URL потока", "LabelPleaseRestart": "Изменения вступят в силу после перезагрузки веб-клиента вручную.", - "CopyStreamURLSuccess": "URL скопирован успешно.", + "CopyStreamURLSuccess": "URL скопирован успешно.", "MusicLibraryHelp": "Просмотрите {0}руководство по именованию музыки{1}.", "FetchingData": "Выборка дополнительных данных", - "ButtonAddImage": "Добавить рисунок", + "ButtonAddImage": "Добавить изображение", "HeaderFavoritePeople": "Избранные люди", "OptionRandom": "Случайный", - "ButtonSplit": "Разделить" + "ButtonSplit": "Разделить", + "SelectAdminUsername": "Выберите имя пользователя для учётной записи администратора.", + "HeaderNavigation": "Навигация", + "LabelVideoResolution": "Разрешение видео:", + "LabelStreamType": "Тип потока:", + "EnableFastImageFadeInHelp": "Включить быстрое появление анимации для загруженных изображений", + "EnableFastImageFadeIn": "Быстрое появление изображения", + "LabelPlayerDimensions": "Размеры проигрывателя:", + "LabelDroppedFrames": "Пропущенные кадры:", + "LabelCorruptedFrames": "Испорченные кадры:", + "CopyStreamURLError": "Произошла ошибка при копировании URL.", + "OptionForceRemoteSourceTranscoding": "Принудительное перекодирование удалённых источников медиаданных (например, эфирное ТВ)", + "NoCreatedLibraries": "Похоже, вы еще не создали ни одной медиатеки. {0}Желаете создать её сейчас?{1}", + "AskAdminToCreateLibrary": "Попросите администратора создать медиатеку.", + "AllowFfmpegThrottling": "Притормаживать перекодировку", + "PlaybackErrorNoCompatibleStream": "Этот клиент несовместим с медиаданными, а сервер не отправляет медиаданные в совместимом формате.", + "AllowFfmpegThrottlingHelp": "Когда перекодирование или переупаковка достаточно далеко опережают текущую позицию воспроизведения, процесс приостанавливается, так что он использует меньше ресурсов. Это наиболее полезно, когда вы редко меняете позиции в видео. Выключите это, если у вас возникли проблемы с воспроизведением.", + "OnWakeFromSleep": "При пробуждении ото сна", + "YadifBob": "YADIF с удвоением", + "OnApplicationStartup": "При запуске приложения", + "EveryXHours": "Каждые {0} часов", + "EveryHour": "Каждый час", + "EveryXMinutes": "Каждые {0} мин", + "WeeklyAt": "{0} в {1}", + "DailyAt": "Ежедневно в {0}", + "PersonRole": "как {0}", + "ListPaging": "{0}-{1} из {2}", + "Yadif": "YADIF", + "Track": "Дорожка", + "Season": "Сезон", + "Person": "Персона", + "OtherArtist": "Другой исполнитель", + "Movie": "Фильм", + "LabelLibraryPageSize": "Размер страницы медиатеки:", + "Episode": "Эпизод", + "ClientSettings": "Параметры клиента", + "BoxSet": "Коллекция", + "Artist": "Исполнитель", + "AlbumArtist": "Исполнитель альбома", + "Album": "Альбом", + "LastSeen": "Последний раз был {0}", + "WriteAccessRequired": "Jellyfin Server требуются права на запись в эту папку. Обеспечьте доступ для записи и попробуйте снова.", + "PathNotFound": "Путь не может быть найден. Убедитесь, что путь правильный и попробуйте снова.", + "ReleaseGroup": "Релиз-группа", + "PreferEmbeddedEpisodeInfosOverFileNames": "Предпочитать встроенную информацию эпизода вместо имён файлов", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Используется информация об эпизоде из встроенных метаданных, если они доступны.", + "LabelLibraryPageSizeHelp": "Устанавливается количество элементов для отображения на странице медиатеки. Установите 0 для отключения нумерации страниц.", + "LabelDeinterlaceMethod": "Метод устранения гребёнки:", + "DeinterlaceMethodHelp": "Выберите метод устранения гребёнки, который будет использоваться при перекодировании чересстрочного содержания.", + "UnsupportedPlayback": "Jellyfin не может расшифровать содержимое, защищенное DRM, но в любом случае будет предпринята попытка расшифровки всего содержимого, включая защищенные заголовки. Некоторые файлы могут выглядеть полностью черными из-за шифрования или других неподдерживаемых функций, таких как интерактивные заголовки.", + "MessageUnauthorizedUser": "В настоящее время у вас нет доступа к серверу. Пожалуйста, свяжитесь с администратором сервера для получения дополнительной информации.", + "HeaderFavoritePlaylists": "Избранные плей-листы" } diff --git a/src/strings/sk.json b/src/strings/sk.json index 127624ade0..12da34c1bd 100644 --- a/src/strings/sk.json +++ b/src/strings/sk.json @@ -5,14 +5,14 @@ "Albums": "Albumy", "All": "Všetko", "AllChannels": "Všetky kanály", - "AllComplexFormats": "Všetky komplexné formáty (ASS, SSA, VOBSUB, PGS, SUB/IDX, atď)", + "AllComplexFormats": "Všetky komplexné formáty (ASS, SSA, VOBSUB, PGS, SUB, IDX, …)", "AllEpisodes": "Všetky epizódy", "AllLanguages": "Všetky jazyky", "AllLibraries": "Všetky knižnice", "AllowMediaConversion": "Povoliť konverziu médií", "AllowRemoteAccess": "Povoliť vzdialené pripojenia k tomuto Jellyfin serveru.", "AllowRemoteAccessHelp": "Nezaškrtnuté znamená, že všetky vzdialené pripojenia budú blokované.", - "AlwaysPlaySubtitles": "Vždy zobraziť titulky", + "AlwaysPlaySubtitles": "Vždy prehrať", "AnyLanguage": "Akýkoľvek jazyk", "AroundTime": "Okolo {0}", "Artists": "Umelci", @@ -21,17 +21,17 @@ "AspectRatio": "Pomer strán", "AttributeNew": "Nové", "AutoBasedOnLanguageSetting": "Automaticky (na základe nastavenia jazyka)", - "Backdrops": "Pozadie", - "BirthDateValue": "Narodil sa: {0}", + "Backdrops": "Pozadia", + "BirthDateValue": "Narodený/á: {0}", "BirthLocation": "Miesto narodenia", "BirthPlaceValue": "Miesto narodenia: {0}", "BookLibraryHelp": "Audioknihy a učebnice sú podporované. Prečítajte si {0}pravidlá pre názvy kníh v Jellyfine{1}.", "Books": "Knihy", "ButtonAdd": "Pridať", "ButtonAddMediaLibrary": "Pridať knižnicu médií", - "ButtonAddScheduledTaskTrigger": "Pridať spúštač", + "ButtonAddScheduledTaskTrigger": "Pridať spúšťač", "ButtonAddServer": "Pridať server", - "ButtonAddUser": "Pridať užívateľa", + "ButtonAddUser": "Pridať používateľa", "ButtonArrowDown": "Dole", "ButtonArrowLeft": "Vľavo", "ButtonArrowRight": "Vpravo", @@ -61,7 +61,7 @@ "ButtonNextTrack": "Nasledujúca stopa", "ButtonOpen": "Otvoriť", "ButtonParentalControl": "Rodičovská kontrola", - "ButtonPause": "Pauza", + "ButtonPause": "Pozastaviť", "ButtonPlay": "Prehrať", "ButtonPreviousTrack": "Predchádzajúca stopa", "ButtonProfile": "Profil", @@ -89,13 +89,13 @@ "ButtonSort": "Zoradiť", "ButtonSubmit": "Potvrdiť", "ButtonSubtitles": "Titulky", - "ButtonTrailer": "Ukážka", + "ButtonTrailer": "Trailer", "ButtonUninstall": "Odinštalovať", "ButtonUp": "Hore", - "ButtonViewWebsite": "Zobraziť web stránku", + "ButtonViewWebsite": "Zobraziť webovú stránku", "ButtonWebsite": "Webové stránky", "Categories": "Kategórie", - "ChannelAccessHelp": "Zvoľte kanály zdieľané s týmto užívateľom. Administrátori budú schopní upraviť všetky kanály použitím správcu metadát.", + "ChannelAccessHelp": "Zvoľte kanály zdieľané s týmto používateľom. Administrátori budú schopní upraviť všetky kanály použitím správcu metadát.", "Channels": "Kanály", "Collections": "Kolekcie", "ColorSpace": "Farebný priestor", @@ -109,8 +109,8 @@ "CriticRating": "Hodnotenie kritikov", "DateAdded": "Dátum pridania", "DatePlayed": "Dátum prehrania", - "DeathDateValue": "Zomrel: {0}", - "DefaultErrorMessage": "Pri spracúvaní požiadavky došlo k chybe. Skúste prosím neskôr znova.", + "DeathDateValue": "Zomrel/a: {0}", + "DefaultErrorMessage": "Pri spracovaní požiadavky došlo k chybe. Prosím, skúste to neskôr znova.", "Delete": "Zmazať", "DeleteDeviceConfirmation": "Ste si istý, že chcete odstrániť toto zariadenie? Objaví sa znovu, keď sa ním používateľ nabudúce prihlási.", "DeleteImage": "Zmazať obrázok", @@ -120,16 +120,15 @@ "DeleteUserConfirmation": "Ste si istý, že chcete zmazať tohto používateľa?", "Descending": "Zostupne", "Desktop": "Stolný počítač", - "DetectingDevices": "Detegujem zariadenia", - "DeviceAccessHelp": "Táto možnosť sa vzťahuje iba na zariadenia, ktoré môžu byť jedinečne identifikované a nezabráni prístup cez prehliadač. Filtrovaním prístupu užívateľských zariadení zabraňuje užívateľom použiť nové zariadenie, pokiaľ neboli tu schválené.", + "DetectingDevices": "Hľadám zariadenia", + "DeviceAccessHelp": "Táto možnosť sa vzťahuje iba na zariadenia, ktoré môžu byť jedinečne identifikované a nezabráni prístup cez prehliadač. Filtrovaním prístupu používateľských zariadení zabraňuje užívateľom použiť nové zariadenie, pokiaľ neboli tu schválené.", "Director": "Režisér", - "DirectorValue": "Režisér: {0}", - "DirectorsValue": "Režiséri: {0}", + "Directors": "Režiséri", "Disc": "Disk", "Disconnect": "Odpojiť", "Dislike": "Nepáči sa mi to", "DisplayInMyMedia": "Zobraziť na domácej obrazovke", - "DisplayMissingEpisodesWithinSeasons": "Zobraziť chýbajúce epizódy v rámci sezóny", + "DisplayMissingEpisodesWithinSeasons": "Zobraziť chýbajúce epizódy v rámci série", "DoNotRecord": "Nenahrávať", "Down": "Dole", "Download": "Stiahnuť", @@ -152,22 +151,21 @@ "Favorite": "Obľúbené", "Favorites": "Obľúbené", "File": "Súbor", - "FileNotFound": "Súbor nenájdený.", + "FileNotFound": "Súbor nebol nájdený.", "FileReadError": "Pri čítaní súboru nastala chyba.", "Filters": "Filtre", "FolderTypeBooks": "Knihy", "FolderTypeMovies": "Filmy", "FolderTypeMusic": "Hudba", "FolderTypeMusicVideos": "Hudobné videá", - "FolderTypeTvShows": "TV", + "FolderTypeTvShows": "Seriály", "FolderTypeUnset": "Zmiešaný obsah", "FormatValue": "Formát: {0}", "Friday": "Piatok", - "Fullscreen": "Na celú obrazovku", + "Fullscreen": "Celá obrazovka", "General": "Všeobecné", - "GenreValue": "Žáner: {0}", + "Genre": "Žáner", "Genres": "Žánre", - "GenresValue": "Žánre: {0}", "GroupBySeries": "Zoskupiť podľa série", "GuestStar": "Hosťujúca hviezda", "Guide": "Sprievodca", @@ -177,9 +175,9 @@ "HeaderActiveDevices": "Aktívne zariadenia", "HeaderActiveRecordings": "Aktívne nahrávky", "HeaderActivity": "Aktivita", - "HeaderAddToCollection": "Pridať do zbierky", - "HeaderAddUpdateImage": "Pridať/nahrať obrázok", - "HeaderAddUser": "Pridať užívateľa", + "HeaderAddToCollection": "Pridať do kolekcie", + "HeaderAddUpdateImage": "Pridať/aktualizovať obrázok", + "HeaderAddUser": "Pridať používateľa", "HeaderAlbums": "Albumy", "HeaderApiKey": "Kľúč API", "HeaderApiKeys": "Kľúče API", @@ -187,11 +185,11 @@ "HeaderAudioSettings": "Nastavenia zvuku", "HeaderAutomaticUpdates": "Automatické aktualizácie", "HeaderBooks": "Knihy", - "HeaderCastAndCrew": "Obsadenie", + "HeaderCastAndCrew": "Obsadenie a štáb", "HeaderChannels": "Kanály", "HeaderChapterImages": "Obrázky kapitol", "HeaderConfigureRemoteAccess": "Nastaviť vzdialený prístup", - "HeaderConfirmPluginInstallation": "Potvrdiť inštaláciu rozšírenia", + "HeaderConfirmPluginInstallation": "Potvrdiť inštaláciu zásuvných modulov", "HeaderConfirmProfileDeletion": "Potvrdiť zmazanie profilu", "HeaderConnectToServer": "Propojiť sa k serveru", "HeaderConnectionFailure": "Chyba pripojenia", @@ -225,7 +223,7 @@ "HeaderItems": "Položky", "HeaderLatestEpisodes": "Najnovšie epizódy", "HeaderLatestMedia": "Najnovšie médiá", - "HeaderLatestMovies": "Posledne pridané Filmy", + "HeaderLatestMovies": "Najnovšie filmy", "HeaderLatestMusic": "Najnovšia hudba", "HeaderLatestRecordings": "Najnovšie nahrávky", "HeaderLibraries": "Knižnice", @@ -238,7 +236,7 @@ "HeaderMedia": "Médiá", "HeaderMediaInfo": "Informácie o médiu", "HeaderMetadataSettings": "Nastavenia metadát", - "HeaderMoreLikeThis": "Podobné", + "HeaderMoreLikeThis": "Podobné ako toto", "HeaderMovies": "Filmy", "HeaderMusicQuality": "Kvalita hudby", "HeaderMusicVideos": "Hudobné videá", @@ -271,7 +269,7 @@ "HeaderRunningTasks": "Bežiace úlohy", "HeaderScenes": "Scény", "HeaderSchedule": "Rozvrh", - "HeaderSeasons": "Sezóny", + "HeaderSeasons": "Série", "HeaderSecondsValue": "{0} sekúnd", "HeaderSelectPath": "Vybrať priečinok", "HeaderSelectServer": "Vybrať server", @@ -308,7 +306,7 @@ "Identify": "Identifikovať", "Images": "Obrázky", "ImportMissingEpisodesHelp": "Ak je možnosť povolená, informácie o chýbajúcich epizódach budú importované do Vašej Jellyfin databázy a budú zobrazené v sériách a seriáloch. Toto môže spôsobiť podstatne dlhšie skenovania knižníc.", - "InstallingPackage": "Inštalujem {0}", + "InstallingPackage": "Inštalujem {0} (verzia{1})", "ItemCount": "{0} položiek", "Items": "Položky", "Kids": "Detské", @@ -320,7 +318,7 @@ "LabelAllowServerAutoRestart": "Povoliť automatický reštart servera pre aplikovanie aktualizácií", "LabelAllowServerAutoRestartHelp": "Server sa reštartuje iba počas obdobia bez aktivity, keď nie je žiadny používateľ aktívny.", "LabelAllowedRemoteAddresses": "Filter vzdialených IP adries:", - "LabelAppName": "Názov apky", + "LabelAppName": "Názov aplikácie", "LabelAppNameExample": "Príklad: Sickbeard, Sonarr", "LabelArtists": "Umelci:", "LabelArtistsHelp": "Oddeľte pomocou ;", @@ -328,13 +326,13 @@ "LabelAutomaticallyRefreshInternetMetadataEvery": "Automaticky obnoviť metadáta z internetu:", "LabelBirthDate": "Dátum narodenia:", "LabelBirthYear": "Rok narodenia:", - "LabelCachePath": "Cesta k medzipamäti:", + "LabelCachePath": "Cesta k cache:", "LabelCachePathHelp": "Špecifikujte vlastnú cestu pre cache súbory ako sú napr. obrázky. Ponechajte prázdne pre pôvodné nastavenia servera.", "LabelCancelled": "Zrušené", "LabelCertificatePassword": "Heslo certifikátu:", "LabelCertificatePasswordHelp": "Ak váš certifikát vyžaduje heslo, zadajte ho tu prosím.", "LabelChannels": "Kanály:", - "LabelCollection": "Zbierka:", + "LabelCollection": "Kolekcia:", "LabelCommunityRating": "Hodnotenie komunity:", "LabelContentType": "Typ obsahu:", "LabelCountry": "Krajina:", @@ -376,11 +374,11 @@ "LabelFont": "Písmo:", "LabelForgotPasswordUsernameHelp": "Zadajte svoje používateľské meno, ak si ho pamätáte.", "LabelFormat": "Formát:", - "LabelServerNameHelp": "Toto meno bude použité na identifikáciu servera. Ak ostane prázdne, bude použitý názov počítača.", + "LabelServerNameHelp": "Tento názov bude použitý na identifikáciu servera. Ak ostane prázdny, bude použitý názov počítača.", "LabelGroupMoviesIntoCollections": "Zoskupiť filmy do kolekcií", "LabelGroupMoviesIntoCollectionsHelp": "Pri zobrazení zoznamu filmov budú filmy patriace do kolekcie zobrazené ako jedna zoskupená položka.", "LabelHardwareAccelerationType": "Hardvérová akcelerácia:", - "LabelHardwareAccelerationTypeHelp": "Toto je experimentálna funkcia a je dostupná len na podporovaných systémoch.", + "LabelHardwareAccelerationTypeHelp": "Hardvérová akcelerácia vyžaduje dodatočnú konfiguráciu.", "LabelHomeScreenSectionValue": "Sekcia domácej obrazovky {0}:", "LabelHttpsPort": "Lokálny HTTPS port:", "LabelIconMaxHeight": "Maximálna výška ikony:", @@ -450,14 +448,14 @@ "LabelProtocolInfo": "Info o protokole:", "LabelPublicHttpPort": "Verejný HTTP port:", "LabelPublicHttpsPort": "Verejný HTTPS port:", - "LabelReadHowYouCanContribute": "Zistite ako môžete prispieť.", + "LabelReadHowYouCanContribute": "Zistite, ako môžete prispieť.", "LabelRecordingPath": "Predvolené umiestnenie nahrávok:", "LabelRecordingPathHelp": "Uveďte predvolené umiestnenie pre ukladanie nahrávok. Ak je ponechané prázdne, použije sa priečinok s programovými dátami servera.", "LabelReleaseDate": "Dátum vydania:", "LabelRuntimeMinutes": "Dĺžka (minúty):", "LabelSaveLocalMetadata": "Uložiť obaly a metadáta do priečinka s médiami", "LabelScreensaver": "Šetrič obrazokvy:", - "LabelSeasonNumber": "Číslo sezóny:", + "LabelSeasonNumber": "Číslo série:", "LabelSelectUsers": "Zvoľte užívateľov:", "LabelSelectVersionToInstall": "Vyberte verziu, ktorú chcete nainštalovať:", "LabelSerialNumber": "Sériové číslo", @@ -473,7 +471,7 @@ "LabelStartWhenPossible": "Spustiť akonáhle je možné:", "LabelStatus": "Stav:", "LabelSubtitleFormatHelp": "Príklad: srt", - "LabelSubtitles": "Titulky:", + "LabelSubtitles": "Titulky", "LabelSupportedMediaTypes": "Podporované typy médií:", "LabelTextBackgroundColor": "Farba pozadia textu:", "LabelTextColor": "Farba textu:", @@ -490,7 +488,7 @@ "LabelTunerType": "Typ tunera:", "LabelType": "Typ:", "LabelUseNotificationServices": "Použiť nasledovné služby:", - "LabelUser": "Užívateľ:", + "LabelUser": "Používateľ:", "LabelUsername": "Používateľské meno:", "LabelValue": "Hodnota:", "LabelVersion": "Verzia:", @@ -503,7 +501,7 @@ "LabelffmpegPath": "Cesta k FFmpeg:", "Large": "Veľké", "LatestFromLibrary": "Najnovšie {0}", - "LearnHowYouCanContribute": "Zistite ako môžete prispieť.", + "LearnHowYouCanContribute": "Zistite, ako môžete prispieť.", "LibraryAccessHelp": "Zvoľte knižnice zdieľané s týmto používateľom. Administrátori budú schopní upraviť všetky priečinky použitím správcu metadát.", "Like": "Páči sa mi to", "Live": "Naživo", @@ -513,7 +511,7 @@ "ManageRecording": "Spravovať nahrávanie", "MarkPlayed": "Označiť ako prehrané", "MarkUnplayed": "Označiť ako neprehrané", - "MaxParentalRatingHelp": "Obsah s vyšším rodičovským hodnotením bude skrytý pre tohto užívateľa.", + "MaxParentalRatingHelp": "Obsah s vyšším rodičovským hodnotením bude skrytý pre tohto používateľa.", "MediaInfoAspectRatio": "Pomer strán", "MediaInfoBitDepth": "Bitová hĺbka", "MediaInfoChannels": "Kanály", @@ -546,8 +544,8 @@ "MessageInvalidUser": "Nesprávne meno alebo heslo. Skúste prosím znovu.", "MessageItemSaved": "Položka uložená.", "MessageItemsAdded": "Položky pridané.", - "MessageNoAvailablePlugins": "Žiadne dostupné rozšírenia.", - "MessageNoPluginsInstalled": "Nemáte nainštalované žiadne rozšírenia.", + "MessageNoAvailablePlugins": "Žiadne dostupné zásuvné moduly.", + "MessageNoPluginsInstalled": "Nemáte nainštalované žiadne zásuvné moduly.", "MessageNothingHere": "Nič tu nie je.", "MessagePleaseEnsureInternetMetadata": "Prosím, uistite sa, že sťahovanie internetových metadát je povolené.", "MessagePleaseWait": "Prosím počkajte. Toto môže chvíľu trvať.", @@ -569,7 +567,7 @@ "MySubtitles": "Moje titulky", "Name": "Meno", "Never": "Nikdy", - "NewCollection": "Nová zbierka", + "NewCollection": "Nová kolekcia", "NewCollectionNameExample": "Príklad: Kolekcia Star Wars", "NewEpisodes": "Nové epizódy", "NewEpisodesOnly": "Iba nové epizódy", @@ -580,12 +578,12 @@ "NoNextUpItemsMessage": "Nič nenájdené. Začnite pozerať vaše seriály!", "NoPluginConfigurationMessage": "Tento zásuvný modul nemá žiadne nastavenia.", "NoSubtitleSearchResultsFound": "Žiadne výsledky.", - "NoSubtitles": "Žiadne titulky", + "NoSubtitles": "Žiadne", "None": "Žiadne", "Normal": "Normálne", "NumLocationsValue": "{0} priečinkov", "OneChannel": "Jeden kanál", - "OnlyForcedSubtitles": "Iba vynútené titulky", + "OnlyForcedSubtitles": "Iba vynútené", "OnlyForcedSubtitlesHelp": "Budú zobrazené iba titulky označené ako vynútené.", "OptionAdminUsers": "Administrátori", "OptionAllUsers": "Všetci používatelia", @@ -609,7 +607,7 @@ "OptionBlockBooks": "Knihy", "OptionBlockMovies": "Filmy", "OptionBlockMusic": "Hudba", - "OptionBlockTrailers": "Ukážky", + "OptionBlockTrailers": "Trailery", "OptionCommunityRating": "Hodnotenie komunity", "OptionContinuing": "Pokračuje", "OptionCriticRating": "Hodnotenie kritikov", @@ -620,8 +618,8 @@ "OptionDateAddedImportTime": "Podľa dátumu pridania do knižnice", "OptionDatePlayed": "Dátum prehrania", "OptionDescending": "Zostupne", - "OptionDisableUser": "Zakázať tohto užívateľa", - "OptionDisableUserHelp": "Ak možnosť nie je povolená, server nepovolí žiadne pripojenia od tohto užívateľa. Aktívne pripojenia budú ihneď ukončené.", + "OptionDisableUser": "Zakázať tohto používateľa", + "OptionDisableUserHelp": "Ak možnosť nie je povolená, server nepovolí žiadne pripojenia od tohto používateľa. Aktívne pripojenia budú ihneď ukončené.", "OptionDislikes": "Nepáči sa", "OptionDownloadArtImage": "Obal", "OptionDownloadBackImage": "Späť", @@ -632,7 +630,6 @@ "OptionEnableAccessFromAllDevices": "Povoliť prístup zo všetkých zariadení", "OptionEnableAccessToAllChannels": "Povoliť prístup ku všetkým kanálom", "OptionEnableAccessToAllLibraries": "Povoliť prístup ku všetkým knižniciam", - "OptionEnableAutomaticServerUpdates": "Povoliť automatické aktualizácie servera", "OptionEnableM2tsMode": "Povoliť M2ts mód", "OptionEnableM2tsModeHelp": "Povoliť režim M2TS pri kódovaní do MPEGTS.", "OptionEnded": "Ukončené", @@ -650,8 +647,8 @@ "OptionLikes": "Páči sa", "OptionMissingEpisode": "Chýbajúce epizódy", "OptionMonday": "Pondelok", - "OptionNameSort": "Meno", - "OptionNew": "Nové...", + "OptionNameSort": "Názov", + "OptionNew": "Nové…", "OptionNone": "Žiadne", "OptionOnAppStartup": "Pri spustení aplikácie", "OptionParentalRating": "Rodičovské hodnotenie", @@ -680,9 +677,9 @@ "OptionWeekly": "Týždenne", "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.", + "PackageInstallCancelled": "{0} (verzia{1}) inštalácia zrušená.", + "PackageInstallCompleted": "{0} (verzia{1}) inštalácia dokončená.", + "PackageInstallFailed": "{0} (verzia {1}) inštalácia zlyhala.", "ParentalRating": "Parental Rating", "PasswordMatchError": "Heslo a potvrdenie hesla sa musia zhodovať.", "PasswordResetComplete": "Heslo bolo obnovené.", @@ -725,7 +722,7 @@ "RefreshMetadata": "Obnoviť metadáta", "ReleaseDate": "Dátum vydania", "RememberMe": "Zapamätať si ma", - "RemoveFromCollection": "Odobrať zo zbierky", + "RemoveFromCollection": "Odobrať z kolekcie", "Repeat": "Opakovať", "RepeatAll": "Opakovať všetko", "RepeatOne": "Opakovať jedno", @@ -752,7 +749,7 @@ "SeriesSettings": "Nastavenia série", "ServerNameIsRestarting": "Jellyfin Server - {0} sa reštartuje.", "ServerNameIsShuttingDown": "Jellyfin Server - {0} sa vypína.", - "ServerRestartNeededAfterPluginInstall": "Po inštalácii rozšírenia bude potrebný reštart Jellyfin servera.", + "ServerRestartNeededAfterPluginInstall": "Po inštalácii zásuvného modulu bude potrebný reštart Jellyfin servera.", "ServerUpdateNeeded": "Tento Jellyfin server treba aktualizovať. Najnovšiu verziu nájdete na {0}", "Settings": "Nastavenia", "SettingsSaved": "Nastavenia uložené.", @@ -782,7 +779,7 @@ "TabCodecs": "Kodeky", "TabCollections": "Zbierky", "TabContainers": "Kontajnery", - "TabDashboard": "Prístrojová doska", + "TabDashboard": "Dashboard", "TabDevices": "Zariadenia", "TabEpisodes": "Epizódy", "TabFavorites": "Obľúbené", @@ -794,14 +791,14 @@ "TabMovies": "Filmy", "TabMusic": "Hudba", "TabMusicVideos": "Hudobné videá", - "TabMyPlugins": "Moje rozšírenia", + "TabMyPlugins": "Moje zásuvné moduly", "TabNetworks": "Siete", "TabNfoSettings": "NFO nastavenia", "TabNotifications": "Upozornenia", "TabOther": "Iné", "TabParentalControl": "Rodičovská kontrola", "TabPassword": "Heslo", - "TabPlugins": "Rozšírenia", + "TabPlugins": "Zásuvné moduly", "TabProfile": "Profil", "TabProfiles": "Profily", "TabRecordings": "Nahrávky", @@ -813,7 +810,7 @@ "TabShows": "Seriály", "TabSongs": "Skladby", "TabSuggestions": "Návrhy", - "TabTrailers": "Ukážky", + "TabTrailers": "Trailery", "TabTranscoding": "Transkódovanie", "TabUpcoming": "Nadchádzajúce", "TabUsers": "Užívatelia", @@ -822,7 +819,7 @@ "Thursday": "Štvrtok", "TitleHardwareAcceleration": "Hardvérová akcelerácia", "TrackCount": "{0} stôp", - "Trailers": "Ukážky", + "Trailers": "Trailery", "Tuesday": "Utorok", "UninstallPluginConfirmation": "Ste si istý, že chcete odinštalovať {0}?", "UninstallPluginHeader": "Odinštalovať rozšírenie", @@ -871,7 +868,7 @@ "ButtonSelectView": "Výber zobrazenia", "CancelRecording": "Zrušiť nahrávanie", "AirDate": "Dátum vysielania", - "Aired": "Vysielané", + "Aired": "Odvysielané", "Alerts": "Upozornenia", "AllowOnTheFlySubtitleExtraction": "Povoliť extrahovanie titulkov za behu", "ButtonFilter": "Filter", @@ -887,7 +884,7 @@ "Display": "Zobrazenie", "EnableBackdrops": "Pozadia", "EnableDisplayMirroring": "Zrkadlenie obrazu", - "Ended": "Ukončené", + "Ended": "Ukončený", "FileReadCancelled": "Čítanie súboru bolo zrušené.", "Folders": "Priečinky", "GuideProviderLogin": "Prihlásenie", @@ -904,7 +901,7 @@ "HeaderStatus": "Stav", "LabelAccessEnd": "Koniec:", "LabelAccessStart": "Začiatok:", - "LabelAirsAfterSeason": "Vysielané po sezóne:", + "LabelAirsAfterSeason": "Vysielané po sérií:", "LabelAlbum": "Album:", "LabelCustomRating": "Vlastné hodnotenie:", "LabelDynamicExternalId": "{0} Id:", @@ -927,17 +924,17 @@ "MessageImageFileTypeAllowed": "Sú podporované iba súbory JPEG a PNG.", "Playlists": "Playlisty", "Sync": "Synchronizácia", - "Box": "Puzdro", - "BoxRear": "Zadnýá časť puzdra", + "Box": "Obal", + "BoxRear": "Obal (zadná časť)", "ButtonLibraryAccess": "Prístup ku knižnici", "ConfirmDeleteItem": "Zmazaním tejto položky odstránite súbor zo súborového systému aj z knižnice médií. Ste si istý/á, že chcete pokračovať?", "ConfirmDeleteItems": "Zmazaním týchto položiek odstránite súbory zo súborového systému aj z knižnice médií. Ste si istý/á, že chcete pokračovať?", - "Continuing": "Pokračovanie", + "Continuing": "Pokračujúci", "Default": "Predvolené", "DirectStreamHelp2": "Priame streamovanie súboru používa veľmi málo procesorového výkonu bez straty kvality videa.", "DirectStreaming": "Priame streamovanie", "DisplayMissingEpisodesWithinSeasonsHelp": "Toto musí byť povolené pre TV knižnice v nastavení servera.", - "DisplayModeHelp": "Zvoľte typ obrazovky, na ktorej používate Jellyfin.", + "DisplayModeHelp": "Vyberte štýl layoutu, ktorý chcete pre rozhranie.", "EnableCinemaMode": "Kino režim", "EnableNextVideoInfoOverlay": "Zobraziť informácie o nasledujúcom videu počas prehrávania", "EnableNextVideoInfoOverlayHelp": "Na konci videa sa zobrazia informácie o nasledujúcom videu v aktuálnom playliste.", @@ -945,7 +942,7 @@ "HeaderAddScheduledTaskTrigger": "Pridať spúšťač", "HeaderAddToPlaylist": "Pridať do playlistu", "HeaderAlert": "Upozornenie", - "HeaderCastCrew": "Herci a obsadenie", + "HeaderCastCrew": "Obsadenie a štáb", "HeaderDownloadSync": "Sťahovanie a synchronizácia", "HeaderExternalIds": "Externé ID:", "HeaderFeatureAccess": "Prístup k funkciám", @@ -955,18 +952,18 @@ "HeaderMediaFolders": "Priečinky médií", "HeaderRemoveMediaFolder": "Odstrániť priečinok médií", "HeaderSelectCertificatePath": "Vybrať cestu k certifikátu", - "HeaderSortOrder": "Poradie zoradzovania", + "HeaderSortOrder": "Poradie zoraďovania", "HeaderSpecialEpisodeInfo": "Informácie o špeciálnej epizóde", - "HeaderSpecialFeatures": "Špeciálne funkcie", + "HeaderSpecialFeatures": "Bonusové materiály", "HeaderSubtitleDownloads": "Sťahovanie titulkov", "HeaderTags": "Tagy", "HeaderVideoType": "Typ videa", "HeaderVideoTypes": "Typy videí", - "LabelAirsBeforeSeason": "Vysielané pred sezónou:", - "LabelAudio": "Zvuk:", + "LabelAirsBeforeSeason": "Vysielané pred sériou:", + "LabelAudio": "Zvuk", "LabelBlockContentWithTags": "Blokovať položky s tagmi:", "LabelDisplayMode": "Režim zobrazenia:", - "LabelDisplaySpecialsWithinSeasons": "Zobraziť špeciálne epizódy v sezóne, v ktorej boli odvysielané", + "LabelDisplaySpecialsWithinSeasons": "Zobraziť špeciálne epizódy v sérií, v ktorej boli odvysielané", "Option3D": "3D", "OptionAlbum": "Album", "OptionBluray": "Blu-ray", @@ -976,8 +973,8 @@ "OptionDownloadPrimaryImage": "Primárne", "OptionDvd": "DVD", "OptionExtractChapterImage": "Povoliť extrakciu obrázkov z videa", - "OptionHasSpecialFeatures": "Špeciálne fukncie", - "OptionHasTrailer": "Ukážka/Trailer", + "OptionHasSpecialFeatures": "Bonusové materiály", + "OptionHasTrailer": "Trailer", "OptionIsHD": "HD", "OptionIsSD": "SD", "OptionList": "Zoznam", @@ -1017,7 +1014,7 @@ "ValueOneAlbum": "1 album", "Absolute": "Absolútne", "LabelDidlMode": "DIDL režim:", - "LabelDateTimeLocale": "Miestne nastavenia dátumu:", + "LabelDateTimeLocale": "Lokálne nastavenia dátumu:", "LabelBlastMessageInterval": "Doba zobrazenie správy (sekundy)", "LabelAlbumArtMaxWidth": "Maximálna šírka obrázku albumu:", "LabelAlbumArtMaxHeight": "Maximálna výška obrázku albumu:", @@ -1029,7 +1026,7 @@ "ThemeSongs": "Tématická hudba", "TabInfo": "Info", "TV": "TV", - "SkipEpisodesAlreadyInMyLibraryHelp": "Epizódy budú porovnané na základe čísla sezóny a epizódy, ak sú k dispozícii.", + "SkipEpisodesAlreadyInMyLibraryHelp": "Epizódy budú porovnané na základe čísla série a epizódy, ak sú k dispozícii.", "SimultaneousConnectionLimitHelp": "Maximálny povolený počet súčasných streamov. Zadajte 0 pre vypnutie obmedzenia.", "RepeatEpisodes": "Opakovanie epizód", "Record": "Nahrávať", @@ -1039,7 +1036,7 @@ "OptionEnableForAllTuners": "Povoliť pre všetky tunery", "OptionEnableExternalContentInSuggestions": "Povoliť externý obsah v návrhoch", "OptionBlockChannelContent": "Obsah internetového kanála", - "OnlyImageFormats": "Iba obrazové formáty (VOBSUB, PGS, SUB, atď)", + "OnlyImageFormats": "Iba obrazové formáty (VOBSUB, PGS, SUB)", "Off": "Vypnuté", "MusicVideo": "Videoklip", "MusicArtist": "Interpret", @@ -1050,11 +1047,11 @@ "HeaderSeriesOptions": "Nastavenia seriálov", "HeaderRestartingServer": "Server sa reštartuje", "HeaderParentalRatings": "Rodičovské hodnotenia", - "HeaderEnabledFields": "Povolenie polia", + "HeaderEnabledFields": "Povolené polia", "HeaderAudioLanguages": "Jazyk zvuku", "HeaderAllowMediaDeletionFrom": "Povoliť zmazanie médií z", "HeaderAdmin": "Admin", - "EnableThemeVideos": "Videá uvodných zvučiek", + "EnableThemeVideos": "Videá úvodných zvučiek", "EnableThemeSongs": "Úvodné zvučky", "EnablePhotosHelp": "Obrázky budú detekované a zobrazené spolu s ostatnými multimediálnymi súbormi.", "EnableColorCodedBackgrounds": "Farebne označené pozadia", @@ -1071,13 +1068,13 @@ "LabelDropShadow": "Vrhať tieň:", "LabelDownMixAudioScaleHelp": "Zosilnenie zvuku pri downmixe. Nastavenie hodnoty na 1 zachová pôvodnú hlasitosť.", "LabelDownMixAudioScale": "Zosilnenie zvuku pri downmixe:", - "LabelDisplayName": "Zobrazované meno:", + "LabelDisplayName": "Zobrazovaný názov:", "LabelDisplayLanguageHelp": "Preklad Jellyfinu je v neustálom vývoji.", "LabelDefaultUserHelp": "Určuje, ktorá používateľská knižnica by mala byť zobrazená na pripojenom zariadení. Toto nastavenie môže byť prepísané pomocou profilov pre každé zariadenie.", "LabelDateAddedBehaviorHelp": "Pokiaľ majú metadáta hodnotu, bude vždy použitá pred niektorou z týchto možností.", "LabelDashboardTheme": "Téma dashboardu servera:", "LabelCustomDeviceDisplayNameHelp": "Nahradte vlastným názvom alebo ponechajte prázdne, aby názov určilo zariadenie.", - "LabelCustomDeviceDisplayName": "Zobrazené meno:", + "LabelCustomDeviceDisplayName": "Zobrazený názov:", "LabelCache": "Cache:", "LabelBurnSubtitles": "Vypáliť titulky:", "LabelBitrate": "Dátový tok:", @@ -1127,10 +1124,10 @@ "HeaderFavoriteBooks": "Obľúbené knihy", "HeaderEnabledFieldsHelp": "Zrušte zaškrtnutie, aby ste zabránili zmenám dát.", "HeaderDisplay": "Zobrazenie", - "HeaderDirectPlayProfile": "Profil Direct Play", - "HeaderDeveloperInfo": "Vývojárske informácie", + "HeaderDirectPlayProfile": "Profil Priameho prehrávania", + "HeaderDeveloperInfo": "Informácie pre vývojára", "HeaderDeleteTaskTrigger": "Vymazať spúšťač úlohy", - "HeaderDefaultRecordingSettings": "Východzie nastavenia nahrávania", + "HeaderDefaultRecordingSettings": "Predvolené nastavenia nahrávania", "HeaderCodecProfileHelp": "Profily kodekov označujú obmedzenia zariadenia pri prehrávaní pomocou špecifických kodekov. Pokiaľ je obmedzenie aplikované, médium bude transkódované aj pokiaľ je kodek nakonfigurovaný na priame prehrávanie.", "HeaderContainerProfileHelp": "Profily kontajnerov označujú obmedzenia zariadenia pri prehrávaní pomocou špecifických formátov. Pokiaľ je obmedzenie aplikované, médium bude transkódované aj pokiaľ je formát nakonfigurovaný na priame prehrávanie.", "HeaderContainerProfile": "Profily kontajnerov", @@ -1141,13 +1138,13 @@ "HeaderBranding": "Značka", "HeaderBlockItemsWithNoRating": "Blokované položky so žiadnymi alebo nerozpoznanými informáciami o hodnotení:", "HeaderAppearsOn": "Objaví sa", - "HeaderApp": "Aplikácia", - "HeaderApiKeysHelp": "Externé aplikácie musia mať vlastný API kľúč, aby mohli komunikovať s Jellyfin Serverom. Kľúče sú vydávané pomocou prihlásenia sa cez Jellyfin účet alebo manuálnym priradením kľúča aplikacií.", + "HeaderApp": "Appka", + "HeaderApiKeysHelp": "Externé aplikácie musia mať vlastný API kľúč, aby mohli komunikovať s Jellyfin Serverom. Kľúče sú vydávané pomocou prihlásenia sa cez Jellyfin účet alebo manuálnym priradením kľúča aplikácií.", "HeaderAdditionalParts": "Dodatočné časti", - "HardwareAccelerationWarning": "Povolenie hardvérovej akcelerácie môže spôsobiť nestabilitu v niektorých podmienkach. Uistite sa, že váš operačný systém a grafické ovládače sú plne aktualizované. Pokiaľ máte po zapnutí problémy s prehrávaním videa, budete musieť zmeniť nastavenie späť na Auto.", + "HardwareAccelerationWarning": "Povolenie hardvérovej akcelerácie môže spôsobiť nestabilitu v niektorých podmienkach. Uistite sa, že váš operačný systém a grafické ovládače sú plne aktualizované. Pokiaľ máte po zapnutí problémy s prehrávaním videa, budete musieť zmeniť nastavenie späť na Žiadne.", "AddItemToCollectionHelp": "Pridať položku do kolekcie jej vyhľadaním a použitím pravého tlačítka myši alebo kliknutím na tlačidlo ponuky a pridať do kolekcie.", "HandledByProxy": "Spracované pomocou reverznej proxy", - "H264EncodingPresetHelp": "Vyberte hodnotu faster pre zlepšenie výkonu alebo hodnotu slower pre zlepšenie kvality.", + "EncoderPresetHelp": "Vyberte hodnotu faster pre zlepšenie výkonu alebo hodnotu slower pre zlepšenie kvality.", "H264CrfHelp": "Constant Rate Factor (CRF) je východzím nastavením kvality pre x264 enkodér. Môžete mu nadstaviť hodnotu medzi 0 a 51, kde nižšia hodnota vedie k vyššej kvalite (za cenu väčšieho súboru). Rozumné hodnoty sú medzi 18 a 28. Východzia hodnota pre x264 je 23, ktorú môžete použiť ako začiatočný bod.", "GuideProviderSelectListings": "Výber zobrazenia", "GroupVersions": "Skupinové verzie", @@ -1164,26 +1161,26 @@ "EnableThemeVideosHelp": "Prehrať videá úvodných zvučiek na pozadí počas prechádzania knižnice.", "EnableThemeSongsHelp": "Prehrať úvodnú zvučku na pozadí pri prechádzaní knižnice.", "EnableStreamLoopingHelp": "Povolte, pokiaľ živé vysielanie obsahuje len pár sekúnd dát a nemusí byť nepretržite požadované. Pokiaľ bude táto funkcia povolená v prípade, že nebude potrebná, môže spôsobiť problémy.", - "EnableStreamLooping": "Auto. cyklenie živých streamov", + "EnableStreamLooping": "Auto cyklenie živých vysielaní", "EnableExternalVideoPlayersHelp": "Ponuka externého prehrávača sa zobrazí pri spustení prehrávania videa.", "EnableBackdropsHelp": "Zobraziť pozadia na pozadí pre niektoré stránky pri prechádzaní knižnice.", "DisplayInOtherHomeScreenSections": "Zobrazenie v sekciách domovskej obrazovky, ako sú najnovšie médiá a pokračovať v pozeraní", - "DirectStreamHelp1": "Médium je kompatibilné zo zariadením nezávisle na rozlíšení alebo type média (H.264, AC3, atď), je však v nekompatibilnom kontajneri (mkv, avi, wmv, atď). Video bude za behu prebalené do kompatibilného kontajnera ešte pred streamovaním do zariadenia.", + "DirectStreamHelp1": "Médium je kompatibilné zo zariadením nezávisle na rozlíšení alebo type média (H.264, AC3, atď.), je však v nekompatibilnom kontajneri (mkv, avi, wmv, atď.). Video bude za behu prebalené do kompatibilného kontajnera ešte pred streamovaním do zariadenia.", "Depressed": "Stlačený", - "DefaultSubtitlesHelp": "Titulky sú načítané v závislosti od východzích a vynútených nastavení v zabudovaných metadátach. Jazykové predvoľby sú zobrané do úvahy až vtedy, keď je k dispozícií viacero možností.", - "DefaultMetadataLangaugeDescription": "Toto sú vaše východzie hodnoty ktoré môžu byť prispôsobené na základe jednotlivých knižníc.", + "DefaultSubtitlesHelp": "Titulky sú načítané v závislosti od predvolených a vynútených nastavení v zabudovaných metadátach. Jazykové predvoľby sú zobrané do úvahy až vtedy, keď je k dispozícií viacero možností.", + "DefaultMetadataLangaugeDescription": "Toto sú vaše predvolené hodnoty ktoré môžu byť prispôsobené na základe jednotlivých knižníc.", "CustomDlnaProfilesHelp": "Vytvorte si vlastný profil pre nové zariadenie alebo pre prepísanie systémového profilu.", "CopyStreamURLSuccess": "URL úspešne skopírovaná.", "CopyStreamURL": "Kopírovať URL adresu streamu", "ConfigureDateAdded": "Konfigurácia, ako sa pridáva dátum, je definovaná v dashboarde Jellyfin Servera pod nastavením Knižnice", "ColorTransfer": "Farba prenosu", "ColorPrimaries": "Primárna farba", - "CinemaModeConfigurationHelp": "Kino režim prináša zážitok ako z kina priamo do vašej obývačky s možnosťou prehrať ukážky a vlastné intrá pred hlavným programom.", + "CinemaModeConfigurationHelp": "Kino režim prináša zážitok ako z kina priamo do vašej obývačky s možnosťou prehrať trailery a vlastné intrá pred hlavným programom.", "ChangingMetadataImageSettingsNewContent": "Zmeny v nastavení metadát alebo v sťahovaní artworkov sa budú vzťahovať len na nový obsah pridaný do vašej knižnice. Pokiaľ chcete aplikovať zmeny na existujúce položky, musíte ich aktualizovať manuálne.", "CancelSeries": "Ukončiť seriál", "ButtonSplit": "Rozdeliť", "ButtonAddImage": "Pridať obrázok", - "BurnSubtitlesHelp": "Určuje, či má server vypaľovať titulky počas prevodu videa v závislosti na formáte tituliek. Vynechanie tejto možnosti výrazne zvýši výkon serveru. Vyberte možnosť Auto, pokiaľ chcete vypálovať do obrazu titulky v grafickom formáte (VOBSUB, PGS, SUB/IDX, atď) a niektoré ASS/SSA titulky.", + "BurnSubtitlesHelp": "Určuje, či má server vpáliť titulky počas transkódovania videa. Vynechanie tejto možnosti výrazne zvýši výkon. Vyberte možnosť Auto, pokiaľ chcete vpáliť do obrazu titulky v grafickom formáte (VOBSUB, PGS, SUB, IDX, …) a niektoré ASS alebo SSA titulky.", "BrowsePluginCatalogMessage": "Prehliadnite si náš katalóg dostupných zásuvných modulov.", "Browse": "Prechádzať", "Blacklist": "Blacklist", @@ -1192,12 +1189,12 @@ "Art": "Umenie", "AlwaysPlaySubtitlesHelp": "Titulky odpovedajúce jazykovej preferencií sa načítajú bez ohľadu na jazyk zvuku.", "AllowedRemoteAddressesHelp": "Zoznam IP adries alebo IP/netmask záznamov pre siete oddelené čiarkami z ktorých sa dá vzdialene pripojiť. Pokiaľ zoznam bude prázdny, všetky adresy budú povolené.", - "AllowOnTheFlySubtitleExtractionHelp": "Vložené titulky môžu byť extrahované z videa a prenesené na klienta vo forme jednoduchého textu aby sa zabránilo transkódovaniu videa. Na niektorých systémoch táto operácia môže trvať dlhší čas a a spôsobiť sekanie videa počas počas extrahovania. Vypnutie tejto funkcie bude mať za následok, že titulky budú počas transkódovania vypálené do samotného videa pokiaľ klientské zariadenie natívne nepodporuje ich formát.", + "AllowOnTheFlySubtitleExtractionHelp": "Vložené titulky môžu byť extrahované z videa a prenesené na klienta vo forme jednoduchého textu, aby sa zabránilo transkódovaniu videa. Na niektorých systémoch táto operácia môže trvať dlhší čas a a spôsobiť sekanie videa počas počas extrahovania. Vypnutie tejto funkcie bude mať za následok, že titulky budú počas transkódovania vypálené do samotného videa pokiaľ klientské zariadenie natívne nepodporuje ich formát.", "Watched": "Pozreté", "TvLibraryHelp": "Pozrite sa na {0}sprievodcu pomenovania TV programov{1}.", "LabelLineup": "Lineup:", "ErrorAddingListingsToSchedulesDirect": "Nastala chyba pri pridávaní lineupu do účtu vášho Direct plánovača. Direct plánovač umožňuje len obmedzený počet lineupov na účet. Možno sa budete musieť prihlásiť na web Direct plánovača a odstrániť ostatné záznamy z vášho účtu pred pokračovaním.", - "Features": "Fukcie", + "Features": "Funkcie", "XmlTvPathHelp": "Cesta k XMLTV súboru. Jellyfin tento súbor načíta a pravidelne ho skontroluje, či neobsahuje aktualizácie. Ste zodpovedný za vytvorenie a aktualizovanie tohoto súboru.", "XmlTvNewsCategoriesHelp": "Programy s týmito kategóriami budú zobrazené ako spravodajské programy. Viacej kategórií oddelte \"|\".", "XmlTvMovieCategoriesHelp": "Programy s týmito kategóriami budú zobrazené ako filmy. Viacej kategórií oddelte \"|\".", @@ -1210,7 +1207,7 @@ "TitleHostingSettings": "Nastavenie hostingu", "Thumb": "Náhľad", "TheseSettingsAffectSubtitlesOnThisDevice": "Toto nastavenie ovplyvní titulky na tomto zariadení", - "TabNetworking": "Sieťovanie", + "TabNetworking": "Sieť", "TabDisplay": "Zobrazenie", "TabAlbumArtists": "Umelec albumu", "SystemDlnaProfilesHelp": "Systémové profily sú len na čítanie. Zmeny systémových profilov budú uložené do nového vlastné profilu.", @@ -1235,7 +1232,7 @@ "PreferEmbeddedTitlesOverFileNamesHelp": "Toto určuje východzí názov zobrazenia, pokiaľ nie sú k dispozícií internetové metadáta alebo lokálne metadáta.", "PreferEmbeddedTitlesOverFileNames": "Preferovať vložené názvy nad názvami súborov", "PleaseConfirmPluginInstallation": "Prosím, kliknite na OK pre potvrdenie, že ste prečítali text uvedený vyššie a chcete pokračovať v inštalácií zásuvného modulu.", - "PlaybackData": "Dáta prehrávania", + "PlaybackData": "Podrobnosti prehrávania", "PlayAllFromHere": "Prehrať všetko odtiaľto", "PasswordResetProviderHelp": "Zvoľte poskytovateľa obnovy hesla, ktorý bude použitý, keď používateľ požiada o obnovu hesla", "OptionThumbCard": "Náhľadové kartičky", @@ -1259,7 +1256,7 @@ "OptionIgnoreTranscodeByteRangeRequests": "Ignorovať požiadavky na transkódovanie bajtového rozsahu", "OptionHlsSegmentedSubtitles": "HLS segmentované titulky", "OptionExternallyDownloaded": "Externé sťahovanie", - "OptionEnableExternalContentInSuggestionsHelp": "Povoliť zahrnutie internetových ukážok a živých TV programov do navrhovaného obsahu.", + "OptionEnableExternalContentInSuggestionsHelp": "Povoliť zahrnutie internetových trailerov a živých TV programov do navrhovaného obsahu.", "OptionDownloadImagesInAdvanceHelp": "Vo východzom stave sa väčšina obrázkov sťahuje až po vyžiadaní Jellyfin aplikáciou. Povolením tejto možnosti sa budú všetky obrázky sťahovať popredu, keď sa budú importovať nové médiá. Toto môže spôsobiť výrazne dlhšie skenovanie knižnice.", "OptionDownloadBoxImage": "Krabica", "OptionDownloadBannerImage": "Banner", @@ -1272,7 +1269,7 @@ "OptionAllowVideoPlaybackRemuxing": "Povoliť prehrávanie videa, ktoré vyžaduje konverziu bez opätovného enkódovania", "OptionAllowSyncTranscoding": "Povoliť sťahovanie a synchronizáciu medií, ktoré vyžadujú transkódovanie", "OptionAllowMediaPlaybackTranscodingHelp": "Obmedzenie prístupu ku transkódovaniu môže spôsobiť zlyhania prehrávania v Jellyfin aplikáciách kvôli nepodporovaným formátom medií.", - "MessageNoTrailersFound": "Ukážky neboli nájdené. Nainštalujte Ukážkový kanál pre rozšírenie vášho filmového zážitku pridaním knižnice ukážok z internetu.", + "MessageNoTrailersFound": "Neboli nájdené žiadne trailery. Nainštalujte Trailer kanál pre rozšírenie vášho filmového zážitku pridaním knižnice trailerov z internetu.", "LanNetworksHelp": "Zoznam IP adries alebo IP/netmask záznamov pre všetky siete oddelené čiarkami ktoré budú považované za lokálnu sieť pri vynucovaní obmedzenia šírky pásma. Pokiaľ je toto nastavené, všetky ostatné IP adresy budú považované za vonkajšiu sieť a budú podliehať obmedzeniam šírky pásma vonkajšej siete. Pokiaľ pole ostane prázdne, podsieť serveru bude považovaná za lokálnu sieť.", "LabelUserAgent": "User agent:", "LabelEnableBlastAliveMessagesHelp": "Povolte v prípade, že server nie je viditeľný inými UPnP zariadeniami na vašej sieti.", @@ -1330,7 +1327,7 @@ "LabelXDlnaCap": "X-DLNA cap:", "LabelVideoCodec": "Video kodek:", "LabelVideoBitrate": "Dátový tok videa:", - "LabelVideo": "Video:", + "LabelVideo": "Video", "LabelVaapiDeviceHelp": "Toto je vykreslovací node, ktorý sa používa na hardvérovú akceleráciu.", "LabelVaapiDevice": "VA API zariadenie:", "LabelUserRemoteClientBitrateLimitHelp": "Prepíše východzie globálne hodnoty nastavené v nastavení prehrávania servera.", @@ -1431,7 +1428,7 @@ "LabelIconMaxHeightHelp": "Maximálne rozlíšenie ikon pomocou prostredníctvom upnp:icon.", "LabelHttpsPortHelp": "Číslo TCP portu, na ktoré by sa mal naviazať Jellyfin HTTPS server.", "LabelHomeNetworkQuality": "Kvalita na domácej sieti:", - "LabelH264EncodingPreset": "Prednastavené H264 enkódovanie:", + "LabelEncoderPreset": "Prednastavené H264 enkódovanie:", "LabelH264Crf": "H264 enkódovanie CRF:", "LabelFriendlyName": "Priateľský názov:", "LabelFolder": "Priečinok:", @@ -1445,7 +1442,7 @@ "LabelEnableDlnaDebugLogging": "Povoliť loggovanie DLNA debugu", "LabelEnableDlnaClientDiscoveryIntervalHelp": "Určuje dobu trvania v sekundách medzi SSDP vyhľadávaniami vykonanými Jellyfinom.", "LabelEnableDlnaClientDiscoveryInterval": "Interval pre objavenie klienta (sekundy)", - "LabelEnableAutomaticPortMapHelp": "Pokus o automatické namapovanie vejerného portu na lokálny port cez UPnP. Toto nemusí fungovať so všetkými modelmi routerov.", + "LabelEnableAutomaticPortMapHelp": "Pokus o automatické namapovanie vejerného portu na lokálny port cez UPnP. Toto nemusí fungovať so všetkými modelmi routerov. Zmeny sa vykonajú až po reštarte servera.", "LabelEmbedAlbumArtDidlHelp": "Niektoré zariadenia preferujú túto metódu pre získavanie obrázku albumu. Ostatným môže zlyhať prehrávanie pokiaľ je táto možnosť povolená.", "LabelBlastMessageIntervalHelp": "Určuje dobu v sekundách medzi vysielaniami správ o serveri.", "LabelBindToLocalNetworkAddressHelp": "Voliteľné. Prepísať lokálnu IP adresu viazanú na http server. Pokiaľ zostane prázdna, server sa naviaže na všetky dostupné adresy. Pri zmene tejto hodnoty sa vyžaduje reštart Jellyfin Servera.", @@ -1453,7 +1450,63 @@ "LabelAlbumArtMaxWidthHelp": "Maximálne rozlíšenie obrázku albumu prostredníctvom upnp:albumArtURI.", "LabelAlbumArtMaxHeightHelp": "Maximálne rozlíšenie obrázku albumu prostredníctvom upnp:albumArtURI.", "LabelAlbumArtHelp": "PN používa obrázok albumu, vrámci dlna:profileID atribútu upnp:albumArtURI. Niektoré zariadenia vyžadujú špecifickú hodnotu, bez ohľadu na veľkosť obrázku.", - "HeaderDirectPlayProfileHelp": "Pridať direct play profil pre definovanie, ktorý formát môže zariadenie natívne zvládnuť.", + "HeaderDirectPlayProfileHelp": "Pridať profil priameho prehrávania pre definovanie, ktorý formát môže zariadenie natívne zvládnuť.", "LabelInNetworkSignInWithEasyPasswordHelp": "Použite jednoduchý PIN kód na prihlásenie v klientoch vo vnútri lokálnej siete. Vaše bežné heslo bude potrebné len pokiaľ ste mimo domova. Pokiaľ je PIN kód ponechaný prázdny, tak nebude potrebovať heslo vo vašej domácej sieti.", - "EasyPasswordHelp": "Váš jednoduchý PIN kód sa dá používať v režime offline na podporovaných zariadeniach a taktiež môže byť použitý ako jednoduché prihlásenie v lokálnej sieti." + "EasyPasswordHelp": "Váš jednoduchý PIN kód sa dá používať v režime offline na podporovaných zariadeniach a taktiež môže byť použitý ako jednoduché prihlásenie v lokálnej sieti.", + "HeaderNavigation": "Navigácia", + "MessageConfirmAppExit": "Chceli by ste odísiť?", + "LabelVideoResolution": "Rozlíšenie videa:", + "LabelStreamType": "Typ streamu:", + "EnableFastImageFadeInHelp": "Povoliť animáciu rýchleho rozjasnenia pre nahrané obrázky", + "EnableFastImageFadeIn": "Rýchle rozjasnenie obrázku", + "LabelPlayerDimensions": "Rozmery prehrávača:", + "LabelDroppedFrames": "Vynechané snímky:", + "LabelCorruptedFrames": "Poškodené snímky:", + "CopyStreamURLError": "Pri kopírovaní URL nastala chyba.", + "OptionForceRemoteSourceTranscoding": "Vynútiť transkódovanie vzdialených mediálnych zdrojov (ako napr. živá TV)", + "NoCreatedLibraries": "Vyzerá to tak, že ste zatiaľ nevytvorili žiadnu knižnicu. {0}Chceli by ste nejakú vytvoriť teraz?{1}", + "AskAdminToCreateLibrary": "Pokiaľ chcete vytvoriť knižnicu, musíte sa spýtať administrátora.", + "PlaybackErrorNoCompatibleStream": "Tento klient nie je kompatibilný s médiom a server neposiela kompatibilný mediálny formát.", + "AllowFfmpegThrottlingHelp": "Keď sa transkódovanie alebo remuxovanie dostane do bodu, kedy je dostatočne vopred voči súčasnej polohe prehrávania, pozastaví proces aby spotrebovával menej zdrojov. Toto je najviac užitočné, keď sa pozerá obsah bez pretáčania. Vypnite túto možnosť, pokiaľ má vaše prehrávanie problémy.", + "AllowFfmpegThrottling": "Obmedzenie transkódovania", + "PreferEmbeddedEpisodeInfosOverFileNames": "Preferovať vložen[ informáciu o epizóde pred názvom súboru", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Toto využíva informáciu o epizóde z vložených metadát, pokiaľ sú dostupne.", + "ClientSettings": "Nastavenie klienta", + "Album": "Album", + "DeinterlaceMethodHelp": "Vyberte metódu odstránenia prekladania obrazu videa pri transkódovaní prekladaného obsahu.", + "OnApplicationStartup": "Pri spustení aplikácie", + "EveryXHours": "Každých {0} hodín", + "EveryHour": "Každú hodinu", + "EveryXMinutes": "Každých {0} minút", + "OnWakeFromSleep": "Pri prebúdzaní zo spánku", + "WeeklyAt": "{0}s na {1}", + "DailyAt": "Denne o {0}", + "LastSeen": "Naposledy videný {0}", + "PersonRole": "ako {0}", + "ListPaging": "{0}-{1} z {2}", + "WriteAccessRequired": "Jellyfin Server vyžaduje práva na zapisovanie do tohoto priečinku. Prosím, uistite sa že má práva na zapisovanie a skúste to znova.", + "PathNotFound": "Táto cesta nebola nájdená. Prosím, uistite sa že cesta je správna a skúste to znovu.", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Track": "Stopa", + "Season": "Séria", + "ReleaseGroup": "Vydavateľ", + "Person": "Osoba", + "OtherArtist": "Ostatný umelci", + "Movie": "FIlm", + "LabelDeinterlaceMethod": "Metóda odstránenia prekladaného videa:", + "Episode": "Epizóda", + "BoxSet": "Box Set", + "Artist": "Umelec", + "AlbumArtist": "Umelec albumu", + "LabelLibraryPageSizeHelp": "Určuje množstvo položiek na zobrazenie na stránke knižnice. Nastavte 0 pre vypnutie stránkovania.", + "LabelLibraryPageSize": "Veľkosť stránky knižnice:", + "MessageUnauthorizedUser": "Momentálne nemáte oprávnenie na prístup k serveru. Prosím, kontaktujte svojho administrátora serveru pre viac informácií.", + "UnsupportedPlayback": "Jellyfin nemôže dešifrovať obsah chránený technológiou DRM, ale pokúsi sa o to, vrátane chránených titulov. Niektoré súbory sa môžu zobraziť ako kompletne čierne z dôvodu, že sú zašifrované alebo obsahujú nepodporované funckie, ako napríklad interaktívne funkcie.", + "Filter": "Filter", + "New": "Nové", + "HeaderFavoritePlaylists": "Obľúbené playlisty", + "ButtonTogglePlaylist": "Playlist", + "ButtonToggleContextMenu": "Viac", + "ApiKeysCaption": "Zoznam v súčasnosti povolených API kľúčov" } diff --git a/src/strings/sl-si.json b/src/strings/sl-si.json index a1e40cad95..a692edbd3f 100644 --- a/src/strings/sl-si.json +++ b/src/strings/sl-si.json @@ -26,7 +26,7 @@ "LabelNext": "Naprej", "LabelPrevious": "Nazaj", "LabelSelectUsers": "Izberi uporabnike:", - "LabelTimeLimitHours": "Casovna omejitev (ure):", + "LabelTimeLimitHours": "Časovna omejitev (ure):", "LabelYourFirstName": "Ime:", "LabelYoureDone": "Koncano!", "MoreUsersCanBeAddedLater": "Uporabnike lahko dodate tudi kasneje preko Nadzorne plošče.", @@ -39,7 +39,7 @@ "OptionHasSubtitles": "Podnapisi", "OptionLikes": "Všeč mi je", "OptionPlayed": "Predvajano", - "OptionReleaseDate": "Datum Izdaje", + "OptionReleaseDate": "Datum izida", "OptionUnplayed": "Nepredvajano", "ParentalRating": "Ocena za starše", "Settings": "Nastavitve", @@ -58,10 +58,10 @@ "TabProfiles": "Profili", "TabShows": "Oddaje", "TabSuggestions": "Predlogi", - "TabUpcoming": "V prihodu", + "TabUpcoming": "Prihajajoče", "TellUsAboutYourself": "Povej nam nekaj o sebi", "ThisWizardWillGuideYou": "Čarovnik vas bo vodil skozi postopek namestitve. Za začetek, izberite jezik.", - "WelcomeToProject": "Dobrodosli v Jellyfin!", + "WelcomeToProject": "Dobrodošli v Jellyfin!", "Absolute": "Absolutno", "AccessRestrictedTryAgainLater": "Dostop je trenutno omejen. Poskusite ponovno kasneje.", "Actor": "Igralec", @@ -92,7 +92,7 @@ "Books": "Knjige", "Channels": "Kanali", "Collections": "Zbirke", - "Favorites": "Priljubljeni", + "Favorites": "Priljubljeno", "Folders": "Mape", "Genres": "Zvrsti", "HeaderAlbumArtists": "Izvajalci albuma", @@ -219,7 +219,7 @@ "ButtonShuffle": "Premešaj", "ButtonShutdown": "Ugasni", "ButtonSignIn": "Prijava", - "ButtonSort": "Sortiraj", + "ButtonSort": "Razvrsti", "ButtonStart": "Začetek", "ButtonStop": "Stop", "ButtonSubtitles": "Podnapisi", @@ -271,8 +271,7 @@ "Down": "Dol", "Dislike": "Ni mi všeč", "Disabled": "Onemogočen", - "DirectorsValue": "Režiserji: {0}", - "DirectorValue": "Režiser: {0}", + "Directors": "Režiserji", "Director": "Režiser", "DetectingDevices": "Zaznavanje naprav", "Desktop": "Namizje", @@ -290,7 +289,7 @@ "CustomDlnaProfilesHelp": "Ustvari prilagojen profil za novo napravo ali preglasi sistemski profil.", "CopyStreamURLSuccess": "URL uspešno kopiran.", "CopyStreamURL": "Kopiraj URL pretakanja", - "ButtonSubmit": "Oddaj", + "ButtonSubmit": "Pošli", "ButtonAddImage": "Dodaj sliko", "ValueSpecialEpisodeName": "Poseben - {0}", "Shows": "Serije", @@ -343,7 +342,7 @@ "HeaderPendingInvitations": "Povabila na čakanju", "HeaderPasswordReset": "Ponastavi geslo", "HeaderPassword": "Geslo", - "HeaderParentalRatings": "Starševska ocena", + "HeaderParentalRatings": "Ocena za starše", "HeaderOnNow": "Zdaj", "HeaderNextVideoPlayingInValue": "Naslednji video se bo predvajal čez {0}", "HeaderNextEpisodePlayingInValue": "Naslednja epizoda se bo predvajala čez {0}", @@ -352,7 +351,7 @@ "HeaderMyMediaSmall": "Moja predstavnost (majhno)", "HeaderMyMedia": "Moja predstavnost", "HeaderMyDevice": "Moja naprava", - "HeaderMusicVideos": "Glasbeni video posnetki", + "HeaderMusicVideos": "Glasbeni videi", "HeaderMusicQuality": "Kvaliteta glasbe", "HeaderMovies": "Filmi", "HeaderMoreLikeThis": "Podobno", @@ -451,10 +450,10 @@ "HeaderActiveDevices": "Aktivne naprave", "HeaderAccessScheduleHelp": "Ustvarite urnik dostopa in omejite dostop v določenih urah.", "HeaderAccessSchedule": "Urnik dostopa", - "HardwareAccelerationWarning": "Omogočanje strojnega pospeševanja lahko povzroči nestabilnost v določenih okoljih. Zagotovite, da so vaš operacijski sistem in gonilniki posodobljeni. Če imate po omogočanju te nastavitve težave s predvajanjem videa, jo nastavite nazaj na samodejno.", + "HardwareAccelerationWarning": "Omogočanje strojnega pospeševanja lahko povzroči nestabilnost v določenih okoljih. Zagotovite, da so vaš operacijski sistem in gonilniki posodobljeni. Če imate po omogočanju te nastavitve težave s predvajanjem videa, jo nastavite nazaj na brez.", "HandledByProxy": "Upravlja reverse proxy", "HDPrograms": "HD programi", - "H264EncodingPresetHelp": "Izberite hitrejšo vrednost za boljšo zmogljivost ali počasnejšo vrednost za boljšo kakovost.", + "EncoderPresetHelp": "Izberite hitrejšo vrednost za boljšo zmogljivost ali počasnejšo vrednost za boljšo kakovost.", "H264CrfHelp": "Faktor stalne hitrosti (CRF) je privzeta nastavitev kakovosti za kodirnik x264. Vrednosti lahko nastavite med 0 in 51, pri čemer nižje vrednosti dosežejo boljšo kakovost (na račun večjih velikosti datotek). Razumne vrednosti so med 18 in 28. Privzeta vrednost za x264 je 23, zato lahko to uporabite kot izhodišče.", "GuideProviderSelectListings": "Izberi sezname", "GuideProviderLogin": "Prijava", @@ -462,8 +461,7 @@ "GuestStar": "Gostujoči igralec", "GroupVersions": "Združi različice", "GroupBySeries": "Združi bo serijah", - "GenresValue": "Zvrsti: {0}", - "GenreValue": "Zvrst: {0}", + "Genre": "Zvrst", "General": "Splošno", "Fullscreen": "Celoten zaslon", "Friday": "Petek", @@ -502,7 +500,7 @@ "ErrorAddingMediaPathToVirtualFolder": "Prišlo je do težave pri dodajanju poti predstavnosti. Preverite ali je pot veljavna in da ima Jellyfin strežnik dovoljenja za dostop.", "Episodes": "Epizode", "EndsAtValue": "Konec ob {0}", - "Ended": "Zaključeno", + "Ended": "Končano", "EnableThemeVideosHelp": "Predvajaj tematske videe v ozadju med brskanjem knjižnice.", "EnableThemeVideos": "Tematski videi", "EnableThemeSongsHelp": "Predvajaj tematske pesmi v ozadju med brskanjem knjižnice.", @@ -542,7 +540,7 @@ "HeaderUploadImage": "Naloži sliko", "HeaderUpcomingOnTV": "Prihaja na TV", "HeaderTypeText": "Vnesi besedilo", - "HeaderTypeImageFetchers": "{0} prejemniki slik", + "HeaderTypeImageFetchers": "{0} pridobivanje slik", "HeaderTuners": "Sprejemniki", "HeaderTunerDevices": "Sprejemniki", "LabelAllowHWTranscoding": "Dovoli strojno pospešeno prekodiranje", @@ -563,10 +561,10 @@ "HeaderStopRecording": "Ustavi snemanje", "HeaderStatus": "Status", "HeaderStartNow": "Začni zdaj", - "HeaderSpecialFeatures": "Posebne lastnosti", + "HeaderSpecialFeatures": "Dodatki", "HeaderSpecialEpisodeInfo": "Informacije o posebni epizodi", "HeaderSortOrder": "Vrstni red", - "HeaderSortBy": "Uredi po", + "HeaderSortBy": "Razvrsti po", "HeaderShutdown": "Ugasni", "HeaderSetupLibrary": "Nastavite vaše knjižnjice predstavnosti", "HeaderServerSettings": "Nastavitve strežnika", @@ -596,7 +594,7 @@ "LabelAppName": "Ime aplikacije", "LabelAppNameExample": "Primer: Sickbeard, Sonarr", "LabelArtistsHelp": "Loči več z ;", - "LabelAudio": "Zvok:", + "LabelAudio": "Zvok", "LabelAudioBitrate": "Bitna hitrost zvoka:", "LabelAudioChannels": "Kanali zvoka:", "LabelAudioCodec": "Zvočni kodek:", @@ -658,7 +656,7 @@ "LabelEnableDlnaClientDiscoveryInterval": "Interval odkrivanja sprejemnikov (sekunde)", "LabelEnableBlastAliveMessagesHelp": "Omogočite, če imajo UPnP naprave težave z zaznavanjem strežnika v omrežju.", "LabelEnableBlastAliveMessages": "Oddajaj sporočila o dostopnosti", - "LabelEnableAutomaticPortMapHelp": "Poskuša avtomatično povezati javna vrata z lokalnimi preko UPnP. To ne deluje z nekaterimi usmerjevalniki.", + "LabelEnableAutomaticPortMapHelp": "Poskuša avtomatično povezati javna vrata z lokalnimi preko UPnP. To ne deluje z nekaterimi usmerjevalniki. Spremembe bodo uveljavljene po ponovnem zagonu strežnika.", "LabelEnableAutomaticPortMap": "Omogoči avtomatično mapiranje vrat", "LabelEmbedAlbumArtDidl": "Vdelaj grafike albuma v Didl", "LabelEasyPinCode": "Enostavna PIN koda:", @@ -687,9 +685,9 @@ "LabelFileOrUrl": "Datoteka ali URL:", "LabelFont": "Pisava:", "LabelGroupMoviesIntoCollections": "Združi filme v zbirke", - "LabelH264EncodingPreset": "Predloga kodiranja H264:", + "LabelEncoderPreset": "Predloga kodiranja H264:", "LabelHardwareAccelerationType": "Strojno pospeševanje:", - "LabelHardwareAccelerationTypeHelp": "To je eksperimentalna funkcija, ki je na voljo zgolj na podprtih sistemih.", + "LabelHardwareAccelerationTypeHelp": "Strojno pospeševanje zahteva dodatno konfiguracijo.", "LabelHomeNetworkQuality": "Kvaliteta v domačem omrežju:", "LabelHttpsPort": "Lokalna HTTPS vrata:", "LabelHttpsPortHelp": "Vrata TCP s katerimi se poveže Jellyfin HTTPS strežnik.", @@ -828,7 +826,7 @@ "OptionAllowMediaPlaybackTranscodingHelp": "Omejitev dostopa do prekodiranja lahko povzroči napake pri predvajanju v Jellyfin aplikacijah zaradi nepodprtih formatov predstavnosti.", "OptionAllowVideoPlaybackRemuxing": "Dovoli predvajanje videoposnetkov, ki zahtevajo pretvarjanje brez prekodiranja", "ViewPlaybackInfo": "Oglejte si informacije o predvajanju", - "WizardCompleted": "To je vse kar potrebujemo za zdaj. Jellyfin je začel zbirati informacije o vaši knjižnici predstavnosti. Oglejte si nekaj naših aplikacij in nato kliknite Zaključi za ogled Nadzorne pološče.", + "WizardCompleted": "To je vse kar potrebujemo za zdaj. Jellyfin je začel zbirati informacije o vaši knjižnici predstavnosti. Oglejte si nekaj naših aplikacij in nato kliknite Zaključi za ogled Nadzorne plošče.", "Suggestions": "Predlogi", "SubtitleDownloadersHelp": "Omogočite in razvrstite želene vire podnapisov po prioriteti.", "NewCollectionHelp": "Zbirke vam omogočajo ustvarjanje prilagojenih skupin filmov in drugih vsebin.", @@ -1038,5 +1036,186 @@ "MediaInfoChannels": "Kanali", "MediaInfoBitrate": "Bitna hitrost", "MediaInfoBitDepth": "Bitna globina", - "HeaderFavoritePeople": "Priljubljene osebe" + "HeaderFavoritePeople": "Priljubljene osebe", + "ReleaseDate": "Datum izida", + "LabelReleaseDate": "Datum izida:", + "Runtime": "Trajanje", + "UserProfilesIntro": "Jellyfin podpira uporabniške profile z natančnimi nastavitvami prikaza, stanjem predvajanja in starševskim nadzorom.", + "TabParentalControl": "Starševski nadzor", + "OptionParentalRating": "Ocena za starše", + "LabelParentalRating": "Ocena za starše:", + "OptionPlayCount": "Število predvajanj", + "LabelTranscodingThreadCount": "Število niti prekodiranja:", + "OptionBlockChannelContent": "Vsebina spletnega kanala", + "OneChannel": "En kanal", + "SortName": "Ime razvrščanja", + "SortChannelsBy": "Razvrsti kanale po:", + "SortByValue": "Razvrsti po {0}", + "Sort": "Razvrsti", + "LabelSortTitle": "Naslov razvrščanja:", + "LabelSortOrder": "Vrstni red:", + "LabelSortBy": "Razvrsti po:", + "Thumb": "Sličica", + "OptionThumbCard": "Sličica", + "OptionThumb": "Sličica", + "OptionDownloadThumbImage": "Sličica", + "ButtonSplit": "Razdeli", + "MessageYouHaveVersionInstalled": "Trenutno je nameščena različica {0}.", + "DashboardVersionNumber": "Različica: {0}", + "LabelVersion": "Različica:", + "LabelSelectVersionToInstall": "Izberite različico za namestitev:", + "Never": "Nikoli", + "ServerUpdateNeeded": "Jellyfin strežnik je potrebno posodobiti. Za prenos najnovejše različice prosimo obiščite {0}", + "LatestFromLibrary": "Najnovejši {0}", + "LabelScheduledTaskLastRan": "Nazadnje zagnano {0}. Čas trajanja {1}.", + "OptionRandom": "Naključno", + "OptionProtocolHttp": "HTTP", + "OptionProfilePhoto": "Slika", + "OptionProfileAudio": "Zvok", + "OptionPremiereDate": "Datum premiere", + "OptionOnInterval": "V intervalu", + "OptionOnAppStartup": "Ob zagonu aplikacije", + "OptionNew": "Novo...", + "OptionMonday": "Ponedeljek", + "OptionMissingEpisode": "Manjkajoče epizode", + "OptionLoginAttemptsBeforeLockoutHelp": "Vrednost nič (0) pomeni 3 poskuse za običajne uporabnike in 5 za skrbnike. Nastavite na -1 za onemogočanje te funkcije.", + "OptionLoginAttemptsBeforeLockout": "Določa število spodletelih poskusov prijave pred zaklenitvijo uporabnika.", + "OptionIsSD": "SD", + "OptionIsHD": "HD", + "OptionImdbRating": "IMDb ocena", + "OptionHomeVideos": "Slike", + "OptionHideUser": "Skrij tega uporabnika z vstopne strani", + "OptionHasTrailer": "Napovednik", + "OptionFriday": "Petek", + "OptionEveryday": "Vsak dan", + "OptionEnableAutomaticServerUpdates": "Omogoči samodejno posodabljanje strežnika", + "OptionDvd": "DVD", + "OptionDownloadMenuImage": "Meni", + "OptionDownloadLogoImage": "Logotip", + "OptionDownloadImagesInAdvanceHelp": "Privzeto se večina slik prenese šele, ko jih zahtevajo aplikacije. Omogočite to možnost za prenos slik vnaprej, pri uvozu predstavnosti. To lahko občutno podaljša preiskovanje knjižnice.", + "OptionDownloadImagesInAdvance": "Prenesi slike vnaprej", + "OptionAllowSyncTranscoding": "Dovoli prenašanje in sinhronizacijo predstavnosti ki zahteva pretvarjanje", + "OptionAllowRemoteControlOthers": "Dovoli daljinsko upravljanje drugih uporabnikov", + "OptionAllowLinkSharingHelp": "Deljene so zgolj spletne strani z informacijami o predstavnosti. Predstavnostne datoteke niso nikoli javno deljene. Deljene strani so časovno omejene in potečejo po {0} dneh.", + "OptionAllowLinkSharing": "Dovoli deljenje na družbenih omrežjih", + "OptionAllowContentDownloading": "Dovoli prenašanje in sinhronizacijo predstavnosti", + "OptionAllUsers": "Vsi uporabniki", + "OptionAlbumArtist": "Izvajalec albuma", + "OptionAlbum": "Album", + "OptionAdminUsers": "Skrbniki", + "Option3D": "3D", + "NumLocationsValue": "{0} mape", + "NoPluginConfigurationMessage": "Ta dodatek nima nobenih nastavitev.", + "No": "Ne", + "News": "Novice", + "NewEpisodesOnly": "Samo nove epizode", + "NewEpisodes": "Nove epizode", + "NewCollectionNameExample": "Primer: Star Wars zbirka", + "NewCollection": "Nova zbirka", + "Name": "Ime", + "MySubtitles": "Moji podnapisi", + "Mute": "Utišaj", + "MoveLeft": "Premakni levo", + "MoveRight": "Premakni desno", + "LabelSkin": "Preobleka:", + "LabelSize": "Velikost:", + "LabelSimultaneousConnectionLimit": "Omejitev števila sočasnih predvajanj:", + "LabelServerName": "Ime strežnika:", + "LabelServerHostHelp": "192.168.1.100:8096 ali https://myserver.com", + "LabelServerHost": "Naslov:", + "LabelSeriesRecordingPath": "Pot za snemanje serij (neobvezno):", + "LabelSerialNumber": "Serijska številka", + "LabelSendNotificationToUsers": "Pošlji obvestila na:", + "LabelSecureConnectionsMode": "Način varne povezave:", + "LabelSeasonNumber": "Številka sezone:", + "LabelScreensaver": "Ohranjevalnik zaslona:", + "LabelSaveLocalMetadataHelp": "Shranjevanje slik v mape predstavnosti omogoča lažji dostop in urejanje slik.", + "LabelSaveLocalMetadata": "Shrani slike v mape predstavnosti", + "LabelRuntimeMinutes": "Čas trajanja (minute):", + "LabelRemoteClientBitrateLimit": "Omejitev bitne hitrosti pretakanja preko interneta (Mbps):", + "LabelRecordingPathHelp": "Določite privzeto lokacijo za shranjevanje posnetkov. Če pustite prazno bo uporabljena mapa namestitve strežnika.", + "LabelRecordingPath": "Privzeta pot posnetkov:", + "LabelRecord": "Snemaj:", + "LabelReasonForTranscoding": "Razlog za prekodiranje:", + "LabelReadHowYouCanContribute": "Naučite se, kako lahko prispevate.", + "LabelPublicHttpsPortHelp": "Številka javnih vrat ki bodo povezana na lokalna HTTPS vrata.", + "LabelPublicHttpsPort": "Številka javnih HTTPS vrat:", + "LabelPublicHttpPortHelp": "Številka javnih vrat ki bodo povezana na lokalna HTTP vrata.", + "LabelProfileContainersHelp": "Ločeno z vejico. Lahko pustite prazno da velja za vse kontejnerje.", + "LabelProfileContainer": "Kontejner:", + "LabelProfileCodecs": "Kodeki:", + "LabelProfileAudioCodecs": "Zvočni kodeki:", + "LabelPostProcessorArgumentsHelp": "Uporabi {path} kot pot do datoteke posnetka.", + "LabelPostProcessorArguments": "Argumenti ukazne vrstice za naknadno obdelavo:", + "LabelPostProcessor": "Aplikacija za naknadno obdelavo:", + "LabelPlayMethod": "Način predvajanja:", + "LabelPlayerDimensions": "Velikost predvajalnika:", + "LabelPlayer": "Predvajalnik:", + "LabelOverview": "Pregled:", + "LabelOriginalAspectRatio": "Izvirno razmerje stranic:", + "LabelNumberOfGuideDaysHelp": "Prenos TV vodiča za več dni omogoča nastavitev snemanja za več dni vnaprej vendar bo prenos trajal dlje. Samodejno prilagodi število dni za prenos glede na število kanalov.", + "LabelNumberOfGuideDays": "Število dni vodiča za prenos:", + "LabelNumber": "Številka:", + "LabelNotificationEnabled": "Omogoči to obvestilo", + "CopyStreamURLError": "Pri kopiranju naslova URL je prišlo do napake.", + "AskAdminToCreateLibrary": "Prosite skrbnika, da ustvari knjižnico.", + "AllowFfmpegThrottlingHelp": "Ko je prekodiranja dovolj pred mestom predvajanja se proces ustavi, da bo porabljal manj sredstev. To je najbolj uporabno pri gledanju brez pogostega premikanja mesta predvajanja. Če naletite na težave s predvajanjem onemogočite to možnost.", + "AllowFfmpegThrottling": "Zaviraj prekodiranje", + "LabelStreamType": "Vrsta pretakanja:", + "LabelStopping": "Ustavljanje", + "LabelStopWhenPossible": "Ustavi, ko je mogoče:", + "LabelStatus": "Status:", + "LabelStartWhenPossible": "Začni, ko je mogoče:", + "LabelSportsCategories": "Športne kategorije:", + "LabelSource": "Vir:", + "LabelSoundEffects": "Zvočni učinki:", + "LabelSkipIfGraphicalSubsPresentHelp": "Ohranjanje besedilnih različic podnapisov omogoča učinkovitejše predvajanje in zmanjša potrebo po prekodiranju.", + "LabelTriggerType": "Tip sprožilca:", + "LabelTranscodingVideoCodec": "Video kodek:", + "LabelTranscodingProgress": "Napredek prekodiranja:", + "LabelTranscodingFramerate": "Hitrost prekodiranja:", + "LabelTranscodes": "Prekodiranje:", + "LabelTranscodingTempPathHelp": "Določite pot po meri za datoteke prekodiranja. Pustite prazno za uporabo privzete lokacije.", + "LabelTranscodePath": "Pot prekodiranja:", + "LabelTranscodingContainer": "Kontejner:", + "LabelTranscodingAudioCodec": "Zvočni kodek:", + "LabelTrackNumber": "Številka skladbe:", + "LabelTime": "Čas:", + "LabelTextColor": "Barva besedila:", + "LabelTextBackgroundColor": "Barva ozadja besedila:", + "LabelTag": "Oznaka:", + "LabelSupportedMediaTypes": "Podprti tipi predstavnosti:", + "LabelSubtitles": "Podnapisi", + "LabelSubtitlePlaybackMode": "Način podnapisov:", + "LabelSubtitleFormatHelp": "Primer: srt", + "LabelSubtitleDownloaders": "Pridobivanje podnapisov:", + "Wednesday": "Sreda", + "ValueVideoCodec": "Video kodek: {0}", + "ValueTimeLimitSingleHour": "Časovna omejitev: 1 ura", + "ValueTimeLimitMultiHour": "Časovna omejitev: {0} ur", + "ValueSongCount": "{0} pesmi", + "ValueMusicVideoCount": "{0} glasbenih videov", + "ValueMovieCount": "{0} filmov", + "ValueMinutes": "{0} minut", + "ValueEpisodeCount": "{0} epizod", + "ValueSeriesCount": "{0} serij", + "ValueSeconds": "{0} sekund", + "ValueOneSong": "1 skladba", + "ValueOneSeries": "1 serija", + "ValueOneMusicVideo": "1 glasbeni video", + "ValueOneMovie": "1 film", + "ValueOneEpisode": "1 epizoda", + "ValueOneAlbum": "1 album", + "ValueContainer": "Kontejner: {0}", + "ValueConditions": "Pogoji: {0}", + "ValueCodec": "Kodek: {0}", + "ValueAudioCodec": "Zvočni kodek: {0}", + "Unrated": "Neocenjeno", + "Unplayed": "Nepredvajano", + "Tuesday": "Torek", + "Trailers": "Napovedniki", + "TitleHardwareAcceleration": "Strojno pospeševanje", + "Thursday": "Četrtek", + "TabUsers": "Uporabniki", + "TabTrailers": "Napovedniki" } diff --git a/src/strings/sr.json b/src/strings/sr.json index 8b1abcfa7e..dc329c1309 100644 --- a/src/strings/sr.json +++ b/src/strings/sr.json @@ -30,5 +30,169 @@ "AddItemToCollectionHelp": "Додајте ставке у колекцију претрагом па затим десним кликом у менију изаберите да додате у колекцију.", "Add": "Додај", "Actor": "Глумац", - "AccessRestrictedTryAgainLater": "Приступ је тренутно ограничен. Покушајте поново касније." + "AccessRestrictedTryAgainLater": "Приступ је тренутно ограничен. Покушајте поново касније.", + "ButtonPause": "Пауза", + "ButtonParentalControl": "Родитељска контрола", + "ButtonOpen": "Отвори", + "ButtonOk": "Ок", + "ButtonOff": "Искључи", + "ButtonNextTrack": "Следећа нумера", + "ButtonNew": "Ново", + "ButtonNetwork": "Мрежа", + "ButtonMore": "Више", + "ButtonManualLogin": "Ручни логин", + "ButtonLibraryAccess": "Приступ библиотеци", + "ButtonLearnMore": "Научи више", + "ButtonInfo": "Информације", + "ButtonHome": "Почетна страна", + "ButtonHelp": "Помоћ", + "ButtonGuide": "Водич", + "ButtonGotIt": "У реду", + "ButtonFullscreen": "Пун екран", + "ButtonForgotPassword": "Заборављена шифра", + "ButtonFilter": "Филтер", + "ButtonDownload": "Преузми", + "ButtonDown": "Доле", + "ButtonDeleteImage": "Обриши слику", + "ButtonDelete": "Обриши", + "ButtonConnect": "Повежи се", + "ButtonChangeServer": "Промени Сервер", + "ButtonCancel": "Откажи", + "ButtonBack": "Назад", + "ButtonAudioTracks": "Избор језика звука", + "ButtonArrowUp": "Горе", + "ButtonArrowRight": "Десно", + "ButtonArrowLeft": "Лево", + "ButtonArrowDown": "Доле", + "ButtonAddUser": "Додај корисника", + "ButtonAddServer": "Додај сервер", + "ButtonAddScheduledTaskTrigger": "Додај прекидач", + "ButtonAddMediaLibrary": "Додај каталог медија", + "ButtonAddImage": "Додај слику", + "ButtonAdd": "Додај", + "BrowsePluginCatalogMessage": "Претражуј наш каталог доступних додатака", + "Browse": "Изабери", + "BoxRear": "Омот (позади)", + "Box": "Омот", + "Blacklist": "Црна листа", + "BirthPlaceValue": "Место рођења: {0}", + "BirthLocation": "Место рођења", + "BirthDateValue": "Рођен", + "AutoBasedOnLanguageSetting": "Аутоматски (зависи од подешавања језика)", + "Audio": "Звук", + "AttributeNew": "Ново", + "AroundTime": "Около", + "AnyLanguage": "Било који језик", + "AlwaysPlaySubtitles": "Увек налепи титлове", + "AllowRemoteAccess": "Дозволи удаљено конектовање на Jellyfin Server.", + "AllowOnTheFlySubtitleExtraction": "Дозволи екстракцију титлова у реалном времену", + "AllowMediaConversionHelp": "Дозволи или забрани приступ функционалности конвертовања", + "AllowMediaConversion": "Дозволи конверзију медија", + "AllowHWTranscodingHelp": "Дозволи тјунеру да конвертује стрим у релном времену. Ово може да смањи потребу за конверзију на серверу.", + "AllLibraries": "Све библиотеке", + "AllLanguages": "Сви језици", + "AllEpisodes": "Све епизоде", + "AllChannels": "Сви канали", + "All": "Све", + "Alerts": "Упозорења", + "Aired": "Емитовано", + "Absolute": "Апсолутно", + "Default": "Уобичајено", + "DeathDateValue": "Преминуо: {0}", + "DatePlayed": "Датум емитовања", + "DateAdded": "Датум додавања", + "CustomDlnaProfilesHelp": "Направите прилагођени профил да бисте циљали на нови уређај или прегазили системски профил.", + "CriticRating": "Оцена критике", + "CopyStreamURLError": "Десила се грешка приликом копирања адресе.", + "CopyStreamURLSuccess": "Адреса копирана успешно.", + "CopyStreamURL": "Копирајте адресу стрим-а", + "Continuing": "Наставља", + "ContinueWatching": "Натавите гледање", + "Connect": "Повежи", + "ConfirmEndPlayerSession": "Да ли желите да искључите Јеллифин {0}?", + "ConfirmDeletion": "ПОтврдите брисање", + "ConfirmDeleteItems": "Брисањем ових ставки избрисаћете их и из система и из ваше библиотеке медија. Јесте ли сигурни да желите да наставите?", + "ConfirmDeleteItem": "Брисањем ове ставке избрисаћете је и из система и из ваше библиотеке медија. Јесте ли сигурни да желите да наставите?", + "ConfirmDeleteImage": "Обришите слику?", + "ConfigureDateAdded": "Конфигуришите како се датум додавања одређује на контролној табли Јеллифин Сервер-а под Подешавања библиотеке", + "Composer": "Композитор", + "CommunityRating": "Рејтинг заједнице", + "ColorTransfer": "Промена боја", + "ColorSpace": "Простор боја", + "ColorPrimaries": "Основне боје", + "ClientSettings": "Подешавања клијента", + "CinemaModeConfigurationHelp": "Режим биоскопа доноси позоришно искуство директно у вашу дневну собу са могућношћу приказинвања трејлера и прилагођених увода пре главне проекције.", + "ChannelNumber": "Број канала", + "ChannelNameOnly": "Само {0} канал", + "ChannelAccessHelp": "Изаберите канале које желите да делите са овим корисником. Администратори ће моћи да уређују све канале помоћу менаџера метаподатака.", + "ChangingMetadataImageSettingsNewContent": "Промене метаподатака или поставки преузимања уметничког дела примењују се само на нови садржај додат у вашу библиотеку. Да бисте применили промене на постојеће наслове, мора ћете ручно освежити њихове метаподатке.", + "Categories": "Категорије", + "CancelSeries": "Откажи серију", + "CancelRecording": "Откажи снимање", + "ButtonWebsite": "Веб сајт", + "ButtonViewWebsite": "Погледајте веб сајт", + "ButtonUp": "Горе", + "ButtonUninstall": "Деинсталирај", + "ButtonTrailer": "Трејлер", + "ButtonSubtitles": "Титлови", + "ButtonSubmit": "Пошаљите", + "ButtonSplit": "Подели", + "ButtonStop": "Заустави", + "ButtonStart": "Почни", + "ButtonSort": "Сортирај", + "ButtonSignOut": "Одјавите се", + "ButtonSignIn": "Пријавите се", + "ButtonShutdown": "Искључи", + "ButtonShuffle": "Промешај", + "ButtonSettings": "Подешавања", + "ButtonSend": "Пошаљи", + "ButtonSelectView": "Изаберите приказ", + "ButtonSelectServer": "Иѕаберите сервер", + "ButtonSelectDirectory": "Изаберите Директоријум", + "ButtonSearch": "Тражи", + "ButtonScanAllLibraries": "Скенирај све библиотеке", + "ButtonSave": "Сачувај", + "ButtonRevoke": "Опозови", + "ButtonResume": "Настави", + "ButtonRestart": "Покрени поново", + "ButtonResetPassword": "Ресетуј шифру", + "ButtonResetEasyPassword": "Ресетујте једноставан ПИН код", + "ButtonRepeat": "Пусти поново", + "ButtonRename": "Преименуј", + "ButtonRemove": "Уклони", + "ButtonRefreshGuideData": "Освежи податке водича", + "ButtonRefresh": "Освежи", + "ButtonQuickStartGuide": "Кратки водич за почетак", + "ButtonProfile": "Профил", + "ButtonPreviousTrack": "Претходна нумера", + "ButtonPlay": "Пусти", + "ButtonEditOtherUserPreferences": "Уредите профил корисника, слику и личне поставке.", + "ButtonEditImages": "Уреди слике", + "ButtonEdit": "Уреди", + "BurnSubtitlesHelp": "Одређује да ли сервер треба да кодира титлове приликом транскодирања видео записа. Избегавање тога увелико ће побољшати перформансе. Изаберите Аутоматски да бисте снимили формате засноване на слици (VOBSUB, PGS, SUB, IDX) и одређене ASS или SSA титлове.", + "BoxSet": "Бокс сет", + "BookLibraryHelp": "Подржани су аудио и текстуалне књиге. Прегледајте {0} водич за именовање књига {1}.", + "Banner": "Банер", + "Backdrops": "Позадине", + "Backdrop": "Позадина", + "Auto": "Ауто", + "AuthProviderHelp": "Изаберите провајдера аутентификације који ће се користити за аутентификацију лозинке овог корисника.", + "AspectRatio": "Однос страна", + "AskAdminToCreateLibrary": "Затражите од администратора да креира библиотеку.", + "Ascending": "Узлазни", + "AsManyAsPossible": "Што је више могуће", + "Artist": "Уметник", + "Art": "Уметност", + "Anytime": "Било када", + "AlwaysPlaySubtitlesHelp": "Титлови који одговарају језичким преференцијама учитават ће се без обзира на језик звука.", + "AllowedRemoteAddressesHelp": "Листа одвојена зарезима ИП адреса или уноса ИП / мрежне маске за мреже којима ће се омогућити даљинско повезивање. Ако је празно, све удаљене адресе ће бити дозвољене.", + "AllowRemoteAccessHelp": "Ако није укључено, све удаљене везе биће блокиране.", + "AllowFfmpegThrottlingHelp": "Кад се транскодовање довољно удаљи од тренутне позиције репродукције, паузирајте поступак тако да троши мање ресурса. Ово је најкорисније када се гледа без тражења. Искључите ово ако имате проблема са репродукцијом.", + "AllowFfmpegThrottling": "Регулише Транскодовање", + "AllowOnTheFlySubtitleExtractionHelp": "Уграђени титлови се могу издвојити из видео записа и доставити клијентима у обичном тексту како би се спречило транскодирање видео записа. У неким системима ово може дуго трајати и може проузроковати да се репродукција видео записа заустави током екстракције. Онемогућите ово да се уграђени титлови уграђују видео транскодирањем када их клијент не подржава.", + "AllComplexFormats": "Сви сложени формати (ASS, SSA, VOBSUB, PGS, SUB, IDX)", + "AlbumArtist": "Извођач албума", + "Album": "Албум", + "AirDate": "Премијера", + "AdditionalNotificationServices": "Прегледајте каталог додатака да бисте инсталирали сервисе за обавештења." } diff --git a/src/strings/sv.json b/src/strings/sv.json index cc273bec17..443549e797 100644 --- a/src/strings/sv.json +++ b/src/strings/sv.json @@ -1,14 +1,14 @@ { - "AccessRestrictedTryAgainLater": "Åtkomst är begränsad. Försök igen senare.", + "AccessRestrictedTryAgainLater": "För närvarande är åtkomsten begränsad. Försök igen senare.", "Actor": "Skådespelare", "Add": "Lägg till", - "AddItemToCollectionHelp": "Lägg till objekt till samlingar genom att först söka efter dom och sen högerklicka eller tappa upp menyn för att lägga till dom.", - "AddToCollection": "Lägg till samling", + "AddItemToCollectionHelp": "Lägg till objekt i samlingar genom att söka efter dem och använda deras högerklick- eller pekmeny för att lägga till dem i en samling.", + "AddToCollection": "Lägg till i samling", "AddToPlayQueue": "Lägg till i spelkö", "AddToPlaylist": "Lägg till i spellista", - "AddedOnValue": "Tillagd {0}", + "AddedOnValue": "Lade till {0}", "AdditionalNotificationServices": "Sök efter fler meddelandetillägg i tilläggskatalogen.", - "AirDate": "Sändningstid", + "AirDate": "Sändningsdatum", "Aired": "Sändes", "Albums": "Album", "All": "Alla", @@ -17,14 +17,14 @@ "AllEpisodes": "Alla avsnitt", "AllLanguages": "Alla språk", "AllLibraries": "Alla bibliotek", - "AllowHWTranscodingHelp": "Aktivera för att låta TV-mottagaren omkoda strömmar. Det kan minska behovet av omkodning på Jellyfin Server.", + "AllowHWTranscodingHelp": "Tillåt TV-mottagaren att omkoda strömmar. Det kan minska behovet av omkodning på Jellyfin Servern.", "AllowOnTheFlySubtitleExtraction": "Tillåt undertextsextrahering under uppspelning", "AllowOnTheFlySubtitleExtractionHelp": "Inbäddade undertexter kan extraheras ur videor och skickas till klienter i textformat för att förhindra omkodning. I vissa system kan detta ta en lång tid och stoppa videouppspelningen under extraheringsprocessen. Avaktivera detta för att bränna in inbäddade undertexter genom omkodning när de inte stöds av klienten.", "AllowRemoteAccess": "Tillåt fjärranslutningar till denna Jellyfin-server.", "AllowRemoteAccessHelp": "Om avaktiverat så blockeras alla fjärranslutningar.", - "AlwaysPlaySubtitles": "Visa alltid undertexter", + "AlwaysPlaySubtitles": "Visa alltid", "AlwaysPlaySubtitlesHelp": "Undertexter på det önskade språket kommer att laddas oavsett ljudspårets språk.", - "AnyLanguage": "Vilket språk som helst", + "AnyLanguage": "Alla språk", "Anytime": "När som helst", "AroundTime": "Runt {0}", "Art": "Grafik", @@ -40,13 +40,13 @@ "BirthDateValue": "Född: {0}", "BirthLocation": "Födelseort", "BirthPlaceValue": "Födelseort:{0}", - "BookLibraryHelp": "Ljud- och textböcker stöds. Läs {0}Jellyfins boknamngivningsguide{1}.", + "BookLibraryHelp": "Ljud- och textböcker stöds. Läs {0}boknamngivningsguide{1}.", "Books": "Böcker", "Box": "Omslag", "BoxRear": "Omslag (baksida)", "Browse": "Bläddra", "BrowsePluginCatalogMessage": "Besök katalogen för att se tillgängliga tillägg.", - "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 Automatisk för att bränna bild-baserade formats (ex. VOBSUB, PGS, SUB/IDX, etc.) men också vissa ASS/SSA undertexter.", + "BurnSubtitlesHelp": "Avgör ifall servern ska \"bränna in\" undertexterna under transkodning. Att undvika detta förbättrar prestandan avsevärt. Välj \"Automatisk\" för att bränna bild-baserade format (ex. VOBSUB, PGS, SUB/IDX, etc.) och vissa ASS/SSA-undertexter.", "ButtonAdd": "Lägg till", "ButtonAddMediaLibrary": "Lägg till mediabibliotek", "ButtonAddScheduledTaskTrigger": "Lägg till utlösare", @@ -69,25 +69,25 @@ "ButtonEditImages": "Ändra bilder", "ButtonEditOtherUserPreferences": "Ändra den här användarens profil, bild och personliga inställningar.", "ButtonFilter": "Filtrera", - "ButtonForgotPassword": "Glömt lösenord", + "ButtonForgotPassword": "Glömt Lösenord", "ButtonFullscreen": "Fullskärm", "ButtonGotIt": "Ok", "ButtonHelp": "Hjälp", "ButtonHome": "Hem", "ButtonLearnMore": "Läs mer", "ButtonLibraryAccess": "Biblioteksåtkomst", - "ButtonManualLogin": "Manuell inloggning:", + "ButtonManualLogin": "Manuell inloggning", "ButtonMore": "Mer", "ButtonNetwork": "Nätverk", "ButtonNew": "Nytillkommet", - "ButtonNextTrack": "Nästa spår:", + "ButtonNextTrack": "Nästa spår", "ButtonOff": "Av", "ButtonOk": "OK", "ButtonOpen": "Öppna", "ButtonParentalControl": "Föräldralås", "ButtonPause": "Paus", "ButtonPlay": "Spela upp", - "ButtonPreviousTrack": "Föregående spår:", + "ButtonPreviousTrack": "Föregående spår", "ButtonProfile": "Profil", "ButtonQuickStartGuide": "Snabbstartguide", "ButtonRefresh": "Uppdatera", @@ -159,12 +159,11 @@ "DetectingDevices": "Söker efter enheter", "DeviceAccessHelp": "Detta tillämpas endast för enheter som kan bli unikt identifierade och som inte förhindrar åtkomst till browsern. Filtering av användarenheter kommer att blockera dom från att använda nya enheter tills dom har blivit godkända här.", "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.", + "DirectStreamHelp1": "Innehållet är kompatibelt med enheten vad gäller upplösning och medietyp (H.264, AC3 osv.) men är i ett inkompatibelt filformat (mkv, avi, wmv osv.). Videofilen kommer att packas om i realtid innan den strömmas 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}", + "Directors": "Regi", "Disabled": "Inaktiverad", "Disc": "Skiva", "Disconnect": "Koppla bort", @@ -174,19 +173,19 @@ "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 i serverkonfigurationen.", - "DisplayModeHelp": "Välj vilken typ av skärm som du kör Jellyfin på.", + "DisplayModeHelp": "Välj vilken layout du vill använda i gränssnittet.", "DoNotRecord": "Spela inte in", "Down": "Ner", "Download": "Ladda ned", "DownloadsValue": "Nedladdningar: {0}", - "DrmChannelsNotImported": "Kanaler med DRM kommer inte att importeras", - "DropShadow": "Visa skugga", + "DrmChannelsNotImported": "Kanaler med DRM kommer inte att importeras.", + "DropShadow": "Mjuk", "EasyPasswordHelp": "Din enkla pin-kod används för att logga in offline på klienter som stödjer det, och kan också användas för enkel inloggning från ditt nätverk.", "Edit": "Ändra", "EditImages": "Ändra bilder", "EditMetadata": "Redigera metadata", "EditSubtitles": "Ändra undertexter", - "EnableBackdrops": "Aktivera fondbilder", + "EnableBackdrops": "Fondbilder", "EnableBackdropsHelp": "Visar fondbilder i bakgrunden av vissa sidor vid bläddring i biblioteket.", "EnableCinemaMode": "Bioläge", "EnableColorCodedBackgrounds": "Färgkodade bakgrundsbilder", @@ -198,9 +197,9 @@ "EnableNextVideoInfoOverlayHelp": "Vid slutet av en video, visa information om nästföljande video i spellistan.", "EnablePhotos": "Visa foton", "EnablePhotosHelp": "Bilder kommer upptäckas och visas tillsammans med andra mediefiler.", - "EnableThemeSongs": "Aktivera ledmotiv", + "EnableThemeSongs": "Signaturmelodi", "EnableThemeSongsHelp": "Spela ledmotiv i bakgrunden vid bläddring i biblioteket.", - "EnableThemeVideos": "Aktivera tema-videos", + "EnableThemeVideos": "Tema-videor", "EnableThemeVideosHelp": "Spela tema-videos i bakgrunden vid bläddring i biblioteket.", "Ended": "Avslutad", "EndsAtValue": "Slutar vid: {0}", @@ -208,13 +207,13 @@ "ErrorAddingMediaPathToVirtualFolder": "Det gick inte att lägga till sökvägen. Kontrollera att sökvägen är korrekt och att Jellyfin Server har rättigheter till sökvägen.", "ErrorAddingTunerDevice": "Det gick inte att lågga till den här TV-mottagaren. Säkerställ att den går att nå och försök igen.", "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.", - "ErrorGettingTvLineups": "Ett fel uppstod vid nedladdningen utav tv-sortimentet. Se till så att uppgifterna stämmer och försök igen.", + "ErrorGettingTvLineups": "Ett fel uppstod vid nedladdningen utav TV-sortimentet. Se till så att uppgifterna stämmer och försök igen.", "ErrorMessageStartHourGreaterThanEnd": "Sluttiden måste vara senare än starttiden.", "ErrorPleaseSelectLineup": "Välj en lineup och försök igen. Om inga lineups finns tillgängliga, kolla så att användarnamn, lösenord och postnummer stämmer.", "ErrorSavingTvProvider": "Ett fel uppstod när TV-tjänsten skulle sparas. Se till att den går att nå och försök igen senare.", "EveryNDays": "Var {0}:e dag", "ExitFullscreen": "Avsluta fullskärm", - "ExtraLarge": "Extra stor", + "ExtraLarge": "Extra Stor", "ExtractChapterImagesHelp": "Att extrahera kapitelrutor möjliggör för klienter att visa grafiska menyer för kapitelval. Aktiviteten kan vara långsam, resurs-intensiv och kan kräva flera gigabyte i utrymme. Aktiviteten körs när nya videofiler upptäcks, och är även schemalagd under nattetid. Schemat går att konfigurera under schemalagda aktiviteter. Det är inte rekommenderat att köra den här aktiviteten vid tider med hög belastning.", "FFmpegSavePathNotFound": "Det gick inte att hitta FFmpeg med den angivna sökvägen. FFprobe måste även finnas i samma mapp. Dessa komponenter inkluderas normalt i samma nedladdning. Var god undersök sökvägen och försök igen.", "Favorite": "Favorit", @@ -229,23 +228,22 @@ "FolderTypeMovies": "Filmer", "FolderTypeMusic": "Musik", "FolderTypeMusicVideos": "Musikvideor", - "FolderTypeTvShows": "Serier", + "FolderTypeTvShows": "TV Serier", "FolderTypeUnset": "Blandat Innehåll", "Folders": "Mappar", "Friday": "Fredag", "Fullscreen": "Fullskärm", "Genres": "Genrer", - "GenresValue": "Genrer: {0}", "GroupBySeries": "Gruppera efter serie", "GroupVersions": "Gruppera versioner", "GuestStar": "Gästmedverkande", "GuideProviderLogin": "Logga in", "GuideProviderSelectListings": "Välj listor", "H264CrfHelp": "Constant Rate Factor (CRF) är kvalitetsinställningen för x264-kodeken. Du kan använda värden mellan 0 och 51, där lägre värden resulterar i bättre kvalitet (på bekostnad av större filstorlekar). Rimliga värden ligger mellan 18 och 28. Det förvalda värdet är 23, som du kan använda som utgångspunkt.", - "H264EncodingPresetHelp": "Välj ett snabbare värde för öka prestandan, eller ett långsammare värde för att utöka kvaliten.", + "EncoderPresetHelp": "Välj ett snabbare värde för öka prestandan, eller ett långsammare värde för att utöka kvaliten.", "HDPrograms": "HD-program", "HandledByProxy": "Hanteras av reverse proxy", - "HardwareAccelerationWarning": "Aktivering av hårdvaruacceleration kan innebära instabilitet i vissa miljöer. Säkerställ att ditt operativsystem och dina grafikdrivrutiner är helt uppdaterade. Om du har problem att spela upp videor när detta är på behöver du ändra tillbaka inställningen till Auto.", + "HardwareAccelerationWarning": "Aktivering av hårdvaruacceleration kan innebära instabilitet i vissa miljöer. Säkerställ att ditt operativsystem och dina grafikdrivrutiner är helt uppdaterade. Om du har problem med uppspelning när detta är på behöver du ändra tillbaka inställningen till Auto.", "HeaderAccessSchedule": "Schema för åtkomst", "HeaderAccessScheduleHelp": "Skapa ett schema för att begränsa åtkomsten till vissa tider.", "HeaderActiveDevices": "Aktiva enheter", @@ -287,7 +285,7 @@ "HeaderContainerProfile": "Behållareprofil", "HeaderContainerProfileHelp": "Behållareprofiler bestämmer begränsningarna hos en enhet när den spelar upp olika filformat. Om en begränsning är aktuell kommer innehållet att kodas om, även om formatet i sig är inställt för direkt avspelning.", "HeaderContinueListening": "Fortsätt lyssna på", - "HeaderContinueWatching": "Fortsätt kolla på", + "HeaderContinueWatching": "Fortsätt kolla", "HeaderCustomDlnaProfiles": "Anpassade profiler", "HeaderDateIssued": "Utgivningsdatum", "HeaderDefaultRecordingSettings": "Standard inspelningsinställningar", @@ -320,9 +318,9 @@ "HeaderFrequentlyPlayed": "Ofta spelade", "HeaderGenres": "Genrer", "HeaderGuideProviders": "Källor för programguide", - "HeaderHttpHeaders": "Http-rubriker", + "HeaderHttpHeaders": "HTTP headers", "HeaderIdentification": "Identifiering", - "HeaderIdentificationCriteriaHelp": "Var god skriv in minst ett identifieringskriterium", + "HeaderIdentificationCriteriaHelp": "Skriv in minst ett kriterie för identifiering.", "HeaderIdentificationHeader": "ID-rubrik", "HeaderIdentifyItemHelp": "Ange ett eller flera sökkriterier. Ta bort kriterier för att få fler träffar.", "HeaderImageSettings": "Bildinställningar", @@ -331,7 +329,7 @@ "HeaderItems": "Objekt", "HeaderKeepRecording": "Fortsätt spela in", "HeaderKeepSeries": "Behåll serie", - "HeaderKodiMetadataHelp": "Jellyfin har stöd för Nfo-metadatafiler. För att aktivera eller inaktivera Nfo-metadata, använd Metadata-fliken för att konfigurera Nfo-stöd för dina mediatyper.", + "HeaderKodiMetadataHelp": "Jellyfin har stöd för NFO-metadatafiler. För att aktivera eller inaktivera NFO-metadata, använd Metadata-fliken för att konfigurera NFO-stöd för dina mediatyper.", "HeaderLatestEpisodes": "Senaste avsnitten", "HeaderLatestMedia": "Nytillkommet", "HeaderLatestMovies": "Nytillkomna filmer", @@ -346,19 +344,19 @@ "HeaderLiveTv": "Live-TV", "HeaderLoginFailure": "Misslyckad inloggning", "HeaderMediaFolders": "Mediamappar", - "HeaderMediaInfo": "Mediainformation", + "HeaderMediaInfo": "Medieinformation", "HeaderMetadataSettings": "Metadatainställningar", "HeaderMoreLikeThis": "Mer som denna", "HeaderMovies": "Filmer", - "HeaderMusicQuality": "Musikkvalitet:", + "HeaderMusicQuality": "Musikkvalitet", "HeaderMusicVideos": "Musikvideor", "HeaderMyDevice": "Min enhet", - "HeaderMyMedia": "Min Media", - "HeaderMyMediaSmall": "Min Media (liten)", + "HeaderMyMedia": "Min media", + "HeaderMyMediaSmall": "Min media (liten)", "HeaderNewApiKey": "Ny API-nyckel", "HeaderNewDevices": "Nya enheter", "HeaderNextEpisodePlayingInValue": "Nästa avsnitt börjar om {0}", - "HeaderNextUp": "Nästa på tur", + "HeaderNextUp": "Nästa", "HeaderNextVideoPlayingInValue": "Nästa video börjar om {0}", "HeaderOnNow": "Visas nu", "HeaderOtherItems": "Övriga objekt", @@ -375,7 +373,7 @@ "HeaderPlaybackError": "Uppspelningsfel", "HeaderPleaseSignIn": "Var god logga in", "HeaderPluginInstallation": "Installation av tillägg", - "HeaderPreferredMetadataLanguage": "Önskat språk för metadata:", + "HeaderPreferredMetadataLanguage": "Önskat språk för metadata", "HeaderProfile": "Profil", "HeaderProfileInformation": "Profilinformation", "HeaderProfileServerSettingsHelp": "Dessa inställningar kontrollerar hur Jellyfin Server presenterar sig för enheten.", @@ -404,7 +402,7 @@ "HeaderSelectTranscodingPath": "Välj plats för mellanlagring vid omkodning", "HeaderSelectTranscodingPathHelp": "Bläddra fram till eller ange plats för omkodarens mellanlagring. Katalogen måste vara tillgänglig för skrivning.", "HeaderSendMessage": "Skicka meddelande", - "HeaderSeries": "Serie:", + "HeaderSeries": "Serier", "HeaderSeriesOptions": "Seriealternativ", "HeaderSeriesStatus": "Seriestatus", "HeaderServerSettings": "Serverinställningar", @@ -452,7 +450,7 @@ "Images": "Bilder", "ImportFavoriteChannelsHelp": "Aktivera för att endast importera kanaler som är märkta som favoriter på den här TV-mottagaren.", "ImportMissingEpisodesHelp": "Om aktiverat importeras information om saknade episoder till din Jellyfin-databas och visas i seriesäsongerna. Detta kan innebära längre tidsåtgång för biblioteksskanningar.", - "InstallingPackage": "Installerar {0}", + "InstallingPackage": "Installerar {0} (version {1})", "InstantMix": "Omedelbar mix", "ItemCount": "{0} objekt", "Items": "Objekt", @@ -479,10 +477,10 @@ "LabelAllowServerAutoRestart": "Tillåt att servern startas om automatiskt efter uppdateringar", "LabelAllowServerAutoRestartHelp": "Servern startas om endast då inga användare är inloggade.", "LabelAppName": "Appens namn", - "LabelAppNameExample": "Exempel: Sickbeard, NzbDrone", + "LabelAppNameExample": "Exempel: Sickbeard, Sonarr", "LabelArtists": "Artister:", "LabelArtistsHelp": "Separera med vid flera ;", - "LabelAudio": "Ljud:", + "LabelAudio": "Ljud", "LabelAudioLanguagePreference": "Önskat ljudspråk:", "LabelAutomaticallyRefreshInternetMetadataEvery": "Uppdatera metadata automatiskt ifrån internet:", "LabelBindToLocalNetworkAddress": "Knyt till lokal nätverksadress:", @@ -506,9 +504,9 @@ "LabelCriticRating": "Kritikerbetyg:", "LabelCurrentPassword": "Nuvarande lösenord:", "LabelCustomCertificatePath": "Sökväg för anpassat SSL-certifikat:", - "LabelCustomCertificatePathHelp": "Lägg upp ditt eget SSL-certifkat i .pfx-format", - "LabelCustomCss": "Egen css:", - "LabelCustomCssHelp": "Applicera din egen css till webbgränssnittet.", + "LabelCustomCertificatePathHelp": "Lägg upp ditt eget SSL-certifkat i .pfx-format.", + "LabelCustomCss": "Egen CSS-stil:", + "LabelCustomCssHelp": "Använd din egen CSS-stil för webbgränssnittet.", "LabelCustomDeviceDisplayName": "Visningsnamn:", "LabelCustomDeviceDisplayNameHelp": "Ange ett anpassat enhetsnamn. Lämna blankt för att använda det namn enheten själv rapporterar.", "LabelCustomRating": "Anpassad åldersgräns:", @@ -523,7 +521,7 @@ "LabelDefaultUser": "Förvald användare:", "LabelDefaultUserHelp": "Anger vilket användarbibliotek som skall visas på anslutna enheter. Denna inställning kan ändras på enhetsbasis med hjälp av en enhetsprofiler.", "LabelDeviceDescription": "Enhetsbeskrivning", - "LabelDidlMode": "Didl-läge:", + "LabelDidlMode": "DIDL-läge:", "LabelDiscNumber": "Skivnummer:", "LabelDisplayLanguage": "Visningsspråk:", "LabelDisplayLanguageHelp": "Att översätta Jellyfin är ett pågående projekt.", @@ -532,17 +530,17 @@ "LabelDisplayName": "Visningsnamn:", "LabelDisplayOrder": "Visningsordning:", "LabelDisplaySpecialsWithinSeasons": "Visa specialavsnitt i de säsonger de sändes i", - "LabelDownMixAudioScale": "Höj nivån vid nedmixning av ljud", + "LabelDownMixAudioScale": "Höj nivån vid nedmixning av ljud:", "LabelDownMixAudioScaleHelp": "Höj nivån vid nedmixning. Sätt värdet till 1 för att behålla den ursprungliga nivån.", "LabelDownloadLanguages": "Språk att hämta:", "LabelDropImageHere": "Släpp en bild här, eller klicka för att bläddra.", - "LabelDropShadow": "Visa skugga:", + "LabelDropShadow": "Skuggning:", "LabelDynamicExternalId": "{0} ID:", "LabelEasyPinCode": "Enkel pin-kod:", "LabelEmbedAlbumArtDidl": "Bädda in omslagsbilder i Didl", "LabelEmbedAlbumArtDidlHelp": "Vissa enheter föredrar den här metoden att ta fram omslagsbilder. Andra kanske avbryter avspelningen om detta val är aktiverat.", "LabelEnableAutomaticPortMap": "Aktivera automatisk koppling av portar", - "LabelEnableAutomaticPortMapHelp": "Automatisk länkning av publik och lokal port via UPnP. Detta kanske inte fungerar med alla routrar.", + "LabelEnableAutomaticPortMapHelp": "Automatisk länkning av publik och lokal port via UPnP. Detta kanske inte fungerar med alla routrar. Obs. Ingenting kommer att ändras förrän servern startats om.", "LabelEnableBlastAliveMessages": "Skicka ut \"jag lever\"-meddelanden", "LabelEnableBlastAliveMessagesHelp": "Aktivera detta om andra UPnP-enheter på nätverket har problem att upptäcka servern.", "LabelEnableDlnaClientDiscoveryInterval": "Intervall för upptäckt av klienter (i sekunder)", @@ -550,12 +548,12 @@ "LabelEnableDlnaDebugLogging": "Aktivera DLNA felsökningsloggning", "LabelEnableDlnaDebugLoggingHelp": "Detta resulterar i mycket stora loggfiler och rekommenderas bara vid felsökning.", "LabelEnableDlnaPlayTo": "Använd DLNA spela-upp-på", - "LabelEnableDlnaPlayToHelp": "Jellyfin kan hitta enheter på ditt nätverk och ge dig möjlighet att fjärrstyra dem.", + "LabelEnableDlnaPlayToHelp": "Hitta enheter på ditt nätverk och ge dig möjlighet att fjärrstyra dem.", "LabelEnableDlnaServer": "Aktivera DLNA-server", - "LabelEnableDlnaServerHelp": "Tillåt att UPnP-enheter på ditt nätverk kan se och spela upp innehåll från din Jellyfin Server.", + "LabelEnableDlnaServerHelp": "Tillåt att UPnP-enheter på ditt nätverk kan se och spela upp innehåll.", "LabelEnableHardwareDecodingFor": "Aktivera hårdvaruomkodning för:", "LabelEnableRealtimeMonitor": "Aktivera bevakning av mappar i realtid", - "LabelEnableRealtimeMonitorHelp": "Förändringar upptäcks omedelbart (i filsystem som stödjer detta)", + "LabelEnableRealtimeMonitorHelp": "Förändringar upptäcks omedelbart (i filsystem som stödjer detta).", "LabelEnableSingleImageInDidlLimit": "Begränsa till en inbäddad bild", "LabelEnableSingleImageInDidlLimitHelp": "Visa enheter kommer inte renderas ordentligt om flera bilder bäddas in i Didl.", "LabelEndDate": "Slutdatum:", @@ -565,21 +563,21 @@ "LabelExtractChaptersDuringLibraryScan": "Extrahera kapitelbildrutor vid genomsökning av biblioteket", "LabelExtractChaptersDuringLibraryScanHelp": "Om aktiverat extraheras kapitelbildrutor när videor importeras vid genomsökning av biblioteket. Om avaktiverat kommer extrahering att ske vid schemalagd kapitelbildrutebehandling, för att snabba upp den regelbundna genomsökningen av biblioteket.", "LabelFailed": "Misslyckades", - "LabelFileOrUrl": "Fil eller url:", + "LabelFileOrUrl": "Fil eller URL:", "LabelFinish": "Klart", "LabelFont": "Typsnitt:", "LabelForgotPasswordUsernameHelp": "Skriv ditt användarnamn, om du kommer ihåg det.", - "LabelFriendlyName": "Visningsnamn", - "LabelServerNameHelp": "Det här namnet används för att identifiera servern, om det lämnas tomt kommer datorns namn att användas.", + "LabelFriendlyName": "Visningsnamn:", + "LabelServerNameHelp": "Det här namnet används för att identifiera servern. Ifall det lämnas tomt används datorns namn.", "LabelGroupMoviesIntoCollections": "Gruppera filmer i samlingsboxar", "LabelGroupMoviesIntoCollectionsHelp": "I filmlistor visas filmer som ingår i en samlingsbox som ett enda objekt.", "LabelH264Crf": "H264-omkodning CRF:", - "LabelH264EncodingPreset": "H264-omkodningsförval:", + "LabelEncoderPreset": "H264-omkodningsförval:", "LabelHardwareAccelerationType": "Hårdvaruacceleration:", "LabelHardwareAccelerationTypeHelp": "Endast tillgängligt på hårdvara med stöd.", "LabelHomeNetworkQuality": "Hemnätverkskvalitet:", "LabelHomeScreenSectionValue": "Hemskärmsdel {0}:", - "LabelHttpsPort": "Lokalt portnummer för https:", + "LabelHttpsPort": "Lokalt portnummer för HTTPS:", "LabelHttpsPortHelp": "Den lokala tcp-port som Jellyfin Server ska lyssna på https.", "LabelIconMaxHeight": "Maxhöjd på ikoner:", "LabelIconMaxHeightHelp": "Högsta upplösning hos ikoner som visas via upnp:icon.", @@ -607,25 +605,25 @@ "LabelLanNetworks": "LAN nätverk:", "LabelLanguage": "Språk:", "LabelLineup": "Uppsättning:", - "LabelLocalHttpServerPortNumber": "Lokalt portnummer för http:", + "LabelLocalHttpServerPortNumber": "Lokalt portnummer för HTTP:", "LabelLocalHttpServerPortNumberHelp": "Den lokala tcp-port som Jellyfin Server ska lyssna på http.", "LabelLockItemToPreventChanges": "Lås det här objektet för att förhindra ändringar", "LabelLoginDisclaimer": "Ansvarsbegränsning vid inloggning:", "LabelLoginDisclaimerHelp": "Detta visas längst ned på inloggningssidan.", "LabelLogs": "Loggfiler:", - "LabelManufacturer": "Tillverkare", + "LabelManufacturer": "Tillverkare:", "LabelManufacturerUrl": "Tillverkarens webaddress", "LabelMatchType": "Matchningstyp:", "LabelMaxBackdropsPerItem": "Högsta antal fondbilder per objekt:", "LabelMaxChromecastBitrate": "Strömningskvalitet för Chromecast:", - "LabelMaxParentalRating": "Högsta tillåtna åldersgräns", - "LabelMaxResumePercentage": "Högsta gräns för återupptagande (%)", - "LabelMaxResumePercentageHelp": "Objekt betraktas som färdigspelade om uppspelningen stoppas efter denna tidpunkt", + "LabelMaxParentalRating": "Högsta tillåtna åldersgräns:", + "LabelMaxResumePercentage": "Högsta gräns för återupptagande i procent:", + "LabelMaxResumePercentageHelp": "Objekt betraktas som färdigspelade om uppspelningen stoppas efter denna tidpunkt.", "LabelMaxScreenshotsPerItem": "Högsta antal skärmdumpar per objekt:", "LabelMaxStreamingBitrate": "Maximal strömningskvalite:", "LabelMaxStreamingBitrateHelp": "Ange högsta bithastighet för strömning.", - "LabelMessageText": "Meddelandetext", - "LabelMessageTitle": "Meddelandetitel", + "LabelMessageText": "Meddelandetext:", + "LabelMessageTitle": "Meddelandetitel:", "LabelMetadataDownloadLanguage": "Önskat språk:", "LabelMetadataDownloadersHelp": "Aktivera och rangordna dina hämtare baserat på prioritet. Lägre prioriterade hämtare används endast för att fylla i saknad information.", "LabelMetadataPath": "Plats för metadata:", @@ -636,10 +634,10 @@ "LabelMetadataSaversHelp": "Välj de filformat du vill använda för att spara dina metadata.", "LabelMethod": "Metod:", "LabelMinBackdropDownloadWidth": "Hämta enbart fondbilder bredare än:", - "LabelMinResumeDuration": "Minsta tid för återupptagande (s)", - "LabelMinResumeDurationHelp": "Objekt med speltid kortare än så här kan ej återupptas", - "LabelMinResumePercentage": "Lägsta gräns för återupptagande (%)", - "LabelMinResumePercentageHelp": "Objekt betraktas som ej spelade om uppspelningen stoppas före denna tidpunkt", + "LabelMinResumeDuration": "Minsta tid för återupptagande:", + "LabelMinResumeDurationHelp": "Objekt med speltid kortare än så här kan ej återupptas.", + "LabelMinResumePercentage": "Lägsta gräns för återupptagande i procent:", + "LabelMinResumePercentageHelp": "Objekt betraktas som ej spelade om uppspelningen stoppas före denna tidpunkt.", "LabelMinScreenshotDownloadWidth": "Hämta enbart skärmdumpar bredare än:", "LabelModelDescription": "Modellbeskrivning", "LabelModelName": "Modellnamn", @@ -648,10 +646,10 @@ "LabelMonitorUsers": "Övervaka aktivitet från:", "LabelMovieCategories": "Filmkategorier:", "LabelMoviePrefix": "Film prefix:", - "LabelMoviePrefixHelp": "Om ett prefix har lagts till filmertitlarna, skriv in det här så att Jellyfin kan hantera dessa korrekt.", + "LabelMoviePrefixHelp": "Om ett prefix har lagts till filmertitlarna, skriv in det här så att servern kan hantera dessa korrekt.", "LabelMovieRecordingPath": "Inspelningssökväg för film (valfri):", "LabelMusicStreamingTranscodingBitrate": "Bithastighet vid omkodning av musik:", - "LabelMusicStreamingTranscodingBitrateHelp": "Ange högsta bithastighet vid strömning av musik", + "LabelMusicStreamingTranscodingBitrateHelp": "Ange högsta bithastighet vid strömning av musik.", "LabelName": "Namn:", "LabelNewName": "Nytt namn:", "LabelNewPassword": "Nytt lösenord:", @@ -660,7 +658,7 @@ "LabelNext": "Nästa", "LabelNotificationEnabled": "Aktivera denna meddelandetyp", "LabelNumber": "Nr:", - "LabelNumberOfGuideDays": "Antal dagars tablå att hämta", + "LabelNumberOfGuideDays": "Antal dagars tablå att hämta:", "LabelNumberOfGuideDaysHelp": "Hämtning av en längre periods tablå ger möjlighet att boka inspelningar och se program längre fram i tiden, men ger längre nedladdningstid. \"Auto\" väljer baserat på antalet kanaler.", "LabelOptionalNetworkPath": "(Valfri) Delad nätverksmapp:", "LabelOptionalNetworkPathHelp": "Om denna mappen delas på ditt nätverk, kan den delade sökvägen tillåta Jellyfin-appar på andra enheter att streama mediafiler direkt.", @@ -691,10 +689,10 @@ "LabelProtocol": "Protokoll:", "LabelProtocolInfo": "Protokollinfo:", "LabelProtocolInfoHelp": "Värde att använda vid svar på GetProtocolInfo-begäran från enheter.", - "LabelPublicHttpPort": "Publikt portnummer för http:", - "LabelPublicHttpPortHelp": "Det publika portnumret som ska mappas till den lokala porten för http.", - "LabelPublicHttpsPort": "Publikt portnummer för https:", - "LabelPublicHttpsPortHelp": "Det publika portnumret som ska mappas till den lokala porten för https.", + "LabelPublicHttpPort": "Publikt portnummer för HTTP:", + "LabelPublicHttpPortHelp": "Det publika portnumret som ska mappas till den lokala porten för HTTP.", + "LabelPublicHttpsPort": "Publikt portnummer för HTTPS:", + "LabelPublicHttpsPortHelp": "Det publika portnumret som ska mappas till den lokala porten för HTTPS.", "LabelReadHowYouCanContribute": "Se hur du kan hjälpa till.", "LabelReasonForTranscoding": "Orsak för omkodning:", "LabelRecord": "Spela in:", @@ -707,7 +705,7 @@ "LabelRuntimeMinutes": "Speltid (min):", "LabelSaveLocalMetadata": "Spara grafik till mediamapparna", "LabelSaveLocalMetadataHelp": "Om grafik sparas tillsammans med media är de enkelt åtkomliga för redigering.", - "LabelScheduledTaskLastRan": "Senast körd {0}, tog {1}", + "LabelScheduledTaskLastRan": "Senast körd {0}, tog {1}.", "LabelScreensaver": "Skärmsläckare:", "LabelSeasonNumber": "Säsongsnummer:", "LabelSelectFolderGroups": "Gruppera automatiskt innehåll från dessa mappar i vyer, t ex Filmer, Musik eller TV:", @@ -718,19 +716,19 @@ "LabelSerialNumber": "Serienummer", "LabelSeriesRecordingPath": "Inspelningssökväg för TV-serier (valfri):", "LabelServerHost": "Värd:", - "LabelServerHostHelp": "192.168.1.100 eller https://min.server.com", - "LabelSimultaneousConnectionLimit": "Begränsning för samtidiga strömmar", + "LabelServerHostHelp": "192.168.1.100:8096 eller https://min.server.com", + "LabelSimultaneousConnectionLimit": "Begränsning för samtidiga strömmar:", "LabelSkin": "Skal:", "LabelSkipBackLength": "'Hoppa bakåt'-längd:", "LabelSkipForwardLength": "'Hoppa framåt'-längd:", - "LabelSkipIfAudioTrackPresent": "Hoppa över om det förvalda ljudspårets språk är samma som det hämtade.", + "LabelSkipIfAudioTrackPresent": "Hoppa över om det förvalda ljudspårets språk är samma som det hämtade", "LabelSkipIfAudioTrackPresentHelp": "Bocka ur denna för att ge undertexter åt alla videor oavsett ljudspårets språk.", "LabelSkipIfGraphicalSubsPresent": "Hoppa över om videofilen redan innehåller inbäddade undertexter", "LabelSkipIfGraphicalSubsPresentHelp": "Att även ha externa undertexter resulterar i en effektivare uppspelning och minskar risken för omkodning.", "LabelSonyAggregationFlags": "\"Aggregation flags\" för Sony:", "LabelSonyAggregationFlagsHelp": "Anger innehållet i elementet aggregationFlags i namnutrymmet urn:schemas-sonycom:av.", "LabelSortBy": "Sortera efter:", - "LabelSortOrder": "Sortering", + "LabelSortOrder": "Sortering:", "LabelSortTitle": "Sorteringstitel:", "LabelSoundEffects": "Ljudeffekter:", "LabelSource": "Källa:", @@ -742,10 +740,10 @@ "LabelSubtitleDownloaders": "Undertextskällor:", "LabelSubtitleFormatHelp": "Exempel: srt", "LabelSubtitlePlaybackMode": "Undertextläge:", - "LabelSubtitles": "Undertexter:", + "LabelSubtitles": "Undertexter", "LabelSupportedMediaTypes": "Mediaformat som stöds:", "LabelTVHomeScreen": "Hemskärm i TV-läge:", - "LabelTag": "Etikett", + "LabelTag": "Etikett:", "LabelTagline": "Slogan:", "LabelTextBackgroundColor": "Bakgrundsfärg för text:", "LabelTextColor": "Textfärg:", @@ -754,10 +752,10 @@ "LabelTime": "Tid:", "LabelTimeLimitHours": "Tidsbegränsning (timmar):", "LabelTitle": "Titel:", - "LabelTrackNumber": "Spår nr", + "LabelTrackNumber": "Spår nr:", "LabelTranscodingAudioCodec": "Ljudkodning:", "LabelTranscodingContainer": "Behållare:", - "LabelTranscodingTempPathHelp": "Denna mapp innehåller tillfälliga filer som används vid omkodning. Ange en plats för dessa, eller lämna blankt för att använda förvald plats.", + "LabelTranscodingTempPathHelp": "Ange en egen sökväg där omkodningar skall sparas för klienter. Lämna blankt för att använda förvald plats.", "LabelTranscodingThreadCount": "Trådar för omkodning:", "LabelTranscodingThreadCountHelp": "Välj maximala antalet trådar som ska användas vid omkodning. Att minska antalet trådar sänker cpu-belastningan men ökar även risken att omkodning inte kan ske snabbt nog för felfri uppspelning.", "LabelTranscodingVideoCodec": "Videokodning:", @@ -781,12 +779,12 @@ "LabelYourFirstName": "Ditt förnamn:", "LabelYoureDone": "Klart!", "LabelZipCode": "Postnummer:", - "LabelffmpegPath": "FFmpeg sökväg:", - "LabelffmpegPathHelp": "Sökvägen till ffmpeg applikationen, eller mappen som innehåller ffmpeg.", + "LabelffmpegPath": "FFmpeg-sökväg:", + "LabelffmpegPathHelp": "Sökvägen till FFmpeg-filen, eller mappen som innehåller FFmpeg.", "Large": "Stor", "LatestFromLibrary": "Senaste {0}", "LearnHowYouCanContribute": "Se hur du kan hjälpa till.", - "LibraryAccessHelp": "Ange vilka mediamappar den här användaren ska ha tillgång till. Administratörer har rättighet att redigera alla mappar i metadatahanteraren.", + "LibraryAccessHelp": "Ange vilka mediemappar den här användaren ska ha tillgång till. Administratörer har rätt att redigera alla mappar i metadatahanteraren.", "Like": "Gilla", "LinksValue": "Länkar: {0}", "List": "Lista", @@ -799,7 +797,7 @@ "MarkUnplayed": "Markera som ospelad", "MaxParentalRatingHelp": "Innehåll med högre gräns visas ej för den här användaren.", "MediaInfoAnamorphic": "Anamorfisk", - "MediaInfoAspectRatio": "Bildförhållande:", + "MediaInfoAspectRatio": "Bildförhållande", "MediaInfoBitDepth": "Färgdjup", "MediaInfoBitrate": "Bithastighet", "MediaInfoChannels": "Kanaler", @@ -832,7 +830,7 @@ "MessageConfirmRemoveMediaLocation": "Är du säker på att du vill ta bort den här platsen?", "MessageConfirmRestart": "Är du säker på att du vill starta om Jellyfin server?", "MessageConfirmRevokeApiKey": "Är du säker på att du vill återkalla den här api-nyckeln? Applikationens koppling till Jellyfin Server kommer avslutas abrupt.", - "MessageConfirmShutdown": "Är du säker på att du vill stänga av Jellyfin server?", + "MessageConfirmShutdown": "Är du säker på att du vill stänga av servern?", "MessageContactAdminToResetPassword": "Vänligen kontakta din systemadministratör för att återställa ditt lösenord.", "MessageCreateAccountAt": "Skapa ett konto på {0}", "MessageDeleteTaskTrigger": "Vill du ta bort denna aktivitetsutlösare?", @@ -856,27 +854,27 @@ "MessageNoTrailersFound": "Hittade inga trailers. Installera Trailer-kanalen och öka biokänslan genom att lägga till ett bibliotek av trailers.", "MessageNothingHere": "Ingenting här.", "MessagePasswordResetForUsers": "Lösenord har tagots bort från följande användare. För att logga in, använd ett blankt lösenord.", - "MessagePlayAccessRestricted": "Uppspelning av detta innehållet är för närvarande begränsat. Kontakta din Jellyfin Server administratör för mer information.", + "MessagePlayAccessRestricted": "Uppspelning av detta innehållet är för närvarande begränsat. Kontakta din server administratör för mer information.", "MessagePleaseEnsureInternetMetadata": "Var god se till att hämtning av metadata via Internet är aktiverad.", "MessagePleaseWait": "Vänligen vänta. Detta kan ta ett tag.", "MessagePluginConfigurationRequiresLocalAccess": "Logga in på din din lokala Jellyfin Server för att konfigurera det här tillägget.", "MessagePluginInstallDisclaimer": "Tillägg skapade av Jellyfin-användare är ett bra sätt att förbättra din Jellyfin-upplevelse med ytterligare funktionalitet. Observera att detta kan påverka din Jellyfin-server så som längre tidsåtgång för biblioteksskanningar, ytterligare bakgrundsprocesser och minskad systemstabilitet.", "MessageReenableUser": "Se nedan för att aktivera igen", "MessageSettingsSaved": "Inställningarna har sparats.", - "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Följande mediaplatser kommer att tas bort från ditt Jellyfin bibliotek:", + "MessageTheFollowingLocationWillBeRemovedFromLibrary": "Följande mediaplatser kommer att tas bort från ditt bibliotek:", "MessageUnableToConnectToServer": "Vi kunde inte upprätta anslutning till vald server just nu. Försäkra dig om att den är påslagen och försök igen.", "MessageUnsetContentHelp": "Innehåll kommer visas som enkla mappar. För bästa resultat, använd en metadata-hanterare för att ställa in typ av innehåll för undermapparna.", "MessageYouHaveVersionInstalled": "Version {0} är installerad.", "MetadataManager": "Metadata-hanteraren", "MinutesAfter": "minuter efter", "MinutesBefore": "minuter före", - "Mobile": "Mobil / Platta", + "Mobile": "Mobil", "Monday": "Måndag", "MoreFromValue": "Mer från {0}", "MoreUsersCanBeAddedLater": "Flera användare kan skapas senare i Kontrollpanelen.", "MoveLeft": "Vänster", "MoveRight": "Höger", - "MovieLibraryHelp": "Läs om {0}Jellyfins namngivningsguide för filmer{1}.", + "MovieLibraryHelp": "Läs om {0} namngivningsguide för filmer{1}.", "Movies": "Filmer", "Mute": "Tyst", "MySubtitles": "Mina undertexter", @@ -900,9 +898,9 @@ "NumLocationsValue": "{0} mappar", "Off": "Av", "OneChannel": "En kanal", - "OnlyForcedSubtitles": "Endast tvingande undertexter", + "OnlyForcedSubtitles": "Endast påtvingad", "OnlyForcedSubtitlesHelp": "Endast undertexter markerade som tvingande kommer att laddas.", - "OnlyImageFormats": "Endast image-format (VOBSUB, PGS, SUB/IDX, etc.)", + "OnlyImageFormats": "Endast bildbaserade format (VOBSUB, PGS, SUB, etc)", "OptionAdminUsers": "Administratörer", "OptionAlbumArtist": "Albumartist", "OptionAllUsers": "Alla användare", @@ -910,7 +908,7 @@ "OptionAllowBrowsingLiveTv": "Tillåt Live-TV åtkomst", "OptionAllowContentDownloading": "Tillåt nedladdning av media", "OptionAllowLinkSharing": "Tillåt delning för sociala medier", - "OptionAllowLinkSharingHelp": "Endast webbsidor med mediainformation delas. Mediafiler delas aldrig publikt. Delningar är tidsbegränsade och upphör efter {0} dagar.", + "OptionAllowLinkSharingHelp": "Endast webbsidor med medieinformation delas. Mediefiler delas aldrig publikt. Delningar är tidsbegränsade och upphör efter {0} dagar.", "OptionAllowManageLiveTv": "Tillåt hantering av Live-TV inspelningar", "OptionAllowMediaPlayback": "Tillåt mediauppspelning", "OptionAllowMediaPlaybackTranscodingHelp": "Att förhindra åtkomst till omkodning kan orsaka uppspelningsfel i Jellyfin-appar på grund av mediaformat som inte stöds.", @@ -919,7 +917,7 @@ "OptionAllowRemoteSharedDevicesHelp": "DLNA-enheter betraktas som delade tills en användare börjar kontrollera den.", "OptionAllowSyncTranscoding": "Tillåt nedladdning som kräver omkodning", "OptionAllowUserToManageServer": "Tillåt denna användare att administrera servern", - "OptionAllowVideoPlaybackRemuxing": "Tillåt videouppspelning som kräver konvertering utan omkodning.", + "OptionAllowVideoPlaybackRemuxing": "Tillåt videouppspelning som kräver konvertering utan omkodning", "OptionAllowVideoPlaybackTranscoding": "Tillåt videouppspelning som kräver omkodning", "OptionAscending": "Stigande", "OptionAutomaticallyGroupSeries": "Slå ihop serier automatiskt som ligger utspritt under flera kataloger", @@ -936,7 +934,7 @@ "OptionCriticRating": "Kritikerbetyg", "OptionCustomUsers": "Anpassad", "OptionDaily": "Dagligen", - "OptionDateAdded": "Inlagd den", + "OptionDateAdded": "Tillagd den", "OptionDateAddedFileTime": "Använd datum då filen skapades", "OptionDateAddedImportTime": "Använd datum för inläsning i biblioteket", "OptionDatePlayed": "Senast visad", @@ -945,7 +943,7 @@ "OptionDisableUserHelp": "Spärrade användare tillåts ej kontakta servern. Eventuella pågående anslutningar avbryts omedelbart.", "OptionDislikes": "Ogillar", "OptionDisplayFolderView": "Visa en mappvy för att visa enkla mediamappar", - "OptionDisplayFolderViewHelp": "Vid aktivering kommer Jellyfinappar att visa en Mappkategori intill ditt mediabibliotek. Detta är användbart om du har enkla mappvyer.", + "OptionDisplayFolderViewHelp": "Visa mappar jämsides med dina andra media bibliotek. Detta kan vara bra om du vill ha en enkel mapp visning.", "OptionDownloadArtImage": "Grafik", "OptionDownloadBackImage": "Baksida", "OptionDownloadBannerImage": "Banderoll", @@ -962,7 +960,6 @@ "OptionEnableAccessFromAllDevices": "Aktivera åtkomst från alla enheter", "OptionEnableAccessToAllChannels": "Aktivera åtkomst till alla kanaler", "OptionEnableAccessToAllLibraries": "Aktivera åtkomst till alla bibliotek", - "OptionEnableAutomaticServerUpdates": "Aktivera automatiska serveruppdateringar", "OptionEnableExternalContentInSuggestions": "Aktivera externt innehåll under förslag", "OptionEnableExternalContentInSuggestionsHelp": "Tillåt internet trailers och livetv-program att visas under förslag på innehåll.", "OptionEnableForAllTuners": "Aktivera för alla TV-mottagare", @@ -976,14 +973,14 @@ "OptionExtractChapterImage": "Aktivera extrahering av kapitelbilder", "OptionFavorite": "Favoriter", "OptionFriday": "Fredag", - "OptionHasSpecialFeatures": "Extramaterial:", + "OptionHasSpecialFeatures": "Extramaterial", "OptionHasSubtitles": "Undertexter", "OptionHasThemeSong": "Ledmotiv", "OptionHasThemeVideo": "Temavideo", "OptionHideUser": "Visa inte den här användaren på inloggningssidorna", "OptionHideUserFromLoginHelp": "Användbart för privata konton eller gömda administratörskonton. Användaren beöver logga in manuellt genom att skriva sitt användarnamn och lösenord.", "OptionHlsSegmentedSubtitles": "HLS-segmenterade undertexter", - "OptionHomeVideos": "Hemvideos & foton", + "OptionHomeVideos": "Foton", "OptionIgnoreTranscodeByteRangeRequests": "Ignorera begäran om \"byte range\" vid omkodning", "OptionIgnoreTranscodeByteRangeRequestsHelp": "Om aktiverad kommer begäran att uppfyllas, men \"byte range\"-rubriken ignoreras.", "OptionImdbRating": "Betyg på IMDB", @@ -1032,9 +1029,9 @@ "OptionWeekly": "Varje vecka", "OriginalAirDateValue": "Ursprungligt sändningsdatum: {0}", "Overview": "Översikt", - "PackageInstallCancelled": "Installationen av {0} avbröts.", - "PackageInstallCompleted": "Installationen av {0} slutfördes.", - "PackageInstallFailed": "Installationen av {0} misslyckades.", + "PackageInstallCancelled": "Installationen av {0} (version {1}) avbröts.", + "PackageInstallCompleted": "Installationen av {0} (version {1}) slutfördes.", + "PackageInstallFailed": "Installationen av {0} (version {1}) misslyckades.", "ParentalRating": "Parental Rating", "PasswordMatchError": "Lösenordet och bekräftelsen måste överensstämma.", "PasswordResetComplete": "Lösenordet har återställts.", @@ -1083,7 +1080,7 @@ "Record": "Spela in", "RecordSeries": "Spela in serie", "RecordingCancelled": "Inspelning avbruten.", - "RecordingScheduled": "Inspelning schemalagd", + "RecordingScheduled": "Inspelning schemalagd.", "Recordings": "Inspelningar", "Refresh": "Uppdatera", "RefreshDialogHelp": "Metadata uppdateras baserat på inställningar och internettjänster som har aktiverats under Jellyfin servers kontrollpanel.", @@ -1183,7 +1180,7 @@ "TabMusicVideos": "Musikvideor", "TabMyPlugins": "Mina tillägg", "TabNetworks": "TV-bolag", - "TabNfoSettings": "nfo-inställingar", + "TabNfoSettings": "NFO-inställingar", "TabNotifications": "Meddelanden", "TabOther": "Övrigt", "TabParentalControl": "Föräldralås", @@ -1196,7 +1193,7 @@ "TabProfiles": "Profiler", "TabRecordings": "Inspelningar", "TabResponses": "Svar", - "TabResumeSettings": "Återuppta-inställningar", + "TabResumeSettings": "Återuppta", "TabScheduledTasks": "Schemalagda aktiviteter", "TabSeries": "Serie", "TabSettings": "Inställningar", @@ -1210,7 +1207,7 @@ "Tags": "Etiketter", "TagsValue": "Etiketter: {0}", "TellUsAboutYourself": "Berätta om dig själv", - "ThemeSongs": "Vinjetter", + "ThemeSongs": "Signaturmelodier", "ThemeVideos": "Temavideos", "TheseSettingsAffectSubtitlesOnThisDevice": "Dessa inställningar påverkar undertexter på den här enheten", "ThisWizardWillGuideYou": "Den här guiden hjälper dig att göra de första inställningarna. För att börja var vänlig välj önskat språk.", @@ -1222,7 +1219,7 @@ "TrackCount": "{0} spår", "Transcoding": "Omkodning", "Tuesday": "Tisdag", - "TvLibraryHelp": "Läs om {0}Jellyfins namngivningsguide för TV-serier{1}.", + "TvLibraryHelp": "Läs om {0} namngivningsguide för TV-serier{1}.", "UninstallPluginConfirmation": "Är du säker på att du vill avinstallera {0}?", "UninstallPluginHeader": "Avinstallera tillägg", "Unmute": "Muting av", @@ -1258,27 +1255,27 @@ "Watched": "Sedd", "Wednesday": "Onsdag", "WelcomeToProject": "Välkommen till Jellyfin!", - "WizardCompleted": "Det är allt vi behöver veta just nu. Jellyfin Server har börjat samla information om ditt mediabibliotek. Kolla in några av våra appar och klicka sedan på Avsluta för att se kontrollpanelen.", + "WizardCompleted": "Det är allt vi behöver veta just nu. Jellyfin har börjat samla information om ditt mediebibliotek. Kolla in några av våra appar och klicka sedan på avsluta för att se kontrollpanelen.", "Writer": "Manusförfattare", - "XmlDocumentAttributeListHelp": "Dessa attribut tillämpas på rotelementet i alla xml-svar.", + "XmlDocumentAttributeListHelp": "Dessa attribut tillämpas på rotelementet i alla XML-svar.", "XmlTvKidsCategoriesHelp": "Program med dessa kategorier kommer visas som program för barn. Separerade med '|'.", "XmlTvMovieCategoriesHelp": "Program med dessa kategorier kommer visas som filmer. Separerade med '|'.", "XmlTvNewsCategoriesHelp": "Program med dessa kategorier kommer visas som nyhetsprogram. Separerade med '|'.", - "XmlTvPathHelp": "En sökväg till en xml-fil för tv. Jellyfin kommer läsa in den här filen och regelbundet leta efter uppdateringar. Du är själv ansvarig för att skapa och uppdatera filen.", + "XmlTvPathHelp": "En sökväg till en XML-fil för tv. Jellyfin kommer läsa in den här filen och regelbundet leta efter uppdateringar. Du är själv ansvarig för att skapa och uppdatera filen.", "XmlTvSportsCategoriesHelp": "Program med dessa kategorier kommer visas som sportprogram. Separerade med '|'.", "Yes": "Ja", "Yesterday": "Igår", "HeaderFavoriteMovies": "Favoritfilmer", "HeaderAudioLanguages": "Ljudspråk", "HeaderAppearsOn": "Medverkar i", - "HeaderApp": "App", + "HeaderApp": "Applikation", "HeaderAdmin": "Administratör", "Guide": "Guide", - "GenreValue": "Genre: {0}", + "Genre": "Genre", "General": "Allmänt", "FastForward": "Snabbspola", - "Extras": "Mer", - "ErrorAddingXmlTvFile": "Det uppstod ett problem vid läsningen av XmlTV filen. Kontrollera att filen är tillgänglig och försök igen.", + "Extras": "Extramaterial", + "ErrorAddingXmlTvFile": "Det uppstod ett problem vid läsningen av XMLTV filen. Kontrollera att filen är tillgänglig och försök igen.", "ErrorAddingListingsToSchedulesDirect": "Det uppstod ett problem när din lista skulle läggas till på ditt Schedules Direct konto. Schedules Direct tillåter bara ett begränsat antal listor per konto. Du kanske behöver logga in på Schedules Direct hemsidan och ta bort andras listningar från ditt konto innan du fortsätter.", "EnableStreamLoopingHelp": "Aktivera enbart detta om direktsändningen enbart innehåller några sekunders data och behöver bli kontinuerligt uppdaterad. Att aktivera denna funktion i onödan kan skapa problem.", "EnableStreamLooping": "Loopa direktsändningar", @@ -1295,12 +1292,12 @@ "ButtonGuide": "Guide", "Blacklist": "Svartlista", "Auto": "Automatisk", - "AuthProviderHelp": "Välj en autentiseringsleverantör för att autentisera denna användares lösenord.", + "AuthProviderHelp": "Välj en autentiserings leverantör som ska användas för att autentisera denna användarens lösenord.", "Ascending": "Stigande", "AllowedRemoteAddressesHelp": "Kommaavgränsad lista av IP-adresser eller IP/nätmask poster för nätverk som kommer bli tillåtna att ansluta avlägset. Om fältet lämnas tomt så kommer alla avlägsna adresser tillåtas.", "AllowMediaConversionHelp": "Tillåt eller neka tillgång till media konvertings funktionen.", "AllowMediaConversion": "Tillåt media konvertering", - "Alerts": "Notiser", + "Alerts": "Alarm", "HeaderMedia": "Media", "HeaderHome": "Hem", "HeaderFavoriteVideos": "Favoritvideor", @@ -1311,15 +1308,15 @@ "HeaderFavoriteShows": "Favoritserier", "HeaderFavoriteBooks": "Favoritböcker", "FormatValue": "Format: {0}", - "CopyStreamURLSuccess": "URL har kopierats.", - "CopyStreamURL": "Kopiera Stream URL", + "CopyStreamURLSuccess": "Videoadress kopierad.", + "CopyStreamURL": "Kopiera videoadress", "FetchingData": "Hämtar ytterligare data", - "HeaderFetcherSettings": "Hämtarinställningar", - "ButtonAddImage": "Lägg till bild", + "HeaderFetcherSettings": "Hämtar inställningar", + "ButtonAddImage": "Lägg till Bild", "HeaderStopRecording": "Stoppa inspelning", - "HeaderImageOptions": "Bildinställningar", - "Absolute": "Absolut", - "HeaderFavoritePeople": "Favoritpersoner", + "HeaderImageOptions": "Bildalternativ", + "Absolute": "Komplett", + "HeaderFavoritePeople": "Favoritmänniskor", "HeaderRestartingServer": "Startar om server", "HeaderStatus": "Status", "LabelPostProcessor": "Program för efterbehandling:", @@ -1328,17 +1325,187 @@ "LabelMetadata": "Metadata:", "LabelFormat": "Format:", "LabelFolder": "Mapp:", - "LabelBaseUrl": "Grund URL:", + "LabelBaseUrl": "Bas-RL:", "LabelAuthProvider": "Autentiseringsleverantör:", "LabelAudioCodec": "Ljudkodek:", "LabelAudioChannels": "Ljudkanaler:", "LabelAllowedRemoteAddressesMode": "Fjärr-IP-adressfilterläge:", "LabelAllowedRemoteAddresses": "Fjärr-IP-adressfilter:", "HttpsRequiresCert": "För att aktivera säkra anslutningar måste du tillhandahålla ett pålitligt SSL-certifikat, till exempel \"Let's Encrypt\". Vänligen ange ett certifikat eller inaktivera säkra anslutningar.", - "HeaderTypeImageFetchers": "{0} Bildhämtare", + "HeaderTypeImageFetchers": "Bildhämtare", "HeaderLiveTvTunerSetup": "Ställ in Live-TV-mottagare", "ButtonSplit": "Dela upp", "LabelCache": "Cache:", "LabelAlbum": "Album:", - "HeaderVideos": "Videor" + "HeaderVideos": "Videor", + "LabelBitrate": "Bithastighet:", + "LabelStreamType": "Stream typ:", + "LabelStatus": "Status:", + "LabelSize": "Storlek:", + "LabelServerName": "Servernamn:", + "LabelSecureConnectionsMode": "Säker uppkopplings läge:", + "EnableFastImageFadeInHelp": "Aktivera snabbare fade-in animationer för laddade bilder", + "EnableFastImageFadeIn": "Snabb bild fade-in", + "LabelPostProcessorArgumentsHelp": "Använd {path} som sökväg till inspelade filen.", + "LabelPostProcessorArguments": "Post-processor kommandoradsargument:", + "LabelDroppedFrames": "Tappade ramar:", + "LabelAudioSampleRate": "Ljudprovfrekvens:", + "LabelAudioBitrate": "Ljudbithastighet:", + "LabelAudioBitDepth": "Ljudbitdjup:", + "LabelPlayMethod": "Spelmetod:", + "LabelPlayerDimensions": "Spelare dimensioner:", + "LabelPasswordResetProvider": "Lösenords Återställning Leverantör:", + "LabelBaseUrlHelp": "Du kan lägga till en egen underkategori här för att få tillgång till servern från en mer unik URL.", + "LabelCorruptedFrames": "Skadade ramar:", + "HeaderParentalRatings": "Föräldrabetyg", + "HeaderNavigation": "Navigering", + "HeaderBranding": "Märke", + "CopyStreamURLError": "Kunde inte kopiera videoadress.", + "AskAdminToCreateLibrary": "Fråga en administratör för att skapa ett bibliotek.", + "Whitelist": "Vitlista", + "VideoRange": "Video räckvidd", + "ValueOneAlbum": "1 album", + "ValueMinutes": "{0} min", + "ValueContainer": "Behållare: {0}", + "UserAgentHelp": "Stöd en egen user-agent HTTP rubrik.", + "Uniform": "Enhetlig", + "Trailers": "Trailers", + "TabTrailers": "Trailers", + "TabServer": "Server", + "TabNetworking": "Nätverk", + "TabMetadata": "Metadata", + "TabInfo": "Info", + "TabAccess": "Tillgång", + "TV": "TV", + "SubtitleOffset": "Undertext justering", + "Smart": "Smart", + "Smaller": "Mindre", + "ShowAdvancedSettings": "Visa avancerade inställningar", + "SeriesDisplayOrderHelp": "Ordna avsnitt via sändnings datum, DVD ordning, eller absolut numrering.", + "SelectAdminUsername": "Vänligen välj ett användarnamn för admin kontot.", + "SaveSubtitlesIntoMediaFoldersHelp": "Spara undertexter vid video filer kommer göra det mer enklare att hantera.", + "Rewind": "Spola tillbaka", + "RequiredForAllRemoteConnections": "Krävs för alla fjärr kopplingar", + "RecordingPathChangeMessage": "Ändring av din inspelnings mapp kommer inte migrera existerande inspelningar från gamla platsen till den nya. Du behöver flytta dom manuellt om så önskas.", + "PreferredNotRequired": "Föredragen, men inte krävande", + "PlaybackData": "Uppspelnings Data", + "PasswordResetProviderHelp": "Välj en Lösenords Återställnings Provider att använda när denna användare begär att återställa lösenordet", + "OptionThumbCard": "Miniatyr kort", + "OptionThumb": "Miniatyr", + "OptionSaveMetadataAsHiddenHelp": "Ändring av detta kommer att tilldelas till ny metadata som sparas. Existerande metadata filer kommer att uppdateras nästa gång dom sparas av Jellyfin Server.", + "OptionResElement": "res element", + "OptionRegex": "Regex", + "OptionRandom": "Slumpmässig", + "OptionProtocolHttp": "HTTP", + "OptionProfileVideo": "Video", + "OptionPosterCard": "Omslags kort", + "OptionPoster": "Omslag", + "OptionMax": "Max", + "OptionLoginAttemptsBeforeLockoutHelp": "Ett värde av noll menas att använda standard av tre försök för normala användare och fem för administratörer. -1 kommer att stänga av denna funktion.", + "OptionLoginAttemptsBeforeLockout": "Avgör hur många felaktiga inloggnings försök som kan utföras innan kontot låses.", + "OptionList": "List", + "OptionIsSD": "SD", + "OptionIsHD": "HD", + "OptionHasTrailer": "Trailer", + "OptionCaptionInfoExSamsung": "CaptionInfoEx (Samsung)", + "OptionBlockTrailers": "Trailers", + "OptionBanner": "Banner", + "OptionAutomatic": "Auto", + "OptionAuto": "Auto", + "OptionArtist": "Artist", + "OptionForceRemoteSourceTranscoding": "Tvinga omkodning på fjärr media källor (som LiveTV)", + "OptionAlbum": "Album", + "Option3D": "3D", + "Normal": "Normal", + "NoCreatedLibraries": "Ser ut som du inte har skapat några bibliotek än. {0}Vill du skapa ett nu?{1}", + "NextUp": "Nästa på tur", + "MusicVideo": "Musik Video", + "MusicLibraryHelp": "Granska {0}musik döpnings guiden{1}.", + "MusicArtist": "Musik Artist", + "MusicAlbum": "Musik Album", + "MoreMediaInfo": "Medieinformation", + "MetadataSettingChangeHelp": "Ändring av metadata inställningar kommer att ske på nytt innehåll som är tillagt framledes. För att uppdatera existerat innehåll, öppna detalj skärmen och tryck på uppdatera knappen, eller utför bulk uppdateringar med metadata hanteraren.", + "Metadata": "Metadata", + "MessageNoServersAvailable": "Inga servrar har hittats med automatiska server sökningen.", + "MessageNoCollectionsAvailable": "Samlingar tillåter dig att njuta av personlig gruppering av Filmer, Serier och Albums. Tryck på + knapen för att skapa samlingar.", + "MessageImageTypeNotSelected": "Vänligen välj en bild typ från rullningslisten.", + "MessageImageFileTypeAllowed": "Endast JPEG och PNG filer stöds.", + "MessageConfirmAppExit": "Vill du avsluta?", + "MediaInfoStreamTypeVideo": "Video", + "MediaInfoStreamTypeSubtitle": "Undertext", + "MediaInfoStreamTypeEmbeddedImage": "Inbäddad bild", + "MediaInfoStreamTypeData": "Data", + "MediaInfoStreamTypeAudio": "Ljud", + "MediaInfoSoftware": "Mjukvara", + "MediaInfoLayout": "Design", + "MediaInfoContainer": "Behållare", + "ManageLibrary": "Hantera bibliotek", + "Live": "Live", + "LeaveBlankToNotSetAPassword": "Du kan lämna detta fält tomt för att inte ange lösenord.", + "LaunchWebAppOnStartupHelp": "Öppna webbgränssnittet i din standardwebbläsare när servern först startar. Detta händer inte när du använder starta om-funktionen.", + "LaunchWebAppOnStartup": "Öppna webbgränssnittet när servern startar", + "LanNetworksHelp": "Kommatecken separerad lista på IP adresser eller IP/nätmask inlägg för nätverk som anses vara på lokala nätverket för att tvinga fram bandbredd begränsningar. Om angett, alla andra IP adresser kommer att anses vara på ett externt nätverk och kommer tilldelas till det externa bandbredd begränsningarna. Om lämnat tomt, endast serverns subnet anses vara på det lokala nätverket.", + "LabelXDlnaDoc": "X-DLNA-dokumentation:", + "LabelXDlnaCap": "X-DLNA-begränsning:", + "LabelWeb": "Webb:", + "LabelVideoResolution": "Video upplösning:", + "LabelVideoCodec": "Video codec:", + "LabelVideoBitrate": "Video bitrate:", + "LabelVideo": "Video", + "DashboardArchitecture": "Arkitektur: {0}", + "DashboardOperatingSystem": "Operativsystem: {0}", + "DashboardServerName": "Server: {0}", + "DashboardVersionNumber": "Version: {0}", + "LabelVersion": "Version:", + "LabelUserLoginAttemptsBeforeLockout": "Felaktiga inloggnings försök innan användare blir utelåst:", + "LabelUserAgent": "Användar agent:", + "LabelTypeText": "Text", + "LabelTypeMetadataDownloaders": "{0} metadata nerladdare:", + "LabelTranscodingProgress": "Omkodning progress:", + "LabelTranscodingFramerate": "Omkodning framerate:", + "LabelTranscodes": "Omkodningar:", + "LabelTranscodePath": "Omkodning sökväg:", + "PlaybackErrorNoCompatibleStream": "Klienten är inte kompatibel med mediaformatet och servern skickar inte ett kompatibelt medieformat.", + "AllowFfmpegThrottlingHelp": "När omkodningen går uppspelningen långt i förväg pausas den tills vidare för att spara resurser. Detta fungerar bäst när du kollar utan att spola mycket; stäng av ifall spelaren krånglar.", + "AllowFfmpegThrottling": "Begränsad omkodning", + "Album": "Album", + "EveryXHours": "Varje {0} timmar", + "EveryHour": "Varje timme", + "EveryXMinutes": "Varje {0} minut(er)", + "OnApplicationStartup": "Vid programstart", + "DailyAt": "Dagligen vid {0}", + "PersonRole": "som {0}", + "ListPaging": "{0}-{1} av {2}", + "WriteAccessRequired": "Jellyfin Server kräver skrivrättigheter till denna katalog. Säkerställ skrivrättigheter och försök igen.", + "PathNotFound": "Sökvägen hittades inte. Säkerställ att sökvägen är korrekt och försök igen.", + "Track": "Spår", + "Season": "Säsong", + "ReleaseGroup": "Releasegrupp", + "PreferEmbeddedEpisodeInfosOverFileNames": "Föredra inbäddad avsnittsinformation före filnamn", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "Detta använder avsnittets information från inbäddad metadata om tillgängligt.", + "Person": "Person", + "OtherArtist": "Annan artist", + "Movie": "Film", + "Episode": "Avsnitt", + "ClientSettings": "Klientinställningar", + "BoxSet": "Samlingsbox", + "Artist": "Artist", + "ButtonTogglePlaylist": "Spellista", + "ButtonToggleContextMenu": "Mer", + "AlbumArtist": "Albumartist", + "LabelLibraryPageSize": "Bibliotekets sidstorlek:", + "LabelDeinterlaceMethod": "Deinterlacing-metod:", + "WeeklyAt": "{0}s vid {1}", + "LastSeen": "Senast sedd {0}", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "Filter": "Filter", + "New": "Ny", + "MessageUnauthorizedUser": "Du har inte behörighet att komma åt servern just nu. Kontakta din serveradministratör för mer information.", + "HeaderFavoritePlaylists": "Favoritspellista", + "OnWakeFromSleep": "Vid start från vilande läge", + "UnsupportedPlayback": "Jellyfin kan inte dekryptera inehåll skyddat av DRM men allt inehåll kommer ändå försökas, även skyddade titlar. Vissa filer kan se helt svart ut på grund av kryptering eller andra funktioner som inte stöds, till exempel interaktiva titlar.", + "LabelLibraryPageSizeHelp": "Sätter en begränsad sidstorlek i bibliotek. Sätt 0 för att avaktivera begränsad sidstorlek.", + "ApiKeysCaption": "Lista av aktiva API-nycklar", + "DeinterlaceMethodHelp": "Välj metod för borttagning av inflätning vid konvertering av inflätat inehåll." } diff --git a/src/strings/tr.json b/src/strings/tr.json index eae0b419c9..d69391ce9a 100644 --- a/src/strings/tr.json +++ b/src/strings/tr.json @@ -14,7 +14,7 @@ "ButtonDelete": "Sil", "ButtonDeleteImage": "Resmi Sil", "ButtonEdit": "Düzenle", - "ButtonFilter": "Filtre", + "ButtonFilter": "Filtrele", "ButtonHelp": "Yardım", "ButtonHome": "Anasayfa", "ButtonInfo": "Bilgi", @@ -22,7 +22,7 @@ "ButtonNew": "Yeni", "ButtonOk": "Tamam", "ButtonPause": "Duraklat", - "ButtonPlay": "Çal", + "ButtonPlay": "Oynat", "ButtonQuickStartGuide": "Hızlı başlangıç rehberi", "ButtonRefreshGuideData": "Kılavuzu Yinele", "ButtonRemove": "Sil", @@ -34,11 +34,11 @@ "ButtonSend": "Gönder", "ButtonSettings": "Ayarlar", "ButtonSignIn": "Giriş Yapın", - "ButtonSignOut": "Sign out", + "ButtonSignOut": "Çıkış Yap", "ButtonSort": "Sırala", "ButtonStop": "Durdur", "ButtonSubtitles": "Altyazılar", - "ChannelAccessHelp": "Bu kullanıcıyla paylaşmak üzere kanalları seç. Yöneticiler bütün kanalları metada yöneticisi ile düzenleyebilcekler.", + "ChannelAccessHelp": "Bu kullanıcıyla paylaşmak üzere kanalları seç. Yöneticiler bütün kanalları metada yöneticisi ile düzenleyebilecekler.", "Continuing": "Devam ediyor", "Delete": "Sil", "DeleteImage": "Resmi Sil", @@ -104,10 +104,10 @@ "LabelDisplayMissingEpisodesWithinSeasons": "Sezondaki kayıp bölümleri göster", "LabelEnableDlnaServer": "DLNA Sunucusunu Etkinleştir", "LabelFinish": "Bitir", - "LabelIconMaxHeight": "İkon Maksimum Yükseklik:", + "LabelIconMaxHeight": "Maksimum simge genişliği:", "LabelIconMaxWidth": "ikon Maksimum Genişlik:", "LabelLanguage": "Dil:", - "LabelManufacturer": "Üretici", + "LabelManufacturer": "Üretici:", "LabelMaxParentalRating": "Maksimum izin verilen ebeveyn değerlendirmesi:", "LabelMessageText": "Mesaj Metni:", "LabelName": "İsim:", @@ -190,7 +190,7 @@ "OptionThursday": "Perşembe", "OptionTrackName": "Parça İsmi", "OptionTuesday": "Salı", - "OptionTvdbRating": "Tvdb Reyting", + "OptionTvdbRating": "TVDB Puanı", "OptionUnplayed": "Çalınmayan", "OptionWednesday": "Çarşamba", "OptionWeekly": "Haftalık", @@ -282,14 +282,14 @@ "Shows": "Diziler", "Songs": "Şarkılar", "Sync": "Eşitle", - "AllChannels": "Bütün kanallar", - "AllComplexFormats": "Bütün karmaşık formatlar (ASS, SSA, VOBSUB, PGS, SUB/IDX, vb.)", - "AllEpisodes": "Bütün bölümler", - "AllLanguages": "Bütün diller", + "AllChannels": "Tüm kanallar", + "AllComplexFormats": "Tüm karmaşık formatlar (ASS, SSA, VOBSUB, PGS, SUB/IDX, vb.)", + "AllEpisodes": "Tüm bölümler", + "AllLanguages": "Tüm diller", "AllowMediaConversion": "Medya dönüşümüne izin ver", - "AddItemToCollectionHelp": "Ögeleri koleksiyona eklemek için arama yapın ve üzerine sağ tıklayın veya sekme menüsünden koleksiyona ekleyin.", + "AddItemToCollectionHelp": "Ögeleri koleksiyona eklemek için; arama yapın ve üzerine sağ tıklayın veya sekme menüsünden koleksiyona ekleyin.", "AllowHWTranscodingHelp": "Ayarlayıcının anında akışları dönüştürmesine izin verin. Bu, sunucunun gerektirdiği kodlamanın azaltılmasına yardımcı olabilir.", - "ColorSpace": "Renk Uzayı", + "ColorSpace": "Renk uzayı", "ButtonConnect": "Bağlan", "ColorTransfer": "Renk transferi", "ButtonPreviousTrack": "Önceki parça", @@ -298,8 +298,8 @@ "ButtonRename": "Yeniden Adlandır", "ButtonRepeat": "Tekrar", "ButtonResume": "Devam Et", - "ButtonRevoke": "geri al", - "ChannelNumber": "Kanal Numarası", + "ButtonRevoke": "Geri al", + "ChannelNumber": "Kanal numarası", "ContinueWatching": "İzlemeye devam et", "CriticRating": "Kritik değerlendirme", "CustomDlnaProfilesHelp": "Yeni bir cihazı hedeflemek veya bir sistem profilini geçersiz kılmak için özel bir profil oluşturun.", @@ -314,11 +314,10 @@ "ColorPrimaries": "Renk primerleri", "DirectStreamHelp2": "Doğrudan Akış, video kalitesinde herhangi bir kayıp olmadan çok az işlem gücü kullanır.", "DirectStreaming": "Doğrudan akış", - "Director": "yönetmen", - "DirectorValue": "Yönetmen: {0}", - "DirectorsValue": "Yöneticiler: {0}", + "Director": "Yönetmen", + "Directors": "Yöneticiler", "Disabled": "Deaktif", - "DisplayModeHelp": "Jellyfin’i çalıştırdığınız ekran türünü seçin.", + "DisplayModeHelp": "Arayüz için kullanılmasını istediğiniz şablonu seçin.", "DoNotRecord": "Kaydetme", "Down": "Aşağı", "Download": "İndir", @@ -333,12 +332,12 @@ "Disc": "Disk", "ButtonAddImage": "Resim ekle", "ButtonAddScheduledTaskTrigger": "Tetikleyici ekle", - "ButtonAddServer": "Sunucu ekle", - "ButtonAudioTracks": "Ses Parçalari", + "ButtonAddServer": "Sunucu Ekle", + "ButtonAudioTracks": "Ses Parçaları", "ButtonChangeServer": "Sunucu Değiştir", - "ButtonGotIt": "Anladım", - "ButtonMore": "Daha", - "ButtonOpen": "Açık", + "ButtonGotIt": "Anlaşıldı", + "ButtonMore": "Dahası", + "ButtonOpen": "Aç", "ButtonArrowUp": "Yukarı", "ButtonNetwork": "Ağ", "ButtonDownload": "İndir", @@ -366,7 +365,7 @@ "DisplayInMyMedia": "Ana ekranda görüntüleme", "DisplayInOtherHomeScreenSections": "En son medya gibi ana ekran bölümlerinde görüntüleyin ve izlemeye devam edin", "EnableBackdrops": "Arka planında", - "BurnSubtitlesHelp": "Altyazı formatına bağlı olarak video dönüştürülürken sunucunun altyazılarda yazıp yazmayacağını belirler. Altyazılarda yanmaktan kaçınmak, sunucu performansını iyileştirir. Görüntü tabanlı biçimleri (VOBSUB, PGS, SUB / IDX, vb.) Ve bazı ASS / SSA altyazılarını yazmak için Otomatik'i seçin.", + "BurnSubtitlesHelp": "Sunucunun video işlendiği esnada, altyazının görüntüye gömülmesini sağlar. Performansı çok düşürür, zorunda kalmadıkça bu özelliği seçmeyin. Görüntü tabanlı biçimleri (VOBSUB, PGS, SUB / IDX, vb.) Ve bazı ASS / SSA altyazıların görüntüye gömülmesi için Otomatik'i seçin.", "ConfirmDeleteItem": "Bu öğeyi silmek, onu hem dosya sisteminden hem de medya kütüphanenizden siler. Devam etmek istediğinize emin misiniz?", "ValueSpecialEpisodeName": "Özel - {0}", "DeviceAccessHelp": "Bu, yalnızca benzersiz şekilde tanımlanabilen ve tarayıcı erişimini engellemeyen cihazlar için geçerlidir. Kullanıcı cihazlarına erişimin filtrelenmesi, burada onaylanana kadar yeni cihazları kullanmalarını önler.", @@ -385,38 +384,38 @@ "Art": "Sanat", "AsManyAsPossible": "Mümkün olduğunca", "Ascending": "yükselen", - "AspectRatio": "Boy oranı", + "AspectRatio": "En/Boy oranı", "Audio": "Ses", "AuthProviderHelp": "Bu kullanıcının şifresini doğrulamak için kullanılacak bir Kimlik Doğrulama Sağlayıcısı seçin.", "AutoBasedOnLanguageSetting": "Otomatik (dil ayarına göre)", "Backdrop": "zemin", "Backdrops": "Zeminler", "Banner": "afiş", - "BirthDateValue": "Doğan: {0}", - "BirthLocation": "Doğum yeri", + "BirthDateValue": "Doğum Tarihi: {0}", + "BirthLocation": "Doğum Yeri", "BirthPlaceValue": "Doğum yeri: {0}", "Auto": "Oto", - "Blacklist": "kara liste", + "Blacklist": "Karaliste", "BoxRear": "Kutu (arka)", "ButtonAddMediaLibrary": "Medya Kitaplığı Ekle", - "ButtonSubmit": "Sunmak", + "ButtonSubmit": "Onayla", "ButtonStart": "Başlat", "ButtonTrailer": "Fragman", "Box": "Kutu", "ButtonViewWebsite": "Web sitesini görüntüle", - "CancelRecording": "Kaydı iptal et", - "CancelSeries": "Serileri iptal et", + "CancelRecording": "Kayıttan Vazgeç", + "CancelSeries": "Dizileri iptal et", "ButtonUninstall": "Kaldır", "ButtonUp": "Yukarı", "ButtonWebsite": "Website", "Categories": "Kategoriler", "DrmChannelsNotImported": "DRM'li kanallar içe aktarılmayacak.", - "DropShadow": "Düşen gölge", + "DropShadow": "Gölge", "CopyStreamURL": "Akış URL’sini kopyala", "DefaultSubtitlesHelp": "Altyazılar, gömülü meta verilerdeki varsayılan ve zorunlu bayraklara göre yüklenir. Birden fazla seçenek olduğunda dil tercihleri göz önünde bulundurulur.", "DeleteDeviceConfirmation": "Bu cihazı silmek istediğinden emin misin? Bir kullanıcı bir sonraki oturum açışında yeniden görünecektir.", "DisplayMissingEpisodesWithinSeasons": "Sezonlardaki eksik bölümleri görüntüleme", - "AlwaysPlaySubtitles": "Her zaman altyazıları oynat", + "AlwaysPlaySubtitles": "Altyazıları her zaman oynat", "CopyStreamURLSuccess": "URL başarıyla kopyalandı.", "DateAdded": "Ekleme Tarihi", "DatePlayed": "Oynanan tarih", @@ -510,10 +509,10 @@ "HeaderActiveDevices": "Aktif Cihazlar", "HeaderAccessScheduleHelp": "Belirli saatlerle erişimi sınırlamak için bir erişim programı oluşturun.", "HeaderAccessSchedule": "Erişim Takvimi", - "HardwareAccelerationWarning": "Donanım ivmesini etkinleştirmek bazı ortamlarda dengesizliğe neden olabilir. İşletim sisteminizin ve video sürücülerinizin tamamen güncel olduğundan emin olun. Bunu etkinleştirdikten sonra video oynatmakta zorluk çekiyorsanız, ayarı tekrar Auto (Otomatik) olarak değiştirmeniz gerekecektir.", + "HardwareAccelerationWarning": "Donanım ivmesini etkinleştirmek bazı ortamlarda dengesizliğe neden olabilir. İşletim sisteminizin ve video sürücülerinizin tamamen güncel olduğundan emin olun. Bunu etkinleştirdikten sonra video oynatmakta zorluk çekiyorsanız, ayarı tekrar \"Hiçbiri\" olarak değiştirmeniz gerekecektir.", "HandledByProxy": "Ters proxy tarafından kullanılır", "HDPrograms": "HD programlar", - "H264EncodingPresetHelp": "Performansı artırmak için daha hızlı bir değer veya kaliteyi artırmak için daha yavaş bir değer seçin.", + "EncoderPresetHelp": "Performansı artırmak için daha hızlı bir değer veya kaliteyi artırmak için daha yavaş bir değer seçin.", "H264CrfHelp": "Sabit Hız Faktörü (CRF), x264 kodlayıcı için varsayılan kalite ayarıdır. Değerleri 0 ile 51 arasında ayarlayabilirsiniz, burada daha düşük değerler daha iyi kaliteyle sonuçlanır (daha yüksek dosya boyutları pahasına). Aklı başında değerleri 18 ila 28 arasındadır. X264 için varsayılan 23, bu nedenle bunu başlangıç noktası olarak kullanabilirsiniz.", "GuideProviderSelectListings": "İlan Seç", "GuideProviderLogin": "Oturum aç", @@ -521,8 +520,7 @@ "GuestStar": "Konuk sanatçı", "GroupVersions": "Grup versiyonları", "GroupBySeries": "Seriye göre gruplandır", - "GenresValue": "Türler: {0}", - "GenreValue": "Tür: {0}", + "Genre": "Tür", "General": "Genel", "Fullscreen": "Tam ekran", "FormatValue": "Biçim: {0}", @@ -651,7 +649,7 @@ "LabelAudioSampleRate": "Ses örnekleme hızı:", "LabelAudioCodec": "Ses kodeği:", "LabelAudioChannels": "Ses kanalları:", - "LabelAudio": "Ses:", + "LabelAudio": "Ses", "LabelAppName": "Uygulama adı", "LabelAllowHWTranscoding": "Donanım kod dönüştürmesine izin ver", "LabelAll": "Tümü", @@ -665,7 +663,7 @@ "Label3DFormat": "3D Formatı:", "Kids": "Çocuklar", "ItemCount": "{0} nesne", - "InstallingPackage": "Yükleniyor {0}", + "InstallingPackage": "Yükleniyor {0} (versiyon {1})", "Images": "Resimler", "Identify": "Tanımla", "Horizontal": "Yatay", @@ -674,12 +672,12 @@ "HeaderYears": "Yıl", "HeaderXmlSettings": "Xml Ayarları", "HeaderXmlDocumentAttributes": "Xml Döküman Öznitelikleri", - "HeaderXmlDocumentAttribute": "Xml Dökümanı Öznitelik", + "HeaderXmlDocumentAttribute": "Xml Döküman Özniteliği", "HeaderUser": "Kullanıcı", "HeaderUploadImage": "Resim Yükle", "HeaderUpcomingOnTV": "TV'de Yaklaşan", "HeaderTypeText": "Metin Gir", - "HeaderTunerDevices": "Tuner Cihazları", + "HeaderTunerDevices": "Alıcı Cihazları", "HeaderThisUserIsCurrentlyDisabled": "Bu kullanıcı şu anda pasif", "HeaderTags": "Etiketler", "HeaderSubtitleProfiles": "Altyazı Profilleri", @@ -693,5 +691,52 @@ "HeaderSortBy": "Sırala", "HeaderShutdown": "Kapat", "HeaderSettings": "Ayarlar", - "LabelLogs": "Günlük:" + "LabelLogs": "Günlük:", + "HeaderSelectMetadataPathHelp": "İçinde meta veri depolamak istediğiniz yola göz atın veya bu yolu girin. Klasörün yazılabilir olması gerekir.", + "HeaderResponseProfileHelp": "Yanıt profilleri, belirli media türlerini oynatırken aygıta gönderilen bilgileri özelleştirmek için bir yol sağlar.", + "HeaderProfileServerSettingsHelp": "Bu değerler Jellyfin Server'ın kendini cihaza nasıl sunacağını kontrol eder.", + "HeaderPlayOn": "Üzerinde oyna", + "HeaderPaths": "Yollar", + "HeaderKodiMetadataHelp": "NFO meta verilerini açmak yada kapatmak için, meta verileri bölümünü kullanın ve her tür medya için seçeneklerinizi ayarlayın.", + "HeaderInstantMix": "Ani mix", + "ButtonSplit": "Ayır", + "Items": "Nesneler", + "HeaderSubtitleProfilesHelp": "Altyazı profilleri cihaz tarafından desteklenen altyazı formatlarını tanımlar.", + "HeaderSubtitleAppearance": "Altyazı Görünümü", + "HeaderSelectTranscodingPathHelp": "Geçici Video Kodlama dosyaları için bir dosya yolu seçin yada yazın. Dosya yoluna yazma yetkisi gereklidir.", + "HeaderSelectTranscodingPath": "Video Kodlaması İçin Geçici Dosya Yolu Seç", + "HeaderSelectServerCachePathHelp": "Önbellek dosyaları için bir dosya yolu seçin yada yazın. Dosya yoluna yazma yetkisi gereklidir.", + "CopyStreamURLError": "URL kopyalanırken bir hata oluştu.", + "OptionNone": "Hiçbiri", + "None": "Hiçbiri", + "HeaderNavigation": "Navigasyon", + "AllowFfmpegThrottling": "Video Kodlamasını Limitle", + "Artist": "Oyuncu", + "Album": "Albüm", + "EveryXMinutes": "Her {0} dakika", + "OnWakeFromSleep": "Uyku modundan çıkılarak uyanıldığında", + "DailyAt": "Her gün {0} 'de", + "LastSeen": "Son görülme {0}", + "WriteAccessRequired": "Jellyfin Sunucusu bu dizine yazma iznine ihtiyaç duymakta. Lütfen yazma izin ayarlarını kontrol edip tekrar deneyiniz.", + "PathNotFound": "Gösterilen yol bulunamadı. Lütfen gösterdiğiniz yolun doğru olduğundan emin olun ve tekrar deneyin.", + "EveryHour": "Her saat", + "EveryXHours": "Her {0} saatte bir", + "OnApplicationStartup": "Uygulama başladığında", + "HttpsRequiresCert": "Güvenli bağlantı kurulabilmesi için, Let's Encrypt gibi güvenilir bir sertifika sağlayıcısından edinilmiş sertifikayı tanıtmanız gerekmektedir. Lütfen bir sertifika tanımlayın ya da güvenli bağlantı seçeneğini devre dışı bırakın.", + "Home": "Anasayfa", + "HideWatchedContentFromLatestMedia": "İzlenmiş içeriği En Son Eklenenler klasöründe gösterme", + "HeaderTypeImageFetchers": "Görüntü İndirici", + "HeaderTracks": "Parçalar", + "HeaderSeriesStatus": "Dizi Durumu", + "HeaderSeriesOptions": "Dizi Seçenekleri", + "Episode": "Bölüm", + "DeinterlaceMethodHelp": "Tarama tipi görüntülerde titreşimi yok etmek için kullanılmasını istediğiniz metodu seçin.", + "ClientSettings": "Kullanıcı Ayarları", + "BoxSet": "Seri Filmler", + "AskAdminToCreateLibrary": "Kütüphane oluşturmak için yöneticiden izin iste.", + "AllowFfmpegThrottlingHelp": "Video dönüşüm işlemleri yeterince ilerlediyse kaynak tüketimini azaltmak için durdur. İleri/geri sarma işlemlerinin az yapıldığı durumlarda çok kullanışlıdır. Oynatım sorunları ile karşılaşırsanız bu özelliği kapatın.", + "AlbumArtist": "Sanatçı", + "HeaderTuners": "Alıcılar", + "HeaderTranscodingProfileHelp": "Kodlama gerekince hangi formatın kullanılacağını belirtmek için kodlama profili ekle.", + "ButtonTogglePlaylist": "Liste" } diff --git a/src/strings/uk.json b/src/strings/uk.json index 57bd678643..1c4c49774d 100644 --- a/src/strings/uk.json +++ b/src/strings/uk.json @@ -20,9 +20,9 @@ "HeaderAutomaticUpdates": "Автоматичне оновлення", "HeaderBooks": "Книги", "HeaderDeleteDevice": "Видалить пристрій", - "HeaderLatestEpisodes": "Останні епізоди", - "HeaderLatestMedia": "Останні медіа", - "HeaderLatestMovies": "Останні фільми", + "HeaderLatestEpisodes": "Нещодавно переглянуті серії", + "HeaderLatestMedia": "Нещодавно переглянуті", + "HeaderLatestMovies": "Нещодавні фільми", "HeaderLatestMusic": "Остання музика", "HeaderMovies": "Фільми", "HeaderSeasons": "Сезони", @@ -93,7 +93,7 @@ "ValueSeriesCount": "{0} серій", "ValueSongCount": "{0} пісень", "AddToPlaylist": "Додати до списку відтворення", - "AccessRestrictedTryAgainLater": "Доступ тимчасово заборонений. Спробуйте пізніше.", + "AccessRestrictedTryAgainLater": "На даний момент доступ заборонений. Будь ласка спробуйте пізніше.", "Actor": "Виконавець", "AllLanguages": "Всі мови", "AllLibraries": "Всі бібліотеки", @@ -102,12 +102,39 @@ "All": "Всі", "AllChannels": "Всі канали", "AllEpisodes": "Всі епізоди", - "AllowRemoteAccess": "Дозволити віддалене підключення до цього сервера Jellyfin", + "AllowRemoteAccess": "Дозволити віддалене підключення до цього сервера Jellyfin.", "AlwaysPlaySubtitles": "Завжди відтворювати субтитри", "AnyLanguage": "Будь-яка мова", "Anytime": "Завжди", "Add": "Додати", "AddedOnValue": "Додано", "Albums": "Альбоми", - "Absolute": "Абсолютний" + "Absolute": "Абсолютний", + "HeaderFavoriteEpisodes": "Улюблені серії", + "Movies": "Фільми", + "Collections": "Колекції", + "Folders": "Директорії", + "HeaderNextUp": "Наступний", + "HeaderAlbumArtists": "Виконавці альбомів", + "HeaderFavoriteSongs": "Улюблені пісні", + "Favorites": "Улюблені", + "HeaderFavoriteAlbums": "Улюблені альбоми", + "Genres": "Жанри", + "Books": "Книги", + "Artists": "Виконавці", + "HeaderLiveTV": "Ефірне ТБ", + "Channels": "Канали", + "HeaderFavoriteArtists": "Улюблені виконавці", + "HeaderFavoriteShows": "Улюблені шоу", + "HeaderContinueWatching": "Продовжити перегляд", + "AddItemToCollectionHelp": "Додайте елементи до колекції за допомогою пошуку або кліком правої кнопкої миші чи натисненням на меню.", + "AllowedRemoteAddressesHelp": "Список з комами, в якості розділювачів, визначає IP-адреси та IP/мережеві маски для мереж, яким дозволено підключатись віддалено. Якщо залишити строку пустою, то усі віддалені підключення будуть дозволені.", + "AllowRemoteAccessHelp": "Якщо не відмічено прапорцем, усі віддалені підключення будуть заблоковані.", + "AllowFfmpegThrottling": "Примусово обмежити перекодування", + "AllowMediaConversionHelp": "Надайте або забороніть доступ для можливості перетворення медіа.", + "AllowMediaConversion": "Дозволити перетворення медіа", + "Alerts": "Термінові сповіщення", + "AlbumArtist": "Виконавець альбому", + "Album": "Альбом", + "AdditionalNotificationServices": "Пошук у каталозі плагінів для встановлення додаткових сервісів сповіщень." } diff --git a/src/strings/ur_PK.json b/src/strings/ur_PK.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/src/strings/ur_PK.json @@ -0,0 +1 @@ +{} diff --git a/src/strings/vi.json b/src/strings/vi.json index 9cb4b48495..e8fbe64eff 100644 --- a/src/strings/vi.json +++ b/src/strings/vi.json @@ -30,7 +30,7 @@ "HeaderLatestEpisodes": "Các tập phim mới nhất", "HeaderLatestMovies": "Phim mới nhất", "HeaderRecentlyPlayed": "Phát gần đây", - "HeaderSeries": "Series:", + "HeaderSeries": "Series", "HeaderStatus": "Trạng thái", "HeaderSystemDlnaProfiles": "Hồ sơ hệ thống", "HeaderUsers": "dùng", @@ -42,7 +42,7 @@ "LabelEnableDlnaPlayTo": "Cho phép DLNA chạy để", "LabelEvent": "Sự kiện:", "LabelFinish": "Kết thúc", - "LabelLanguage": "Ngôn ngữ", + "LabelLanguage": "Ngôn ngữ:", "LabelName": "Tên:", "LabelNewPassword": "Mật khẩu mới:", "LabelNewPasswordConfirm": "Xác nhận mật khẩu mới:", @@ -51,7 +51,7 @@ "LabelSaveLocalMetadata": "Lưu các ảnh nghệ thuật và metadata vào trong các thư mục media", "LabelSaveLocalMetadataHelp": "Lưu các ảnh nghệ thuật và metadata vào trong các thư mục media, sẽ đưa chúng vào một nơi bạn có thể chỉnh sửa dễ dàng hơn.", "LabelTime": "Thời gian:", - "LabelYourFirstName": "Tên của Bạn", + "LabelYourFirstName": "Tên của bạn:", "LabelYoureDone": "Bạn đã hoàn thành!", "MaxParentalRatingHelp": "Nội dung với đánh giá cao hơn sẽ được ẩn đi từ người dùng này.", "MessageNothingHere": "Không có gì ở đây.", @@ -87,7 +87,7 @@ "OptionTrackName": "Tên bài", "ParentalRating": "Parental Rating", "PasswordMatchError": "Mật khẩu và mật khẩu xác nhận cần phải khớp nhau .", - "PasswordResetComplete": "Mật khẩu đã được reset", + "PasswordResetComplete": "Mật khẩu đã được cài đặt lại.", "PasswordResetConfirmation": "Bạn có chắc muốn reset mật khẩu?", "PasswordSaved": "Mật khẩu đã được lưu.", "Saturday": "Thứ Bảy", @@ -116,7 +116,561 @@ "ThisWizardWillGuideYou": "Thủ thuật này sẽ hướng dẫn quá trình cài đặt cho bạn. Để bắt đầu, vui lòng lựa chọn ngôn ngữ bạn ưa thích.", "UninstallPluginConfirmation": "Bạn có chắc muốn gỡ bỏ{0}?", "UninstallPluginHeader": "Gỡ bỏ Plugin", - "AccessRestrictedTryAgainLater": "Truy cập hiện đang hạn chế. Hãy thử lại sau.", + "AccessRestrictedTryAgainLater": "Truy cập hiện đang bị hạn chế. Hãy thử lại sau.", "AddToCollection": "Thêm vào bộ sưu tập", - "Actor": "Diễn viên" + "Actor": "Diễn viên", + "ButtonRevoke": "Thu hồi", + "ButtonResume": "Tiếp tục", + "ButtonRestart": "Khởi động lại", + "ButtonResetEasyPassword": "Đặt lại mã pin nhanh", + "ButtonRepeat": "Lặp lại", + "ButtonRename": "Đổi tên", + "ButtonRefreshGuideData": "Làm mới dữ liệu hướng dẫn", + "ButtonRefresh": "Làm mới", + "ButtonQuickStartGuide": "Hướng dẫn nhanh", + "ButtonProfile": "Hồ sơ", + "ButtonPreviousTrack": "Bài trước", + "ButtonPlay": "Chơi", + "ButtonPause": "Tạm dừng", + "ButtonParentalControl": "Kiểm soát của cha mẹ", + "ButtonOpen": "Mở", + "ButtonOff": "Tắt", + "ButtonNextTrack": "Tiếp theo", + "ButtonNetwork": "Mạng", + "ButtonMore": "Thêm", + "ButtonManualLogin": "Đăng nhập thủ công", + "ButtonLibraryAccess": "Truy cập thư viện", + "ButtonLearnMore": "Tìm hiểu thêm", + "ButtonInfo": "Thông tin", + "ButtonHome": "Trang chủ", + "ButtonHelp": "Giúp đỡ", + "ButtonGuide": "Hướng dẫn", + "ButtonGotIt": "Hiểu rồi", + "ButtonFullscreen": "Toàn màn hình", + "ButtonForgotPassword": "Quên mật khẩu", + "ButtonFilter": "Lọc", + "ButtonEditOtherUserPreferences": "Chỉnh sửa thông tin, hình ảnh và sở thích cá nhân.", + "ButtonEditImages": "Sửa hình ảnh", + "ButtonEdit": "Sửa", + "ButtonDownload": "Tải", + "ButtonDown": "Xuống", + "ButtonDelete": "Xoá", + "ButtonConnect": "Kết nối", + "ButtonChangeServer": "Đổi máy chủ", + "ButtonBack": "Lùi", + "ButtonAudioTracks": "Track âm thanh", + "ButtonArrowUp": "Lên", + "ButtonArrowRight": "Phải", + "ButtonArrowLeft": "Trái", + "ButtonArrowDown": "Xuống", + "ButtonAddServer": "Thêm máy chủ", + "ButtonAddScheduledTaskTrigger": "Thêm kích hoạt", + "ButtonAddMediaLibrary": "Thêm thư viện Media", + "ButtonAddImage": "Thêm hình ảnh", + "BurnSubtitlesHelp": "Xác định xem máy chủ có nên ghi phụ đề khi chuyển đổi video hay không. Tránh thực hiện việc này sẽ cải thiện hiệu suất máy chủ đáng kể. Chọn Tự động để ghi các phụ đề có định dạng dựa trên hình ảnh (VOBSUB, PGS, SUB, IDX) và một vài phụ đề ASS/SSA nhất định.", + "Browse": "Duyệt", + "BoxRear": "Hộp (mặt sau)", + "Books": "Sách", + "BookLibraryHelp": "Âm thanh và sách văn bản được hỗ trợ. Xem lại {0}hướng dẫn đặt tên sách{1}.", + "Blacklist": "Danh sách đen", + "BirthPlaceValue": "Nơi sinh: {0}", + "BirthLocation": "Nơi sinh", + "BirthDateValue": "Sinh năm: {0}", + "Backdrops": "Phông nền", + "Backdrop": "Phông nền", + "AutoBasedOnLanguageSetting": "Tự động (dựa trên cài đặt ngôn ngữ)", + "Auto": "Tự động", + "AuthProviderHelp": "Chọn Nhà cung cấp xác thực sẽ được sử dụng để xác thực mật khẩu người dùng này.", + "Audio": "Âm thanh", + "AttributeNew": "Tạo mới", + "AspectRatio": "Tỷ lệ khung hình", + "AskAdminToCreateLibrary": "Yêu cầu quản trị viên tạo thư viện.", + "Ascending": "Tăng dần", + "AsManyAsPossible": "Càng nhiều càng tốt", + "Artists": "Nghệ Sĩ", + "AroundTime": "Khoảng {0}", + "Anytime": "Bất cứ lúc nào", + "AnyLanguage": "Ngôn Ngữ Bất Kỳ", + "AlwaysPlaySubtitlesHelp": "Phụ đề phù hợp với sở thích ngôn ngữ sẽ được tải bất kể ngôn ngữ âm thanh.", + "AlwaysPlaySubtitles": "Luôn hiển thị phụ đề", + "AllowedRemoteAddressesHelp": "Danh sách địa chỉ IP được phân tách bằng dấu phẩy hoặc các mục IP/netmask cho các mạng sẽ được phép kết nối từ xa. Nếu để trống, tất cả các địa chỉ sẽ được cho phép.", + "AllowRemoteAccessHelp": "Nếu không được chọn, tất cả các kết nối từ xa sẽ bị chặn.", + "AllowRemoteAccess": "Cho phép kết nối từ xa đến Máy chủ Jellyfin.", + "AllowOnTheFlySubtitleExtractionHelp": "Phụ đề nhúng có thể được trích xuất từ video và dùng như văn bản thuần túy để giúp ngăn chặn chuyển mã video. Trên một số hệ thống, việc này có thể mất nhiều thời gian và khiến quá trình phát video bị đình trệ trong quá trình trích xuất. Vô hiệu hóa điều này để có phụ đề nhúng được ghi trong chuyển mã video khi chúng không được thiết bị khách hỗ trợ.", + "AllowOnTheFlySubtitleExtraction": "Cho phép trích xuất phụ đề trực tiếp", + "AllowMediaConversionHelp": "Cấp hoặc từ chối truy cập vào tính năng chuyển đổi media.", + "AllowMediaConversion": "Cho phép chuyển đổi media", + "AllowHWTranscodingHelp": "Cho phép bộ chỉnh chuyển mã stream khi đang chơi. Điều này có thể giúp giảm tải của máy chủ khi chuyển mã.", + "AllLibraries": "Tất cả các thư viện", + "AllLanguages": "Tất cả các ngôn ngữ", + "AllEpisodes": "Tất cả các tập phim", + "AllComplexFormats": "Tất cả các định dạng phức tạp (ASS, SSA, VOBSUB, PGS, SUB, IDX)", + "AllChannels": "Tất cả các kênh", + "Alerts": "Cảnh Báo", + "Albums": "Albums", + "Aired": "Đã phát sóng", + "AirDate": "Ngày phát sóng", + "AdditionalNotificationServices": "Duyệt qua danh mục plugin để cài đặt các dịch vụ thông báo bổ sung.", + "AddedOnValue": "Đã thêm {0}", + "AddToPlaylist": "Thêm vào danh sách phát", + "AddToPlayQueue": "Thêm vào hàng đợi", + "AddItemToCollectionHelp": "Thêm các mục vào bộ sưu tập bằng cách tìm kiếm và nhấp chuột phải hoặc nhấn vào menu để thêm chúng vào bộ sưu tập.", + "Absolute": "Tuyệt đối", + "ButtonSend": "Gửi", + "ButtonSelectView": "Chọn chế độ xem", + "ButtonSelectServer": "Chọn máy chủ", + "ButtonScanAllLibraries": "Quét tất cả các thư viện", + "ButtonOk": "Đồng Ý", + "ButtonShuffle": "Xáo trộn", + "Categories": "Phân loại", + "CancelRecording": "Ngưng ghi hình", + "ButtonWebsite": "Trang web", + "ButtonViewWebsite": "Xem trang web", + "ButtonUp": "Lên", + "ButtonUninstall": "Gỡ cài đặt", + "ButtonTrailer": "Tóm tắt", + "ButtonSubtitles": "Phụ đề", + "ButtonSubmit": "Đăng", + "ButtonSplit": "Tách", + "ButtonStop": "Ngưng", + "ButtonStart": "Bắt đầu", + "ButtonSignIn": "Đăng nhập", + "ButtonShutdown": "Tắt", + "ButtonSettings": "Cài đặt", + "DefaultErrorMessage": "Có lỗi xảy ra trong lúc xử lý yêu cầu của bạn. Xin hãy thử lại sau.", + "Default": "Mặc định", + "DeathDateValue": "Không hoạt động: {0}", + "DatePlayed": "Ngày phát", + "DateAdded": "Ngày thêm vào", + "CustomDlnaProfilesHelp": "Tạo một bộ thiết lập tuỳ chọn dành cho một thiết bị mới hoặc thay thế một thiết lập hệ thống.", + "CriticRating": "Đánh giá phê bình", + "CopyStreamURLError": "Có lỗi xảy ra lúc sao chép URL.", + "CopyStreamURLSuccess": "URL đã được sao chép.", + "CopyStreamURL": "Sao Chép URL Phát Sóng", + "Continuing": "Tiếp tục", + "ContinueWatching": "Tiếp tục xem", + "Connect": "Kết nối", + "ConfirmEndPlayerSession": "Bạn có muốn tắt máy chủ Jellyfin trên {0}?", + "ConfirmDeletion": "Xác Nhận Xoá", + "ConfirmDeleteItems": "Xoá những mục này sẽ xoá chúng khỏi ổ cứng và thư viện của bạn. Bạn có chắc chắn muốn tiếp tục?", + "ConfirmDeleteItem": "Xoá mục này sẽ xoá nó khỏi ổ cứng và thư viện của bạn. Bạn có chắc chắn muốn tiếp tục?", + "ConfirmDeleteImage": "Bạn có chắc chắn xoá ảnh này?", + "ConfigureDateAdded": "Thiết lập cách xác định \"ngày thêm vào\" trong mục cài đặt Thư Viện của phần quản lý máy chủ Jellyfin", + "Composer": "Tác giả", + "CommunityRating": "Đánh giá của cộng đồng", + "ColorTransfer": "Chuyển đổi màu", + "ColorSpace": "Bộ mã màu", + "ColorPrimaries": "Những màu chủ đạo", + "Collections": "Bộ sưu tập", + "ClientSettings": "Cài đặt thiết bị phát", + "CinemaModeConfigurationHelp": "Chế độ Cinema giúp bạn mang lại trải nghiệm rạp chiếu phim ngay tại phòng khách với khả năng phát trailers và những đoạn mở đầu tuỳ chọn trước phần chính của bộ phim.", + "ChannelNumber": "Kênh số", + "Channels": "Kênh", + "ChannelNameOnly": "Chỉ kênh {0}", + "ChannelAccessHelp": "Chọn những kênh để chia vẻ với người dùng này. Người quản lý sẽ có thể thay đổi toàn bộ kênh bằng cách sử dụng bộ quản lý thông tin.", + "ChangingMetadataImageSettingsNewContent": "Thay đổi về thiết lập của việc tải thông tin hoặc hình ảnh sẽ chỉ có tác dụng với những nội dung mới được thêm vào thư viện. Để những thiết lập mới có tác dụng với nội dung đã có sẵn, bạn sẽ phải cập nhật lại thông tin của chúng.", + "CancelSeries": "Ngưng series", + "ButtonTogglePlaylist": "Danh sách phát", + "ButtonToggleContextMenu": "Thêm", + "BoxSet": "Tuyển tập", + "Box": "Hộp", + "Banner": "Ảnh bìa", + "Art": "Nghệ thuật", + "Artist": "Nghệ Sĩ", + "AllowFfmpegThrottlingHelp": "Tạm dừng quá trình chuyển mã hoặc chuyển đổi định dạng để tiết kiệm tài nguyên máy chủ khi việc này đã đủ để phát so với vị trí hiện tại. Điều này hữu hiệu khi không tua nhanh thường xuyên lúc nghe nhạc hoặc xem phim. Hãy tắt tính năng này nếu có hiện tượng giật lag khi nghe nhạc hoặc xem phim.", + "AllowFfmpegThrottling": "Điều tiết sự chuyển mã", + "AlbumArtist": "Nghệ sĩ Album", + "Album": "Album", + "DisplayMissingEpisodesWithinSeasonsHelp": "Thiết lập này cũng phải được kích hoạt trong thiết lập máy chủ dành cho thư viện phim bộ.", + "DisplayMissingEpisodesWithinSeasons": "Hiển thị những tập phim bị thiếu trong mỗi phần", + "DisplayInOtherHomeScreenSections": "Những phần hiển thị trên trang chính như là nội dung mới nhất và nội dung tiếp theo", + "DisplayInMyMedia": "Hiển thị trên trang chính", + "Display": "Hiển thị", + "Dislike": "Không thích", + "Disconnect": "Ngắt kết nối", + "Disc": "Đĩa", + "Disabled": "Đã vô hiệu hoá", + "Directors": "Đạo Diễn", + "Director": "Đạo Diễn", + "DirectStreaming": "Phát trực tuyến", + "DirectStreamHelp2": "Phát trực tuyến sử dụng rất ít tài nguyên máy chủ mà không giảm chất lượng video.", + "DirectStreamHelp1": "Nội dung này tương thích với thiết bị về độ phân giải và dạng mã hoá (H.264, AC3, v.v.), nhưng lại không tương tích định dạng (mkv, avi, wmv, v.v.). Video sẽ được chuyển đổi định dạng trực tiếp ngay trước khi phát trên thiết bị.", + "DirectPlaying": "Phát trực tiếp", + "DeviceAccessHelp": "Thiết lập này chỉ áp dụng cho những thiết bị có thể định danh và sẽ không chặn được truy cập từ trình duyệt. Chọn lọc thiết bị người dùng sẽ chặn người dùng này truy cập từ những thiết bị mới cho đến khi được duyệt.", + "DetectingDevices": "Đang tìm kiếm thiết bị", + "Desktop": "Máy tính", + "Descending": "Giảm dần", + "Depressed": "Hạ xuống", + "DeleteUserConfirmation": "Bạn có chắc chắn muốn xoá người dùng này?", + "DeleteMedia": "Xoá nội dung", + "DeleteDeviceConfirmation": "Bạn có chắc chắn muốn xoá thiết bị này? Nó sẽ xuất hiện lại khi người dùng đăng nhập bằng thiết bị đó.", + "DeinterlaceMethodHelp": "Chọn phương pháp khử xen kẽ khi chuyển mã những nội dung sử dụng phương pháp quét xen kẽ.", + "DefaultSubtitlesHelp": "Phụ đề được sử dụng dựa vào thiết lập mặc định (default) và bắt buộc (forced) trong phần thông tin bổ trợ. Tuỳ chọn ưu tiên ngôn ngữ sẽ có tác dụng khi có nhiều phụ đề khác nhau.", + "DefaultMetadataLangaugeDescription": "Đây là thiết lập mặc định chung, bạn có thể tuỳ chỉnh thiết lập riêng cho từng thư viện.", + "DisplayModeHelp": "Chọn kiểu bố trí giao diện mà bạn muốn.", + "Download": "Tải xuống", + "Down": "Xuống", + "DoNotRecord": "Không ghi lại", + "EnableCinemaMode": "Chế độ rạp phim", + "EnableBackdropsHelp": "Hiển thị phông nền phía sau một số trang khi xem thư viện.", + "EnableBackdrops": "Phông nền", + "EditSubtitles": "Chỉnh sửa phụ đề", + "EditMetadata": "Chỉnh sửa thông tin", + "EditImages": "Chỉnh sửa hình ảnh", + "Edit": "Chỉnh sửa", + "EasyPasswordHelp": "Mã PIN tiện lợi được sử dụng cho việc truy cập offline trên những thiết bị được hỗ trợ và cũng có thể sử dụng dành cho truy cập dễ dàng trong nội mạng.", + "DropShadow": "Đổ Bóng", + "DrmChannelsNotImported": "Những kênh được bảo vệ bản quyền sẽ không được nhập vào.", + "DownloadsValue": "{0} đã tải xuống", + "EnableColorCodedBackgrounds": "Màu nền theo loại kênh", + "HeaderDateIssued": "Ngày Phát Hành", + "HeaderContinueWatching": "Tiếp Tục Xem", + "HeaderContinueListening": "Tiếp Tục Nghe", + "HeaderCodecProfileHelp": "Bộ giải mã chỉ ra những kiểu mã hoá nhất định mà một thiết bị có thể phát. Nếu một nội dung không thể phát, nó sẽ được chuyển mã, thậm chí nếu kiểu mã hoá đó được thiết lập phát trực tiếp.", + "HeaderContainerProfileHelp": "Bộ định dạng chỉ ra những định dạng nhất định mà một thiết bị có thể phát. Nếu nội dung có định dạng không thể phát, nội dung sẽ được chuyển đổi định dạng, kể cả khi định dạng đó được thiết lập phát trực tiếp.", + "HeaderContainerProfile": "Bộ Định Dạng", + "HeaderConnectionFailure": "Kế Nối Thất Bại", + "HeaderConnectToServer": "Kết Nối Đến Máy Chủ", + "HeaderConfirmRevokeApiKey": "Thu Hồi Quyền Truy Cập API Key", + "HeaderConfirmProfileDeletion": "Xác Nhận Xoá Hồ Sơ", + "HeaderConfirmPluginInstallation": "Xác Nhận Cài Đặt Plugin", + "HeaderConfigureRemoteAccess": "Thiết Lập Truy Cập Từ Xa", + "HeaderCodecProfile": "Bộ Giải Mã", + "HeaderChapterImages": "Hình Ảnh Phân Đoạn", + "HeaderChannels": "Kênh", + "HeaderChannelAccess": "Quyền Truy Cập Kênh", + "HeaderCastCrew": "Diễn Viên & Ê-kíp", + "HeaderCastAndCrew": "Diễn Viên & Ê-kíp", + "HeaderCancelSeries": "Huỷ Series", + "HeaderCancelRecording": "Dừng Ghi Âm/Ghi Hình", + "HeaderBranding": "Tạo Thương Hiệu", + "HeaderBooks": "Sách", + "HeaderBlockItemsWithNoRating": "Khoá những mục không có thông tin đánh giá hoặc thông tin không đáng tin cậy:", + "HeaderAudioSettings": "Cài Đặt Âm Thanh", + "HeaderAudioBooks": "Sách Nói", + "HeaderAppearsOn": "Xuất Bản Vào", + "HeaderApp": "Ứng dụng", + "HeaderApiKeysHelp": "Những ứng dụng khác cần có \"API key\" để tương tác với máy chủ Jellyfin. Những mã này được tạo ra bằng cách đăng nhập vào máy chủ Jellyfin, hoặc bạn có thể cung cấp cho ứng dụng một mã truy cập.", + "HeaderApiKeys": "API Keys", + "HeaderApiKey": "API Key", + "HeaderAllowMediaDeletionFrom": "Cho Phép Xoá Nội Dung", + "HeaderAlert": "Thông Báo", + "HeaderAlbums": "Albums", + "HeaderAlbumArtists": "Nghệ Sĩ Album", + "HeaderAdmin": "Quản Trị", + "HeaderAdditionalParts": "Phần Bổ Sung", + "HeaderAddUpdateImage": "Thêm/Thay Đổi Hình Ảnh", + "HeaderAddToPlaylist": "Thêm vào Danh Sách Phát", + "HeaderAddToCollection": "Thêm vào Bộ Sưu Tập", + "HeaderAddScheduledTaskTrigger": "Thêm Kích Hoạt Tác Vụ", + "HeaderActivity": "Hoạt Động", + "HeaderActiveRecordings": "Bản Ghi Hình/Ghi Âm Đang Hoạt Động", + "HardwareAccelerationWarning": "Bật tính năng hỗ trợ từ phần cứng có thể gây ra sự bất ổn trong một vài môi trường. Hãy chắc chắn rằng điều hành và driver thiết bị đồ hoạ đã được cập nhật mới nhất. Nếu gặp vấn đề khi phát video sau khi bật tính năng này, bạn nên tắt tính năng này.", + "HeaderActiveDevices": "Thiết Bị Đang Hoạt Động", + "HeaderAccessScheduleHelp": "Tạo một thời gian biểu để giới hạn quyền truy cập vào một số khung giờ nhất định.", + "HeaderAccessSchedule": "Thời Gian Truy Cập", + "HandledByProxy": "Được xử lý bằng phương thức đảo ngược proxy", + "HDPrograms": "Chương trình chất lượng cao (HD)", + "EncoderPresetHelp": "Chọn một giá trị nhanh hơn để cải thiện hiệu suất máy chủ, hoặc một giá trị chậm hơn để tăng chất lượng video.", + "H264CrfHelp": "Hệ Số Tỉ Lệ Cố Định (Constant Rate Factor (CRF)) là thiết lập chất lượng mặc định dành cho bộ mã hoá x264. Bạn có thể điều chỉnh giá trị trong khoảng 0 đến 51, trong đó giá trị càng nhỏ thì chất lượng càng tốt (đồng nghĩa với việc dung lượng tập tin lớn hơn). Giá trị vừa phải nằm trong khoảng từ 18 đến 28. Giá trị mặc định dành cho x264 là 23, vì thế bạn có thể sử dụng nó để bắt đầu điều chỉnh cho phù hợp.", + "GuideProviderSelectListings": "Chọn Danh Sách", + "GuideProviderLogin": "Đăng nhập", + "Guide": "Lịch phát sóng", + "GuestStar": "Ngôi sao khách mời", + "GroupVersions": "Chia nhóm theo phiên bản", + "GroupBySeries": "Chia nhóm theo bộ", + "Genres": "Thể loại", + "Genre": "Thể loại", + "General": "Tổng Hợp", + "Fullscreen": "Toàn màn hình", + "Friday": "Thứ Sáu", + "FormatValue": "Định dạng: {0}", + "Folders": "Thư mục", + "FolderTypeUnset": "Nội Dung Tổng Hợp", + "FolderTypeMusicVideos": "Video Âm Nhạc", + "FolderTypeMusic": "Nhạc", + "FolderTypeMovies": "Phim lẻ", + "FolderTypeBooks": "Sách", + "Filters": "Bộ lọc", + "File": "Tập tin", + "FetchingData": "Đang tải thêm thông tin", + "Features": "Mục đặc trưng", + "Favorites": "Mục yêu thích", + "Favorite": "Mục yêu thích", + "FastForward": "Tua nhanh", + "FFmpegSavePathNotFound": "Máy chủ không thể tìm thấy chương trình FFmpeg trong đường dẫn bạn đã nhập. FFprobe thì cũng cần thiết và phải nằm trong cùng thư mục bên trên. Những phần mềm này thường được tổng hợp cùng nhau trong một lượt tải. Hãy thử lại sau khi kiểm tra đường dẫn.", + "Extras": "Đặc biệt", + "ExtractChapterImagesHelp": "Trích xuất hình ảnh từ những phân đoạn chính sẽ cho phép thiết bị phát hiển thị bảng lựa chọn cảnh thông qua những hình ảnh đó. Quá trình đó có thể chậm, cần nhiều tài nguyên máy chủ, và có thể cần một vài gigabytes trống. Điều này sẽ được thực hiện khi video được tìm thấy, và cũng như trong tác vụ hàng đêm. Thời gian thực hiện tác vụ này có thể điều chỉnh trong phần cài đặt tác vụ thường xuyên. Không nên thực hiện quá trình này trong giờ sử dụng cao điểm.", + "ExtraLarge": "Rất Lớn", + "ExitFullscreen": "Thoát khỏi chế độ toàn màn hình", + "EveryNDays": "Mỗi {0} ngày", + "ErrorSavingTvProvider": "Có lỗi xảy ra khi lưu thông tin của nhà cung cấp TV này. Hãy thử lại khi chắc chắn rằng nó có thể truy cập.", + "ErrorPleaseSelectLineup": "Hãy chọn một danh sách và thử lại. Nếu không có danh sách nào sẵn sàng, hãy chắc chắn rằng thông tin tài khoản, mật khẩu, và mã bưu điện đều chính xác.", + "ErrorMessageStartHourGreaterThanEnd": "Thời gian kết thúc phải lớn hơn thời gian bắt đầu.", + "ErrorGettingTvLineups": "Có lỗi xảy ra khi tải danh sách TV này. Hãy thử lại khi chắc chắn rằng thông tin của bạn chính xác.", + "ErrorDeletingItem": "Có lỗi xảy ra khi xoá mục này khỏi máy chủ Jellyfin. Hãy thử lại sau khi kiểm tra chắc chắn rằng máy chủ Jellyfin có quyền ghi/xoá vào thư mục nội dung.", + "ErrorAddingXmlTvFile": "Có lỗi xảy ra khi truy cập tài liệu XMLTV. Hãy thử lại khi chắc chắn rằng tài liệu này tồn tại.", + "ErrorAddingTunerDevice": "Có lỗi xảy ra khi thêm vào thiết bị bắt sóng này. Hãy thử lại khi chắc chắn rằng nó có thể truy cập.", + "ErrorAddingMediaPathToVirtualFolder": "Có lỗi xảy ra khi thêm đường dẫn này. Hãy chắc chắn rằng đường dẫn này đúng và máy chủ Jellyfin có quyền truy cập dữ liệu ở đường dẫn đó.", + "ErrorAddingListingsToSchedulesDirect": "Có lỗi xảy ra khi thêm danh sách này vào tài khoản Schedules Direct của bạn. Schedules Direct chỉ cho phép một số lượng danh sách nhất định mỗi tài khoản. Bạn có thể cần phải đăng nhập vào trang web của Schedules Direct và xoá những danh sách khác trước khi có thể thêm danh sách mới.", + "Episodes": "Tập", + "Episode": "Tập", + "EndsAtValue": "Kết thúc tại {0}", + "Ended": "Đã kết thúc", + "EnableThemeVideosHelp": "Phát nền những video chủ đề khi lướt qua thư viện nội dung.", + "EnableThemeVideos": "Video chủ đề", + "EnableThemeSongsHelp": "Phát những bài hát chủ đề khi lướt qua thư viện nội dung.", + "EnableThemeSongs": "Nhạc chủ đề", + "EnableStreamLoopingHelp": "Cho phép tính năng này nếu live streams chỉ dài một vài giây và cần được lặp lại liên tục. Bật tính năng này khi không cần thiết có thể gây ra nhiều vấn đề khác.", + "EnableStreamLooping": "Tự động phát lại live streams", + "EnablePhotosHelp": "Hình ảnh sẽ được nhận diện và hiển thị bên cạnh những nội dung media.", + "EnablePhotos": "Hiển thị hình ảnh", + "EnableNextVideoInfoOverlayHelp": "Khi ở phần cuối video, hiển thị thông tin về video tiếp theo trong danh sách phát hiện tại.", + "EnableNextVideoInfoOverlay": "Hiển thị thông tin video tiếp theo ở phần cuối video", + "EnableHardwareEncoding": "Sử dụng phần cứng để hỗ trợ chuyển mã", + "EnableExternalVideoPlayersHelp": "Phần mềm phát video từ thiết bị sẽ được hiển thị khi bắt đầu phát video.", + "EnableExternalVideoPlayers": "Sử dụng phần mềm phát video từ thiết bị", + "EnableDisplayMirroring": "Cho phép trình chiếu trên thiết bị khác", + "HeaderProfileInformation": "Thông Tin Hồ Sơ", + "HeaderProfile": "Hồ Sơ", + "HeaderPreferredMetadataLanguage": "Ngôn Ngữ Thông Tin Bổ Trợ Yêu Thích", + "HeaderPluginInstallation": "Cài Đặt Plugin", + "HeaderPleaseSignIn": "Hãy đăng nhập", + "HeaderPlaybackError": "Lỗi Phát Sóng", + "HeaderPlayback": "Phát Nội Dung", + "HeaderPlayOn": "Phát Trên", + "HeaderPlayAll": "Phát Tất Cả", + "HeaderPinCodeReset": "Đặt Lại Mã PIN", + "HeaderPhotoAlbums": "Album Ảnh", + "HeaderPeople": "Nhân Vật", + "HeaderPendingInvitations": "Những Lời Mời Đang Chờ", + "HeaderPaths": "Đường Dẫn", + "HeaderPasswordReset": "Đặt Lại Mật Khẩu", + "HeaderPassword": "Mật Khẩu", + "HeaderParentalRatings": "Đánh Giá Của Phụ Huynh", + "HeaderOtherItems": "Những Mục Khác", + "HeaderOnNow": "Phát Sóng Hiện Tại", + "HeaderNextVideoPlayingInValue": "Video Tiếp Theo Sẽ Phát trong {0}", + "HeaderNextUp": "Tiếp Theo", + "HeaderNextEpisodePlayingInValue": "Tập Tiếp Theo Sẽ Được Chạy trong {0}", + "HeaderNewDevices": "Thiết Bị Mới", + "HeaderNewApiKey": "Mã API Mới", + "HeaderNavigation": "Điều Hướng", + "HeaderMyMediaSmall": "Nội Dung Của Tôi (cỡ nhỏ)", + "HeaderMyMedia": "Nội Dung Của Tôi", + "HeaderMyDevice": "Thiết Bị Của Tôi", + "HeaderMusicVideos": "Video Âm Nhạc", + "HeaderMusicQuality": "Chất Lượng Âm Nhạc", + "HeaderMovies": "Phim", + "HeaderMoreLikeThis": "Nội Dung Tương Tự", + "HeaderMetadataSettings": "Cài Đặt Dữ Liệu Bổ Trợ", + "HeaderMediaInfo": "Thông Tin Nội Dung", + "HeaderMediaFolders": "Thư Mục Chứa Nội Dung", + "HeaderMedia": "Nội Dung", + "HeaderLoginFailure": "Đăng Nhập Không Thành Công", + "HeaderLiveTvTunerSetup": "Cài Đặt Bộ Bắt Sóng TV", + "HeaderLiveTv": "Truyền Hình Trực Tiếp", + "HeaderLiveTV": "Truyền Hình Trực Tiếp", + "HeaderLibrarySettings": "Cài Đặt Thư Viện", + "HeaderLibraryOrder": "Thứ Tự Thư Viện", + "HeaderLibraryFolders": "Thư Mục Của Thư Viện", + "HeaderLibraryAccess": "Truy Cập Thư Viện", + "HeaderLibraries": "Thư Viện", + "HeaderLatestRecordings": "Bản Ghi Âm/Ghi Hình Mới Nhất", + "HeaderLatestMusic": "Âm Nhạc Mới Nhất", + "HeaderLatestMedia": "Nội Dung Mới Nhất", + "HeaderKodiMetadataHelp": "Để bật hoặc tắt dữ liệu từ NFO, hãy chỉnh sửa thư viện trong phần cài đặt thư viện của Jellyfin và điều chỉnh phần lưu trữ dữ liệu bổ trợ.", + "HeaderKeepSeries": "Lưu Series", + "HeaderKeepRecording": "Tiếp Tục Ghi Âm/Ghi Hình", + "HeaderItems": "Mục", + "HeaderInstantMix": "Trộn Lẫn Nhanh", + "HeaderInstall": "Cài Đặt", + "HeaderImageSettings": "Thiết Lập Hình Ảnh", + "HeaderImageOptions": "Tuỳ Chọn Hình Ảnh", + "HeaderIdentifyItemHelp": "Hãy nhập một hoặc nhiều điều kiện tìm kiếm. Xoá điều kiện để tăng số lượng kết quả tìm kiếm.", + "HeaderIdentificationHeader": "Thông Tin Nhận Biết Trong Phần Đầu", + "HeaderIdentificationCriteriaHelp": "Nhập vào ít nhật một thông tin nhận biết.", + "HeaderIdentification": "Thông Tin Nhận Biết", + "HeaderHttpHeaders": "HTTP Headers", + "HeaderHome": "Trang Chủ", + "HeaderGuideProviders": "Nhà Cung Cấp Lịch Phát Sóng TV", + "HeaderGenres": "Thể Loại", + "HeaderForgotPassword": "Quên Mật Khẩu", + "HeaderForKids": "Dành Cho Trẻ Em", + "HeaderFilters": "Bộ Lọc", + "HeaderFetcherSettings": "Cài Đặt Chương Trình Tải Xuống", + "HeaderFetchImages": "Tải Hình Ảnh:", + "HeaderFeatures": "Nổi Bật", + "HeaderFavoritePeople": "Nhân Vật Yêu Thích", + "HeaderFavoriteAlbums": "Album Yêu Thích", + "HeaderFavoriteBooks": "Sách Yêu Thích", + "HeaderFavoriteVideos": "Video Yêu Thích", + "HeaderFavoriteSongs": "Bài Hát Yêu Thích", + "HeaderFavoriteArtists": "Nghệ Sĩ Yêu Thích", + "HeaderFavoriteEpisodes": "Tập Phim Yêu Thích", + "HeaderFavoriteShows": "Chương Trình Yêu Thích", + "HeaderFavoriteMovies": "Phim Yêu Thích", + "HeaderExternalIds": "Mã Định Danh Từ Bên Ngoài:", + "HeaderError": "Lỗi", + "HeaderEpisodes": "Tập", + "HeaderEnabledFieldsHelp": "Bỏ chọn một mục để khoá lựa chọn đó và không để nó thay đổi.", + "HeaderEnabledFields": "Những Mục Được Kích Hoạt", + "HeaderEditImages": "Chỉnh Sửa Hình Ảnh", + "HeaderEasyPinCode": "Mã PIN Đơn Giản", + "HeaderDownloadSync": "Tải Xuống Và Đồng Bộ", + "HeaderDisplay": "Hiển Thị", + "HeaderDirectPlayProfileHelp": "Thêm thiết lập phát trực tiếp để chỉ ra những định dạng mà thiết bị có thể phát trực tiếp mà không cần chuyển mã.", + "HeaderDirectPlayProfile": "Thiết Lập Phát Trực Tiếp", + "HeaderDevices": "Thiết Bị", + "HeaderDeviceAccess": "Truy Cập Thiết Bị", + "HeaderDeveloperInfo": "Thông Tin Nhà Phát Triển", + "HeaderDetectMyDevices": "Tìm Kiếm Những Thiết Bị Của Tôi", + "HeaderDeleteTaskTrigger": "Xoá Kích Hoạt Tác Vụ", + "HeaderDeleteProvider": "Xoá Nhà Cung Cấp", + "HeaderDeleteItems": "Xoá Những Mục Này", + "HeaderDeleteItem": "Xoá Mục Này", + "HeaderDeleteDevice": "Xoá Thiết Bị", + "HeaderDefaultRecordingSettings": "Thiết Lập Ghi Âm/Ghi Hình Mặc Định", + "HeaderRecordingOptions": "Tuỳ Chọn Ghi Âm/Ghi Hình", + "HeaderProfileServerSettingsHelp": "Những thông tin này về máy chủ Jellyfin sẽ hiển thị trên các thiết bị phát được kết nối.", + "HeaderSettings": "Cài Đặt", + "HeaderServerSettings": "Cài Đặt Máy Chủ", + "HeaderSeriesStatus": "Trạng Thái Series", + "HeaderSeriesOptions": "Tuỳ Chọn Series", + "HeaderSendMessage": "Gửi Tin Nhắn", + "HeaderSelectTranscodingPathHelp": "Hãy chọn đường dẫn để lưu tạm những tập tin chuyển mã. Máy chủ phải có quyền ghi trên thư mục đó.", + "HeaderSelectTranscodingPath": "Chọn Đường Dẫn Chuyển Mã", + "HeaderSelectServerCachePathHelp": "Hãy chọn đường dẫn để lưu tập tin ghi tạm cho máy chủ. Máy chủ phải có quyền ghi trên thư mục đó.", + "HeaderSelectServerCachePath": "Chọn Đường Dẫn Ghi Tạm Cho Máy Chủ", + "HeaderSelectServer": "Chọn Máy Chủ", + "HeaderSelectPath": "Chọn Đường Dẫn", + "HeaderSelectMetadataPathHelp": "Hãy chọn đường dẫn mà bạn muốn lưu thông tin bổ trợ. Máy chủ phải có quyền ghi trên thư mục đó.", + "HeaderSelectMetadataPath": "Chọn Đường Dẫn Thông Tin Bổ Trợ", + "HeaderSelectCertificatePath": "Chọn Đường Dẫn Đến Chứng Chỉ", + "HeaderSecondsValue": "{0} Giây", + "HeaderSeasons": "Phần", + "HeaderSchedule": "Lịch Phát Sóng", + "HeaderScenes": "Phân Cảnh", + "HeaderRunningTasks": "Những Tác Vụ Hoạt Động", + "HeaderRevisionHistory": "Lịch Sử Chỉnh Sửa", + "HeaderRestartingServer": "Đang Khởi Động Lại Máy Chủ", + "HeaderRestart": "Khởi Động Lại", + "HeaderResponseProfileHelp": "Hồ sơ phản hồi là phương thức tuỳ chỉnh thông tin gửi về thiết bị phát khi phát một số nội dung nhất định.", + "HeaderResponseProfile": "Hồ Sơ Phản Hồi", + "HeaderRemoveMediaLocation": "Xoá Đường Dẫn Nội Dung", + "HeaderRemoveMediaFolder": "Xoá Thư Mục Nội Dung", + "HeaderRemoteControl": "Điều Khiển Từ Xa", + "HeaderRecordingPostProcessing": "Xử Lý Sau Khi Ghi Âm/Ghi Hình", + "HeaderSortOrder": "Thứ tự Sắp xếp", + "HeaderSortBy": "Sắp xếp theo", + "HeaderStartNow": "Bắt đầu", + "HeaderSetupLibrary": "Thiết lập thư viện nội dung của bạn", + "HeaderTracks": "Bài Hát", + "HeaderThisUserIsCurrentlyDisabled": "Người dùng này hiện tại đang bị khoá", + "HeaderTaskTriggers": "Kích Hoạt Tác Vụ", + "HeaderTags": "Nhãn", + "HeaderSubtitleProfilesHelp": "Hồ sơ phụ đề chỉ ra những định dạng phụ đề được hỗ trợ bởi thiết bị phát.", + "HeaderSubtitleProfiles": "Hồ Sơ Phụ Đề", + "HeaderSubtitleProfile": "Hồ Sơ Phụ Đề", + "HeaderSubtitleDownloads": "Tải Phụ Đề", + "HeaderSubtitleAppearance": "Giao Diện Phụ Đề", + "HeaderStopRecording": "Ngừng Ghi Hình/Ghi Âm", + "HeaderSpecialFeatures": "Những Phần Đặc Biệt Nổi Bật", + "HeaderSpecialEpisodeInfo": "Thông Tin Tập Đặc Biệt", + "HeaderShutdown": "Tắt Máy Chủ", + "LabelCustomDeviceDisplayNameHelp": "Cung cấp một tên hiển thị riêng hoặc bỏ trống để sử dụng tên có sẵn của thiết bị.", + "LabelCustomDeviceDisplayName": "Tên hiển thị:", + "LabelCustomCssHelp": "Áp dụng tuỳ chỉnh riêng của bạn vào giao diện trang web.", + "LabelCustomCss": "CSS tuỳ chọn:", + "LabelCustomCertificatePathHelp": "Đường dẫn đến tập tin PKCS #12 chứa chứng chỉ (certificate) và khoá riêng (private key) để bật tính năng TLS trên một tên miền tuỳ chọn.", + "LabelCustomCertificatePath": "Đường dẫn đến chứng chỉ SSL:", + "LabelCriticRating": "Đánh giá phê bình:", + "LabelCorruptedFrames": "Những khung hình bị lỗi:", + "LabelContentType": "Loại nội dung:", + "LabelCommunityRating": "Đánh giá của cộng đồng:", + "LabelCollection": "Bộ Sưu Tập:", + "LabelChannels": "Kênh:", + "LabelCertificatePasswordHelp": "Nếu chứng chỉ của bạn cần mật khẩu, hãy nhập nó ở đây.", + "LabelCertificatePassword": "Mật khẩu chứng chỉ:", + "LabelCancelled": "Đã Huỷ", + "LabelCachePathHelp": "Chọn một đường dẫn cho những tập tin lưu tạm như là hình ảnh. Bỏ trống để sử dụng cài đặt mặc định của máy chủ.", + "LabelCachePath": "Đường dẫn cache:", + "LabelCache": "Cache:", + "LabelBurnSubtitles": "Nhúng phụ đề:", + "LabelBlockContentWithTags": "Chặn những mục có nhãn:", + "LabelBlastMessageIntervalHelp": "Xác định thời gian tồn tại giữa các tin nhắn (tính bằng giây).", + "LabelBlastMessageInterval": "Thời gian tồn tại của tin nhắn (giây)", + "LabelBitrate": "Bitrate:", + "LabelBirthYear": "Năm sinh:", + "LabelBirthDate": "Ngày sinh:", + "LabelBindToLocalNetworkAddressHelp": "Không bắt buộc. Cài đặt đè địa chỉ IP nội bộ để kết nối đến máy chủ HTTP. Nếu bỏ trống, máy chủ sẽ cài đặt vào toàn bộ những địa chỉ nội bộ có sẵn. Nếu thay đổi tuỳ chọn này, cần phải khởi động lại máy chủ Jellyfin để có tác dụng.", + "LabelBindToLocalNetworkAddress": "Cài đặt vào địa chỉ nội bộ:", + "LabelAutomaticallyRefreshInternetMetadataEvery": "Tự động cập nhật dữ liệu bổ trợ từ Internet:", + "LabelAuthProvider": "Nhà Cung Cấp Xác Thực:", + "LabelAudioSampleRate": "Sample rate âm thanh:", + "LabelAudioCodec": "Bộ giải mã âm thanh:", + "LabelAudioChannels": "Các kênh âm thanh:", + "LabelAudioBitrate": "Bitrate của âm thanh:", + "LabelAudioBitDepth": "Chiều sâu của âm thanh:", + "LabelAudio": "Âm Thanh", + "LabelArtistsHelp": "Sử dụng dấu ; để tách rời nhiều nghệ", + "LabelArtists": "Nghệ sĩ:", + "LabelAppNameExample": "Ví dụ: Sickbeard, Sonarr", + "LabelAppName": "Tên ứng dụng", + "LabelAllowedRemoteAddressesMode": "Chế độ bộ lọc địa chỉ IP từ xa:", + "LabelAllowedRemoteAddresses": "Bộ lọc địa chỉ IP từ xa:", + "LabelAllowServerAutoRestartHelp": "Máy chủ chỉ khởi động lại trong thời gian rỗi khi không có người dùng đang sử dụng.", + "LabelAllowHWTranscoding": "Cho phép chuyển mã bằng phần cứng", + "LabelAll": "Tất Cả", + "LabelAlbumArtists": "Nghệ sĩ album:", + "LabelAlbumArtPN": "Bìa album PN:", + "LabelAlbumArtMaxWidthHelp": "Độ phân giải cao nhất của bìa album thông qua upnp:albumArtURI.", + "LabelAlbumArtMaxWidth": "Chiều ngang lớn nhất của bìa album:", + "LabelAlbumArtMaxHeightHelp": "Độ phân giải cao nhất của bìa album thông qua upnp:albumArtURI.", + "LabelAlbumArtMaxHeight": "Chiều cao lớn nhất của bìa album:", + "LabelAlbumArtHelp": "PN được sử dụng cho bìa album, trong dlna:profileID thuộc tính upnp:albumArtURI. Một vài thiết bị phát cần một giá trị đặc biệt, không ảnh hưởng đến kích thước của hình ảnh.", + "LabelAlbum": "Album:", + "LabelAirsBeforeSeason": "Phát sóng trước mùa:", + "LabelAirsBeforeEpisode": "Phát sóng trước tập:", + "LabelAirsAfterSeason": "Phát sóng sau mùa:", + "LabelAirTime": "Thời gian phát sóng:", + "LabelAirDays": "Ngày phát sóng:", + "LabelAccessStart": "Thời gian bắt đầu:", + "LabelAccessEnd": "Thời gian kết thúc:", + "LabelAccessDay": "Ngày trong tuần:", + "LabelAbortedByServerShutdown": "(Đã huỷ bởi máy chủ ngừng hoạt động)", + "Label3DFormat": "Định dạng 3D:", + "Kids": "Trẻ Em", + "Items": "Mục", + "ItemCount": "{0} mục", + "InstantMix": "Trộn Lẫn Nhanh", + "InstallingPackage": "Đang cài đặt {0} (phiên bản {1})", + "ImportMissingEpisodesHelp": "Nếu bật tuỳ chọn này, thông tin bị thiếu trong các tập phim sẽ được nhập vào cơ sở dữ liệu của máy chủ Jellyfin và hiển thị trong các phần và series. Điều này có thể làm việc quét thư viện lâu hơn rất nhiều.", + "ImportFavoriteChannelsHelp": "Nếu bật tuỳ chọn này, chỉ những kênh yêu thích trong thiết bị bắt sóng sẽ được nhập vào.", + "Images": "Hình Ảnh", + "Identify": "Nhận Dạng", + "HttpsRequiresCert": "Để bật kết nối bảo mật, bạn cần phải cung cấp một Chứng Chỉ SSL đáng tin cậy, ví dụ như \"Let's Encrypt\". Hãy cung cấp Chứng Chỉ SSL hoặc là tắt tính năng kết nối bảo mật.", + "Horizontal": "Nằm Ngang", + "Home": "Trang Chủ", + "HideWatchedContentFromLatestMedia": "Ẩn những nội dung đã xem khỏi phần nội dung mới nhất", + "Hide": "Ẩn", + "Help": "Trợ Giúp", + "HeadersFolders": "Thư Mục", + "HeaderYears": "Năm", + "HeaderXmlSettings": "Cài Đặt XML", + "HeaderXmlDocumentAttributes": "Những Thuộc Tính Tài Liệu XML", + "HeaderXmlDocumentAttribute": "Thuộc Tính Tài Liệu XML", + "HeaderVideos": "Videos", + "HeaderVideoTypes": "Kiểu Video", + "HeaderVideoType": "Kiểu Video", + "HeaderVideoQuality": "Chất Lượng Video", + "HeaderUser": "Người Dùng", + "HeaderUploadImage": "Tải Lên Hình Ảnh", + "HeaderUpcomingOnTV": "Sắp Phát Sóng Trên TV", + "HeaderTypeText": "Nhập nội dung", + "HeaderTypeImageFetchers": "{0} Trình Tải Hình Ảnh", + "HeaderTuners": "Bộ Điều Khiển Thu Phát Sóng", + "HeaderTunerDevices": "Thiết Bị Bắt Sóng", + "HeaderTranscodingProfileHelp": "Thêm hồ sơ chuyển mã để chỉ ra những định dạng nên dùng khi cần chuyển mã.", + "HeaderTranscodingProfile": "Hồ Sơ Chuyển Mã" } diff --git a/src/strings/zh-cn.json b/src/strings/zh-cn.json index ec589c367d..41eb27c9bf 100644 --- a/src/strings/zh-cn.json +++ b/src/strings/zh-cn.json @@ -1,32 +1,32 @@ { - "AccessRestrictedTryAgainLater": "访问目前受限。请稍后再试。", + "AccessRestrictedTryAgainLater": "目前访问受限。请稍后再试。", "Actor": "演员", "Add": "添加", - "AddItemToCollectionHelp": "通过搜索并使用鼠标右键单击或点击菜单将项目添加到集合中, 将项目添加到集合中。", - "AddToCollection": "加入收藏", + "AddItemToCollectionHelp": "通过搜索项目并右键或轻触得到的弹出菜单来将项目添加到集合中。", + "AddToCollection": "加入集合", "AddToPlayQueue": "添加至播放队列", - "AddToPlaylist": "添加到播放列表", + "AddToPlaylist": "添加至播放列表", "AddedOnValue": "已添加 {0}", "AdditionalNotificationServices": "浏览插件目录来安装额外的通知访问服务。", "AirDate": "播出日期", - "Aired": "已发布", + "Aired": "已播出", "Albums": "专辑", "Alerts": "警告", "All": "全部", "AllChannels": "所有频道", - "AllComplexFormats": "所有高级特效格式字幕(ASS, SSA, VOBSUB, PGS, SUB/IDX 等)", + "AllComplexFormats": "所有复杂格式字幕 (ASS, SSA, VOBSUB, PGS, SUB, IDX 等)", "AllEpisodes": "所有剧集", "AllLanguages": "所有语言", "AllLibraries": "所有媒体库", "AllowHWTranscodingHelp": "允许调谐器即时转码。这可能有助于减少Jellyfin 媒体服务器的转码工作。", "AllowMediaConversion": "允许媒体转换", - "AllowMediaConversionHelp": "授予或拒绝访问转换媒体功能。", - "AllowOnTheFlySubtitleExtraction": "允许同时提取字幕", + "AllowMediaConversionHelp": "授予或拒绝访问媒体转换功能。", + "AllowOnTheFlySubtitleExtraction": "允许实时提取字幕", "AllowOnTheFlySubtitleExtractionHelp": "为避免视频转码,可以从视频中提取内置的字幕,并以纯文本的形式发送给客户端。在某些系统中这个提取的进程可能会花费较长时间并导致视频播放出现卡顿。如果禁用这个选项,当内置字幕不能被客户端设备原生支持时,字幕将通过视频转码被烧录进视频中。", "AllowRemoteAccess": "允许与此 Jellyfin 服务器进行远程连接。", "AllowRemoteAccessHelp": "如果取消勾选,所有的远程连接将会被阻止。", - "AllowedRemoteAddressesHelp": "将允许远程连接的网络的 ip 地址或 ip/网掩码条目的逗号分隔列表。如果留空, 则允许所有远程地址。", - "AlwaysPlaySubtitles": "总是显示字幕", + "AllowedRemoteAddressesHelp": "允许远程连接的 IP 地址或 IP/子网掩码 的列表,以逗号分隔。如果留空,则允许所有远程地址。", + "AlwaysPlaySubtitles": "总是显示", "AlwaysPlaySubtitlesHelp": "无论音频为何种语言,都将加载与语言偏好匹配的字幕。", "Anytime": "任何时间", "AroundTime": "{0} 左右", @@ -40,15 +40,15 @@ "Backdrop": "背景", "Backdrops": "背景", "Banner": "横幅", - "BirthDateValue": "出生: {0}", + "BirthDateValue": "出生:{0}", "BirthLocation": "出生地", - "BirthPlaceValue": "出生地: {0}", + "BirthPlaceValue": "出生地:{0}", "Blacklist": "黑名单", "BookLibraryHelp": "现已支持音频和文本书籍。浏览{0}有声读物命名指南{1}。", "Books": "书籍", "Browse": "浏览", "BrowsePluginCatalogMessage": "浏览我们的插件目录来查看现有插件。", - "BurnSubtitlesHelp": "根据字幕格式确定服务器在转换视频时是否应压制字幕。避免压制字幕会提高服务器性能。选择“自动”以压制基于图像的字幕格式(如 VOBSUB, PGS, SUB/IDX 等)和一些复杂的 ASS/SSA 字幕。", + "BurnSubtitlesHelp": "服务器在转换视频时是否应压制字幕。避免压制字幕会提高服务器性能。选择“自动”以压制基于图像的字幕格式(如 VOBSUB, PGS, SUB, IDX 等)和一些复杂的 ASS/SSA 字幕。", "ButtonAdd": "添加", "ButtonAddMediaLibrary": "添加媒体库", "ButtonAddScheduledTaskTrigger": "添加触发器", @@ -146,7 +146,7 @@ "CustomDlnaProfilesHelp": "为新的设备创建自定义配置文件或覆盖原有系统配置文件。", "DateAdded": "加入日期", "DatePlayed": "播放日期", - "DeathDateValue": "去世: {0}", + "DeathDateValue": "去世:{0}", "Default": "默认", "DefaultErrorMessage": "处理请求时发生错误。请稍后尝试。", "DefaultMetadataLangaugeDescription": "这些是你的默认设置并且可以在你的每个媒体库中被单独自定义。", @@ -217,7 +217,7 @@ "EveryNDays": "每 {0} 天", "ExitFullscreen": "退出全屏", "ExtraLarge": "特大", - "ExtractChapterImagesHelp": "提取章节图像将允许客户端显示一个图像形式的场景选择菜单。这个提取的过程可能会非常缓慢、占用大量 CPU 资源,并且可能需要几个GB的硬盘空间。提取将会在视频被发现时启动,同时也作为一个夜间计划任务运行。这个任务可以在“计划任务”选项中进行设置。不建议在高峰使用时间运行这个任务。", + "ExtractChapterImagesHelp": "提取剧集图片将允许客户端显示一个图像形式的场景选择菜单。这个提取的过程可能会非常缓慢、占用大量 CPU 资源,并且可能需要几个GB的硬盘空间。提取将会在视频被发现时启动,同时也作为一个夜间计划任务运行。这个任务可以在“计划任务”选项中进行设置。不建议在高峰使用时间运行这个任务。", "Extras": "额外", "FFmpegSavePathNotFound": "我们无法通过你输入的路径定位 FFmpeg。FFprobe 同样也是必要的并且应该被放在同一个文件夹中。他们通常会被打包在一起以供下载。请检查这个路径然后再试一次。", "FastForward": "快进", @@ -244,10 +244,10 @@ "GuideProviderLogin": "登入", "GuideProviderSelectListings": "选择列表", "H264CrfHelp": "The Constant Rate Factor (CRF) 是 x264 编码器的默认质量设置。您可以设置介于0和51之间的值, 其中较低的值将导致更好的质量 (以更高的文件大小为代价)。正常值介于18和28之间。x264 的默认值为 23, 因此可以将其用作起始点。", - "H264EncodingPresetHelp": "选择一个更快的值以提升性能,或者选择一个更慢的值以提升质量。", + "EncoderPresetHelp": "选择一个更快的值以提升性能,或者选择一个更慢的值以提升质量。", "HDPrograms": "高清节目", "HandledByProxy": "由反向代理处理", - "HardwareAccelerationWarning": "启动硬件加速可能在某些环境下导致系统不稳定。请确认你的操作系统和视频驱动程序是最新的。如果你在开启此项后播放视频产生困难,那么你需要将此选项设置回”自动“。", + "HardwareAccelerationWarning": "启动硬件加速可能在某些环境下导致系统不稳定。请确认你的操作系统和显卡驱动程序是最新的。如果你在开启此项后播放视频时遇到困难,那么你需要将此选项设置回“没有”。", "HeaderAccessSchedule": "访问计划", "HeaderAccessScheduleHelp": "创建一个访问计划以限制可访问的时间段。", "HeaderActiveDevices": "活动的设备", @@ -277,7 +277,7 @@ "HeaderCastCrew": "演职人员", "HeaderChannelAccess": "频道访问", "HeaderChannels": "频道", - "HeaderChapterImages": "章节图片", + "HeaderChapterImages": "剧集图片", "HeaderCodecProfile": "编解码器配置", "HeaderCodecProfileHelp": "编解码器的配置文件标明了设备播放特定编码时的限制。如果在限制之内则媒体将被转码,否则编解码器将被配置为直接播放。", "HeaderConfigureRemoteAccess": "配置远程访问", @@ -289,7 +289,7 @@ "HeaderContainerProfile": "媒体载体配置", "HeaderContainerProfileHelp": "媒体载体的配置文件标明了设备播放特定媒体格式时的限制。如果在限制之内则媒体将被转码,否则媒体格式将被配置为直接播放。", "HeaderContinueListening": "继续听", - "HeaderContinueWatching": "继续观看", + "HeaderContinueWatching": "继续观影", "HeaderCustomDlnaProfiles": "自定义配置", "HeaderDateIssued": "发布日期", "HeaderDefaultRecordingSettings": "默认录制设定", @@ -360,7 +360,7 @@ "HeaderMyMediaSmall": "我的媒体 (小)", "HeaderNewApiKey": "新 API 密钥", "HeaderNewDevices": "新设备", - "HeaderNextUp": "下一步", + "HeaderNextUp": "接下来", "HeaderOnNow": "现在", "HeaderOtherItems": "其他项目", "HeaderParentalRatings": "家长分级", @@ -449,12 +449,12 @@ "Hide": "隐藏", "HideWatchedContentFromLatestMedia": "从最新媒体中隐藏已观看的内容", "Home": "首页", - "HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 如 \"允许加密\"。请提供证书或禁用安全连接。", + "HttpsRequiresCert": "要启用安全连接, 您需要提供一个受信任的 SSL 证书, 例如 Let's Encrypt 。请提供证书或禁用安全连接。", "Identify": "识别", "Images": "图片", "ImportFavoriteChannelsHelp": "如果启用,只有在协调器设备中被标记为我的最爱的频道才会被导入。", "ImportMissingEpisodesHelp": "如果启用,会将缺少的剧集信息导入到你的 Jellyfin 数据库并分季分剧显示。可能会大大延长媒体库扫描时间。", - "InstallingPackage": "正在安装 {0}", + "InstallingPackage": "正在安装 {0}(版本 {1})", "InstantMix": "即时混音", "ItemCount": "{0} 项", "Kids": "儿童", @@ -474,7 +474,7 @@ "LabelAlbumArtMaxHeightHelp": "通过UPnP显示的专辑封面超链接的最大分辨率。", "LabelAlbumArtMaxWidth": "专辑封面最大宽度:", "LabelAlbumArtMaxWidthHelp": "通过UPnP显示的专辑封面超链接的最大分辨率。", - "LabelAlbumArtPN": "专辑封面PN :", + "LabelAlbumArtPN": "专辑封面PN:", "LabelAlbumArtists": "专辑作家:", "LabelAll": "所有", "LabelAllowHWTranscoding": "允许硬件转码", @@ -483,7 +483,7 @@ "LabelAllowedRemoteAddresses": "远程IP地址过滤器:", "LabelAllowedRemoteAddressesMode": "远程IP地址过滤器模式:", "LabelAppName": "APP名称", - "LabelAppNameExample": "例如: Sickbeard, Sonarr", + "LabelAppNameExample": "例如:Sickbeard, Sonarr", "LabelArtists": "艺术家:", "LabelArtistsHelp": "独立多功能 ;", "LabelAudioLanguagePreference": "首选音频语言:", @@ -506,6 +506,7 @@ "LabelCollection": "收藏:", "LabelCommunityRating": "公众评分:", "LabelContentType": "内容类型:", + "LabelCorruptedFrames": "损坏的帧:", "LabelCountry": "国家:", "LabelCriticRating": "影评人评分:", "LabelCurrentPassword": "当前密码:", @@ -536,17 +537,18 @@ "LabelDisplayName": "显示名称:", "LabelDisplayOrder": "显示顺序:", "LabelDisplaySpecialsWithinSeasons": "显示季中所播出的特集", - "LabelDownMixAudioScale": "缩混音频增强:", - "LabelDownMixAudioScaleHelp": "缩混音频增强。值为A将保留原来的音量。", + "LabelDownMixAudioScale": "降混音频增强:", + "LabelDownMixAudioScaleHelp": "降混音时增强音频。值为 1 时将保留原始音量。", "LabelDownloadLanguages": "下载语言:", "LabelDropImageHere": "拖拽或点击选择图像于此处。", + "LabelDroppedFrames": "丢弃的帧:", "LabelDropShadow": "阴影:", "LabelDynamicExternalId": "{0} Id:", "LabelEasyPinCode": "简易PIN码:", "LabelEmbedAlbumArtDidl": "在DIDL中嵌入专辑封面", "LabelEmbedAlbumArtDidlHelp": "有些设备首选这种方式获取专辑封面。启用该选项可能导致其他设备播放失败。", "LabelEnableAutomaticPortMap": "开启自动端口映射", - "LabelEnableAutomaticPortMapHelp": "勾选以通过 UPnP 自动映射公共端口到本地端口。这个选项在某些不支持的路由器上可能不起作用。", + "LabelEnableAutomaticPortMapHelp": "尝试通过UPnP将公共端口自动映射到本地端口。这可能不适用于某些型号的路由器。需要服务器重新启动后才会应用更改。", "LabelEnableBlastAliveMessages": "爆发活动信号", "LabelEnableBlastAliveMessagesHelp": "如果该服务器不能被网络中的其他UPnP设备检测到,请启用此选项。", "LabelEnableDlnaClientDiscoveryInterval": "客户端搜寻时间间隔(秒)", @@ -566,8 +568,8 @@ "LabelEpisodeNumber": "集号:", "LabelEvent": "事件:", "LabelEveryXMinutes": "每:", - "LabelExtractChaptersDuringLibraryScan": "媒体库扫描过程中解压章节图像", - "LabelExtractChaptersDuringLibraryScanHelp": "当媒体库导入视频并扫描时,将提取章节图像。否则,章节图像将在之后的计划任务提取,而媒体库会更快完成扫描。", + "LabelExtractChaptersDuringLibraryScan": "媒体库扫描过程中解压剧集图片", + "LabelExtractChaptersDuringLibraryScanHelp": "当媒体库导入视频并扫描时,将提取剧集图片。否则,剧集图片将在之后的计划任务提取,而媒体库会更快完成扫描。", "LabelFailed": "失败", "LabelFileOrUrl": "文件或网址:", "LabelFinish": "完成", @@ -579,11 +581,11 @@ "LabelGroupMoviesIntoCollections": "批量添加电影到收藏", "LabelGroupMoviesIntoCollectionsHelp": "显示电影列表时,属于一个收藏的电影将显示为一个分组。", "LabelH264Crf": "H264 CRF 编码质量等级:", - "LabelH264EncodingPreset": "H264 编码预设:", + "LabelEncoderPreset": "H264 和 H265 编码预设:", "LabelHardwareAccelerationType": "硬件加速:", - "LabelHardwareAccelerationTypeHelp": "此特性只能在支持的系统上使用。", + "LabelHardwareAccelerationTypeHelp": "硬件加速需要额外配置。", "LabelHomeNetworkQuality": "家庭网络质量:", - "LabelHomeScreenSectionValue": "主屏幕模块{0}:", + "LabelHomeScreenSectionValue": "主屏幕模块{0}:", "LabelHttpsPort": "本地 HTTPS 端口号:", "LabelHttpsPortHelp": "Jellyfin HTTPS 服务器监听端口。", "LabelIconMaxHeight": "图标最大高度:", @@ -626,7 +628,7 @@ "LabelMaxResumePercentage": "恢复播放最大百分比:", "LabelMaxResumePercentageHelp": "如果在此时间之后停止播放,媒体会标记为“已播放”。", "LabelMaxScreenshotsPerItem": "每个项目最大截图数目:", - "LabelMaxStreamingBitrate": "最大串流质量:", + "LabelMaxStreamingBitrate": "最大串流质量:", "LabelMaxStreamingBitrateHelp": "请指定一个流媒体串流时的最大比特率。", "LabelMessageText": "消息文本:", "LabelMessageTitle": "消息标题:", @@ -681,9 +683,10 @@ "LabelPersonRole": "角色:", "LabelPlaceOfBirth": "出生地:", "LabelPlayDefaultAudioTrack": "播放默认音轨无论是什么语言", + "LabelPlayerDimensions": "播放器尺寸:", "LabelPlaylist": "播放列表:", - "LabelPostProcessor": "后处理应用程序:", - "LabelPostProcessorArguments": "处理器后命令行参数:", + "LabelPostProcessor": "后处理应用程序:", + "LabelPostProcessorArguments": "处理器后命令行参数:", "LabelPostProcessorArgumentsHelp": "使用 {path} 作为录制文件的路径。", "LabelPreferredDisplayLanguage": "首选显示语言:", "LabelPreferredDisplayLanguageHelp": "Jellyfin的翻译工作是一个不断推进的工程项目。", @@ -702,8 +705,8 @@ "LabelPublicHttpPortHelp": "映射到本地 HTTP 端口的公开端口号。", "LabelPublicHttpsPort": "公开 HTTPS 端口号:", "LabelPublicHttpsPortHelp": "映射到本地 HTTPS 端口的公开端口号。", - "LabelReadHowYouCanContribute": "学习如何构建。", - "LabelReasonForTranscoding": "转码的原因:", + "LabelReadHowYouCanContribute": "了解如何做出贡献。", + "LabelReasonForTranscoding": "转码原因:", "LabelRecord": "录制:", "LabelRecordingPath": "默认录制路径:", "LabelRecordingPathHelp": "指定一个默认位置用于存储转码文件。如果该位置留空,服务器的程序数据文件夹将被使用。", @@ -746,10 +749,11 @@ "LabelStatus": "状态:", "LabelStopWhenPossible": "当可能时自动停止:", "LabelStopping": "停止", + "LabelStreamType": "串流类型:", "LabelSubtitleDownloaders": "字幕下载器:", "LabelSubtitleFormatHelp": "例如:SRT", "LabelSubtitlePlaybackMode": "字幕模式:", - "LabelSubtitles": "字幕:", + "LabelSubtitles": "字幕", "LabelSupportedMediaTypes": "支持的媒体类型:", "LabelTVHomeScreen": "TV 模式主屏幕:", "LabelTag": "标签:", @@ -776,7 +780,7 @@ "LabelTypeText": "文本", "LabelUseNotificationServices": "使用以下服务:", "LabelUser": "用户:", - "LabelUserAgent": "用户代理:", + "LabelUserAgent": "用户代理:", "LabelUserLibrary": "用户程序库:", "LabelUserLibraryHelp": "选择一个在设备上显示的用户媒体库。留空则使用默认设置。", "LabelUserRemoteClientBitrateLimitHelp": "覆盖服务器“播放”设置的全局默认值。", @@ -787,6 +791,7 @@ "LabelVersion": "版本:", "LabelVersionInstalled": "{0} 已安装", "LabelVersionNumber": "版本 {0}", + "LabelVideoResolution": "视频分辨率:", "LabelXDlnaCap": "X-DLNA CAP:", "LabelXDlnaCapHelp": "决定在 urn:schemas-dlna-org:device-1-0 namespace 中的 X_DLNACAP 元素的内容。", "LabelXDlnaDoc": "X-DLNA DOC:", @@ -797,7 +802,7 @@ "LabelZipCode": "邮编:", "LabelffmpegPath": "FFmpeg 路径:", "LabelffmpegPathHelp": "FFmpeg 应用程序的文件,或者包含了 FFmpeg 的文件夹的路径。", - "LanNetworksHelp": "在强制带宽限制时, 将在本地网络上考虑的网络的 ip 地址或 ip/网络掩码条目的逗号分隔列表。如果设置, 所有其他 IP 地址将被视为在外部网络上, 并且将受到外部带宽限制。如果保留为空, 则只将服务器的子网视为本地网络。", + "LanNetworksHelp": "在强制带宽限制时,认作本地网络上的 IP 地址或 IP/网络掩码条目的逗号分隔列表。如果设置此项,所有其它 IP 地址将被视为在外部网络上,并且将受到外部带宽限制。如果保留为空,则只将服务器的子网视为本地网络。", "Large": "大", "LatestFromLibrary": "最新的{0}", "LearnHowYouCanContribute": "学习如何构建。", @@ -855,7 +860,7 @@ "MessageDownloadQueued": "下载已列队。", "MessageEnablingOptionLongerScans": "启用此选项可能会大大延长媒体库扫描时间。", "MessageFileReadError": "读取文件发生错误。", - "MessageForgotPasswordFileCreated": "已在服务器上创建了以下文件, 并包含有关后续步骤说明:", + "MessageForgotPasswordFileCreated": "已在服务器上创建了以下文件, 并包含有关后续步骤说明:", "MessageForgotPasswordInNetworkRequired": "请连接你的家庭网络后再试一次以开始密码重置流程。", "MessageInstallPluginFromApp": "这个插件必须从你打算使用的应用程序中安装。", "MessageInvalidForgotPasswordPin": "无效的或过期的 pin 码。请再试一次。", @@ -916,9 +921,9 @@ "Normal": "普通", "NumLocationsValue": "{0} 个文件夹", "OneChannel": "一个频道", - "OnlyForcedSubtitles": "只显示强制字幕", + "OnlyForcedSubtitles": "仅强制字幕", "OnlyForcedSubtitlesHelp": "只有被标记为“强制”的字幕会被加载。", - "OnlyImageFormats": "仅图像格式(VOBSUB, PGS, SUB等)", + "OnlyImageFormats": "仅图像格式(VOBSUB, PGS, SUB 等)", "OptionAdminUsers": "管理员", "OptionAlbum": "专辑", "OptionAlbumArtist": "专辑艺术家", @@ -983,7 +988,6 @@ "OptionEnableAccessFromAllDevices": "允许所有设备访问", "OptionEnableAccessToAllChannels": "允许访问所有频道", "OptionEnableAccessToAllLibraries": "允许访问所有媒体库", - "OptionEnableAutomaticServerUpdates": "开启自动服务器更新", "OptionEnableExternalContentInSuggestions": "在建议中启用外部内容", "OptionEnableExternalContentInSuggestionsHelp": "允许建议的内容中包含互联网预告片和电视直播节目。", "OptionEnableForAllTuners": "给所有调谐器开启", @@ -994,7 +998,7 @@ "OptionEstimateContentLength": "转码时,估计内容长度", "OptionEveryday": "每天", "OptionExternallyDownloaded": "外部下载", - "OptionExtractChapterImage": "开启章节图像提取", + "OptionExtractChapterImage": "开启剧集图片提取", "OptionFavorite": "我的最爱", "OptionFriday": "星期五", "OptionHasSpecialFeatures": "特殊功能", @@ -1045,7 +1049,7 @@ "OptionRuntime": "播放时长", "OptionSaturday": "星期六", "OptionSaveMetadataAsHidden": "保存媒体资料和图像为隐藏文件", - "OptionSaveMetadataAsHiddenHelp": "更改此项将适用于保存向前的新元数据。在下次 Jellyfin 服务器保存时, 现有元数据文件将被更新。", + "OptionSaveMetadataAsHiddenHelp": "更改此项将应用于以后保存的元数据。现有元数据文件将在下一次 Jellyfin 服务器保存它们时被更新。", "OptionSpecialEpisode": "特集", "OptionSubstring": "子串", "OptionSunday": "星期天", @@ -1062,9 +1066,9 @@ "OptionWeekly": "每周", "OriginalAirDateValue": "首映日期:{0}", "Overview": "概述", - "PackageInstallCancelled": "{0} 安装被取消。", - "PackageInstallCompleted": "{0} 安装完成。", - "PackageInstallFailed": "{0} 安装失败。", + "PackageInstallCancelled": "{0}(版本 {1}) 的安装被取消。", + "PackageInstallCompleted": "{0}(版本 {1})安装完成。", + "PackageInstallFailed": "{0}(版本 {1})安装失败。", "ParentalRating": "家长分级", "PasswordMatchError": "密码和确认密码必须匹配。", "PasswordResetComplete": "密码已重置。", @@ -1306,16 +1310,14 @@ "BoxRear": "盒子(背面)", "ChannelNumber": "频道号码", "ColorSpace": "色彩空间", - "DirectorValue": "导演:{0}", - "DirectorsValue": "导演:{0}", + "Directors": "导演", "ColorTransfer": "色彩转换", "ConfirmDeleteItem": "这将同时在磁盘和媒体库中删除这个项目。确认删除?", "ConfirmDeleteItems": "这将同时在磁盘和媒体库中删除这些项目。确认删除?", "ConfirmEndPlayerSession": "确认要关闭位于{0}的Jellyfin吗?", "ValueSeconds": "{0}秒", "Features": "功能", - "GenreValue": "风格 : {0}", - "GenresValue": "风格 : {0}", + "Genre": "风格", "Guide": "指南", "HeaderCancelRecording": "取消录制", "HeaderFavoriteMovies": "最爱的电影", @@ -1325,16 +1327,16 @@ "HeaderFavoriteVideos": "最爱的视频", "HeaderVideoType": "视频类型", "Items": "项目", - "LabelAudio": "音频:", + "LabelAudio": "音频", "LabelServerName": "服务器名称:", "LabelTranscodePath": "转码路径:", "LabelTranscodes": "转码:", "AuthProviderHelp": "选择用于验证此用户密码的身份验证提供者。", "ColorPrimaries": "基色", "ConfigureDateAdded": "在Jellyfin Server仪表板媒体库的设置里确认如何添加日期", - "DisplayModeHelp": "选择您正在运行Jellyfin的屏幕类型。", + "DisplayModeHelp": "选择您想要的界面布局风格。", "EnableColorCodedBackgrounds": "彩色背景", - "ErrorDeletingItem": "服务器删除项目时出错。请确认服务器具有对媒体文件夹的写入权限并重试。", + "ErrorDeletingItem": "从 Jellyfin Server 删除项目时出错。请确认 Jellyfin Server 是否拥有对媒体目录的写权限,然后重试。", "GroupBySeries": "按系列分组", "HeaderApp": "应用程序", "DirectStreamHelp1": "该媒体文件的分辨率和编码(H.264、AC3 等)与您的设备兼容,但容器格式(.mkv、.avi、.wmv 等)不受支持。因此,视频在串流至您的设备之前将会被即时封装为另一种格式。", @@ -1344,7 +1346,7 @@ "HeaderFavoriteArtists": "最爱的艺术家", "HeaderKeepRecording": "继续录制", "HeaderKeepSeries": "保持系列", - "HeaderMusicQuality": "音质", + "HeaderMusicQuality": "音频质量", "HeaderNextEpisodePlayingInValue": "下一集在 {0} 后播放", "HeaderNextVideoPlayingInValue": "下一部影片在 {0} 后播放", "HeaderPlayOn": "播放在", @@ -1361,8 +1363,8 @@ "LabelUserLoginAttemptsBeforeLockout": "用户被封禁前可尝试的次数:", "DashboardVersionNumber": "版本:{0}", "DashboardServerName": "服务器:{0}", - "LabelVideo": "视频:", - "LabelWeb": "网站: ", + "LabelVideo": "视频", + "LabelWeb": "网站:", "LeaveBlankToNotSetAPassword": "您可以将此字段留空以设置空密码。", "LinksValue": "链接:{0}", "LiveBroadcasts": "直播", @@ -1418,7 +1420,7 @@ "DashboardArchitecture": "架构:{0}", "GroupVersions": "按版本分组", "LaunchWebAppOnStartup": "当启动服务器时,打开Web界面", - "LaunchWebAppOnStartupHelp": "这个插件已经被成功安装。 服务器需要重启以使该插件生效。", + "LaunchWebAppOnStartupHelp": "服务器启动时在默认浏览器中打开网页端。使用重启服务器功能时此项不生效。", "MusicAlbum": "音乐专辑", "MusicArtist": "音乐艺术家", "MusicVideo": "音乐视频", @@ -1434,30 +1436,80 @@ "MessageNoServersAvailable": "未能自动发现服务器。", "TabNetworking": "联网", "HeaderFavoriteBooks": "最爱的书籍", - "LabelVideoCodec": "视频编码:", - "LabelVideoBitrate": "视频码率:", - "LabelTranscodingProgress": "转码进度:", - "LabelTranscodingFramerate": "转码帧率:", - "LabelSize": "大小:", + "LabelVideoCodec": "视频编码:", + "LabelVideoBitrate": "视频码率:", + "LabelTranscodingProgress": "转码进度:", + "LabelTranscodingFramerate": "转码帧率:", + "LabelSize": "大小:", "LabelPleaseRestart": "改动将在手动重启客户端后生效。", - "LabelPlayMethod": "播放方式:", - "LabelFolder": "文件夹:", - "LabelBitrate": "比特率:", - "LabelAudioSampleRate": "采样率:", - "LabelAudioCodec": "编码:", - "LabelAudioChannels": "声道:", - "LabelAudioBitrate": "比特率:", - "LabelAudioBitDepth": "采样位宽:", + "LabelPlayMethod": "播放方式:", + "LabelFolder": "文件夹:", + "LabelBitrate": "比特率:", + "LabelAudioSampleRate": "采样率:", + "LabelAudioCodec": "音频编码:", + "LabelAudioChannels": "声道:", + "LabelAudioBitrate": "比特率:", + "LabelAudioBitDepth": "采样位宽:", "FetchingData": "提取其他数据", "CopyStreamURLSuccess": "已成功复制URL地址。", "CopyStreamURL": "复制串流URL地址", "ButtonAddImage": "添加图片", - "LabelPlayer": "播放器:", - "LabelBaseUrl": "基础 URL:", + "LabelPlayer": "播放器:", + "LabelBaseUrl": "基础 URL:", "LabelBaseUrlHelp": "您可以在此处添加自定义子目录,以便从更唯一的 URL 访问服务器。", "MusicLibraryHelp": "重播 {0}音乐命名指南{1}。", "HeaderFavoritePeople": "最喜欢的人物", "OptionRandom": "随机", "ButtonSplit": "拆分", - "SelectAdminUsername": "请为管理员账户选择一个用户名。" + "SelectAdminUsername": "请为管理员账户选择一个用户名。", + "HeaderNavigation": "导航", + "CopyStreamURLError": "复制URL地址时发生错误。", + "MessageConfirmAppExit": "你要退出吗?", + "EnableFastImageFadeIn": "快速图片淡入", + "EnableFastImageFadeInHelp": "为已加载的图片启用更快的图片淡入动画", + "OptionForceRemoteSourceTranscoding": "强制远程转码(像电视直播一样)", + "NoCreatedLibraries": "看上去您还未创建任何资料库。{0} 您想现在创建一个吗? {1}", + "AskAdminToCreateLibrary": "请联系管理员以创建一个新的资料库。", + "PlaybackErrorNoCompatibleStream": "该客户端与媒体不兼容,服务器未发送兼容的媒体格式。", + "AllowFfmpegThrottlingHelp": "当转码或者再封装的进度距离当前播放进度足够远时,暂停这个过程以减少资源消耗。当观看视频时不经常调整播放进度的情况下,这个功能将非常有用。如果你遇到了播放问题,请关闭这个选项。", + "AllowFfmpegThrottling": "限制转码速度", + "PreferEmbeddedEpisodeInfosOverFileNames": "优先使用内置的剧集信息而不是文件名", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "这将在内置元数据含剧集信息时使用内置信息。", + "ClientSettings": "客户端设置", + "Track": "音轨", + "Season": "季", + "ReleaseGroup": "发行组", + "Person": "人物", + "OtherArtist": "其他艺术家", + "Movie": "电影", + "Episode": "剧集", + "BoxSet": "套装", + "Artist": "艺术家", + "AlbumArtist": "专辑艺术家", + "Album": "专辑", + "ListPaging": "{2} 的 {0}-{1}", + "WeeklyAt": "每周第 {0} 天的 {1}", + "OnWakeFromSleep": "当从睡眠中唤醒时", + "DailyAt": "每天的 {0}", + "LastSeen": "上次观看 {0}", + "PersonRole": "作为 {0}", + "OnApplicationStartup": "当应用启动时", + "EveryXHours": "每 {0} 小时", + "EveryHour": "每小时", + "EveryXMinutes": "每 {0} 分钟", + "WriteAccessRequired": "Jellyfin 服务端需要此文件夹的写入权限。请确认是否拥有写入权限并重试。", + "PathNotFound": "无法找到此路径。请确认路径有效并重试。", + "YadifBob": "YADIF Bob", + "Yadif": "YADIF", + "LabelDeinterlaceMethod": "反交错方法:", + "DeinterlaceMethodHelp": "选择对隔行扫描内容进行转码时所用的反交错方法。", + "LabelLibraryPageSize": "媒体库分页阈值:", + "LabelLibraryPageSizeHelp": "设置媒体库页面每页要显示的最多媒体个数。设置为 0 以禁用分页。", + "UnsupportedPlayback": "Jellyfin无法解密被DRM保护的内容,但仍然会尝试播放包括受保护内容在内的所有内容。某些文件由于被加密或包含不受支持的特性(如互动标题),在播放时可能显示为黑屏。", + "MessageUnauthorizedUser": "您目前无权访问服务器。更多有关信息,请与服务器管理员联系。", + "Filter": "过滤", + "New": "新的", + "HeaderFavoritePlaylists": "收藏的播放列表", + "ButtonTogglePlaylist": "播放列表", + "ButtonToggleContextMenu": "更多" } diff --git a/src/strings/zh-hk.json b/src/strings/zh-hk.json index b83aaf0330..2d9634d333 100644 --- a/src/strings/zh-hk.json +++ b/src/strings/zh-hk.json @@ -347,5 +347,27 @@ "AllLanguages": "全部語言", "All": "全部", "AddedOnValue": "已添加 {0}", - "AddToPlaylist": "添加至播放清單" + "AddToPlaylist": "添加至播放清單", + "ValueSpecialEpisodeName": "特典 - {0}", + "Sync": "同步", + "Songs": "歌曲", + "Shows": "節目", + "Playlists": "播放清單", + "Photos": "相片", + "Movies": "電影", + "HeaderLiveTV": "電視直播", + "HeaderFavoriteSongs": "最愛的歌曲", + "HeaderFavoriteShows": "最愛的節目", + "HeaderFavoriteEpisodes": "最愛的劇集", + "HeaderFavoriteArtists": "最愛藝術家", + "HeaderFavoriteAlbums": "最愛專輯", + "HeaderContinueWatching": "繼續觀看", + "HeaderAlbumArtists": "專輯藝術家", + "Genres": "風格", + "Folders": "檔案夾", + "Favorites": "我的最愛", + "Collections": "合輯", + "Channels": "頻道", + "Books": "圖書", + "Albums": "專輯" } diff --git a/src/strings/zh-tw.json b/src/strings/zh-tw.json index 4397c06c56..f5020837f8 100644 --- a/src/strings/zh-tw.json +++ b/src/strings/zh-tw.json @@ -45,7 +45,7 @@ "Edit": "編輯", "EditImages": "編輯圖片", "Ended": "完結", - "EndsAtValue": "完結於{0}", + "EndsAtValue": "於 {0} 結束", "Favorite": "加到最愛", "File": "檔案", "FileNotFound": "未找到檔案。", @@ -67,13 +67,13 @@ "HeaderDeleteItem": "刪除項目", "HeaderEasyPinCode": "簡易 PIN 碼", "HeaderFeatureAccess": "可以使用的功能", - "HeaderFetchImages": "抓取圖像:", + "HeaderFetchImages": "擷取圖像:", "HeaderForgotPassword": "忘記密碼", "HeaderFrequentlyPlayed": "經常播放", "HeaderGuideProviders": "節目表提供者", "HeaderImageSettings": "圖像設置", "HeaderInstantMix": "瞬時混播", - "HeaderLatestEpisodes": "最新節目單元", + "HeaderLatestEpisodes": "最新劇集", "HeaderLatestMovies": "最新電影", "HeaderLatestRecordings": "最新錄影的節目", "HeaderLatestSongs": "最新歌曲", @@ -106,7 +106,7 @@ "LabelAllowServerAutoRestart": "允許伺服器自動重新啟動去安裝更新資料", "LabelAllowServerAutoRestartHelp": "伺服器只會在沒有使用者在使用時重新啟動。", "LabelAudioLanguagePreference": "音頻語言偏好選項:", - "LabelCachePath": "緩存路徑:", + "LabelCachePath": "快取路徑:", "LabelCollection": "收藏櫃:", "LabelContentType": "內容類型:", "LabelCountry": "國家:", @@ -116,7 +116,7 @@ "LabelEnableDlnaClientDiscoveryInterval": "尋找客戶端時間間隔(秒)", "LabelEnableDlnaDebugLogging": "記錄 DLNA 除錯資料到日誌", "LabelEnableDlnaDebugLoggingHelp": "將會建立非常大的日誌檔案,建議在進行故障排除時啟用。", - "LabelEnableDlnaPlayTo": "播放到DLNA設備", + "LabelEnableDlnaPlayTo": "播放到 DLNA 設備", "LabelEnableRealtimeMonitor": "啟用實時監控", "LabelEnableRealtimeMonitorHelp": "支持的檔案系統上的更改,將會立即處理。", "LabelEvent": "事件:", @@ -149,15 +149,15 @@ "LabelTime": "時間:", "LabelTriggerType": "觸發類型:", "LabelUser": "使用者:", - "LabelYourFirstName": "你的名字:", - "LabelYoureDone": "完成!", + "LabelYourFirstName": "您的名字:", + "LabelYoureDone": "完成,耶!", "LibraryAccessHelp": "選擇媒體資料夾與此使用者共享。管理員將可以使用中繼資料管理器編輯所有的媒體資料夾。", "Like": "喜歡", "MaxParentalRatingHelp": "具有較高的家長評級內容將從這使用者被隱藏。", "MessageAreYouSureDeleteSubtitles": "您真的要刪除這個字幕檔嗎?", "MessageDownloadQueued": "下載已排程。", "MessageItemsAdded": "已新增項目。", - "MessageNoMovieSuggestionsAvailable": "目前並沒有推薦的電影。開始觀看並對您的電影評分後,我們就會為您推薦您可能會喜歡的內容。", + "MessageNoMovieSuggestionsAvailable": "目前並沒有推薦的電影,開始觀看並對您的電影評分後,我們就會為您推薦您可能會喜歡的內容。", "MessageNothingHere": "這裡沒有什麼。", "MessagePasswordResetForUsers": "下列使用者的密碼已被重新設置。該使用者現在可以使用在密碼重置時所使用之 PIN 代碼進行登入。", "MessagePleaseEnsureInternetMetadata": "請確保已啟用從互聯網下載媒體資料。", @@ -181,7 +181,7 @@ "OptionBluray": "藍光", "OptionCommunityRating": "社區評分", "OptionContinuing": "持續", - "OptionCriticRating": "評論家評價", + "OptionCriticRating": "影評人評價", "OptionDaily": "每日", "OptionDateAdded": "新增日期", "OptionDatePlayed": "播放日期", @@ -235,7 +235,7 @@ "OptionWeekly": "每週", "OriginalAirDateValue": "原始播出日期:{0}", "ParentalRating": "Parental Rating", - "PasswordMatchError": "密碼和密碼確認必須一致。", + "PasswordMatchError": "兩個密碼必須一致。", "PasswordResetComplete": "密碼已重設。", "PasswordResetConfirmation": "你確定要重設密碼?", "PasswordSaved": "密碼已保存。", @@ -245,8 +245,8 @@ "RecordingCancelled": "已取消排程錄製。", "RecordingScheduled": "已排程錄製。", "Refresh": "重新整理", - "RefreshDialogHelp": "詳細資料的更新方式會依據Jellyfin的設定及已經啟用的網路服務來進行。", - "ReplaceAllMetadata": "取代所有詳細資料", + "RefreshDialogHelp": "詳細資料的更新方式會依據 Jellyfin 的設定及已經啟用的網路服務來進行。", + "ReplaceAllMetadata": "取代所有中繼資料", "ReplaceExistingImages": "取代現有圖片", "Saturday": "星期六", "Save": "保存", @@ -291,24 +291,24 @@ "TabTrailers": "預告", "TabTranscoding": "轉碼中", "TabUpcoming": "接下來", - "TellUsAboutYourself": "請自我介紹一下你自己", - "ThisWizardWillGuideYou": "此精靈將帶你完成安裝過程。開始之前,請選擇您慣用的語言。", + "TellUsAboutYourself": "介紹一下自己", + "ThisWizardWillGuideYou": "此精靈將帶你完成安裝過程,開始之前,請選擇您慣用的語言。", "Thursday": "星期四", - "TrackCount": "{0}個曲目", + "TrackCount": "{0} 個曲目", "Tuesday": "星期二", - "UninstallPluginConfirmation": "你確定要卸載{0}?", - "UninstallPluginHeader": "卸載插件", + "UninstallPluginConfirmation": "你確定要解除安裝 {0}?", + "UninstallPluginHeader": "解除安裝插件", "UserProfilesIntro": "Jellyfin 可單獨對使用者進行設定,所有使用者擁有自己的顯示設置,播放狀態和家長控制。", "Users": "使用者", "VersionNumber": "版本 {0}", "Wednesday": "星期三", "WelcomeToProject": "歡迎使用 Jellyfin!", - "WizardCompleted": "這就是我們所需的全部資訊,Jellyfin 現在正在收集你的媒體櫃的資料,在這段時間內,不妨參考我們推出的應用程式。按一下完成進入伺服器總覽頁。", + "WizardCompleted": "這就是我們所需的全部資訊,Jellyfin 現在正在收集你的媒體櫃的資料,在這段時間內,不妨參考我們推出的應用程式。按一下完成進入控制台。", "Actor": "演員", "AddToPlayQueue": "加入播放清單", "AddToPlaylist": "加入播放列表", "Absolute": "絕對", - "AccessRestrictedTryAgainLater": "您的存取目前受限,請稍後再試。", + "AccessRestrictedTryAgainLater": "目前存取受限,請稍後再試。", "AddedOnValue": "已加入 {0}", "AdditionalNotificationServices": "請瀏覽附加元件目錄以安裝額外的通知服務。", "Albums": "專輯", @@ -328,7 +328,7 @@ "Art": "圖像", "Artists": "演出者", "AsManyAsPossible": "越多越好", - "Ascending": "由少到多", + "Ascending": "遞增", "AspectRatio": "長寬比", "AttributeNew": "新增", "Audio": "音訊", @@ -367,7 +367,7 @@ "ButtonConnect": "連結", "ButtonDown": "下", "ButtonDownload": "下載", - "ButtonEditOtherUserPreferences": "編輯此使用者的內容,大頭貼和個人設定。", + "ButtonEditOtherUserPreferences": "編輯此使用者的內容、大頭貼和個人設定。", "ButtonFullscreen": "全螢幕", "ButtonHelp": "幫助", "ButtonInfo": "詳細資料", @@ -418,7 +418,7 @@ "CloudSyncFeatureDescription": "將您的媒體備份到雲端當作簡單的備份,收藏和轉檔。", "Collections": "合輯", "Composer": "作曲家", - "ConfigureDateAdded": "調整伺服器怎麼判定媒體褲的「新增日期」", + "ConfigureDateAdded": "調整伺服器怎麼判定媒體庫的「新增日期」", "ConfirmDeleteImage": "刪除圖片?", "ConfirmDeleteItems": "刪除這些項目會將檔案從系統和媒體庫中刪除。你真的要繼續嗎?", "ConfirmEndPlayerSession": "您要在 {0} 秒後將 Jellyfin關機嗎?", @@ -453,8 +453,7 @@ "DirectStreamHelp2": "直接串流檔案會占用非常少的處理效能並且影片的品質不會有任何損失。", "DirectStreaming": "直接串流", "Director": "導演", - "DirectorValue": "導演: {0}", - "DirectorsValue": "導演: {0}", + "Directors": "導演", "Disabled": "已停用", "Disc": "光碟", "Disconnect": "斷開連結", @@ -463,7 +462,7 @@ "DisplayInOtherHomeScreenSections": "在“最新媒體”和“繼續觀看“等主畫面區塊中顯示", "DisplayMissingEpisodesWithinSeasons": "顯示每季缺少的劇集", "DisplayMissingEpisodesWithinSeasonsHelp": "必須在 Jellyfin 伺服器的電視媒體庫設定中啟用該功能。", - "DisplayModeHelp": "選擇您正在運行Jellyfin的螢幕類型。", + "DisplayModeHelp": "選擇您想要的界面樣式。", "DoNotRecord": "不要錄", "Down": "下", "DownloadItemLimitHelp": "非必要。 設置要下載的項目數限制。", @@ -499,7 +498,7 @@ "EnterFFmpegLocation": "輸入 FFmpeg 路徑", "Episodes": "劇集", "Error": "錯誤", - "ErrorAddingListingsToSchedulesDirect": "", + "ErrorAddingListingsToSchedulesDirect": "在將電視節目時間表新增到您的 Schedules Direct 帳號時出現錯誤。每個 Schedules Direct 帳號只允許有限的時間表。您在繼續前可能需要登入 Schedules Direct 網站並刪除帳號中的其它列表。", "ErrorAddingGuestAccount1": "新增Jellyfin Connect時發生錯誤。你的賓客有建立Jellyfin帳號嗎?他們可以在 {0} 創建帳號。", "ErrorAddingGuestAccount2": "若你還是遇到問題,請發送email至 {0} 並附上你和他們的email帳號。", "ErrorAddingJellyfinConnectAccount1": "新增Jellyfin Connect時發生錯誤。您有建立Jellyfin帳號嗎?您可以在 {0} 創建帳號。", @@ -507,17 +506,17 @@ "ErrorAddingJellyfinConnectAccount3": "這個 Jellyfin 帳號已經被連接至一個本地帳號。一個 Jellyfin帳號 只能同時被連接到一個本機帳號。", "ErrorAddingMediaPathToVirtualFolder": "新增媒體路徑時發生錯誤,請確認路徑是否有效,且你的 Jellyfin 伺服器有對該位置的存取權。", "ErrorAddingTunerDevice": "新增調諧器設備時發生錯誤,請確認它是否可被存取後再試一次。", - "ErrorAddingXmlTvFile": "存取 XMLTV 文件時發生錯誤。請確認該檔案是否存在後再試一次。", + "ErrorAddingXmlTvFile": "存取 XMLTV 檔案時發生錯誤,請確認該檔案是否存在後再試一次。", "ErrorConnectServerUnreachable": "處理請求時發生錯誤。您的伺服器無法與我們位於 {0} 的 Jellyfin Connect伺服器溝通。請確認你的伺服器有網路連結且防火牆或其他安全性程式允許這個程式對外溝通。", - "ErrorDeletingItem": "從Jellyfin伺服器刪除項目時發生錯誤。請確認伺服器有那個磁碟的寫入權限並再試一次。", - "ErrorGettingTvLineups": "下載電視節目表時發生錯誤,請確認你的資訊是正確的然後再試一次。", + "ErrorDeletingItem": "從 Jellyfin 伺服器刪除項目時發生錯誤,請確認伺服器對該磁碟有寫入權限並再試一次。", + "ErrorGettingTvLineups": "下載電視節目表時發生錯誤,請確認你的資訊是否正確並重試。", "ErrorMessagePasswordNotMatchConfirm": "密碼和密碼確認必須吻合。", "ErrorMessageStartHourGreaterThanEnd": "結束時間必須在開始時間後。", "ErrorMessageUsernameInUse": "用戶名已存在。請重新選個名稱再試。", "ErrorPleaseSelectLineup": "請選擇節目表,然後再試一次。如果沒有可用的節目表,請檢查您的使用者名稱、密碼和郵遞區號是否正確。", "ErrorReachingJellyfinConnect": "連接 Jellyfin Connect 伺服器時發生錯誤。請確認你的網絡狀態是否穩定後再試一次。", "ErrorRemovingJellyfinConnectAccount": "移除 Jellyfin Connect 帳號時發生錯誤。請確認你的網絡狀態是否穩定後再試一次。", - "ErrorSavingTvProvider": "儲存電視供應商時發生錯誤。請確認它是可存取後再試一次。", + "ErrorSavingTvProvider": "儲存電視供應商時發生錯誤,請確認是否可存取並重試。", "EveryNDays": "每 {0} 天", "ExitFullscreen": "結束全螢幕", "ExtraLarge": "特大", @@ -539,20 +538,19 @@ "FreeAppsFeatureDescription": "享受免費的Jellyfin應用程式。", "Fullscreen": "全螢幕", "General": "一般", - "GenreValue": "類型 : {0}", + "Genre": "類型", "Genres": "風格", - "GenresValue": "類型 : {0}", "GroupBySeries": "按系列分組", "GroupVersions": "按版本分組", - "GuestStar": "特邀明星", + "GuestStar": "客串", "GuestUserNotFound": "未找到用戶。請確保用戶名稱正確後重試,或者嘗試輸入他們的電子郵件地址。", "Guide": "指南", "GuideProviderSelectListings": "選擇列表", - "H264CrfHelp": "The Constant Rate Factor (CRF) 是 x264 編碼器的默認畫質設置。此方法允許編碼器自動分配位元速率來試著達到一定輸出品質。讓每個畫格得到它需要的位元數來保持所需的品質等級。CRF 會得到最佳的位元速率分配結果。", - "H264EncodingPresetHelp": "速度越慢則會得到更好的壓縮編碼效率。", - "HDPrograms": "HD節目", + "H264CrfHelp": "CRF 是 x264 編碼器的預設畫質設置。此方法允許編碼器自動分配位元速率來試著達到一定輸出品質。讓每個畫格得到它需要的位元數來保持所需的品質等級。CRF 會得到最佳的位元速率分配結果。", + "EncoderPresetHelp": "速度越慢則會得到更好的壓縮編碼效率。", + "HDPrograms": "HD 節目", "HandledByProxy": "由反向代理處理", - "HardwareAccelerationWarning": "啟動硬體加速可能在某些環境下導致系統不穩定。請確認你的作業系統和影片驅動程式是最新的。如果你在開啟此項後播放影片產生困難,那麼你需要將此選項設回”自動“。", + "HardwareAccelerationWarning": "啟動硬體加速可能在某些環境下導致系統不穩定。請確認你的作業系統和影片驅動程式是最新的。如果你在開啟此項後難以播放影片,那麼你需要將此選項設回「無」。", "HeaderAccessSchedule": "存取時程", "HeaderAccessScheduleHelp": "建立一個存取時程以限制可存取的時段。", "HeaderActiveDevices": "運行中裝置", @@ -572,7 +570,7 @@ "HeaderAllowMediaDeletionFrom": "允許從中刪除媒體", "HeaderApiKey": "API 金鑰", "HeaderApiKeys": "API 金鑰", - "HeaderApiKeysHelp": "外部應用程式需要有一個 API 金鑰以用於和 Jellyfin 伺服器溝通。金鑰將在通過 Jellyfin 帳戶登入時自動發行,或者你可以手動為應用程式產生一個金鑰。", + "HeaderApiKeysHelp": "外部應用程式需要有一個 API 金鑰以用於和 Jellyfin 伺服器溝通。金鑰會在 Jellyfin 使用者登入時自動發行,或者你可以手動為應用程式產生一個金鑰。", "HeaderApp": "應用程式", "HeaderAppearsOn": "同時出現於", "HeaderAudio": "音訊", @@ -608,12 +606,12 @@ "HeaderConfirmRecordingCancellation": "確認取消錄製", "HeaderConfirmRecordingDeletion": "確認刪除錄影", "HeaderConfirmRemoveUser": "移除用戶", - "HeaderConfirmRevokeApiKey": "撤銷 API 金鑰", + "HeaderConfirmRevokeApiKey": "重置 API 金鑰", "HeaderConfirmSeriesCancellation": "確認系列取消", "HeaderConfirmation": "確認", "HeaderConnectToServer": "連結至伺服器", "HeaderConnectionFailure": "連結失敗", - "HeaderContainerProfile": "影片容器設定檔", + "HeaderContainerProfile": "影片載體設定", "HeaderContainerProfileHelp": "影片容器的設定檔標明了設備播放特定媒體格式時的限制。如果在限制之內則媒體將被轉碼,否則媒體格式將被設定為直接播放。", "HeaderContinueListening": "繼續聆聽", "HeaderContinueWatching": "繼續觀賞", @@ -630,7 +628,7 @@ "HeaderDeleteTaskTrigger": "刪除任務觸發條件", "HeaderDestination": "目的地", "HeaderDetectMyDevices": "偵測我的設備", - "HeaderDeveloperInfo": "開發者訊息", + "HeaderDeveloperInfo": "開發者資訊", "HeaderDevice": "裝置", "HeaderDeviceAccess": "允許裝置存取", "HeaderDevices": "裝置", @@ -653,7 +651,7 @@ "HeaderFavoriteAlbums": "最愛專輯", "HeaderFavoriteArtists": "最愛演出者", "HeaderFavoriteCollections": "最愛收藏", - "HeaderFavoriteEpisodes": "最愛級數", + "HeaderFavoriteEpisodes": "最愛影集", "HeaderFavoriteMovies": "最愛電影", "HeaderFavoritePlaylists": "最愛播放列表", "HeaderFavoriteShows": "最愛節目", @@ -670,7 +668,7 @@ "HeaderHomePage": "主畫面", "HeaderHomeScreen": "主畫面", "HeaderHomeScreenSettings": "主畫面設定", - "HeaderHttpHeaders": "Http 標頭", + "HeaderHttpHeaders": "HTTP 標頭", "HeaderIdentification": "身份識別", "HeaderIdentificationCriteriaHelp": "至少輸入一個識別標準。", "HeaderIdentificationHeader": "身份識別標題", @@ -873,9 +871,9 @@ "HeaderVideoType": "影片類型", "HeaderVideoTypes": "影片類型", "HeaderVideos": "影片", - "HeaderXmlDocumentAttribute": "XML檔案屬性", - "HeaderXmlDocumentAttributes": "XML檔案屬性", - "HeaderXmlSettings": "XML設置", + "HeaderXmlDocumentAttribute": "XML 檔案屬性", + "HeaderXmlDocumentAttributes": "XML 檔案屬性", + "HeaderXmlSettings": "XML 設置", "HeaderYears": "年份", "HeadersFolders": "資料夾", "Hide": "隱藏", @@ -885,14 +883,14 @@ "HttpsRequiresCert": "要啟用安全連線,您需要提供受信任的SSL證書,如 Let's Encrypt。 請提供證書,或停用安全連線。", "Identify": "識別", "Images": "圖片", - "ImportFavoriteChannelsHelp": "如果啟用,只有在調諧器設備中被標記為我的最愛的頻道才會被導入。", - "ImportMissingEpisodesHelp": "如果啟用,有關缺失劇集的數據導入您的Jellyfin媒體庫,並在季節和系列中顯示。 這可能會導致媒體庫掃描延長。", - "InstallingPackage": "正在安装 {0}", + "ImportFavoriteChannelsHelp": "若啟用,只有在調諧器設備中被標記為我的最愛的頻道才會被導入。", + "ImportMissingEpisodesHelp": "若啟用,有關缺失劇集的數據導入您的 Jellyfin 媒體庫,並在季節和系列中顯示。 這可能會導致媒體庫掃描延長。", + "InstallingPackage": "正在安装 {0}(版本 {1})", "InstantMix": "即時混音", "Items": "項目", "Kids": "兒童", - "Label3DFormat": "3D格式:", - "LabelAbortedByServerShutdown": "(因為伺服器關閉被中止)", + "Label3DFormat": "3D 格式:", + "LabelAbortedByServerShutdown": "(因為伺服器關閉被中止)", "LabelAccessDay": "一周中的何時:", "LabelAccessEnd": "結束時間:", "LabelAccessStart": "開始時間:", @@ -906,24 +904,24 @@ "LabelAlbumArtMaxHeight": "專輯封面最大高度:", "LabelAlbumArtMaxHeightHelp": "通過 upnp:albumArtURI 顯示的專輯封面超鏈接的最大分辨率。", "LabelAlbumArtMaxWidth": "專輯封面最大寬度:", - "LabelAlbumArtMaxWidthHelp": "通過upnp:albumArtURI顯示的專輯封面超鏈接的最大分辨率。", - "LabelAlbumArtPN": "專輯封面PN :", + "LabelAlbumArtMaxWidthHelp": "通過 upnp:albumArtURI 顯示的專輯封面超鏈接的最大解析度。", + "LabelAlbumArtPN": "專輯封面 PN :", "LabelAlbumArtists": "專輯作家:", "LabelAll": "所有", "LabelAllowHWTranscoding": "允許硬體轉碼", - "LabelAllowedRemoteAddresses": "遠端IP地址過濾:", - "LabelAllowedRemoteAddressesMode": "遠端IP地址過濾模式:", - "LabelAppName": "APP名稱", - "LabelAppNameExample": "例如: Sickbeard, Sonarr", + "LabelAllowedRemoteAddresses": "遠端 IP 過濾:", + "LabelAllowedRemoteAddressesMode": "遠端 IP 過濾模式:", + "LabelAppName": "APP 名稱", + "LabelAppNameExample": "例如:可愛蹦蹦主機、小安的 Jellyfin", "LabelArtists": "藝人:", "LabelArtistsHelp": "分開多重使用 ;", - "LabelAudio": "音頻:", + "LabelAudio": "音頻", "LabelAuthProvider": "認證提供者:", "LabelAutomaticallyRefreshInternetMetadataEvery": "從網路自動刷新數據:", "LabelBindToLocalNetworkAddress": "聯結本地網絡地址:", - "LabelBindToLocalNetworkAddressHelp": "(可選的)覆蓋 HTTP 服務器綁定的本地 IP 地址。如果留空,服務器將會監聽所有可用的地址。改變這個值需要重啟 Jellyfin 伺服器\n。", + "LabelBindToLocalNetworkAddressHelp": "(選用)覆蓋 HTTP 服務器綁定的本地 IP 地址。如果留空,服務器將會監聽所有可用的地址。改變這個值需要重啟 Jellyfin 伺服器。", "LabelBirthDate": "出生日期:", - "LabelBirthYear": "出生年份:", + "LabelBirthYear": "出生年:", "LabelBlastMessageInterval": "活動信號的時間間隔(秒)", "LabelBlastMessageIntervalHelp": "確定伺服器活動消息之間的持續時間(秒)。", "LabelBlockContentWithTags": "通過標籤鎖定內容:", @@ -942,17 +940,17 @@ "LabelCustomCssHelp": "於 Web 介面套用您的自訂樣式。", "LabelCustomDeviceDisplayName": "顯示名稱:", "Depressed": "凹陷", - "HeaderHome": "主頁", + "HeaderHome": "首頁", "HeaderSelectMetadataPathHelp": "瀏覽或者輸入路徑以用於保存中繼資料,請確保資料夾可以寫入。", "HeaderSelectServerCachePathHelp": "瀏覽或者輸入路徑以用於伺服器快取檔案。請確保該資料夾可以被寫入。", "LabelCustomDeviceDisplayNameHelp": "指定自訂的顯示名稱,或者留空以使用設備自己報告的名稱。", "LabelCustomRating": "自訂分級:", - "LabelDashboardTheme": "儀表板佈景主題:", + "LabelDashboardTheme": "控制台佈景主題:", "LabelDateAdded": "新增日期:", "LabelDateAddedBehavior": "新内容加入的日期應使用:", "LabelDateTimeLocale": "設定時區:", "LabelDeathDate": "死亡時間:", - "LabelDefaultScreen": "預設螢幕:", + "LabelDefaultScreen": "預設分頁:", "LabelDefaultUser": "預設使用者:", "LabelDeviceDescription": "裝置說明", "LabelDidlMode": "DIDL 模式:", @@ -968,13 +966,13 @@ "OptionMax": "最大", "LabelAudioBitDepth": "音訊位元深度:", "LabelBaseUrl": "根路徑:", - "LabelIconMaxHeight": "Icon 最高高度:", + "LabelIconMaxHeight": "圖示最高高度:", "LabelHttpsPortHelp": "Jellyfin 的 HTTPS 伺服器應綁定的 TCP 端口。", "LabelIconMaxHeightHelp": "通過 upnp:icon 的圖標最大解析度。", "CopyStreamURL": "複製串流連結", "MediaInfoDefault": "預設", "MediaInfoStreamTypeAudio": "音訊", - "LabelDateAddedBehaviorHelp": "如果原本就有中繼資料,則將始終在這些選項之一之前使用它。", + "LabelDateAddedBehaviorHelp": "如果原本就有中繼資料,將會優先使用其數據。", "LabelScreensaver": "螢幕保護程式:", "LabelSeasonNumber": "季:", "LabelDropImageHere": "拖移圖片到這裡,或是點擊來選取。", @@ -990,7 +988,7 @@ "LabelVersionInstalled": "{0} 已安裝", "DashboardVersionNumber": "版本:{0}", "DashboardServerName": "伺服器:{0}", - "NoSubtitles": "沒有字幕", + "NoSubtitles": "無", "List": "清單", "OptionAllowMediaPlayback": "允許播放媒體", "OneChannel": "單聲道", @@ -1012,7 +1010,7 @@ "ValueCodec": "編碼:{0}", "ValueSongCount": "{0} 首歌", "LabelFileOrUrl": "檔案或路徑:", - "LabelKodiMetadataSaveImagePaths": "在 nfo 檔案中儲存圖片路徑", + "LabelKodiMetadataSaveImagePaths": "在 NFO 檔案中儲存圖片路徑", "LabelLanNetworks": "區域網路:", "LabelMetadataPathHelp": "指定自訂路徑來儲存下載的圖片與中繼資料。", "LabelZipCode": "郵遞區號:", @@ -1026,7 +1024,7 @@ "ShowAdvancedSettings": "顯示進階選項", "ShowTitle": "顯示標題", "ShowYear": "顯示年份", - "Shuffle": "隨ㄔㄧ", + "Shuffle": "隨機播放", "Smart": "智慧", "HeaderFavoriteBooks": "最愛的書籍", "LabelAudioBitrate": "音訊比特率:", @@ -1046,7 +1044,7 @@ "LabelExtractChaptersDuringLibraryScan": "於媒體庫掃描時擷取章節圖片", "LabelHttpsPort": "本地 HTTPS 端口:", "LabelFailed": "失敗", - "LabelSubtitles": "字幕:", + "LabelSubtitles": "字幕", "LabelSupportedMediaTypes": "支援的媒體類型:", "LabelTextBackgroundColor": "文字背景顏色:", "LabelTextColor": "文字顏色:", @@ -1062,7 +1060,7 @@ "LabelTypeText": "文本", "LabelUsername": "使用者名稱:", "DashboardOperatingSystem": "作業系統:{0}", - "LabelVideo": "影片:", + "LabelVideo": "影片", "LabelVideoCodec": "影片編碼:", "LabelYear": "年:", "LatestFromLibrary": "最新 {0}", @@ -1132,7 +1130,7 @@ "ManageRecording": "管理錄影", "MessageAlreadyInstalled": "已安裝此版本。", "MessageConfirmRestart": "您確定要重新啟動嗎?", - "Metadata": "ˊ中繼資料", + "Metadata": "中繼資料", "OptionAllUsers": "所有使用者", "OptionHomeVideos": "圖片", "OptionPoster": "海報", @@ -1146,7 +1144,7 @@ "TV": "電視", "TabUsers": "使用者", "Trailers": "預告", - "LabelImageFetchersHelp": "按優先級啟用並排列您喜歡的圖片抓取器。", + "LabelImageFetchersHelp": "啟用並按優先順序排序您的首選圖片擷取器。", "LabelDownMixAudioScale": "縮混時的音訊增強:", "LabelDownMixAudioScaleHelp": "縮混時增強音訊。其中一個音軌將保持原始音量。", "LabelDownloadLanguages": "下載語言:", @@ -1164,7 +1162,7 @@ "LabelSelectUsers": "選擇使用者:", "LabelSelectVersionToInstall": "選擇要安裝的版本:", "LabelSendNotificationToUsers": "傳送通知給:", - "LabelSortBy": "排序依:", + "LabelSortBy": "排序按照:", "LabelVideoBitrate": "影片比特率:", "MediaInfoSize": "大小", "MediaInfoTimestamp": "時間戳", @@ -1195,7 +1193,7 @@ "LabelKodiMetadataDateFormat": "釋出日期格式:", "LabelIconMaxWidth": "Icon 最寬寬度:", "LabelGroupMoviesIntoCollectionsHelp": "顯示電影列表時,屬於相同集合的電影將作為分組項目顯示。", - "LabelH264EncodingPreset": "H264 解碼品質:", + "LabelEncoderPreset": "H264 解碼品質:", "LabelHardwareAccelerationType": "硬體加速:", "LabelIconMaxWidthHelp": "通過 upnp:icon 的圖標最大解析度。", "LabelImportOnlyFavoriteChannels": "僅限收藏的頻道", @@ -1276,7 +1274,7 @@ "LabelKodiMetadataEnableExtraThumbs": "複製 extrafanart 到 extrathumbs 欄位", "LabelMovieCategories": "電影分類:", "LabelMoviePrefix": "電影前綴:", - "LabelProfileContainer": "影片容器:", + "LabelProfileContainer": "影片容器:", "LabelDropShadow": "陰影:", "LabelSecureConnectionsMode": "安全連接模式:", "LabelTVHomeScreen": "電視模式主畫面:", @@ -1297,9 +1295,9 @@ "Up": "上", "ValueOneSeries": "1 劇集", "Writer": "編劇", - "XmlTvMovieCategoriesHelp": "有這些類別的節目會被當作電影。用「|」分隔多個。", + "XmlTvMovieCategoriesHelp": "有這些類別的節目會被當作電影,以「|」來分隔多個項目。", "ValueSeriesCount": "{0} 劇集", - "LabelHardwareAccelerationTypeHelp": "這個功能只能在支援的系統上使用。", + "LabelHardwareAccelerationTypeHelp": "硬件加速需要額外的配置。", "LabelHomeNetworkQuality": "區域網路畫質:", "LabelHomeScreenSectionValue": "主畫面模塊 {0}:", "LabelMetadataDownloadersHelp": "啟用媒體屬性下載器的優先次序,愈下次序只會用來填補缺少的信息。", @@ -1312,7 +1310,6 @@ "OptionDownloadBannerImage": "橫幅", "OptionEnableAccessToAllChannels": "允許存取所有頻道", "OptionEnableAccessToAllLibraries": "允許存取所有媒體庫", - "OptionEnableAutomaticServerUpdates": "啟用自動更新", "OptionEnableForAllTuners": "开启所有调谐器", "OptionExtractChapterImage": "開啟章節圖片擷取", "OptionEnableM2tsModeHelp": "當編碼為 MPEGTS 時啟用 M2TS 模式。", @@ -1320,7 +1317,7 @@ "OptionEstimateContentLength": "轉檔時,估計內容長度", "OptionExternallyDownloaded": "外部下載", "OptionHlsSegmentedSubtitles": "HLS 分段字幕", - "OptionLoginAttemptsBeforeLockout": "確定在被封鎖之前可以登入失敗幾次。", + "OptionLoginAttemptsBeforeLockout": "在被封鎖之前可以登入失敗幾次。", "OptionRequirePerfectSubtitleMatch": "只下載與我的影片檔案完美匹配的字幕", "PlayCount": "播放次數", "Series": "電視劇", @@ -1345,7 +1342,7 @@ "LabelMoviePrefixHelp": "若前綴套用到電影標題,請在此處輸入它來方便伺服器能夠正確處理。", "LabelMovieRecordingPath": "電影錄製路徑(選用):", "LabelNotificationEnabled": "啟用這個通知", - "LabelProfileContainersHelp": "以逗號分隔。留空則適用於所有影片容器。", + "LabelProfileContainersHelp": "以逗號分隔,留空則適用於所有影片容器。", "LabelSelectFolderGroupsHelp": "未選中的資料夾將在其自己的檢視中顯示。", "LabelSerialNumber": "序號", "LabelSeriesRecordingPath": "電視劇錄影路徑(選用):", @@ -1370,7 +1367,7 @@ "LabelUserLibraryHelp": "選擇在裝置上顯示的使用者媒體庫,留空則使用預設設定值。", "LabelUserLoginAttemptsBeforeLockout": "使用者被封鎖前可嘗試的次數:", "LabelVaapiDeviceHelp": "此渲染節點用來硬體加速。", - "LabelWeb": "網站: ", + "LabelWeb": "網站:", "LabelXDlnaCapHelp": "決定在 urn:schemas-dlna-org:device-1-0 namespace 中的 X_DLNACAP 元素的內容。", "LabelXDlnaDocHelp": "決定在 urn:schemas-dlna-org:device-1-0 namespace 中的 X-Dlna doc 元素的內容。", "LaunchWebAppOnStartup": "在啟動伺服器時啟動使用者介面", @@ -1401,7 +1398,7 @@ "MessageDirectoryPickerLinuxInstruction": "使用 Linux on Arch Linux、CentOS、Debian、Fedora、openSUSE 或 Ubuntu 作業系統,您必須授權使用者至少讀取權限來存取您的儲存路徑。", "MessageEnablingOptionLongerScans": "啟用這個選項可能會延長媒體庫的掃描時間。", "MessageFileReadError": "讀取檔案時發生錯誤。", - "MessageForgotPasswordInNetworkRequired": "請檢查您的區域網路後再試一次來開始密碼重置流程。", + "MessageForgotPasswordInNetworkRequired": "請檢查您的區域網路後再開始密碼重置流程。", "MessageForgotPasswordFileCreated": "已在伺服器上建立了以下檔案,並包含有關後續步驟說明:", "MessageNoAvailablePlugins": "沒有可用的模組。", "MessageNoServersAvailable": "無法自動偵測伺服器。", @@ -1417,7 +1414,7 @@ "News": "新聞", "NoNewDevicesFound": "找不到裝置,要添加新調諧器,請關閉此對話框並手動輸入裝置訊息。", "OnlyForcedSubtitles": "僅顯示強制字幕", - "OnlyImageFormats": "僅圖片格式(VOBSUB、PGS、SUB 等)", + "OnlyImageFormats": "圖片格式(VOBSUB、PGS、SUB)", "OptionAllowLinkSharingHelp": "只有網頁包含的媒體訊息會被共享,媒體檔案本身不會被公開共享,共享的內容會在 {0} 天後到期。", "OptionAllowRemoteSharedDevices": "允許遠端控制共享裝置", "OptionAllowSyncTranscoding": "允許需要轉檔的媒體下載和同步", @@ -1444,7 +1441,7 @@ "OptionSubstring": "子串", "OptionWeekdays": "工作日", "Overview": "概述", - "PackageInstallCancelled": "{0} 安裝被取消。", + "PackageInstallCancelled": "{0} (版本 {1})安裝被取消。", "PlayAllFromHere": "從這裡開始全部播放", "PleaseAddAtLeastOneFolder": "請點擊新增按鈕,新增至少一個資料夾到這個媒體庫。", "PleaseConfirmPluginInstallation": "點擊「OK」以確認您已經閱讀了上述內容並希望繼續安裝模組。", @@ -1462,7 +1459,7 @@ "ProductionLocations": "產地", "Programs": "節目", "Quality": "品質", - "PackageInstallFailed": "{0} 安裝失敗。", + "PackageInstallFailed": "{0} (版本 {1}) 安裝失敗。", "QueueAllFromHere": "將這裡的全部內容加入佇列", "Raised": "提高", "Rate": "評等", @@ -1477,7 +1474,7 @@ "Uniform": "輪廓", "Unmute": "取消靜音", "Unplayed": "尚未播放", - "TvLibraryHelp": "查看{0}電視命名指南{1}。", + "TvLibraryHelp": "查看 {0} 電視命名指南 {1} 。", "LabelMonitorUsers": "監控活動:", "LabelPleaseRestart": "改動將在手動重啟用戶端後生效。", "LabelProfileCodecsHelp": "以逗號分隔。留空則適用於所有編解碼器。", @@ -1485,7 +1482,7 @@ "LabelInNetworkSignInWithEasyPasswordHelp": "你可以在你的家庭網路中使用你的簡易 PIN 碼登錄 Jellyfin 應用程式,僅在你使用外部網路時才需要輸入密碼,如果 PIN 碼留空,那麼在你的區域網路中便不需輸入密碼。", "LabelReleaseDate": "釋出日期:", "LabelRemoteClientBitrateLimit": "網際網路串流傳輸位元率限制(Mbps):", - "LanNetworksHelp": "", + "LanNetworksHelp": "在強制頻寬限制時,認作本地網路上的 IP 地址或 IP/子網域遮罩項目的逗號分隔列表。若設置此項,所有其它 IP 地址將被視作在外部網路上,并且將受到外部頻寬限制。如果保留爲空,則只將服務器的子網域遮罩作本地網路。", "OptionIgnoreTranscodeByteRangeRequests": "忽略轉檔位元組範圍請求", "OptionIgnoreTranscodeByteRangeRequestsHelp": "如果啟用,這些請求會被兌現,但會忽略的位元組範圍標頭。", "OptionLoginAttemptsBeforeLockoutHelp": "若值為 0,則表示將允許普通使用者嘗試三次、管理員嘗試五次的預設值,設定為 -1 來停用此功能。", @@ -1494,7 +1491,7 @@ "RecordingPathChangeMessage": "更改錄製資料夾不會將現有錄製從舊位置遷移到新的,您需要手動移動它們。", "RestartPleaseWaitMessage": "Jellyfin 伺服器將重新啟動,這將花費幾分鐘時間。", "LabelEmbedAlbumArtDidl": "於 Didl 中嵌入專輯封面", - "LabelEnableAutomaticPortMapHelp": "自動嘗試映射公共連接埠到 UPnP 本地連接埠。這可能無法用於某些路由器。", + "LabelEnableAutomaticPortMapHelp": "自動嘗試映射公共連接埠到 UPnP 本地連接埠。這可能無法用於某些路由器。需重新啓動伺服器。", "LabelEmbedAlbumArtDidlHelp": "有些裝置使用這個方式來取得專輯封面,啟用這個選項可能導致其他設備播放失敗。", "SettingsWarning": "更改這些值可能會導致不穩定或連線故障。如果您遇到任何問題,建議將它們重新更改為預設值。", "LabelEnableSingleImageInDidlLimitHelp": "若在 Didl 中嵌入多個圖片,某些裝置可能無法正常顯示。", @@ -1510,8 +1507,8 @@ "SystemDlnaProfilesHelp": "系統設定檔案是唯讀的,更改系統設定檔案將被儲存到自訂的新設定檔案。", "LabelNumber": "編號:", "LabelNumberOfGuideDays": "下載電視指南日數:", - "OnlyForcedSubtitlesHelp": "只有標記為「強制」的字幕會被載入。", - "PackageInstallCompleted": "{0} 安裝完成。", + "OnlyForcedSubtitlesHelp": "僅被標記為「強制」的字幕會被載入。", + "PackageInstallCompleted": "{0} (版本 {1}) 安裝完成。", "OptionDisplayFolderViewHelp": "在其他媒體庫旁邊顯示資料夾,對想要一個普通的資料夾檢視很有用。", "LabelReasonForTranscoding": "轉檔原因:", "LabelRecord": "錄影:", @@ -1537,7 +1534,7 @@ "LabelSportsCategories": "體育分類:", "LabelStartWhenPossible": "當可能時自動開始:", "LabelVaapiDevice": "VA API 裝置:", - "DashboardArchitecture": "結構:{0}", + "DashboardArchitecture": "架構:{0}", "MediaInfoSampleRate": "採樣率", "MessageContactAdminToResetPassword": "請聯繫您的管理員來重置密碼。", "MessageUnsetContentHelp": "內容將顯示為純資料夾,建議使用中繼資料管理器設置子資料夾的內容類型。", @@ -1545,7 +1542,7 @@ "OptionCustomUsers": "自訂", "OptionDateAddedFileTime": "使用檔案建立日期", "OptionReportByteRangeSeekingWhenTranscodingHelp": "這對一些時間跳轉緩慢的裝置是必要的。", - "XmlTvNewsCategoriesHelp": "有這些類別的節目會被當作新聞節目。用「|」分隔多個。", + "XmlTvNewsCategoriesHelp": "有這些類別的節目會被當作新聞節目,以「|」來分隔多個項目。", "LabelKodiMetadataEnableExtraThumbsHelp": "為了相容 Kodi 主題,下載的圖片將被同時儲存在 extrafanart 和 extrathumbs 資料夾中。", "LabelInternetQuality": "網路畫質:", "LabelKodiMetadataEnablePathSubstitutionHelp": "允許將圖片的路徑以伺服器路徑來替換。", @@ -1578,7 +1575,7 @@ "LabelPostProcessorArguments": "處理器後命令行參數:", "LabelPostProcessorArgumentsHelp": "使用 {path} 作為錄製檔案的路徑。", "LabelPreferredDisplayLanguage": "首選語言:", - "LabelPreferredDisplayLanguageHelp": "翻譯 Jellyfin 是一個進行中的項目。", + "LabelPreferredDisplayLanguageHelp": "歡迎一起翻譯 Jellyfin!", "LabelPreferredSubtitleLanguage": "字幕語言偏好:", "LabelProtocol": "協議:", "LabelProtocolInfo": "協議資訊:", @@ -1587,7 +1584,7 @@ "LabelProtocolInfoHelp": "當響應來自裝置的 GetProtocolInfo(獲取協議訊息)請求時,該值將被使用。", "LabelPublicHttpPortHelp": "公開連接埠應映射到本地 HTTP 連接埠。", "LabelPublicHttpsPortHelp": "公開連接埠應映射到本地 HTTPS 連接埠。", - "LabelReadHowYouCanContribute": "了解如何作出貢獻。", + "LabelReadHowYouCanContribute": "瞭解如何一同貢獻。", "LabelSelectFolderGroups": "自動將以下資料夾中的內容分組到視圖中,例如電影、音樂和電視:", "LabelStatus": "狀態:", "LiveBroadcasts": "直播", @@ -1606,13 +1603,13 @@ "Vertical": "垂直", "VideoRange": "影片範圍", "ViewPlaybackInfo": "查看播放訊息", - "XmlTvSportsCategoriesHelp": "有這些類別的節目會被當作體育節目。用「|」分隔多個。", + "XmlTvSportsCategoriesHelp": "有這些類別的節目會被當作體育節目,以「|」來分隔多個項目。", "XmlTvPathHelp": "XML 電視檔案的路徑,Jellyfin 將讀取該檔案並定期檢查其更新,您負責建立和更新檔案。", "MessageInvalidForgotPasswordPin": "簡易代碼錯誤或已過期,請再試一次。", "OptionAllowVideoPlaybackTranscoding": "允許播放需要轉檔的影片", "Small": "小", "Smaller": "更小", - "XmlTvKidsCategoriesHelp": "有這些類別的節目會被當作兒童節目。用「|」分隔多個。", + "XmlTvKidsCategoriesHelp": "有這些類別的節目會被當作兒童節目,以「|」來分隔多個項目。", "TabResponses": "響應", "LabelDisplaySpecialsWithinSeasons": "顯示劇集季度中的特集", "LabelNumberOfGuideDaysHelp": "下載更多電視指南資料會提供更好時間表查看能力,但將需要更長的下載時間。自動基於頻道數目來選擇。", @@ -1625,5 +1622,61 @@ "PlaceFavoriteChannelsAtBeginning": "將喜愛的頻道置頂", "PlaybackData": "恢復播放資料", "OptionRandom": "隨機", - "HeaderFavoritePeople": "最愛人物" + "HeaderFavoritePeople": "最愛人物", + "XmlDocumentAttributeListHelp": "這些屬性會在每一個XML回應的根元素上應用。", + "SkipEpisodesAlreadyInMyLibraryHelp": "劇集將使用季和劇集編號進行比較。", + "SelectAdminUsername": "請為管理員賬戶選擇一個用戶名。", + "CopyStreamURLError": "複製網址的時候發生錯誤.", + "OptionSaveMetadataAsHiddenHelp": "更改此項將應用於以後保存的元數據。現有元數據文件將在下一次 Jellyfin 伺服器保存它們時被更新。", + "OptionAllowRemoteSharedDevicesHelp": "DLNA裝置將被視為共享中,直至有使用者控制。", + "OptionForceRemoteSourceTranscoding": "强制遠端轉碼(像電視直播一樣)", + "MessageConfirmAppExit": "您要退出嗎?", + "LaunchWebAppOnStartupHelp": "伺服器啓動時在默認游覽器中打開網頁端。使用重啓伺服器功能時此項不生效。", + "LabelVideoResolution": "視頻解析度:", + "LabelStreamType": "串流類型:", + "EnableFastImageFadeInHelp": "對已載入的圖片啟用更快的淡入動畫", + "EnableFastImageFadeIn": "圖片快速淡入效果", + "LabelPlayerDimensions": "播放器尺寸:", + "LabelDroppedFrames": "丟棄的幀:", + "LabelCorruptedFrames": "損壞的幀:", + "ButtonSplit": "分割", + "AskAdminToCreateLibrary": "如要建立資料庫,請求管理員。", + "NoCreatedLibraries": "看來您還未創任何媒體庫。{0}立刻創一個新的嗎?{1}", + "ClientSettings": "用戶設定", + "AllowFfmpegThrottlingHelp": "當轉檔或重組進度大量超前目前播放進度時,將暫停轉檔節省消耗的資源。在不常跳播的時候最有效。如果遇到播放問題,請關閉此功能。", + "AllowFfmpegThrottling": "限制轉檔", + "PreferEmbeddedEpisodeInfosOverFileNamesHelp": "這將會使用內建劇集資料。", + "PlaybackErrorNoCompatibleStream": "用戶端與該媒體不相容,伺服器也未傳送相容的媒體格式。", + "PreferEmbeddedEpisodeInfosOverFileNames": "優先使用內建劇集資訊而不是檔案名稱", + "OtherArtist": "其他歌手", + "Artist": "歌手", + "AlbumArtist": "專輯歌手", + "Album": "專輯", + "YadifBob": "YADIF Bob", + "WriteAccessRequired": "Jellyfin 伺服器需要此資料夾的寫入權限,請確認是否擁有寫入權限並重試。", + "PathNotFound": "無法找到此路徑,請確認路徑可用並重試。", + "Track": "音軌", + "Yadif": "YADIF", + "ListPaging": "{2} 的 {0}-{1}", + "PersonRole": "作為 {0}", + "LastSeen": "上次觀看 {0}", + "DailyAt": "每日的 {0}", + "WeeklyAt": "每週第 {0} 天的 {1}", + "OnWakeFromSleep": "當從睡眠中喚醒時", + "EveryXMinutes": "每 {0} 分鐘", + "EveryHour": "每小時", + "EveryXHours": "每 {0} 小時", + "OnApplicationStartup": "當應用程式啟動時", + "Season": "季", + "ReleaseGroup": "發行組織", + "Person": "人物", + "Movie": "電影", + "LabelLibraryPageSizeHelp": "設置媒體庫頁面每頁要顯示的最多媒體個數。設置為 0 來停用分頁。", + "LabelLibraryPageSize": "媒體庫分頁大小:", + "LabelDeinterlaceMethod": "反交錯方法:", + "Episode": "劇集", + "DeinterlaceMethodHelp": "選擇對隔行掃描內容進行轉碼時所用的反交錯方法。", + "BoxSet": "套裝", + "UnsupportedPlayback": "Jellyfin 無法解密受 DRM 保護的內容,但仍然會嘗試播放所有內容。某些檔案由於被加密或包含如互動標題等不受支援的內容,在播放時可能會沒有畫面。", + "MessageUnauthorizedUser": "您目前無權存取伺服器,請與您的伺服器管理員聯繫以獲取更多訊息。" } diff --git a/src/themes/appletv/theme.css b/src/themes/appletv/theme.css index acc7ef8210..760038ad72 100644 --- a/src/themes/appletv/theme.css +++ b/src/themes/appletv/theme.css @@ -1,60 +1,70 @@ .skinHeader, html { color: #222; - color: rgba(0, 0, 0, .87) + color: rgba(0, 0, 0, 0.87); } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #303030 + background-color: #303030; } .emby-collapsible-button { border-color: #ccc; - border-color: rgba(0, 0, 0, .158) + border-color: rgba(0, 0, 0, 0.158); } .collapseContent { - background-color: #eaeaea + background-color: #eaeaea; } .formDialogHeader:not(.formDialogHeader-clear), .skinHeader-withBackground { - color: rgba(0, 0, 0, .7); + color: rgba(0, 0, 0, 0.7); background: #303030; - background: linear-gradient(to right, #BCBCBC, #A7B4B7, #BEB5A5, #ADBEC2, #B9C7CB) + background: -webkit-gradient(linear, left top, right top, from(#bcbcbc), color-stop(#a7b4b7), color-stop(#beb5a5), color-stop(#adbec2), to(#b9c7cb)); + background: -webkit-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: -o-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); } .skinHeader.semiTransparent { - backdrop-filter: none !important + -webkit-backdrop-filter: none !important; + backdrop-filter: none !important; } .pageTitleWithDefaultLogo { - background-image: url(../logodark.png) + background-image: url(../../assets/img/banner-dark.png); } html { - background: #D5E9F2 + background: #d5e9f2; } .backgroundContainer, -.dialog { - background: #D5E9F2; - background-size: 100% 100% +.dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu { + background: #d5e9f2; + -webkit-background-size: 100% 100%; + background-size: 100% 100%; } .backgroundContainer.withBackdrop { - background: linear-gradient(to bottom, rgba(192, 212, 222, .94), rgba(235, 250, 254, .94), rgba(227, 220, 212, .94), rgba(206, 214, 216, .94), rgba(192, 211, 218, .94)) + background: -webkit-gradient(linear, left top, left bottom, from(rgba(192, 212, 222, 0.94)), color-stop(rgba(235, 250, 254, 0.94)), color-stop(rgba(227, 220, 212, 0.94)), color-stop(rgba(206, 214, 216, 0.94)), to(rgba(192, 211, 218, 0.94))); + background: -webkit-linear-gradient(top, rgba(192, 212, 222, 0.94), rgba(235, 250, 254, 0.94), rgba(227, 220, 212, 0.94), rgba(206, 214, 216, 0.94), rgba(192, 211, 218, 0.94)); + background: -o-linear-gradient(top, rgba(192, 212, 222, 0.94), rgba(235, 250, 254, 0.94), rgba(227, 220, 212, 0.94), rgba(206, 214, 216, 0.94), rgba(192, 211, 218, 0.94)); + background: linear-gradient(to bottom, rgba(192, 212, 222, 0.94), rgba(235, 250, 254, 0.94), rgba(227, 220, 212, 0.94), rgba(206, 214, 216, 0.94), rgba(192, 211, 218, 0.94)); } .actionSheet { - background: #f0f0f0 + background: #f0f0f0; } .paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -64,31 +74,31 @@ html { .fab, .raised { background: #fff; - background: rgba(0, 0, 0, .14); - color: inherit + background: rgba(0, 0, 0, 0.14); + color: inherit; } .fab:focus, .raised:focus { - background: rgba(0, 0, 0, .24) + background: rgba(0, 0, 0, 0.24); } .button-submit { background: #00a4dc; - color: #fff + color: #fff; } .button-submit:focus { - background: #0cb0e8 + background: #0cb0e8; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .checkboxLabel { - color: inherit + color: inherit; } .checkboxListLabel, @@ -97,49 +107,49 @@ html { .paperListLabel, .textareaLabelUnfocused { color: #555; - color: rgba(0, 0, 0, .7) + color: rgba(0, 0, 0, 0.7); } .button-link, .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: green + color: #00a4dc; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .paperList, .visualCardBox { background-color: #fff; - background-color: rgba(0, 0, 0, .1) + background-color: rgba(0, 0, 0, 0.1); } .defaultCardBackground1 { - background-color: #009688 + background-color: #009688; } .defaultCardBackground2 { - background-color: #D32F2F + background-color: #d32f2f; } .defaultCardBackground3 { - background-color: #0288D1 + background-color: #0288d1; } .defaultCardBackground4 { - background-color: #388E3C + background-color: #388e3c; } .defaultCardBackground5 { - background-color: #F57F17 + background-color: #f57f17; } .formDialogFooter:not(.formDialogFooter-clear) { border-top: 1px solid #ddd; - border-top: 1px solid rgba(0, 0, 0, .08) + border-top: 1px solid rgba(0, 0, 0, 0.08); } .cardText-secondary, @@ -150,173 +160,186 @@ html { .programSecondaryTitle, .secondaryText { color: #888; - color: rgba(0, 0, 0, .5) + color: rgba(0, 0, 0, 0.5); } .actionsheetDivider { background: #ddd; - background: rgba(0, 0, 0, .14) + background: rgba(0, 0, 0, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .formDialogHeader a, .toast { - color: #fff + color: #fff; } .actionSheetMenuItem:hover { - background-color: #ddd + background-color: #ddd; } .toast { background: #303030; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .appfooter, -.formDialogFooter:not(.formDialogFooter-clear) { - color: rgba(0, 0, 0, .7); +.formDialogFooter:not(.formDialogFooter-clear), +.playlistSectionButton { + color: rgba(0, 0, 0, 0.7); background: #303030; - background: linear-gradient(to right, #BCBCBC, #A7B4B7, #BEB5A5, #ADBEC2, #B9C7CB) + background: -webkit-gradient(linear, left top, right top, from(#bcbcbc), color-stop(#a7b4b7), color-stop(#beb5a5), color-stop(#adbec2), to(#b9c7cb)); + background: -webkit-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: -o-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); } .nowPlayingBarSecondaryText { - color: #999 + color: #999; } .itemSelectionPanel { - border: 1px solid #00a4dc + border: 1px solid #00a4dc; } .selectionCommandsPanel { background: #00a4dc; - color: #fff + color: #fff; } .upNextDialog-countdownText { - color: #00a4dc + color: #00a4dc; } .alphaPickerButton { color: #555; - color: rgba(0, 0, 0, .7); - background-color: transparent + color: rgba(0, 0, 0, 0.7); + background-color: transparent; } .alphaPickerButton-selected, .alphaPickerButton-tv:focus { background-color: #00a4dc; - color: #fff !important + color: #fff !important; +} + +.detailSticky { + background: #303030; + background: -webkit-gradient(linear, left top, right top, from(#bcbcbc), color-stop(#a7b4b7), color-stop(#beb5a5), color-stop(#adbec2), to(#b9c7cb)); + background: -webkit-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: -o-linear-gradient(left, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); + background: linear-gradient(to right, #bcbcbc, #a7b4b7, #beb5a5, #adbec2, #b9c7cb); } .detailTableBodyRow-shaded:nth-child(even) { background: #f8f8f8; - background: rgba(0, 0, 0, .1) + background: rgba(0, 0, 0, 0.1); } .listItem-border { - border-color: rgba(0, 0, 0, .1) !important + border-color: rgba(0, 0, 0, 0.1) !important; } .listItem:focus { - background: rgba(0, 0, 0, .2) + background: rgba(0, 0, 0, 0.2); } .progressring-spiner { - border-color: #00a4dc + border-color: #00a4dc; } .mediaInfoText { color: #333; - background: #fff + background: #fff; } .mediaInfoTimerIcon, .starIcon { - color: #CB272A + color: #cb272a; } .emby-input, .emby-textarea { color: inherit; - background: rgba(255, 255, 255, .9); - border: .07em solid rgba(0, 0, 0, .158); - border-radius: .15em + background: rgba(255, 255, 255, 0.9); + border: 0.16em solid rgba(0, 0, 0, 0.158); + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #00a4dc + border-color: #00a4dc; } .emby-select-withcolor { color: inherit; - background: rgba(255, 255, 255, .9); - border: .07em solid rgba(0, 0, 0, .158) + background: rgba(255, 255, 255, 0.9); + border: 0.07em solid rgba(0, 0, 0, 0.158); } -.emby-checkbox:checked+span+.checkboxOutline, +.emby-checkbox:checked + span + .checkboxOutline, .emby-select-withcolor:focus { - border-color: #00a4dc -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #fff; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { border-color: #00a4dc; } -.emby-select-withcolor>option { +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #fff; +} + +.emby-checkbox:checked + span + .checkboxOutline, +.itemProgressBarForeground { + background-color: #00a4dc; +} + +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border-color: #00a4dc; +} + +.emby-select-withcolor > option { color: #000; - background: #fff + background: #fff; } .emby-select-tv-withcolor:focus { background-color: #00a4dc; - color: #fff -} - -.emby-checkbox:checked+span+.checkboxOutline, -.itemProgressBarForeground { - background-color: #00a4dc + color: #fff; } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, .fullSyncIndicator, .playedIndicator { - background: #00a4dc + background: #00a4dc; } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { - background: #fff + background: #fff; } .navMenuOption:hover { - background: #f2f2f2 + background: #f2f2f2; } .navMenuOption-selected { background: #00a4dc !important; - color: #fff + color: #fff; } .emby-button.show-focus:focus { background: #00a4dc; - color: #fff + color: #fff; } .emby-tab-button { @@ -339,88 +362,89 @@ html { .guide-channelHeaderCell, .programCell { border-color: #555; - border-color: rgba(0, 0, 0, .1) + border-color: rgba(0, 0, 0, 0.1); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: rgba(0, 0, 0, .1) !important + background: rgba(0, 0, 0, 0.1) !important; } .guide-channelHeaderCell:focus, .programCell:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(0, 0, 0, .54) + color: rgba(0, 0, 0, 0.54); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #00a4dc + color: #00a4dc; } .guide-date-tab-button.show-focus:focus { background-color: #00a4dc; - color: #fff + color: #fff; } .infoBanner { color: #000; background: #fff3a5; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 + color: #4285f4; } .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #00a4dc !important + border-color: #00a4dc !important; } .metadataSidebarIcon { - color: #00a4dc + color: #00a4dc; } diff --git a/src/themes/blueradiance/theme.css b/src/themes/blueradiance/theme.css index cd1999702e..3e86782f37 100644 --- a/src/themes/blueradiance/theme.css +++ b/src/themes/blueradiance/theme.css @@ -1,58 +1,72 @@ +* { + scrollbar-color: #3b3b3b #202020; +} + .skinHeader, html { color: #ddd; - color: rgba(255, 255, 255, .8) + color: rgba(255, 255, 255, 0.8); } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #303030 + background-color: #303030; } .emby-collapsible-button { border-color: #383838; - border-color: rgba(255, 255, 255, .135) + border-color: rgba(255, 255, 255, 0.135); } .skinHeader-withBackground { background: #303030; - background: linear-gradient(to right, #291A31, #033664, #011432, #141A3A, #291A31) + background: -webkit-gradient(linear, left top, right top, from(#291a31), color-stop(#033664), color-stop(#011432), color-stop(#141a3a), to(#291a31)); + background: -webkit-linear-gradient(left, #291a31, #033664, #011432, #141a3a, #291a31); + background: -o-linear-gradient(left, #291a31, #033664, #011432, #141a3a, #291a31); + background: linear-gradient(to right, #291a31, #033664, #011432, #141a3a, #291a31); } .skinHeader.semiTransparent { + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; - background-color: rgba(0, 0, 0, .3); - background: linear-gradient(rgba(0, 0, 0, .6), rgba(0, 0, 0, 0)) + background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.6)), to(rgba(0, 0, 0, 0))); + background: -webkit-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: -o-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background-color: rgba(0, 0, 0, 0.3); } .pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) + background-image: url(../../assets/img/banner-light.png); } .dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu, html { - background-color: #033361 + background-color: #033361; } .backgroundContainer { background: url(bg.jpg) center top no-repeat #033361; - background-size: cover + -webkit-background-size: cover; + background-size: cover; } .backgroundContainer.withBackdrop { - opacity: .86 + opacity: 0.86; } -@media (orientation:portrait) { +@media (orientation: portrait) { .backgroundContainer { - background-position: 30% top + background-position: 30% top; } } .paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -61,32 +75,32 @@ html { .fab, .raised { - background: rgba(0, 0, 0, .5); - color: rgba(255, 255, 255, .87) + background: rgba(0, 0, 0, 0.5); + color: rgba(255, 255, 255, 0.87); } .fab:focus, .raised:focus { - background: rgba(0, 0, 0, .7) + background: rgba(0, 0, 0, 0.7); } .button-submit { background: #00a4dc; - color: #fff + color: #fff; } .button-submit:focus { background: #0cb0e8; - color: #fff + color: #fff; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .checkboxLabel { - color: inherit + color: inherit; } .checkboxListLabel, @@ -95,17 +109,17 @@ html { .paperListLabel, .textareaLabelUnfocused { color: #bbb; - color: rgba(255, 255, 255, .7) + color: rgba(255, 255, 255, 0.7); } .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: #00a4dc + color: #00a4dc; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .collapseContent, @@ -113,27 +127,27 @@ html { .formDialogHeader:not(.formDialogHeader-clear), .paperList, .visualCardBox { - background-color: rgba(0, 0, 0, .5) + background-color: rgba(0, 0, 0, 0.5); } .defaultCardBackground1 { - background-color: #d2b019 + background-color: #d2b019; } .defaultCardBackground2 { - background-color: #338abb + background-color: #338abb; } .defaultCardBackground3 { - background-color: #6b689d + background-color: #6b689d; } .defaultCardBackground4 { - background-color: #dd452b + background-color: #dd452b; } .defaultCardBackground5 { - background-color: #5ccea9 + background-color: #5ccea9; } .cardText-secondary, @@ -144,186 +158,199 @@ html { .programSecondaryTitle, .secondaryText { color: #999; - color: rgba(255, 255, 255, .5) + color: rgba(255, 255, 255, 0.5); } .actionsheetDivider { background: #444; - background: rgba(255, 255, 255, .14) + background: rgba(255, 255, 255, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .actionSheetMenuItem:hover { - background-color: rgba(0, 0, 0, .5) + background-color: rgba(0, 0, 0, 0.5); } .toast { background: #303030; color: #fff; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } -.appfooter { +.appfooter, +.playlistSectionButton { background: #033664; color: #ccc; - color: rgba(255, 255, 255, .78) + color: rgba(255, 255, 255, 0.78); } -@supports (backdrop-filter:blur(10px)) { - .appfooter-blurred { - background: rgba(1, 2, 50, .7); - backdrop-filter: blur(20px) +@supports (backdrop-filter:blur(10px)) or (-webkit-backdrop-filter:blur(10px)) { + .appfooter { + background: rgba(1, 2, 50, 0.7); + backdrop-filter: blur(20px); } } .itemSelectionPanel { - border: 1px solid #00a4dc + border: 1px solid #00a4dc; } .selectionCommandsPanel { background: #00a4dc; - color: #fff + color: #fff; } .upNextDialog-countdownText { - color: #00a4dc + color: #00a4dc; } .alphaPickerButton { color: #999; - color: rgba(255, 255, 255, .5); - background-color: transparent + color: rgba(255, 255, 255, 0.5); + background-color: transparent; } .alphaPickerButton-selected { - color: #fff + color: #fff; } .alphaPickerButton-tv:focus { background-color: #00a4dc; - color: #fff !important + color: #fff !important; +} + +.detailSticky { + background: #303030; + background: -webkit-gradient(linear, left top, right top, from(#291a31), color-stop(#033664), color-stop(#011432), color-stop(#141a3a), to(#291a31)); + background: -webkit-linear-gradient(left, #291a31, #033664, #011432, #141a3a, #291a31); + background: -o-linear-gradient(left, #291a31, #033664, #011432, #141a3a, #291a31); + background: linear-gradient(to right, #291a31, #033664, #011432, #141a3a, #291a31); } .detailTableBodyRow-shaded:nth-child(even) { background: #1c1c1c; - background: rgba(30, 30, 30, .9) + background: rgba(30, 30, 30, 0.9); } .listItem-border { - border-color: rgba(255, 255, 255, .1) !important + border-color: rgba(255, 255, 255, 0.1) !important; } .listItem:focus { - background: rgba(0, 0, 0, .3) + background: rgba(0, 0, 0, 0.3); } .progressring-spiner { - border-color: #00a4dc + border-color: #00a4dc; +} + +.button-flat:hover { + color: #00a4dc; } -.button-flat-accent, .button-link { - color: #00a4dc + color: #00a4dc; } .mediaInfoText { color: #ddd; - background: rgba(170, 170, 190, .2) + background: rgba(170, 170, 190, 0.2); } .mediaInfoTimerIcon, .starIcon { - color: #CB272A + color: #cb272a; } .emby-input, .emby-textarea { color: inherit; - background: rgba(0, 0, 0, .5); - border: .07em solid transparent; - border-radius: .15em + background: rgba(0, 0, 0, 0.5); + border: 0.16em solid transparent; + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #00a4dc + border-color: #00a4dc; } .emby-select-withcolor { color: inherit; - background: rgba(0, 0, 0, .5); - border: .07em solid transparent + background: rgba(0, 0, 0, 0.5); + border: 0.07em solid transparent; } -.emby-select-withcolor>option { +.emby-select-withcolor > option { color: inherit; - background: #222 + background: #222; } .emby-select-withcolor:focus { - border-color: #00a4dc !important + border-color: #00a4dc !important; } .emby-select-tv-withcolor:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } -.emby-checkbox:checked+span+.checkboxOutline { - border-color: #00a4dc -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #fff; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { +.emby-checkbox:checked + span + .checkboxOutline { border-color: #00a4dc; } -.emby-checkbox:checked+span+.checkboxOutline, +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #fff; +} + +.emby-checkbox:checked + span + .checkboxOutline, .itemProgressBarForeground { - background-color: #00a4dc + background-color: #00a4dc; +} + +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border-color: #00a4dc; } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, .fullSyncIndicator, .playedIndicator { - background: #00a4dc + background: #00a4dc; } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { - background-color: rgba(0, 0, 0, .5) + background-color: rgba(0, 0, 0, 0.5); } .drawer-open { - background-color: #011432 + background-color: #011432; } .navMenuOption:hover { - background: rgba(221, 221, 221, 0.068) + background: rgba(221, 221, 221, 0.068); } .navMenuOption-selected { background: #00a4dc !important; - color: #fff + color: #fff; } .emby-button.show-focus:focus { background: #00a4dc; - color: #fff + color: #fff; } .emby-tab-button { @@ -331,7 +358,7 @@ html { } .emby-tab-button-active { - color: #00a4dc + color: #00a4dc; } .emby-tab-button.show-focus:focus { @@ -345,111 +372,114 @@ html { .channelPrograms, .guide-channelHeaderCell, .programCell { - border-color: rgba(255, 255, 255, .05) + border-color: rgba(255, 255, 255, 0.05); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: rgba(0, 0, 0, .4) !important + background: rgba(0, 0, 0, 0.4) !important; } .guide-channelHeaderCell:focus, .programCell:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(255, 255, 255, .3) + color: rgba(255, 255, 255, 0.3); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #00a4dc + color: #00a4dc; } .guide-date-tab-button.show-focus:focus { background-color: #00a4dc; - color: #fff + color: #fff; } .infoBanner { color: #ddd; background: #111; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 + color: #4285f4; } .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #00a4dc !important + border-color: #00a4dc !important; +} + +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); +} + +::-webkit-scrollbar-track-piece { + background-color: #3b3b3b; } .layout-desktop ::-webkit-scrollbar { width: 1em; - height: 1em -} - -::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) -} - -::-webkit-scrollbar-track-piece { - background-color: #3b3b3b + height: 1em; } ::-webkit-scrollbar-thumb:horizontal, ::-webkit-scrollbar-thumb:vertical { border-radius: 2px; - background: center no-repeat #888 + -webkit-border-radius: 2px; + background: center no-repeat #888; } .timeslotHeaders-desktop::-webkit-scrollbar { - height: .7em + height: 0.7em; } .metadataSidebarIcon { - color: #00a4dc + color: #00a4dc; } diff --git a/src/themes/dark/theme.css b/src/themes/dark/theme.css index 1bcf3af28f..f9163d82f5 100644 --- a/src/themes/dark/theme.css +++ b/src/themes/dark/theme.css @@ -1,46 +1,54 @@ +* { + scrollbar-width: thin; + scrollbar-color: #3b3b3b #202020; +} + .skinHeader, html { color: #ddd; - color: rgba(255, 255, 255, .8) + color: rgba(255, 255, 255, 0.8); } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #101010 + background-color: #101010; } .emby-collapsible-button { border-color: #383838; - border-color: rgba(255, 255, 255, .135) + border-color: rgba(255, 255, 255, 0.135); } .skinHeader-withBackground { - background-color: #101010 + background-color: #202020; } .skinHeader.semiTransparent { + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background-color: rgba(0, 0, 0, 0.4); } .pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) + background-image: url(../../assets/img/banner-light.png); } .backgroundContainer, .dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu, html { - background-color: #101010 + background-color: #101010; } .backgroundContainer.withBackdrop { - background-color: rgba(0, 0, 0, .86) + background-color: rgba(0, 0, 0, 0.86); } .paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -50,31 +58,31 @@ html { .fab, .raised { background: #303030; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .fab:focus, .raised:focus { - background: #383838 + background: #383838; } .button-submit { background: #00a4dc; - color: #fff + color: #fff; } .button-submit:focus { background: #0cb0e8; - color: #fff + color: #fff; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .checkboxLabel { - color: inherit + color: inherit; } .checkboxListLabel, @@ -83,17 +91,17 @@ html { .paperListLabel, .textareaLabelUnfocused { color: #bbb; - color: rgba(255, 255, 255, .7) + color: rgba(255, 255, 255, 0.7); } .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: #00a4dc + color: #00a4dc; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .collapseContent, @@ -101,27 +109,27 @@ html { .formDialogHeader:not(.formDialogHeader-clear), .paperList, .visualCardBox { - background-color: #242424 + background-color: #242424; } .defaultCardBackground1 { - background-color: #d2b019 + background-color: #d2b019; } .defaultCardBackground2 { - background-color: #338abb + background-color: #338abb; } .defaultCardBackground3 { - background-color: #6b689d + background-color: #6b689d; } .defaultCardBackground4 { - background-color: #dd452b + background-color: #dd452b; } .defaultCardBackground5 { - background-color: #5ccea9 + background-color: #5ccea9; } .cardText-secondary, @@ -132,175 +140,188 @@ html { .programSecondaryTitle, .secondaryText { color: #999; - color: rgba(255, 255, 255, .5) + color: rgba(255, 255, 255, 0.5); } .actionsheetDivider { background: #444; - background: rgba(255, 255, 255, .14) + background: rgba(255, 255, 255, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .actionSheetMenuItem:hover { - background-color: #242424 + background-color: #242424; } .toast { background: #303030; color: #fff; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } -.appfooter { - background: #101010; +.appfooter, +.playlistSectionButton { + background: #202020; color: #ccc; - color: rgba(255, 255, 255, .78) + color: rgba(255, 255, 255, 0.78); } .itemSelectionPanel { - border: 1px solid #00a4dc + border: 1px solid #00a4dc; } .selectionCommandsPanel { background: #00a4dc; - color: #fff + color: #fff; } .upNextDialog-countdownText { - color: #00a4dc + color: #00a4dc; } .alphaPickerButton { color: #999; - color: rgba(255, 255, 255, .5); - background-color: transparent + color: rgba(255, 255, 255, 0.5); + background-color: transparent; } .alphaPickerButton-selected { - color: #fff + color: #fff; } .alphaPickerButton-tv:focus { background-color: #00a4dc; - color: #fff !important + color: #fff !important; } .detailTableBodyRow-shaded:nth-child(even) { background: #1c1c1c; - background: rgba(30, 30, 30, .9) + background: rgba(30, 30, 30, 0.9); +} + +.detailSticky { + background: rgba(32, 32, 32, 0.8); +} + +.noBackdrop .detailSticky { + background: #202020; } .listItem-border { - border-color: rgba(34, 34, 34, .9) !important + border-color: rgba(34, 34, 34, 0.9) !important; } .listItem:focus { - background: #333 + background: #333; } .progressring-spiner { - border-color: #00a4dc + border-color: #00a4dc; +} + +.button-flat:hover { + color: #00a4dc; } -.button-flat-accent, .button-link { - color: #00a4dc + color: #00a4dc; } .mediaInfoText { color: #ddd; - background: rgba(170, 170, 190, .2) + background: rgba(170, 170, 190, 0.2); } .mediaInfoTimerIcon, .starIcon { - color: #CB272A + color: #cb272a; } .emby-input, .emby-textarea { color: inherit; background: #292929; - border: .07em solid #292929; - border-radius: .15em + border: 0.16em solid #292929; + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #00a4dc + border-color: #00a4dc; } .emby-select-withcolor { color: inherit; background: #292929; - border: .07em solid #292929 + border: 0.07em solid #292929; } -.emby-select-withcolor>option { +.emby-select-withcolor > option { color: inherit; - background: #222 + background: #222; } .emby-select-withcolor:focus { - border-color: #00a4dc !important + border-color: #00a4dc !important; } .emby-select-tv-withcolor:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } -.emby-checkbox:checked+span+.checkboxOutline { - border-color: #00a4dc -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #fff; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { +.emby-checkbox:checked + span + .checkboxOutline { border-color: #00a4dc; } -.emby-checkbox:checked+span+.checkboxOutline, +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #fff; +} + +.emby-checkbox:checked + span + .checkboxOutline, .itemProgressBarForeground { - background-color: #00a4dc + background-color: #00a4dc; +} + +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border-color: #00a4dc; } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, .fullSyncIndicator, .playedIndicator { - background: #00a4dc + background: #00a4dc; } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { - background-color: #101010 + background-color: #101010; } .navMenuOption:hover { - background: #252528 + background: #252528; } .navMenuOption-selected { background: #00a4dc !important; - color: #fff + color: #fff; } .emby-button.show-focus:focus { background: #00a4dc; - color: #fff + color: #fff; } .emby-tab-button { @@ -322,111 +343,113 @@ html { .channelPrograms, .guide-channelHeaderCell, .programCell { - border-color: rgba(255, 255, 255, .05) + border-color: rgba(255, 255, 255, 0.05); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: #1e1e1e !important + background: #1e1e1e !important; } .guide-channelHeaderCell:focus, .programCell:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(255, 255, 255, .3) + color: rgba(255, 255, 255, 0.3); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #00a4dc + color: #00a4dc; } .guide-date-tab-button.show-focus:focus { background-color: #00a4dc; - color: #fff + color: #fff; } .infoBanner { color: #ddd; background: #111; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 + color: #4285f4; } .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #00a4dc !important -} - -.layout-desktop ::-webkit-scrollbar { - width: 1em; - height: 1em + border-color: #00a4dc !important; } ::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); } ::-webkit-scrollbar-track-piece { - background-color: #3b3b3b + background-color: #3b3b3b; +} + +.layout-desktop ::-webkit-scrollbar { + width: 0.4em; } ::-webkit-scrollbar-thumb:horizontal, ::-webkit-scrollbar-thumb:vertical { border-radius: 2px; - background: center no-repeat #888 + -webkit-border-radius: 2px; + background: center no-repeat #888; } .timeslotHeaders-desktop::-webkit-scrollbar { - height: .7em + height: 0.7em; } .metadataSidebarIcon { - color: #00a4dc + color: #00a4dc; } diff --git a/src/themes/emby/theme.css b/src/themes/emby/theme.css deleted file mode 100644 index 15c329ce7d..0000000000 --- a/src/themes/emby/theme.css +++ /dev/null @@ -1,432 +0,0 @@ -.skinHeader, -html { - color: #ddd; - color: rgba(255, 255, 255, .8) -} - -.wizardStartForm, -.ui-corner-all, -.ui-shadow { - background-color: #1f1f1f -} - -.emby-collapsible-button { - border-color: #383838; - border-color: rgba(255, 255, 255, .135) -} - -.skinHeader-withBackground { - background-color: #1f1f1f -} - -.skinHeader.semiTransparent { - backdrop-filter: none !important; - background-color: rgba(0, 0, 0, 0.4); -} - -.pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) -} - -.backgroundContainer, -.dialog, -html { - background-color: #1a1a1a -} - -.backgroundContainer.withBackdrop { - background-color: rgba(0, 0, 0, .86) -} - -.paper-icon-button-light:hover:not(:disabled) { - color: #52b54b; - background-color: rgba(82, 181, 75, .2); -} - -.paper-icon-button-light.show-focus:focus { - color: #52b54b; -} - -.fab, -.raised { - background: #303030; - color: rgba(255, 255, 255, .87) -} - -.fab:focus, -.raised:focus { - background: #383838 -} - -.button-submit { - background: #52b54b; - color: #fff -} - -.button-submit:focus { - background: #5EC157; - color: #fff -} - -.button-delete { - background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) -} - -.checkboxLabel { - color: inherit -} - -.checkboxListLabel, -.inputLabel, -.inputLabelUnfocused, -.paperListLabel, -.textareaLabelUnfocused { - color: #bbb; - color: rgba(255, 255, 255, .7) -} - -.inputLabelFocused, -.selectLabelFocused, -.textareaLabelFocused { - color: #52b54b -} - -.checkboxOutline { - border-color: currentColor -} - -.collapseContent, -.formDialogFooter:not(.formDialogFooter-clear), -.formDialogHeader:not(.formDialogHeader-clear), -.paperList, -.visualCardBox { - background-color: #242424 -} - -.defaultCardBackground1 { - background-color: #d2b019 -} - -.defaultCardBackground2 { - background-color: #338abb -} - -.defaultCardBackground3 { - background-color: #6b689d -} - -.defaultCardBackground4 { - background-color: #dd452b -} - -.defaultCardBackground5 { - background-color: #5ccea9 -} - -.cardText-secondary, -.fieldDescription, -.guide-programNameCaret, -.listItem .secondary, -.nowPlayingBarSecondaryText, -.programSecondaryTitle, -.secondaryText { - color: #999; - color: rgba(255, 255, 255, .5) -} - -.actionsheetDivider { - background: #444; - background: rgba(255, 255, 255, .14) -} - -.cardFooter-vibrant .cardText-secondary { - color: inherit; - opacity: .5 -} - -.actionSheetMenuItem:hover { - background-color: #242424 -} - -.toast { - background: #303030; - color: #fff; - color: rgba(255, 255, 255, .87) -} - -.appfooter { - background: #101010; - color: #ccc; - color: rgba(255, 255, 255, .78) -} - -.itemSelectionPanel { - border: 1px solid #52b54b -} - -.selectionCommandsPanel { - background: #52b54b; - color: #fff -} - -.upNextDialog-countdownText { - color: #52b54b -} - -.alphaPickerButton { - color: #999; - color: rgba(255, 255, 255, .5); - background-color: transparent -} - -.alphaPickerButton-selected { - color: #fff -} - -.alphaPickerButton-tv:focus { - background-color: #52b54b; - color: #fff !important -} - -.detailTableBodyRow-shaded:nth-child(even) { - background: #1c1c1c; - background: rgba(30, 30, 30, .9) -} - -.listItem-border { - border-color: rgba(34, 34, 34, .9) !important -} - -.listItem:focus { - background: #333 -} - -.progressring-spiner { - border-color: #52b54b -} - -.button-flat-accent, -.button-link { - color: #52b54b -} - -.mediaInfoText { - color: #ddd; - background: rgba(170, 170, 190, .2) -} - -.mediaInfoTimerIcon, -.starIcon { - color: #CB272A -} - -.emby-input, -.emby-textarea { - color: inherit; - background: #292929; - border: .07em solid #292929; - border-radius: .15em -} - -.emby-input:focus, -.emby-textarea:focus { - border-color: #52b54b -} - -.emby-select-withcolor { - color: inherit; - background: #292929; - border: .07em solid #292929 -} - -.emby-select-withcolor>option { - color: inherit; - background: #222 -} - -.emby-select-withcolor:focus { - border-color: #52b54b !important -} - -.emby-select-tv-withcolor:focus { - background-color: #52b54b !important; - color: #fff !important -} - -.emby-checkbox:checked+span+.checkboxOutline { - border-color: #52b54b -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #fff; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { - border-color: #52b54b; -} - -.emby-checkbox:checked+span+.checkboxOutline, -.itemProgressBarForeground { - background-color: #52b54b -} - -.itemProgressBarForeground-recording { - background-color: #CB272A -} - -.countIndicator, -.fullSyncIndicator, -.playedIndicator { - background: #52b54b -} - -.fullSyncIndicator { - color: #fff -} - -.mainDrawer { - background-color: #1c1c1c -} - -.navMenuOption:hover { - background: #252528 -} - -.navMenuOption-selected { - background: #52b54b !important; - color: #fff -} - -.emby-button.show-focus:focus { - background: #52b54b; - color: #fff -} - -.emby-tab-button { - color: #999; -} - -.emby-tab-button-active { - color: #52b54b; -} - -.emby-tab-button.show-focus:focus { - color: #52b54b; -} - -.emby-tab-button:hover { - color: #52b54b; -} - -.channelPrograms, -.guide-channelHeaderCell, -.programCell { - border-color: rgba(255, 255, 255, .05) -} - -.programCell-sports { - background: #3949AB !important -} - -.programCell-movie { - background: #5E35B1 !important -} - -.programCell-kids { - background: #039BE5 !important -} - -.programCell-news { - background: #43A047 !important -} - -.programCell-active { - background: #1e1e1e !important -} - -.guide-channelHeaderCell:focus, -.programCell:focus { - background-color: #52b54b !important; - color: #fff !important -} - -.guide-programTextIcon { - color: #1e1e1e; - background: #555 -} - -.guide-headerTimeslots { - color: inherit -} - -.guide-date-tab-button { - color: #555; - color: rgba(255, 255, 255, .3) -} - -.guide-date-tab-button.emby-tab-button-active, -.guide-date-tab-button:focus { - color: #52b54b -} - -.guide-date-tab-button.show-focus:focus { - background-color: #52b54b; - color: #fff -} - -.infoBanner { - color: #ddd; - background: #111; - padding: 1em; - border-radius: .25em -} - -.ratingbutton-icon-withrating { - color: #c33 -} - -.downloadbutton-icon-complete, -.downloadbutton-icon-on { - color: #4285F4 -} - -.playstatebutton-icon-played { - color: #c33 -} - -.repeatButton-active { - color: #4285F4 -} - -.card:focus .cardBox.visualCardBox, -.card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #52b54b !important -} - -.layout-desktop ::-webkit-scrollbar { - width: 1em; - height: 1em -} - -::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) -} - -::-webkit-scrollbar-track-piece { - background-color: #3b3b3b -} - -::-webkit-scrollbar-thumb:horizontal, -::-webkit-scrollbar-thumb:vertical { - border-radius: 2px; - background: center no-repeat #888 -} - -.timeslotHeaders-desktop::-webkit-scrollbar { - height: .7em -} - -.metadataSidebarIcon { - color: #00a4dc -} diff --git a/src/themes/light/theme.css b/src/themes/light/theme.css index 9f97054f34..114ef7c3b1 100644 --- a/src/themes/light/theme.css +++ b/src/themes/light/theme.css @@ -1,60 +1,65 @@ .skinHeader, html { color: #222; - color: rgba(0, 0, 0, .87) + color: rgba(0, 0, 0, 0.87); } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #303030 + background-color: #303030; } .emby-collapsible-button { border-color: #ccc; - border-color: rgba(0, 0, 0, .158) + border-color: rgba(0, 0, 0, 0.158); } .collapseContent { - background-color: #eaeaea + background-color: #eaeaea; } .skinHeader-withBackground { background-color: #303030; color: #ccc; - color: rgba(255, 255, 255, .87); - box-shadow: 0 .0725em .29em 0 rgba(0, 0, 0, .37) + color: rgba(255, 255, 255, 0.87); + -webkit-box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); + box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); } .osdHeader { - box-shadow: none !important + -webkit-box-shadow: none !important; + box-shadow: none !important; } .skinHeader.semiTransparent { + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; background-color: rgba(0, 0, 0, 0.4); } .pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) + background-image: url(../../assets/img/banner-light.png); } .backgroundContainer, html { - background-color: #f2f2f2 + background-color: #f2f2f2; } .backgroundContainer.withBackdrop { - background-color: rgba(255, 255, 255, .80) + background-color: rgba(255, 255, 255, 0.8); } -.dialog { - background-color: #f0f0f0 +.dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu { + background-color: #f0f0f0; } .paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -64,30 +69,30 @@ html { .fab, .raised { background: #d8d8d8; - color: inherit + color: inherit; } .fab:focus, .raised:focus { - background: #ccc + background: #ccc; } .button-submit { background: #00a4dc; - color: #fff + color: #fff; } .button-submit:focus { - background: #0cb0e8 + background: #0cb0e8; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .checkboxLabel { - color: inherit + color: inherit; } .checkboxListLabel, @@ -95,55 +100,55 @@ html { .inputLabelUnfocused, .paperListLabel, .textareaLabelUnfocused { - color: #555 + color: #555; } .button-link, .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: green + color: #00a4dc; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .paperList, .visualCardBox { - background-color: #fff + background-color: #fff; } .defaultCardBackground1 { - background-color: #009688 + background-color: #009688; } .defaultCardBackground2 { - background-color: #D32F2F + background-color: #d32f2f; } .defaultCardBackground3 { - background-color: #0288D1 + background-color: #0288d1; } .defaultCardBackground4 { - background-color: #388E3C + background-color: #388e3c; } .defaultCardBackground5 { - background-color: #F57F17 + background-color: #f57f17; } .formDialogHeader:not(.formDialogHeader-clear) { background-color: #00a4dc; - color: #fff + color: #fff; } .formDialogFooter:not(.formDialogFooter-clear) { background-color: #f0f0f0; border-top: 1px solid #ddd; - border-top: 1px solid rgba(0, 0, 0, .08); - color: inherit + border-top: 1px solid rgba(0, 0, 0, 0.08); + color: inherit; } .cardText-secondary, @@ -153,171 +158,181 @@ html { .nowPlayingBarSecondaryText, .programSecondaryTitle, .secondaryText { - color: #888 + color: #888; } .actionsheetDivider { background: #ddd; - background: rgba(0, 0, 0, .14) + background: rgba(0, 0, 0, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .formDialogHeader a, .toast { - color: #fff + color: #fff; } .actionSheetMenuItem:hover { - background-color: #ddd + background-color: #ddd; } .toast { background: #303030; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } -.appfooter { +.appfooter, +.playlistSectionButton { background: #282828; color: #ccc; - color: rgba(255, 255, 255, .78) + color: rgba(255, 255, 255, 0.78); } .nowPlayingBarSecondaryText { - color: #999 + color: #999; } .itemSelectionPanel { - border: 1px solid #00a4dc + border: 1px solid #00a4dc; } .selectionCommandsPanel { background: #00a4dc; - color: #fff + color: #fff; } .upNextDialog-countdownText { - color: #00a4dc + color: #00a4dc; } .alphaPickerButton { color: #555; - color: rgba(0, 0, 0, .7); - background-color: transparent + color: rgba(0, 0, 0, 0.7); + background-color: transparent; } .alphaPickerButton-selected, .alphaPickerButton-tv:focus { background-color: #00a4dc; - color: #fff !important + color: #fff !important; +} + +.detailSticky { + background-color: #303030; + color: #ccc; + color: rgba(255, 255, 255, 0.87); + -webkit-box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); + box-shadow: 0 0.0725em 0.29em 0 rgba(0, 0, 0, 0.37); } .detailTableBodyRow-shaded:nth-child(even) { - background: #f8f8f8 + background: #f8f8f8; } .listItem-border { - border-color: #f0f0f0 !important + border-color: #f0f0f0 !important; } .listItem:focus { - background: #ddd + background: #ddd; } .progressring-spiner { - border-color: #00a4dc + border-color: #00a4dc; } .mediaInfoText { color: #333; - background: #fff + background: #fff; } .mediaInfoTimerIcon, .starIcon { - color: #CB272A + color: #cb272a; } .emby-input, .emby-textarea { color: inherit; background: #fff; - border: .07em solid rgba(0, 0, 0, .158); - border-radius: .15em + border: 0.16em solid rgba(0, 0, 0, 0.158); + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #00a4dc + border-color: #00a4dc; } .emby-select-withcolor { color: inherit; background: #fff; - border: .07em solid rgba(0, 0, 0, .158) + border: 0.07em solid rgba(0, 0, 0, 0.158); } -.emby-checkbox:checked+span+.checkboxOutline, +.emby-checkbox:checked + span + .checkboxOutline, .emby-select-withcolor:focus { - border-color: #00a4dc -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #000; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { border-color: #00a4dc; } -.emby-select-withcolor>option { +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #000; +} + +.emby-checkbox:checked + span + .checkboxOutline, +.itemProgressBarForeground { + background-color: #00a4dc; +} + +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border-color: #00a4dc; +} + +.emby-select-withcolor > option { color: #000; - background: #fff + background: #fff; } .emby-select-tv-withcolor:focus { background-color: #00a4dc; - color: #fff -} - -.emby-checkbox:checked+span+.checkboxOutline, -.itemProgressBarForeground { - background-color: #00a4dc + color: #fff; } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, .fullSyncIndicator, .playedIndicator { - background: #00a4dc + background: #00a4dc; } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { - background: #fff + background: #fff; } .navMenuOption:hover { - background: #f2f2f2 + background: #f2f2f2; } .navMenuOption-selected { background: #00a4dc !important; - color: #fff + color: #fff; } .emby-button.show-focus:focus { background: #00a4dc; - color: #fff + color: #fff; } .emby-tab-button { @@ -339,88 +354,89 @@ html { .channelPrograms, .guide-channelHeaderCell, .programCell { - border-color: rgba(0, 0, 0, .12) + border-color: rgba(0, 0, 0, 0.12); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: rgba(0, 0, 0, .1) !important + background: rgba(0, 0, 0, 0.1) !important; } .guide-channelHeaderCell:focus, .programCell:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(0, 0, 0, .54) + color: rgba(0, 0, 0, 0.54); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #00a4dc + color: #00a4dc; } .guide-date-tab-button.show-focus:focus { background-color: #00a4dc; - color: #fff + color: #fff; } .infoBanner { color: #000; background: #fff3a5; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 + color: #4285f4; } .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #00a4dc !important + border-color: #00a4dc !important; } .metadataSidebarIcon { - color: #00a4dc + color: #00a4dc; } diff --git a/src/themes/logowhite.png b/src/themes/logowhite.png deleted file mode 100644 index 560d910d74..0000000000 Binary files a/src/themes/logowhite.png and /dev/null differ diff --git a/src/themes/purple-haze/bg.jpg b/src/themes/purplehaze/bg.jpg similarity index 100% rename from src/themes/purple-haze/bg.jpg rename to src/themes/purplehaze/bg.jpg diff --git a/src/themes/purple-haze/theme.css b/src/themes/purplehaze/theme.css similarity index 51% rename from src/themes/purple-haze/theme.css rename to src/themes/purplehaze/theme.css index fb871b59f5..82b774a736 100644 --- a/src/themes/purple-haze/theme.css +++ b/src/themes/purplehaze/theme.css @@ -1,58 +1,67 @@ .skinHeader, html { color: #f8f8fe; - color: rgba(248, 248, 254, 0.973) + color: rgba(248, 248, 254, 0.973); } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #303030 + background-color: #303030; } .emby-collapsible-button { border-color: #383838; - border-color: rgba(255, 255, 255, .135) + border-color: rgba(255, 255, 255, 0.135); } .skinHeader-withBackground { background: #000420; - background: linear-gradient(to right, #000420 0%,#06256f 18%,#2b052b 38%,#2b052b 68%,#06256f 81%,#000420 100%); + background: -moz-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); + background: -webkit-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); + background: linear-gradient(to right, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); } .skinHeader.semiTransparent { + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; - background-color: rgba(0, 0, 0, .3); - background: linear-gradient(rgba(0, 0, 0, .6), rgba(0, 0, 0, 0)) + background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.6)), to(rgba(0, 0, 0, 0))); + background: -webkit-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: -o-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background-color: rgba(0, 0, 0, 0.3); } .pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) + background-image: url(../../assets/img/banner-light.png); } .dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu, html { - background-color: #230c33 + background-color: #230c33; } .backgroundContainer { background: url(bg.jpg) center top no-repeat #030322; - background-size: cover + -webkit-background-size: cover; + background-size: cover; } .backgroundContainer.withBackdrop { - opacity: .86 + opacity: 0.86; } -@media (orientation:portrait) { +@media (orientation: portrait) { .backgroundContainer { - background-position: 30% top + background-position: 30% top; } } .paper-icon-button-light:hover:not(:disabled) { color: rgb(12, 232, 214); - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -60,35 +69,35 @@ html { } progress { - border-radius: .4em; + border-radius: 0.4em; } progress::-webkit-progress-bar { - border-radius: .4em; + border-radius: 0.4em; } progress::-moz-progress-bar { - border-radius: .4em; + border-radius: 0.4em; } progress::-webkit-progress-value { - border-radius: .4em; + border-radius: 0.4em; } .fab, .raised { - background: rgba(0, 0, 0, .5); - color: rgba(255, 255, 255, .87); + background: rgba(0, 0, 0, 0.5); + color: rgba(255, 255, 255, 0.87); } .fab:focus, .raised:focus { - background: #ff77f1 + background: #ff77f1; } div[data-role=controlgroup] a.ui-btn-active { background: #55828b !important; - color: #e1e5f2 !important + color: #e1e5f2 !important; } a[data-role=button] { @@ -106,7 +115,21 @@ a[data-role=button] { .button-alt, .btnOption { background: rgb(72, 195, 200); - color: rgb(225, 229, 242) + color: rgb(225, 229, 242); +} + +#btnResetPassword, +.btnForgotPassword, +.btnCancel, +.button-cancel { + background: rgba(0, 0, 0, 0.5); + color: rgba(255, 255, 255, 0.87); +} + +.alphaPickerButton { + color: #999; + color: rgba(255, 255, 255, 0.5); + background-color: transparent; } #btnResetPassword:hover, @@ -128,39 +151,31 @@ a[data-role=button] { .btnManual:hover, .block:hover { background: rgb(12, 232, 214); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .button-submit:focus { - background: #ff77f1 + background: #ff77f1; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) -} - -#btnResetPassword, -.btnForgotPassword, -.btnCancel, -.button-cancel { - background: rgba(0, 0, 0, .5); - color: rgba(255, 255, 255, .87); + color: rgba(255, 255, 255, 0.87); } .itemName { - color: #f1f7ee + color: #f1f7ee; } .textareaLabel, .sectionTitle, .fieldDescription, .checkboxLabel { - color: #f1f7ee + color: #f1f7ee; } .checkboxLabel { - color: inherit + color: inherit; } .selectLabel, @@ -176,15 +191,15 @@ a[data-role=button] { .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: #ff77f1 + color: #ff77f1; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .cardContent { - border-radius: 1.000em + border-radius: 1em; } .collapseContent, @@ -192,36 +207,37 @@ a[data-role=button] { .formDialogHeader:not(.formDialogHeader-clear), .paperList, .visualCardBox { - background-color: rgba(0, 0, 0, .5); - border-radius: 1.000em + background-color: rgba(0, 0, 0, 0.5); + border-radius: 1em; } .cardOverlayContainer { border-radius: 0.8em; } + .visualCardBox .cardOverlayContainer { - border-bottom-right-radius: 0em; - border-bottom-left-radius: 0em; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; } .defaultCardBackground1 { - background-color: #d2b019 + background-color: #d2b019; } .defaultCardBackground2 { - background-color: #338abb + background-color: #338abb; } .defaultCardBackground3 { - background-color: #6b689d + background-color: #6b689d; } .defaultCardBackground4 { - background-color: #dd452b + background-color: #dd452b; } .defaultCardBackground5 { - background-color: #5ccea9 + background-color: #5ccea9; } .cardText-secondary, @@ -232,150 +248,156 @@ a[data-role=button] { .programSecondaryTitle, .secondaryText { color: #999; - color: rgba(255, 255, 255, .5) + color: rgba(255, 255, 255, 0.5); } .actionsheetDivider { background: #444; - background: rgba(255, 255, 255, .14) + background: rgba(255, 255, 255, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .actionSheetMenuItem:hover { - background-color: rgba(0, 0, 0, .5) + background-color: rgba(0, 0, 0, 0.5); } .toast { background: #303030; color: #f8f8fe; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } -.appfooter { +.appfooter, +.playlistSectionButton { background: #06256f; color: #ccc; - color: rgba(255, 255, 255, .78) + color: rgba(255, 255, 255, 0.78); } -@supports (backdrop-filter:blur(10px)) { - .appfooter-blurred { - background: rgba(6, 37, 111, .7); - backdrop-filter: blur(20px) +@supports (backdrop-filter:blur(10px)) or (-webkit-backdrop-filter:blur(10px)) { + .appfooter { + background: rgba(6, 37, 111, 0.7); + backdrop-filter: blur(20px); } } .itemSelectionPanel { - border: 1px solid #48C3C8 + border: 1px solid #48c3c8; } .selectionCommandsPanel { - background: #48C3C8; - color: #f8f8fe + background: #48c3c8; + color: #f8f8fe; } .upNextDialog-countdownText { - color: #48C3C8 -} - -.alphaPickerButton { - color: #999; - color: rgba(255, 255, 255, .5); - background-color: transparent + color: #48c3c8; } .alphaPickerButton-selected { - color: #0ce8d6 + color: #0ce8d6; } .alphaPickerButton-tv:focus { background: #ff77f1; - color: #f8f8fe !important + color: #f8f8fe !important; +} + +.detailSticky { + background: #000420; + background: -moz-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); + background: -webkit-linear-gradient(left, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); + background: linear-gradient(to right, #000420 0%, #06256f 18%, #2b052b 38%, #2b052b 68%, #06256f 81%, #000420 100%); } .detailTableBodyRow-shaded:nth-child(even) { background: #1c1c1c; - background: rgba(30, 30, 30, .9) + background: rgba(30, 30, 30, 0.9); } .listItem-border { - border-color: rgba(255, 255, 255, .1) !important + border-color: rgba(255, 255, 255, 0.1) !important; } .listItem:focus { - background: rgba(0, 0, 0, .3) + background: rgba(0, 0, 0, 0.3); } .progressring-spiner { - border-color: #48C3C8 + border-color: #48c3c8; +} + +.button-flat:hover { + color: #48c3c8; } -.button-flat-accent, .button-link { - color: #48C3C8 + color: #48c3c8; } .mediaInfoText { color: #f8f8fe; - background: rgba(170, 170, 190, .2) + background: rgba(170, 170, 190, 0.2); } .mediaInfoTimerIcon, .starIcon { - color: #f2b01e + color: #f2b01e; } .emby-input, .emby-textarea { color: inherit; - background: rgba(0, 0, 0, .5); - border: .07em solid transparent; - border-radius: .15em + background: rgba(0, 0, 0, 0.5); + border: 0.16em solid transparent; + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #ff77f1 + border-color: #ff77f1; } .emby-select-withcolor { color: inherit; - background: rgba(0, 0, 0, .5); - border: .07em solid transparent + background: rgba(0, 0, 0, 0.5); + border: 0.07em solid transparent; } -.emby-select-withcolor>option { +.emby-select-withcolor > option { color: inherit; - background: #030322d7 + background: #030322d7; } .emby-select-withcolor:focus { - border-color: #ff77f1 !important + border-color: #ff77f1 !important; } .emby-select-tv-withcolor:focus { background-color: #ff77f1 !important; - color: #fff !important + color: #fff !important; } -.emby-checkbox:checked+span+.checkboxOutline { +.emby-checkbox:checked + span + .checkboxOutline { background-color: #030322; - border:2px solid rgb(72, 195, 200); + border: 0.14em solid rgb(72, 195, 200); } .emby-checkbox:checked + span + .checkboxOutline > .checkboxIcon-checked { color: rgb(12, 232, 214); } -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { - border:2px solid #ff77f1; +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #ff77f1; } -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #ff77f1; +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border: 0.14em solid #ff77f1; } .itemProgressBarForeground { @@ -383,7 +405,7 @@ a[data-role=button] { } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, @@ -393,30 +415,39 @@ a[data-role=button] { } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { color: #f8f8fe; - background: rgba(0, 0, 0, .5) + background: rgba(0, 0, 0, 0.5); } .drawer-open { - background-color: #030322 + background-color: #030322; } .navMenuOption:hover { - background: rgba(221, 221, 221, 0.068) + background: rgba(221, 221, 221, 0.068); } .navMenuOption-selected { background: #6f0765 !important; - color: #f8f8fe + color: #f8f8fe; } .emby-button.show-focus:focus { background: #8ae9c1; - color: #f8f8fe + color: #f8f8fe; +} + +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__outer-circle, +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles svg .mdl-radio__inner-circle { + color: #ff77f1; +} + +.mdl-radio.show-focus .mdl-radio__button:focus + .mdl-radio__circles .mdl-radio__focus-circle { + background: #00a4dc; } .emby-tab-button { @@ -438,129 +469,82 @@ a[data-role=button] { .channelPrograms, .guide-channelHeaderCell, .programCell { - border-color: rgba(255, 255, 255, .05) + border-color: rgba(255, 255, 255, 0.05); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: rgba(0, 0, 0, .4) !important + background: rgba(0, 0, 0, 0.4) !important; } .guide-channelHeaderCell:focus, .programCell:focus { - background-color: #48C3C8 !important; - color: #fff !important + background-color: #48c3c8 !important; + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(255, 255, 255, .3) + color: rgba(255, 255, 255, 0.3); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #ff77f1 + color: #ff77f1; } .guide-date-tab-button.show-focus:focus { - background-color: #48C3C8; - color: #fff + background-color: #48c3c8; + color: #fff; } .infoBanner { color: #0e0f2d; background: #dbe6ff; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 -} - -.card:focus .cardBox.visualCardBox, -.card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #ff77f1 !important -} - -.layout-desktop, -.scrollY { - scrollbar-width: thin; - scrollbar-color: #888 rgba(59, 59, 59, 0.5) -} - -.layout-desktop ::-webkit-scrollbar { - width: .4em; - height: 1em -} - -::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) -} - -::-webkit-scrollbar-track-piece { - background-color: rgba(59, 59, 59, 0.5) -} - -::-webkit-scrollbar-thumb:horizontal, -::-webkit-scrollbar-thumb:vertical { - border-radius: 2px; - background: center no-repeat #888 -} - -.timeslotHeaders-desktop::-webkit-scrollbar { - height: .7em -} - -.mediaInfoOfficialRating { - border: .09em solid #583fa0; - background-color: #dbe6ff; - color: #0e0f2d; -} - -.metadataSidebarIcon { - color: #dbe6ff -} - -.personCard .overflowPortraitCard { - width: 40vw; + color: #4285f4; } .personCard .cardScalable { @@ -568,17 +552,67 @@ a[data-role=button] { border: 1px solid rgb(255, 255, 255); } +.card:focus .cardBox.visualCardBox, +.card:focus .cardBox:not(.visualCardBox) .cardScalable { + border-color: #ff77f1 !important; +} + +.layout-desktop, +.scrollY { + scrollbar-width: thin; + scrollbar-color: #888 rgba(59, 59, 59, 0.5); +} + +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); +} + +::-webkit-scrollbar-track-piece { + background-color: rgba(59, 59, 59, 0.5); +} + +.layout-desktop ::-webkit-scrollbar { + width: 0.4em; + height: 1em; +} + +::-webkit-scrollbar-thumb:horizontal, +::-webkit-scrollbar-thumb:vertical { + border-radius: 2px; + -webkit-border-radius: 2px; + background: center no-repeat #888; +} + +.timeslotHeaders-desktop::-webkit-scrollbar { + height: 0.7em; +} + +.mediaInfoOfficialRating { + border: 0.09em solid #583fa0; + background-color: #dbe6ff; + color: #0e0f2d; +} + +.metadataSidebarIcon { + color: #dbe6ff; +} + +.personCard .overflowPortraitCard { + width: 40vw; +} + .personCard .cardPadder-overflowPortrait, .personCard .cardPadder-portrait { padding-bottom: 100%; contain: strict; } -.personCard .coveredImage { +.personCard .coveredImage { clip-path: circle(50% at 50% 50%); } -.personCard .cardOverlayContainer { +.personCard .cardOverlayContainer { clip-path: circle(50% at 50% 50%); } diff --git a/src/themes/wmc/theme.css b/src/themes/wmc/theme.css index 1f417b1706..e7d4c0371b 100644 --- a/src/themes/wmc/theme.css +++ b/src/themes/wmc/theme.css @@ -1,54 +1,70 @@ +* { + scrollbar-color: #3b3b3b #202020; +} + html { color: #eee; - color: rgba(255, 255, 255, .9); - background-color: #0F3562 + color: rgba(255, 255, 255, 0.9); + background-color: #0f3562; } .wizardStartForm, .ui-corner-all, .ui-shadow { - background-color: #0C2450 + background-color: #0c2450; } .emby-collapsible-button { border-color: #383838; - border-color: rgba(255, 255, 255, .135) + border-color: rgba(255, 255, 255, 0.135); } .skinHeader { color: #ccc; - color: rgba(255, 255, 255, .78) + color: rgba(255, 255, 255, 0.78); } .formDialogHeader:not(.formDialogHeader-clear), .skinHeader-withBackground { - background-color: #0C2450; - background: linear-gradient(to bottom, #0C2450, #081B3B) + background: -webkit-gradient(linear, left top, left bottom, from(#0c2450), to(#081b3b)); + background: -webkit-linear-gradient(top, #0c2450, #081b3b); + background: -o-linear-gradient(top, #0c2450, #081b3b); + background: linear-gradient(to bottom, #0c2450, #081b3b); + background-color: #0c2450; } .skinHeader.semiTransparent { + -webkit-backdrop-filter: none !important; backdrop-filter: none !important; - background-color: rgba(0, 0, 0, .3); - background: linear-gradient(rgba(0, 0, 0, .6), rgba(0, 0, 0, 0)) + background: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.6)), to(rgba(0, 0, 0, 0))); + background: -webkit-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: -o-linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background: linear-gradient(rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0)); + background-color: rgba(0, 0, 0, 0.3); } .pageTitleWithDefaultLogo { - background-image: url(../logowhite.png) + background-image: url(../../assets/img/banner-light.png); } .backgroundContainer, -.dialog { - background-color: #0F3562; - background: linear-gradient(to bottom, #0F3562, #1162A4, #03215F) +.dialog, +.nowPlayingPlaylist, +.nowPlayingContextMenu { + background: -webkit-gradient(linear, left top, left bottom, from(#0f3562), color-stop(#1162a4), to(#03215f)); + background: -webkit-linear-gradient(top, #0f3562, #1162a4, #03215f); + background: -o-linear-gradient(top, #0f3562, #1162a4, #03215f); + background: linear-gradient(to bottom, #0f3562, #1162a4, #03215f); + background-color: #0f3562; } .backgroundContainer.withBackdrop { - background: rgba(17, 98, 164, .9) + background: rgba(17, 98, 164, 0.9); } .paper-icon-button-light:hover:not(:disabled) { color: #00a4dc; - background-color: rgba(0,164,220, .2); + background-color: rgba(0, 164, 220, 0.2); } .paper-icon-button-light.show-focus:focus { @@ -58,31 +74,31 @@ html { .fab, .raised { background: #082845; - color: #fff + color: #fff; } .fab:focus, .raised:focus { - background: #143451 + background: #143451; } .button-submit { background: #00a4dc; - color: #fff + color: #fff; } .button-submit:focus { background: #0cb0e8; - color: #fff + color: #fff; } .button-delete { background: rgb(247, 0, 0); - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .checkboxLabel { - color: inherit + color: inherit; } .checkboxListLabel, @@ -91,43 +107,43 @@ html { .paperListLabel, .textareaLabelUnfocused { color: #bbb; - color: rgba(255, 255, 255, .7) + color: rgba(255, 255, 255, 0.7); } .inputLabelFocused, .selectLabelFocused, .textareaLabelFocused { - color: #00a4dc + color: #00a4dc; } .checkboxOutline { - border-color: currentColor + border-color: currentColor; } .collapseContent, .paperList, .visualCardBox { - background-color: #0F3562 + background-color: #0f3562; } .defaultCardBackground1 { - background-color: #d2b019 + background-color: #d2b019; } .defaultCardBackground2 { - background-color: #338abb + background-color: #338abb; } .defaultCardBackground3 { - background-color: #6b689d + background-color: #6b689d; } .defaultCardBackground4 { - background-color: #dd452b + background-color: #dd452b; } .defaultCardBackground5 { - background-color: #5ccea9 + background-color: #5ccea9; } .cardText-secondary, @@ -138,170 +154,182 @@ html { .programSecondaryTitle, .secondaryText { color: #999; - color: rgba(255, 255, 255, .5) + color: rgba(255, 255, 255, 0.5); } .actionsheetDivider { background: #ddd; - background: rgba(255, 255, 255, .14) + background: rgba(255, 255, 255, 0.14); } .cardFooter-vibrant .cardText-secondary { color: inherit; - opacity: .5 + opacity: 0.5; } .toast { - background: #081B3B; + background: #081b3b; color: #fff; - color: rgba(255, 255, 255, .87) + color: rgba(255, 255, 255, 0.87); } .appfooter, -.formDialogFooter:not(.formDialogFooter-clear) { - background: #0C2450; - background: linear-gradient(to top, #0C2450, #081B3B); - color: rgba(255, 255, 255, .78) +.formDialogFooter:not(.formDialogFooter-clear), +.playlistSectionButton { + background: #0c2450; + background: -webkit-gradient(linear, left bottom, left top, from(#0c2450), to(#081b3b)); + background: -webkit-linear-gradient(bottom, #0c2450, #081b3b); + background: -o-linear-gradient(bottom, #0c2450, #081b3b); + background: linear-gradient(to top, #0c2450, #081b3b); + color: rgba(255, 255, 255, 0.78); } .itemSelectionPanel { - border: 1px solid #00a4dc + border: 1px solid #00a4dc; } .selectionCommandsPanel { background: #00a4dc; - color: #fff + color: #fff; } .upNextDialog-countdownText { - color: #00a4dc + color: #00a4dc; } .alphaPickerButton { color: #999; - color: rgba(255, 255, 255, .5); - background-color: transparent + color: rgba(255, 255, 255, 0.5); + background-color: transparent; } .alphaPickerButton-selected, .alphaPickerButton-tv:focus { background-color: #00a4dc; - color: #fff !important + color: #fff !important; +} + +.detailSticky { + background-color: #081b3b; } .detailTableBodyRow-shaded:nth-child(even) { background: #1c1c1c; - background: rgba(0, 0, 0, .3) + background: rgba(0, 0, 0, 0.3); } .listItem-border { - border-color: rgba(0, 0, 0, .3) !important + border-color: rgba(0, 0, 0, 0.3) !important; } .listItem:focus { - background: #333 + background: #333; } .progressring-spiner { - border-color: #00a4dc + border-color: #00a4dc; +} + +.button-flat:hover { + color: #00a4dc; } -.button-flat-accent, .button-link { - color: #00a4dc + color: #00a4dc; } .mediaInfoText { color: #ddd; - background: rgba(170, 170, 190, .2) + background: rgba(170, 170, 190, 0.2); } .mediaInfoTimerIcon, .starIcon { - color: #CB272A + color: #cb272a; } .emby-input, .emby-textarea { color: inherit; - background: rgba(255, 255, 255, .2); - border: .07em solid rgba(255, 255, 255, .135); - border-radius: .15em + background: rgba(255, 255, 255, 0.2); + border: 0.16em solid rgba(255, 255, 255, 0.135); + -webkit-border-radius: 0.2em; + border-radius: 0.2em; } .emby-input:focus, .emby-textarea:focus { - border-color: #00a4dc + border-color: #00a4dc; } .emby-select-withcolor { color: inherit; - background: rgba(255, 255, 255, .2); - border: .07em solid rgba(255, 255, 255, .135) + background: rgba(255, 255, 255, 0.2); + border: 0.07em solid rgba(255, 255, 255, 0.135); } -.emby-checkbox:checked+span+.checkboxOutline, +.emby-checkbox:checked + span + .checkboxOutline, .emby-select-withcolor:focus { - border-color: #00a4dc -} - -.emby-checkbox:focus+span+.checkboxOutline { - border-color: #fff; -} - -.emby-checkbox:focus:not(:checked)+span+.checkboxOutline { border-color: #00a4dc; } -.emby-select-withcolor>option { +.emby-checkbox:focus + span + .checkboxOutline { + border-color: #fff; +} + +.emby-checkbox:checked + span + .checkboxOutline, +.itemProgressBarForeground { + background-color: #00a4dc; +} + +.emby-checkbox:focus:not(:checked) + span + .checkboxOutline { + border-color: #00a4dc; +} + +.emby-select-withcolor > option { color: #000; - background: #fff + background: #fff; } .emby-select-tv-withcolor:focus { background-color: #00a4dc; - color: #fff -} - -.emby-checkbox:checked+span+.checkboxOutline, -.itemProgressBarForeground { - background-color: #00a4dc + color: #fff; } .itemProgressBarForeground-recording { - background-color: #CB272A + background-color: #cb272a; } .countIndicator, .fullSyncIndicator, .playedIndicator { - background: #00a4dc + background: #00a4dc; } .fullSyncIndicator { - color: #fff + color: #fff; } .mainDrawer { - background-color: #0F3562; + background-color: #0f3562; color: #ccc; - color: rgba(255, 255, 255, .7) + color: rgba(255, 255, 255, 0.7); } .actionSheetMenuItem:hover, .navMenuOption:hover { background: #252528; - background: rgba(0, 0, 0, .2) + background: rgba(0, 0, 0, 0.2); } .navMenuOption-selected { background: #00a4dc !important; - color: #fff + color: #fff; } .emby-button.show-focus:focus { background: #00a4dc; - color: #fff + color: #fff; } .emby-tab-button { @@ -309,7 +337,7 @@ html { } .emby-tab-button-active { - color: #fff + color: #fff; } .emby-tab-button.show-focus:focus { @@ -324,107 +352,110 @@ html { .guide-channelHeaderCell, .programCell { border-color: #999; - border-color: rgba(255, 255, 255, .1) + border-color: rgba(255, 255, 255, 0.1); } .programCell-sports { - background: #3949AB !important + background: #3949ab !important; } .programCell-movie { - background: #5E35B1 !important + background: #5e35b1 !important; } .programCell-kids { - background: #039BE5 !important + background: #039be5 !important; } .programCell-news { - background: #43A047 !important + background: #43a047 !important; } .programCell-active { - background: rgba(0, 0, 0, .3) !important + background: rgba(0, 0, 0, 0.3) !important; } .guide-channelHeaderCell:focus, .programCell:focus { background-color: #00a4dc !important; - color: #fff !important + color: #fff !important; } .guide-programTextIcon { color: #1e1e1e; - background: #555 + background: #555; } .guide-headerTimeslots { - color: inherit + color: inherit; } .guide-date-tab-button { color: #555; - color: rgba(255, 255, 255, .3) + color: rgba(255, 255, 255, 0.3); } .guide-date-tab-button.emby-tab-button-active, .guide-date-tab-button:focus { - color: #00a4dc + color: #00a4dc; } .guide-date-tab-button.show-focus:focus { background-color: #00a4dc; - color: #fff + color: #fff; } .infoBanner { color: #000; background: #fff3a5; padding: 1em; - border-radius: .25em + -webkit-border-radius: 0.25em; + border-radius: 0.25em; } .ratingbutton-icon-withrating { - color: #c33 + color: #c33; } .downloadbutton-icon-complete, .downloadbutton-icon-on { - color: #4285F4 + color: #4285f4; } .playstatebutton-icon-played { - color: #c33 + color: #c33; } .repeatButton-active { - color: #4285F4 + color: #4285f4; } .card:focus .cardBox.visualCardBox, .card:focus .cardBox:not(.visualCardBox) .cardScalable { - border-color: #fff !important + border-color: #fff !important; +} + +::-webkit-scrollbar-track { + box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); +} + +::-webkit-scrollbar-track-piece { + background-color: #081b3b; } .layout-desktop ::-webkit-scrollbar { width: 1em; - height: 1em -} - -::-webkit-scrollbar-track { - box-shadow: inset 0 0 6px rgba(0, 0, 0, .3) -} - -::-webkit-scrollbar-track-piece { - background-color: #081B3B + height: 1em; } ::-webkit-scrollbar-thumb:horizontal, ::-webkit-scrollbar-thumb:vertical { border-radius: 2px; - background: center no-repeat rgba(255, 255, 255, .7) + -webkit-border-radius: 2px; + background: center no-repeat rgba(255, 255, 255, 0.7); } .metadataSidebarIcon { - color: #00a4dc + color: #00a4dc; } diff --git a/src/tv.html b/src/tv.html index 1327d53ffe..ceb5c51b44 100644 --- a/src/tv.html +++ b/src/tv.html @@ -3,13 +3,13 @@
- - - + + +
-
-
+
+
@@ -45,11 +45,9 @@
-
@@ -61,9 +59,9 @@
- - - + + +
diff --git a/src/useredit.html b/src/useredit.html index 201901744f..253387b4ac 100644 --- a/src/useredit.html +++ b/src/useredit.html @@ -6,7 +6,7 @@ @@ -89,6 +89,10 @@ ${OptionAllowVideoPlaybackRemuxing} +
${OptionAllowMediaPlaybackTranscodingHelp}
diff --git a/src/userlibraryaccess.html b/src/userlibraryaccess.html index 4653fd07eb..8a6177585a 100644 --- a/src/userlibraryaccess.html +++ b/src/userlibraryaccess.html @@ -6,7 +6,7 @@ diff --git a/src/usernew.html b/src/usernew.html index bca1e72fea..fac036aa8d 100644 --- a/src/usernew.html +++ b/src/usernew.html @@ -5,7 +5,7 @@

${HeaderAddUser}

- ${Help} + ${Help}
diff --git a/src/userparentalcontrol.html b/src/userparentalcontrol.html index 6c35913338..2c13ec8012 100644 --- a/src/userparentalcontrol.html +++ b/src/userparentalcontrol.html @@ -4,7 +4,7 @@ @@ -31,7 +31,7 @@

${LabelBlockContentWithTags}

@@ -41,7 +41,7 @@

${HeaderAccessSchedule}

diff --git a/src/userpassword.html b/src/userpassword.html index f38e395999..119a0212de 100644 --- a/src/userpassword.html +++ b/src/userpassword.html @@ -4,7 +4,7 @@ diff --git a/src/userprofiles.html b/src/userprofiles.html index 1272957e57..98237645dd 100644 --- a/src/userprofiles.html +++ b/src/userprofiles.html @@ -6,9 +6,9 @@

${HeaderUsers}

- ${Help} + ${Help}
diff --git a/src/videoosd.html b/src/videoosd.html index 4d18787a5d..452c8a9af8 100644 --- a/src/videoosd.html +++ b/src/videoosd.html @@ -8,7 +8,7 @@

- autorenew + ${FetchingData}
@@ -18,54 +18,54 @@
- +
@@ -76,7 +76,7 @@
diff --git a/src/wizardfinish.html b/src/wizardfinish.html index e593c430fa..4d54a10cd4 100644 --- a/src/wizardfinish.html +++ b/src/wizardfinish.html @@ -5,11 +5,11 @@

${WizardCompleted}

diff --git a/src/wizardlibrary.html b/src/wizardlibrary.html index 710bf55816..3a5ca5069b 100644 --- a/src/wizardlibrary.html +++ b/src/wizardlibrary.html @@ -3,7 +3,7 @@

${HeaderSetupLibrary}

- +

@@ -11,12 +11,12 @@
diff --git a/src/wizardremoteaccess.html b/src/wizardremoteaccess.html index f0375a4e2d..f7ce47dc93 100644 --- a/src/wizardremoteaccess.html +++ b/src/wizardremoteaccess.html @@ -21,12 +21,12 @@
diff --git a/src/wizardsettings.html b/src/wizardsettings.html index cced04c5b3..d4f537cf98 100644 --- a/src/wizardsettings.html +++ b/src/wizardsettings.html @@ -16,12 +16,12 @@
diff --git a/src/wizardstart.html b/src/wizardstart.html index 1308fcb2ea..05e282bee3 100644 --- a/src/wizardstart.html +++ b/src/wizardstart.html @@ -4,7 +4,7 @@

${WelcomeToProject}

- + ${ButtonQuickStartGuide}
@@ -20,7 +20,7 @@
diff --git a/src/wizarduser.html b/src/wizarduser.html index 7d7fdc08e0..3ce0b3ba74 100644 --- a/src/wizarduser.html +++ b/src/wizarduser.html @@ -22,12 +22,12 @@
diff --git a/webpack.common.js b/webpack.common.js index 5e0f885267..03beb63a73 100644 --- a/webpack.common.js +++ b/webpack.common.js @@ -1,35 +1,37 @@ -const path = require("path"); +const path = require('path'); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -const CopyPlugin = require("copy-webpack-plugin"); +const CopyPlugin = require('copy-webpack-plugin'); const Assets = [ - "alameda/alameda.js", - "requirejs/require.js", - "libass-wasm/dist/subtitles-octopus-worker.js", - "libass-wasm/dist/subtitles-octopus-worker.data", - "libass-wasm/dist/subtitles-octopus-worker.wasm" + 'alameda/alameda.js', + 'native-promise-only/npo.js', + 'libass-wasm/dist/js/subtitles-octopus-worker.js', + 'libass-wasm/dist/js/subtitles-octopus-worker.data', + 'libass-wasm/dist/js/subtitles-octopus-worker.wasm', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.js', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.data', + 'libass-wasm/dist/js/subtitles-octopus-worker-legacy.js.mem' ]; module.exports = { - context: path.resolve(__dirname, "src"), - entry: "./bundle.js", + context: path.resolve(__dirname, 'src'), + entry: './bundle.js', resolve: { modules: [ - path.resolve(__dirname, "node_modules") + path.resolve(__dirname, 'node_modules') ] }, + output: { + filename: 'bundle.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'amd-require' + }, plugins: [ - new CleanWebpackPlugin(), - new CopyPlugin([{ - from: "**/*", - to: "." - }]), new CopyPlugin( Assets.map(asset => { return { from: path.resolve(__dirname, `./node_modules/${asset}`), - to: path.resolve(__dirname, "./dist/libraries") + to: path.resolve(__dirname, './dist/libraries') }; }) ) diff --git a/webpack.dev.js b/webpack.dev.js index d3791e679f..716cfb2d07 100644 --- a/webpack.dev.js +++ b/webpack.dev.js @@ -1,36 +1,53 @@ -const path = require("path"); -const common = require("./webpack.common"); -const merge = require("webpack-merge"); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const ConcatPlugin = require('webpack-concat-plugin'); +const path = require('path'); +const common = require('./webpack.common'); +const merge = require('webpack-merge'); +const packageConfig = require('./package.json'); module.exports = merge(common, { - mode: "development", + mode: 'development', output: { - filename: "bundle.js", - path: path.resolve(__dirname, "dist"), - libraryTarget: "amd-require" + filename: 'bundle.js', + path: path.resolve(__dirname, 'dist'), + libraryTarget: 'amd-require' }, + devtool: 'inline-source-map', module: { rules: [ + { + test: /\.js$/, + exclude: /node_modules[\\/](?!jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, + use: { + loader: 'babel-loader', + options: { + presets: packageConfig.babel.presets + } + } + }, { test: /\.css$/i, - use: ["style-loader", "css-loader", "postcss-loader"] + use: [ + 'style-loader', + 'css-loader', + { + loader: 'postcss-loader', + options: { + config: { + path: __dirname + } + } + } + ] }, { test: /\.(png|jpg|gif)$/i, - use: ["file-loader"] + use: ['file-loader'] + }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader' + ] } ] - }, - plugins: [ - new HtmlWebpackPlugin({ - filename: 'index.html', - template: 'index.html' - }), - new ConcatPlugin({ - name: 'scripts/apploader.js', - filesToConcat: ['./standalone.js', './scripts/apploader.js'] - }) - ] + } }); diff --git a/webpack.prod.js b/webpack.prod.js index 319d8f14fc..eb39f82cd4 100644 --- a/webpack.prod.js +++ b/webpack.prod.js @@ -1,23 +1,45 @@ -const path = require("path"); -const common = require("./webpack.common"); -const merge = require("webpack-merge"); +const common = require('./webpack.common'); +const merge = require('webpack-merge'); +const packageConfig = require('./package.json'); module.exports = merge(common, { - mode: "production", - output: { - filename: "bundle.js", - path: path.resolve(__dirname, "dist"), - libraryTarget: "amd-require" - }, + mode: 'production', module: { rules: [ + { + test: /\.js$/, + exclude: /node_modules[\\/](?!jellyfin-apiclient|query-string|split-on-first|strict-uri-encode)/, + use: { + loader: 'babel-loader', + options: { + presets: packageConfig.babel.presets + } + } + }, { test: /\.css$/i, - use: ["style-loader", "css-loader", "postcss-loader"] + use: [ + 'style-loader', + 'css-loader', + { + loader: 'postcss-loader', + options: { + config: { + path: __dirname + } + } + } + ] }, { test: /\.(png|jpg|gif)$/i, - use: ["file-loader"] + use: ['file-loader'] + }, + { + test: /\.(woff|woff2|eot|ttf|otf)$/, + use: [ + 'file-loader' + ] } ] } diff --git a/yarn.lock b/yarn.lock index 705eac6a19..c1191c619b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,22 +2,779 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== dependencies: - "@babel/highlight" "^7.0.0" + "@babel/highlight" "^7.8.3" -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== +"@babel/compat-data@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.9.6.tgz#3f604c40e420131affe6f2c8052e9a275ae2049b" + integrity sha512-5QPTrNen2bm7RBc7dsOmcA5hbrS4O2Vhmk5XOL4zWW/zD/hV0iinpefDlkm+tBBy8kDtFaaeEvmAqt+nURAV2g== dependencies: + browserslist "^4.11.1" + invariant "^2.2.4" + semver "^5.5.0" + +"@babel/core@>=7.2.2", "@babel/core@>=7.9.0", "@babel/core@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.9.6.tgz#d9aa1f580abf3b2286ef40b6904d390904c63376" + integrity sha512-nD3deLvbsApbHAHttzIssYqgb883yU/d9roe4RZymBCDaZryMJDbptVpEpeQuRh4BJ+SYI8le9YGxKvFEvl1Wg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.6" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helpers" "^7.9.6" + "@babel/parser" "^7.9.6" + "@babel/template" "^7.8.6" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.2" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + +"@babel/generator@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.9.6.tgz#5408c82ac5de98cda0d77d8124e99fa1f2170a43" + integrity sha512-+htwWKJbH2bL72HRluF8zumBxzuX0ZZUFl3JLNyoUjM/Ho8wnVpPXM6aUz8cfKDqQ/h7zHqKt4xzJteUosckqQ== + dependencies: + "@babel/types" "^7.9.6" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + +"@babel/helper-annotate-as-pure@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.8.3.tgz#60bc0bc657f63a0924ff9a4b4a0b24a13cf4deee" + integrity sha512-6o+mJrZBxOoEX77Ezv9zwW7WV8DdluouRKNY/IR5u/YTMuKHgugHOzYWlYvYLpLA9nPsQCAAASpCIbjI9Mv+Uw== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.8.3.tgz#c84097a427a061ac56a1c30ebf54b7b22d241503" + integrity sha512-5eFOm2SyFPK4Rh3XMMRDjN7lBH0orh3ss0g3rTYZnBQ+r6YPj7lgDyCvPphynHvUrobJmeMignBr6Acw9mAPlw== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-compilation-targets@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.9.6.tgz#1e05b7ccc9d38d2f8b40b458b380a04dcfadd38a" + integrity sha512-x2Nvu0igO0ejXzx09B/1fGBxY9NXQlBW2kZsSxCJft+KHN8t9XWzIvFxtPHnBOAXpVsdxZKZFbRUC8TsNKajMw== + dependencies: + "@babel/compat-data" "^7.9.6" + browserslist "^4.11.1" + invariant "^2.2.4" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/helper-create-regexp-features-plugin@^7.8.3", "@babel/helper-create-regexp-features-plugin@^7.8.8": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.8.8.tgz#5d84180b588f560b7864efaeea89243e58312087" + integrity sha512-LYVPdwkrQEiX9+1R29Ld/wTrmQu1SSKYnuOk3g0CkcZMA1p0gsNxJFj/3gBdaJ7Cg0Fnek5z0DsMULePP7Lrqg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + regexpu-core "^4.7.0" + +"@babel/helper-define-map@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.8.3.tgz#a0655cad5451c3760b726eba875f1cd8faa02c15" + integrity sha512-PoeBYtxoZGtct3md6xZOCWPcKuMuk3IHhgxsRRNtnNShebf4C8YonTSblsK4tvDbm+eJAw2HAPOfCr+Q/YRG/g== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/types" "^7.8.3" + lodash "^4.17.13" + +"@babel/helper-explode-assignable-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.8.3.tgz#a728dc5b4e89e30fc2dfc7d04fa28a930653f982" + integrity sha512-N+8eW86/Kj147bO9G2uclsg5pwfs/fqqY5rwgIL7eTBklgXjcOJ3btzS5iM6AitJcftnY7pm2lGsrJVYLGjzIw== + dependencies: + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-function-name@^7.8.3", "@babel/helper-function-name@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" + integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.9.5" + +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-hoist-variables@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.8.3.tgz#1dbe9b6b55d78c9b4183fc8cdc6e30ceb83b7134" + integrity sha512-ky1JLOjcDUtSc+xkt0xhYff7Z6ILTAHKmZLHPxAhOP0Nd77O+3nCsd6uSVYur6nJnCI029CrNbYlc0LoPfAPQg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-member-expression-to-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.8.3.tgz#659b710498ea6c1d9907e0c73f206eee7dadc24c" + integrity sha512-fO4Egq88utkQFjbPrSHGmGLFqmrshs11d46WI+WZDESt7Wu7wN2G2Iu+NMMZJFDOVRHAMIkB5SNh30NtwCA7RA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-imports@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.8.3.tgz#7fe39589b39c016331b6b8c3f441e8f0b1419498" + integrity sha512-R0Bx3jippsbAEtzkpZ/6FIiuzOURPcMjHp+Z6xPe6DtApDJx+w7UYyOLanZqO8+wKR9G10s/FmHXvxaMd9s6Kg== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-module-transforms@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.9.0.tgz#43b34dfe15961918707d247327431388e9fe96e5" + integrity sha512-0FvKyu0gpPfIQ8EkxlrAydOWROdHpBmiCiRwLkUiBGhCUPRRbVD2/tm3sFr/c/GWFrQ/ffutGUAnx7V0FzT2wA== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-simple-access" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/template" "^7.8.6" + "@babel/types" "^7.9.0" + lodash "^4.17.13" + +"@babel/helper-optimise-call-expression@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.8.3.tgz#7ed071813d09c75298ef4f208956006b6111ecb9" + integrity sha512-Kag20n86cbO2AvHca6EJsvqAd82gc6VMGule4HwebwMlwkpXuVqrNRj6CkCV2sKxgi9MyAUnZVnZ6lJ1/vKhHQ== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" + integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== + +"@babel/helper-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.8.3.tgz#139772607d51b93f23effe72105b319d2a4c6965" + integrity sha512-BWt0QtYv/cg/NecOAZMdcn/waj/5P26DR4mVLXfFtDokSR6fyuG0Pj+e2FqtSME+MqED1khnSMulkmGl8qWiUQ== + dependencies: + lodash "^4.17.13" + +"@babel/helper-remap-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.8.3.tgz#273c600d8b9bf5006142c1e35887d555c12edd86" + integrity sha512-kgwDmw4fCg7AVgS4DukQR/roGp+jP+XluJE5hsRZwxCYGg+Rv9wSGErDWhlI90FODdYfd4xG4AQRiMDjjN0GzA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-wrap-function" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-replace-supers@^7.8.3", "@babel/helper-replace-supers@^7.8.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.9.6.tgz#03149d7e6a5586ab6764996cd31d6981a17e1444" + integrity sha512-qX+chbxkbArLyCImk3bWV+jB5gTNU/rsze+JlcF6Nf8tVTigPJSI1o1oBow/9Resa1yehUO9lIipsmu9oG4RzA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.8.3" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + +"@babel/helper-simple-access@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.8.3.tgz#7f8109928b4dab4654076986af575231deb639ae" + integrity sha512-VNGUDjx5cCWg4vvCTR8qQ7YJYZ+HBjxOgXEl7ounz+4Sn7+LMD3CFrCTEU6/qXKbA2nKg21CwhhBzO0RpRbdCw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + +"@babel/helper-validator-identifier@^7.9.0", "@babel/helper-validator-identifier@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" + integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== + +"@babel/helper-wrap-function@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" + integrity sha512-LACJrbUET9cQDzb6kG7EeD7+7doC3JNvUgTEQOx2qaO1fKlzE/Bf05qs9w1oXQMmXlPO65lC3Tq9S6gZpTErEQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.3" + "@babel/types" "^7.8.3" + +"@babel/helpers@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.9.6.tgz#092c774743471d0bb6c7de3ad465ab3d3486d580" + integrity sha512-tI4bUbldloLcHWoRUMAj4g1bF313M/o6fBKhIsb3QnGVPwRm9JsNf/gqMkQ7zjqReABiffPV6RWj7hEglID5Iw== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.9.6" + "@babel/types" "^7.9.6" + +"@babel/highlight@^7.8.3": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.9.0.tgz#4e9b45ccb82b79607271b2979ad82c7b68163079" + integrity sha512-lJZPilxX7Op3Nv/2cvFdnlepPXDxi29wxteT57Q965oc5R9v86ztx0jfxVrTcBk8C2kcPkkDa2Z4T3ZsPPVWsQ== + dependencies: + "@babel/helper-validator-identifier" "^7.9.0" chalk "^2.0.0" - esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/parser@^7.8.6", "@babel/parser@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.9.6.tgz#3b1bbb30dabe600cd72db58720998376ff653bc7" + integrity sha512-AoeIEJn8vt+d/6+PXDRPaksYhnlbMIiejioBZvvMQsOjW/JYK6k/0dKnvvP3EhK5GfMBWDPtrxRtegWdAcdq9Q== + +"@babel/plugin-proposal-async-generator-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.8.3.tgz#bad329c670b382589721b27540c7d288601c6e6f" + integrity sha512-NZ9zLv848JsV3hs8ryEh7Uaz/0KsmPLqv0+PdkDJL1cJy0K4kOCFa8zc1E3mp+RHPQcpdfb/6GovEsW4VDrOMw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + +"@babel/plugin-proposal-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.8.3.tgz#38c4fe555744826e97e2ae930b0fb4cc07e66054" + integrity sha512-NyaBbyLFXFLT9FP+zk0kYlUlA8XtCUbehs67F0nnEg7KICgMc2mNkIeu9TYhKzyXMkrapZFwAhXLdnt4IYHy1w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + +"@babel/plugin-proposal-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.8.3.tgz#da5216b238a98b58a1e05d6852104b10f9a70d6b" + integrity sha512-KGhQNZ3TVCQG/MjRbAUwuH+14y9q0tpxs1nWWs3pbSleRdDro9SAMMDyye8HhY1gqZ7/NqIc8SKhya0wRDgP1Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.0" + +"@babel/plugin-proposal-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.8.3.tgz#e4572253fdeed65cddeecfdab3f928afeb2fd5d2" + integrity sha512-TS9MlfzXpXKt6YYomudb/KU7nQI6/xnapG6in1uZxoxDghuSMZsPb6D2fyUwNYSAp4l1iR7QtFOjkqcRYcUsfw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + +"@babel/plugin-proposal-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.8.3.tgz#5d6769409699ec9b3b68684cd8116cedff93bad8" + integrity sha512-jWioO1s6R/R+wEHizfaScNsAx+xKgwTLNXSh7tTC4Usj3ItsPEhYkEpU4h+lpnBwq7NBVOJXfO6cRFYcX69JUQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + +"@babel/plugin-proposal-object-rest-spread@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.6.tgz#7a093586fcb18b08266eb1a7177da671ac575b63" + integrity sha512-Ga6/fhGqA9Hj+y6whNpPv8psyaK5xzrQwSPsGPloVkvmH+PqW1ixdnfJ9uIO06OjQNYol3PMnfmJ8vfZtkzF+A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.9.5" + +"@babel/plugin-proposal-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" + integrity sha512-0gkX7J7E+AtAw9fcwlVQj8peP61qhdg/89D5swOkjYbkboA2CVckn3kiyum1DE0wskGb7KJJxBdyEBApDLLVdw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + +"@babel/plugin-proposal-optional-chaining@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.9.0.tgz#31db16b154c39d6b8a645292472b98394c292a58" + integrity sha512-NDn5tu3tcv4W30jNhmc2hyD5c56G6cXx4TesJubhxrJeCvuuMpttxr0OnNCqbZGhFjLrg+NIhxxC+BK5F6yS3w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4", "@babel/plugin-proposal-unicode-property-regex@^7.8.3": + version "7.8.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.8.8.tgz#ee3a95e90cdc04fe8cd92ec3279fa017d68a0d1d" + integrity sha512-EVhjVsMpbhLw9ZfHWSx2iy13Q8Z/eg8e8ccVWt23sWQK5l1UdkoLJPN5w69UA4uITGBnEZD2JOe4QOHycYKv8A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.8" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-async-generators@^7.8.0": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-dynamic-import@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-json-strings@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.0", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.8.3.tgz#0e3fb63e09bea1b11e96467271c8308007e7c41f" + integrity sha512-H7dCMAdN83PcCmqmkHB5dtp+Xa9a6LKSvA2hiFBC/5alSHxM5VgWZXFqDi0YFe8XNGT6iCa+z4V4zSt/PdZ7Dw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-object-rest-spread@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.0": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.8.3.tgz#3acdece695e6b13aaf57fc291d1a800950c71391" + integrity sha512-kwj1j9lL/6Wd0hROD3b/OZZ7MSrZLqqn9RAZ5+cYYsflQ9HZBIKCUkr3+uL1MEJ1NePiUbf98jjiMQSv0NMR9g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-arrow-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.8.3.tgz#82776c2ed0cd9e1a49956daeb896024c9473b8b6" + integrity sha512-0MRF+KC8EqH4dbuITCWwPSzsyO3HIWWlm30v8BbbpOrS1B++isGxPnnuq/IZvOX5J2D/p7DQalQm+/2PnlKGxg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-async-to-generator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.8.3.tgz#4308fad0d9409d71eafb9b1a6ee35f9d64b64086" + integrity sha512-imt9tFLD9ogt56Dd5CI/6XgpukMwd/fLGSrix2httihVe7LOGVPhyhMh1BU5kDM7iHD08i8uUtmV2sWaBFlHVQ== + dependencies: + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-remap-async-to-generator" "^7.8.3" + +"@babel/plugin-transform-block-scoped-functions@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.8.3.tgz#437eec5b799b5852072084b3ae5ef66e8349e8a3" + integrity sha512-vo4F2OewqjbB1+yaJ7k2EJFHlTP3jR634Z9Cj9itpqNjuLXvhlVxgnjsHsdRgASR8xYDrx6onw4vW5H6We0Jmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-block-scoping@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.8.3.tgz#97d35dab66857a437c166358b91d09050c868f3a" + integrity sha512-pGnYfm7RNRgYRi7bids5bHluENHqJhrV4bCZRwc5GamaWIIs07N4rZECcmJL6ZClwjDz1GbdMZFtPs27hTB06w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + lodash "^4.17.13" + +"@babel/plugin-transform-classes@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz#800597ddb8aefc2c293ed27459c1fcc935a26c2c" + integrity sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" + integrity sha512-O5hiIpSyOGdrQZRQ2ccwtTVkgUDBBiCuK//4RJ6UfePllUTCENOzKxfh6ulckXKc0DixTFLCfb2HVkNA7aDpzA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-destructuring@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz#72c97cf5f38604aea3abf3b935b0e17b1db76a50" + integrity sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" + integrity sha512-kLs1j9Nn4MQoBYdRXH6AeaXMbEJFaFu/v1nQkvib6QzTj8MZI5OQzqmD83/2jEM1z0DLilra5aWO5YpyC0ALIw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-duplicate-keys@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.8.3.tgz#8d12df309aa537f272899c565ea1768e286e21f1" + integrity sha512-s8dHiBUbcbSgipS4SMFuWGqCvyge5V2ZeAWzR6INTVC3Ltjig/Vw1G2Gztv0vU/hRG9X8IvKvYdoksnUfgXOEQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.8.3.tgz#581a6d7f56970e06bf51560cd64f5e947b70d7b7" + integrity sha512-zwIpuIymb3ACcInbksHaNcR12S++0MDLKkiqXHl3AzpgdKlFNhog+z/K0+TGW+b0w5pgTq4H6IwV/WhxbGYSjQ== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.9.0.tgz#0f260e27d3e29cd1bb3128da5e76c761aa6c108e" + integrity sha512-lTAnWOpMwOXpyDx06N+ywmF3jNbafZEqZ96CGYabxHrxNX8l5ny7dt4bK/rGwAh9utyP2b2Hv7PlZh1AAS54FQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.8.3.tgz#279373cb27322aaad67c2683e776dfc47196ed8b" + integrity sha512-rO/OnDS78Eifbjn5Py9v8y0aR+aSYhDhqAwVfsTl0ERuMZyr05L1aFSCJnbv2mmsLkit/4ReeQ9N2BgLnOcPCQ== + dependencies: + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.8.3.tgz#aef239823d91994ec7b68e55193525d76dbd5dc1" + integrity sha512-3Tqf8JJ/qB7TeldGl+TT55+uQei9JfYaregDcEAyBZ7akutriFrt6C/wLYIer6OYhleVQvH/ntEhjE/xMmy10A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-member-expression-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.8.3.tgz#963fed4b620ac7cbf6029c755424029fa3a40410" + integrity sha512-3Wk2EXhnw+rP+IDkK6BdtPKsUE5IeZ6QOGrPYvw52NwBStw9V1ZVzxgK6fSKSxqUvH9eQPR3tm3cOq79HlsKYA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-modules-amd@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.9.6.tgz#8539ec42c153d12ea3836e0e3ac30d5aae7b258e" + integrity sha512-zoT0kgC3EixAyIAU+9vfaUVKTv9IxBDSabgHoUCBP6FqEJ+iNiN7ip7NBKcYqbfUDfuC2mFCbM7vbu4qJgOnDw== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-commonjs@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.9.6.tgz#64b7474a4279ee588cacd1906695ca721687c277" + integrity sha512-7H25fSlLcn+iYimmsNe3uK1at79IE6SKW9q0/QeEHTMC9MdOZ+4bA+T1VFB5fgOqBWoqlifXRzYD0JPdmIrgSQ== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-simple-access" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-systemjs@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.9.6.tgz#207f1461c78a231d5337a92140e52422510d81a4" + integrity sha512-NW5XQuW3N2tTHim8e1b7qGy7s0kZ2OH3m5octc49K1SdAKGxYxeIx7hiIz05kS1R2R+hOWcsr1eYwcGhrdHsrg== + dependencies: + "@babel/helper-hoist-variables" "^7.8.3" + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + babel-plugin-dynamic-import-node "^2.3.3" + +"@babel/plugin-transform-modules-umd@^7.9.0": + version "7.9.0" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.9.0.tgz#e909acae276fec280f9b821a5f38e1f08b480697" + integrity sha512-uTWkXkIVtg/JGRSIABdBoMsoIeoHQHPTL0Y2E7xf5Oj7sLqwVsNXOkNk0VJc7vF0IMBsPeikHxFjGe+qmwPtTQ== + dependencies: + "@babel/helper-module-transforms" "^7.9.0" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.8.3.tgz#a2a72bffa202ac0e2d0506afd0939c5ecbc48c6c" + integrity sha512-f+tF/8UVPU86TrCb06JoPWIdDpTNSGGcAtaD9mLP0aYGA0OS0j7j7DHJR0GTFrUZPUU6loZhbsVZgTh0N+Qdnw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + +"@babel/plugin-transform-new-target@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.8.3.tgz#60cc2ae66d85c95ab540eb34babb6434d4c70c43" + integrity sha512-QuSGysibQpyxexRyui2vca+Cmbljo8bcRckgzYV4kRIsHpVeyeC3JDO63pY+xFZ6bWOBn7pfKZTqV4o/ix9sFw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-object-super@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.8.3.tgz#ebb6a1e7a86ffa96858bd6ac0102d65944261725" + integrity sha512-57FXk+gItG/GejofIyLIgBKTas4+pEU47IXKDBWFTxdPd7F80H8zybyAY7UoblVfBhBGs2EKM+bJUu2+iUYPDQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz#173b265746f5e15b2afe527eeda65b73623a0795" + integrity sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-property-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" + integrity sha512-uGiiXAZMqEoQhRWMK17VospMZh5sXWg+dlh2soffpkAl96KAm+WZuJfa6lcELotSRmooLqg0MWdH6UUq85nmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-regenerator@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.8.7.tgz#5e46a0dca2bee1ad8285eb0527e6abc9c37672f8" + integrity sha512-TIg+gAl4Z0a3WmD3mbYSk+J9ZUH6n/Yc57rtKRnlA/7rcCvpekHXe0CMZHP1gYp7/KLe9GHTuIba0vXmls6drA== + dependencies: + regenerator-transform "^0.14.2" + +"@babel/plugin-transform-reserved-words@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.8.3.tgz#9a0635ac4e665d29b162837dd3cc50745dfdf1f5" + integrity sha512-mwMxcycN3omKFDjDQUl+8zyMsBfjRFr0Zn/64I41pmjv4NJuqcYlEtezwYtw9TFd9WR1vN5kiM+O0gMZzO6L0A== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-shorthand-properties@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.8.3.tgz#28545216e023a832d4d3a1185ed492bcfeac08c8" + integrity sha512-I9DI6Odg0JJwxCHzbzW08ggMdCezoWcuQRz3ptdudgwaHxTjxw5HgdFJmZIkIMlRymL6YiZcped4TTCB0JcC8w== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.8.3.tgz#9c8ffe8170fdfb88b114ecb920b82fb6e95fe5e8" + integrity sha512-CkuTU9mbmAoFOI1tklFWYYbzX5qCIZVXPVy0jpXgGwkplCndQAa58s2jr66fTeQnA64bDox0HL4U56CFYoyC7g== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-sticky-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.8.3.tgz#be7a1290f81dae767475452199e1f76d6175b100" + integrity sha512-9Spq0vGCD5Bb4Z/ZXXSK5wbbLFMG085qd2vhL1JYu1WcQ5bXqZBAYRzU1d+p79GcHs2szYv5pVQCX13QgldaWw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-regex" "^7.8.3" + +"@babel/plugin-transform-template-literals@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.8.3.tgz#7bfa4732b455ea6a43130adc0ba767ec0e402a80" + integrity sha512-820QBtykIQOLFT8NZOcTRJ1UNuztIELe4p9DCgvj4NK+PwluSJ49we7s9FB1HIGNIYT7wFUJ0ar2QpCDj0escQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-typeof-symbol@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.8.4.tgz#ede4062315ce0aaf8a657a920858f1a2f35fc412" + integrity sha512-2QKyfjGdvuNfHsb7qnBBlKclbD4CfshH2KvDabiijLMGXPHJXGxtDzwIF7bQP+T0ysw8fYTtxPafgfs/c1Lrqg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-transform-unicode-regex@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.8.3.tgz#0cef36e3ba73e5c57273effb182f46b91a1ecaad" + integrity sha512-+ufgJjYdmWfSQ+6NS9VGUR2ns8cjJjYbrbi11mZBTaWm+Fui/ncTLFF28Ei1okavY+xkojGr1eJxNsWYeA5aZw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/polyfill@^7.8.7": + version "7.8.7" + resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.8.7.tgz#151ec24c7135481336168c3bd8b8bf0cf91c032f" + integrity sha512-LeSfP9bNZH2UOZgcGcZ0PIHUt1ZuHub1L3CVmEyqLxCeDLm4C5Gi8jRH8ZX2PNpDhQCo0z6y/+DIs2JlliXW8w== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.4" + +"@babel/preset-env@^7.8.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.6.tgz#df063b276c6455ec6fcfc6e53aacc38da9b0aea6" + integrity sha512-0gQJ9RTzO0heXOhzftog+a/WyOuqMrAIugVYxMYf83gh1CQaQDjMtsOpqOwXyDL/5JcWsrCm8l4ju8QC97O7EQ== + dependencies: + "@babel/compat-data" "^7.9.6" + "@babel/helper-compilation-targets" "^7.9.6" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.6" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.5" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.9.5" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.6" + "@babel/plugin-transform-modules-commonjs" "^7.9.6" + "@babel/plugin-transform-modules-systemjs" "^7.9.6" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.9.5" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.6" + browserslist "^4.11.1" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + +"@babel/preset-modules@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" + integrity sha512-Ra3JXOHBq2xd56xSF7lMKXdjBn3T772Y1Wet3yWnkDly9zHvJki029tAFzvAAK5cf4YV3yoxuP61crYRol6SVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/runtime@^7.7.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" + integrity sha512-64AF1xY3OAkFHqOb9s4jpgk1Mm5vDZ4L3acHvAml+53nO1XbXLuDodsVpO4OIUsmemlUHMxNdYMNJmsvOwLrvQ== + dependencies: + regenerator-runtime "^0.13.4" + +"@babel/template@^7.8.3", "@babel/template@^7.8.6": + version "7.8.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" + integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.6" + "@babel/types" "^7.8.6" + +"@babel/traverse@^7.8.3", "@babel/traverse@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.9.6.tgz#5540d7577697bf619cc57b92aa0f1c231a94f442" + integrity sha512-b3rAHSjbxy6VEAvlxM8OV/0X4XrG72zoxme6q1MOoe2vd0bEc+TwayhuC1+Dfgqh1QEG+pj7atQqvUprHIccsg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.9.6" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.9.6" + "@babel/types" "^7.9.6" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + +"@babel/types@^7.4.4", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.9.0", "@babel/types@^7.9.5", "@babel/types@^7.9.6": + version "7.9.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.6.tgz#2c5502b427251e9de1bd2dff95add646d95cc9f7" + integrity sha512-qxXzvBO//jO9ZnoasKF1uJzHd2+M6Q2ZPIVfnFps8JJvXy0ZBbwbNOmE6SGIY5XOY6d1Bo5lb9d9RJ8nv3WSeA== + dependencies: + "@babel/helper-validator-identifier" "^7.9.5" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@csstools/convert-colors@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" + integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== + +"@gulp-sourcemaps/identity-map@1.X": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9" + integrity sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ== + dependencies: + acorn "^5.0.3" + css "^2.2.1" + normalize-path "^2.1.1" + source-map "^0.6.0" + through2 "^2.0.3" + +"@gulp-sourcemaps/map-sources@1.X": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" + integrity sha1-iQrnxdjId/bThIYCFazp1+yUW9o= + dependencies: + normalize-path "^2.0.1" + through2 "^2.0.3" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -26,16 +783,62 @@ call-me-maybe "^1.0.1" glob-to-regexp "^0.3.0" +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + "@nodelib/fs.stat@^1.1.2": version "1.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + +"@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== + +"@stylelint/postcss-css-in-js@^0.37.1": + version "0.37.1" + resolved "https://registry.yarnpkg.com/@stylelint/postcss-css-in-js/-/postcss-css-in-js-0.37.1.tgz#41e5e7660f73d88227610e18c6ebb262d56ac125" + integrity sha512-UMf2Rni3JGKi3ZwYRGMYJ5ipOA5ENJSKMtYA/pE1ZLURwdh7B5+z2r73RmWvub+N0UuH1Lo+TGfCgYwPvqpXNw== + dependencies: + "@babel/core" ">=7.9.0" + +"@stylelint/postcss-markdown@^0.36.1": + version "0.36.1" + resolved "https://registry.yarnpkg.com/@stylelint/postcss-markdown/-/postcss-markdown-0.36.1.tgz#829b87e6c0f108014533d9d7b987dc9efb6632e8" + integrity sha512-iDxMBWk9nB2BPi1VFQ+Dc5+XpvODBHw2n3tYpaBZuEAFQlbtF9If0Qh5LTTwSi/XwdbJ2jt+0dis3i8omyggpw== + dependencies: + remark "^12.0.0" + unist-util-find-all-after "^3.0.1" + "@types/anymatch@*": version "1.3.1" resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -50,46 +853,92 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/html-minifier-terser@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#551a4589b6ee2cc9c1dff08056128aec29b94880" + integrity sha512-iYCgjm1dGPRuo12+BStjd1HiVQqhlRhWDOQigNxn023HcjnhsiFz9pc6CzJj4HwDCSQca9bxTL4PxJDbkdm3PA== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/minimist@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6" + integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY= + "@types/node@*": - version "12.7.12" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.12.tgz#7c6c571cc2f3f3ac4a59a5f2bd48f5bdbc8653cc" - integrity sha512-KPYGmfD0/b1eXurQ59fXD1GBzhSQfz6/lKBxkaHX9dKTzjXbK68Zt7yGUxUsCS1jeTy/8aL+d9JEr+S54mpkWQ== + version "13.13.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.4.tgz#1581d6c16e3d4803eb079c87d4ac893ee7501c2c" + integrity sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA== + +"@types/normalize-package-data@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + +"@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + +"@types/q@^1.5.1": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" + integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== -"@types/tapable@*": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" - integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== +"@types/tapable@*", "@types/tapable@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.5.tgz#9adbc12950582aa65ead76bffdf39fe0c27a3c02" + integrity sha512-/gG2M/Imw7cQFp8PGvz/SwocNrmKFjFsm5Pb8HdbHkZ1K8pmuPzOX4VeVoiEecFCVf4CsN1r3/BRvx+6sNqwtQ== "@types/uglify-js@*": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" - integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ== + version "3.9.0" + resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.9.0.tgz#4490a140ca82aa855ad68093829e7fd6ae94ea87" + integrity sha512-3ZcoyPYHVOCcLpnfZwD47KFLr8W/mpUcgjpf1M4Q78TMJIw7KMAHSjiCLJp1z3ZrBR9pTLbe191O0TldFK5zcw== dependencies: source-map "^0.6.1" +"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.3.tgz#9c088679876f374eb5983f150d4787aa6fb32d7e" + integrity sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ== + +"@types/vfile-message@*": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-2.0.0.tgz#690e46af0fdfc1f9faae00cd049cc888957927d5" + integrity sha512-GpTIuDpb9u4zIO165fUy9+fXcULdD8HFRNli04GehoMVbeNq7D6OBnqSmg3lxZnC+UvgUhEWKxdKiwYUkGltIw== + dependencies: + vfile-message "*" + +"@types/vfile@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@types/vfile/-/vfile-3.0.2.tgz#19c18cd232df11ce6fa6ad80259bc86c366b09b9" + integrity sha512-b3nLFGaGkJ9rzOcuXRfHkZMdjsawuDD0ENL9fzTophtBg8FJHSGbH7daXkEpcwy3v7Xol3pAvsmlYyFhR4pqJw== + dependencies: + "@types/node" "*" + "@types/unist" "*" + "@types/vfile-message" "*" + "@types/webpack-sources@*": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" - integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + version "0.1.7" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.7.tgz#0a330a9456113410c74a5d64180af0cbca007141" + integrity sha512-XyaHrJILjK1VHVC4aVlKsdNN5KBTwufMb43cQs+flGxtPAf/1Qwl8+Q0tp5BwEGaI8D6XT1L+9bSWXckgkjTLw== dependencies: "@types/node" "*" "@types/source-list-map" "*" source-map "^0.6.1" -"@types/webpack@^4.4.31": - version "4.41.0" - resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.0.tgz#b813a044d8b0dec7dfcd7622fdbe327bde06eb9a" - integrity sha512-tWkdf9nO0zFgAY/EumUKwrDUhraHKDqCPhwfFR/R8l0qnPdgb9le0Gzhvb7uzVpouuDGBgiE//ZdY+5jcZy2TA== +"@types/webpack@^4.4.31", "@types/webpack@^4.41.8": + version "4.41.12" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.12.tgz#0386ee2a2814368e2f2397abb036c0bf173ff6c3" + integrity sha512-BpCtM4NnBen6W+KEhrL9jKuZCXVtiH6+0b6cxdvNt2EwU949Al334PjQSl2BeAyvAX9mgoNNG21wvjP3xZJJ5w== dependencies: "@types/anymatch" "*" "@types/node" "*" @@ -98,150 +947,149 @@ "@types/webpack-sources" "*" source-map "^0.6.0" -"@webassemblyjs/ast@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" - integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ== +"@webassemblyjs/ast@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== dependencies: - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" -"@webassemblyjs/floating-point-hex-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721" - integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ== +"@webassemblyjs/floating-point-hex-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== -"@webassemblyjs/helper-api-error@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7" - integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA== +"@webassemblyjs/helper-api-error@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== -"@webassemblyjs/helper-buffer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204" - integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q== +"@webassemblyjs/helper-buffer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== -"@webassemblyjs/helper-code-frame@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e" - integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ== +"@webassemblyjs/helper-code-frame@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== dependencies: - "@webassemblyjs/wast-printer" "1.8.5" + "@webassemblyjs/wast-printer" "1.9.0" -"@webassemblyjs/helper-fsm@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452" - integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow== +"@webassemblyjs/helper-fsm@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== -"@webassemblyjs/helper-module-context@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245" - integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g== +"@webassemblyjs/helper-module-context@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== dependencies: - "@webassemblyjs/ast" "1.8.5" - mamacro "^0.0.3" + "@webassemblyjs/ast" "1.9.0" -"@webassemblyjs/helper-wasm-bytecode@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61" - integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ== +"@webassemblyjs/helper-wasm-bytecode@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== -"@webassemblyjs/helper-wasm-section@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf" - integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA== +"@webassemblyjs/helper-wasm-section@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" -"@webassemblyjs/ieee754@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e" - integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g== +"@webassemblyjs/ieee754@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10" - integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A== +"@webassemblyjs/leb128@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc" - integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw== +"@webassemblyjs/utf8@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== -"@webassemblyjs/wasm-edit@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a" - integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q== +"@webassemblyjs/wasm-edit@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/helper-wasm-section" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-opt" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - "@webassemblyjs/wast-printer" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/helper-wasm-section" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-opt" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + "@webassemblyjs/wast-printer" "1.9.0" -"@webassemblyjs/wasm-gen@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc" - integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg== +"@webassemblyjs/wasm-gen@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" -"@webassemblyjs/wasm-opt@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264" - integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q== +"@webassemblyjs/wasm-opt@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-buffer" "1.8.5" - "@webassemblyjs/wasm-gen" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-buffer" "1.9.0" + "@webassemblyjs/wasm-gen" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" -"@webassemblyjs/wasm-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d" - integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw== +"@webassemblyjs/wasm-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-wasm-bytecode" "1.8.5" - "@webassemblyjs/ieee754" "1.8.5" - "@webassemblyjs/leb128" "1.8.5" - "@webassemblyjs/utf8" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-wasm-bytecode" "1.9.0" + "@webassemblyjs/ieee754" "1.9.0" + "@webassemblyjs/leb128" "1.9.0" + "@webassemblyjs/utf8" "1.9.0" -"@webassemblyjs/wast-parser@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c" - integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg== +"@webassemblyjs/wast-parser@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/floating-point-hex-parser" "1.8.5" - "@webassemblyjs/helper-api-error" "1.8.5" - "@webassemblyjs/helper-code-frame" "1.8.5" - "@webassemblyjs/helper-fsm" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/floating-point-hex-parser" "1.9.0" + "@webassemblyjs/helper-api-error" "1.9.0" + "@webassemblyjs/helper-code-frame" "1.9.0" + "@webassemblyjs/helper-fsm" "1.9.0" "@xtuc/long" "4.2.2" -"@webassemblyjs/wast-printer@1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc" - integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg== +"@webassemblyjs/wast-printer@1.9.0": + version "1.9.0" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/wast-parser" "1.8.5" + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -267,15 +1115,38 @@ accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-jsx@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" - integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== +acorn-jsx@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" + integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== -acorn@^6.0.7, acorn@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51" - integrity sha512-JD0xT5FCRDNyjDda3Lrg/IxFscp9q4tiYtxE1/nOzlKCk7hIRuYjhq1kCNkbPjMRMZuFq20HNQn1I9k8Oj0E+Q== +acorn@5.X, acorn@^5.0.3: + version "5.7.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" + integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== + +acorn@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== + +acorn@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.1.1.tgz#e35668de0b402f359de515c5482a1ab9f89a69bf" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== + +after@0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" + integrity sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8= + +aggregate-error@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" + integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" ajv-errors@^1.0.0: version "1.0.1" @@ -287,30 +1158,61 @@ ajv-keywords@^3.1.0, ajv-keywords@^3.4.1: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da" integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ== -ajv@^6.1.0, ajv@^6.10.2, ajv@^6.9.1: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== +ajv@^6.1.0, ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.0, ajv@^6.5.5: + version "6.12.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.2.tgz#c629c5eced17baf314437918d2da88c99d5958cd" + integrity sha512-k+V+hzjm5q/Mr8ef/1Y9goCmlsK4I6Sm74teeyGvFk1XrOsbsKLjEdrvny42CZ+a8sXbk8KWpY/bDwS+FLL2UQ== dependencies: - fast-deep-equal "^2.0.1" + fast-deep-equal "^3.1.1" fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.4.1" uri-js "^4.2.2" -alameda@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/alameda/-/alameda-1.3.0.tgz#6f5a633940440f7adfa7ab4490326c508f7f360e" - integrity sha512-DRhAXboxtfpHTawg5XRH9mJ3soyd5QocfD47BwgvbI5ryxCs+ga6yju2K0bvFRxINzRBnoJVlUIq/ndVBk6w1Q== +alameda@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/alameda/-/alameda-1.4.0.tgz#ca53cad0feb5e24994a9be859e0593e8c2d8f58c" + integrity sha512-d6nIRyg4SD/zBupcfZ3lUis58l4H/3U7c1RBtFkcz/7u1dDIQwx26KUvKJ35esOVP6WsAjmRoP2VQ39kQZT/Gg== + +alphanum-sort@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU= + +ansi-colors@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" + integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== + dependencies: + ansi-wrap "^0.1.0" ansi-colors@^3.0.0: version "3.2.4" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf" integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-colors@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-escapes@^4.2.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== + dependencies: + type-fest "^0.11.0" + +ansi-gray@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" + integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= + dependencies: + ansi-wrap "0.1.0" ansi-html@0.0.7: version "0.0.7" @@ -332,6 +1234,16 @@ ansi-regex@^4.1.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -339,6 +1251,24 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + +ansi-wrap@0.1.0, ansi-wrap@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" + integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= + +any-promise@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -347,11 +1277,35 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" +append-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/append-buffer/-/append-buffer-1.0.2.tgz#d8220cf466081525efea50614f3de6514dfa58f1" + integrity sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE= + dependencies: + buffer-equal "^1.0.0" + aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +arch@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.1.1.tgz#8f5c2731aa35a30929221bb0640eed65175ec84e" + integrity sha512-BLM56aPo9vLLFVa8+/+pJLnrZ7QGGTVHWsCwieAWT9o9K8UeGaQbzZbGoabWLOo2ksBCztoXdqBZBplqLDDCSg== + +archive-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" + integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= + dependencies: + file-type "^4.2.0" + +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= + are-we-there-yet@~1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" @@ -372,16 +1326,45 @@ arr-diff@^4.0.0: resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.1.0: +arr-filter@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/arr-filter/-/arr-filter-1.1.2.tgz#43fdddd091e8ef11aa4c45d9cdc18e2dff1711ee" + integrity sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4= + dependencies: + make-iterator "^1.0.0" + +arr-flatten@^1.0.1, arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== +arr-map@^2.0.0, arr-map@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/arr-map/-/arr-map-2.0.2.tgz#3a77345ffc1cf35e2a91825601f9e58f2e24cac4" + integrity sha1-Onc0X/wc814qkYJWAfnljy4kysQ= + dependencies: + make-iterator "^1.0.0" + arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + integrity sha1-7/UuN1gknTO+QCuLuOVkuytdQDE= + +array-each@^1.0.0, array-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + integrity sha1-p5SvDAWrF1KEbudTofIRoFugxE8= + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" @@ -392,14 +1375,57 @@ array-flatten@^2.1.0: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== -array-union@^1.0.1: +array-includes@^3.0.3: + version "3.1.1" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.1.tgz#cdd67e6852bdf9c1215460786732255ed2459348" + integrity sha512-c2VXaCHl7zPsvpkFsw4nxvFie4fh1ur9bpcgsVkIjqn0H/Xwdg+7fv3n2r/isyS8EBj5b06M9kHyZuIr4El6WQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0" + is-string "^1.0.5" + +array-initial@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-initial/-/array-initial-1.1.0.tgz#2fa74b26739371c3947bd7a7adc73be334b3d795" + integrity sha1-L6dLJnOTccOUe9enrcc74zSz15U= + dependencies: + array-slice "^1.0.0" + is-number "^4.0.0" + +array-last@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/array-last/-/array-last-1.3.0.tgz#7aa77073fec565ddab2493f5f88185f404a9d336" + integrity sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg== + dependencies: + is-number "^4.0.0" + +array-slice@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4" + integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w== + +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + +array-union@^1.0.1, array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= dependencies: array-uniq "^1.0.1" -array-uniq@^1.0.1: +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array-uniq@^1.0.1, array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= @@ -409,11 +1435,29 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.flat@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b" + integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +arraybuffer.slice@~0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675" + integrity sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog== + arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= +arrify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -423,6 +1467,18 @@ asn1.js@^4.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" +asn1@~0.2.3: + version "0.2.4" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + assert@^1.1.1: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" @@ -436,54 +1492,169 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-metadata-inferer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ast-metadata-inferer/-/ast-metadata-inferer-0.1.1.tgz#66e24fae9d30ca961fac4880b7fc466f09b25165" + integrity sha512-hc9w8Qrgg9Lf9iFcZVhNjUnhrd2BBpTlyCnegPVvCe6O0yMrF57a6Cmh7k+xUsfUOMh9wajOL5AsGOBNEyTCcw== + astral-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async-done@^1.2.0, async-done@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2" + integrity sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.2" + process-nextick-args "^2.0.0" + stream-exhaust "^1.0.1" + +async-each-series@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/async-each-series/-/async-each-series-0.1.1.tgz#7617c1917401fd8ca4a28aadce3dbae98afeb432" + integrity sha1-dhfBkXQB/Yykooqtzj266Yr+tDI= + async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI= + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== -async@^1.5.2: +async-settle@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-settle/-/async-settle-1.0.0.tgz#1d0a914bb02575bec8a8f3a74e5080f72b2c0c6b" + integrity sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs= + dependencies: + async-done "^1.2.2" + +async@1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= -atob@^2.1.1: +async@^2.6.2: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + +atob@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -autoprefixer@^9.7.3: - version "9.7.3" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.3.tgz#fd42ed03f53de9beb4ca0d61fb4f7268a9bb50b4" - integrity sha512-8T5Y1C5Iyj6PgkPSFd0ODvK9DIleuPKUPYniNxybS47g2k2wFgLZ46lGQHlBuGKIAEV8fbCDfKCCRS1tvOgc3Q== +autoprefixer@^9.0.0, autoprefixer@^9.6.1, autoprefixer@^9.7.6: + version "9.7.6" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.6.tgz#63ac5bbc0ce7934e6997207d5bb00d68fa8293a4" + integrity sha512-F7cYpbN7uVVhACZTeeIeealwdGM6wMtfWARVLTy5xmKtgVdBNJvbDRoCK3YO1orcs7gv/KwYlb3iXwu9Ug9BkQ== dependencies: - browserslist "^4.8.0" - caniuse-lite "^1.0.30001012" + browserslist "^4.11.1" + caniuse-lite "^1.0.30001039" chalk "^2.4.2" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.23" - postcss-value-parser "^4.0.2" + postcss "^7.0.27" + postcss-value-parser "^4.0.3" + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + +aws4@^1.8.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" + integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== + +axios@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" + integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + +babel-loader@^8.0.6: + version "8.1.0" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.1.0.tgz#c611d5112bd5209abe8b9fa84c3e4da25275f1c3" + integrity sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw== + dependencies: + find-cache-dir "^2.1.0" + loader-utils "^1.4.0" + mkdirp "^0.5.3" + pify "^4.0.1" + schema-utils "^2.6.5" + +babel-plugin-dynamic-import-node@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + +bach@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" + integrity sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA= + dependencies: + arr-filter "^1.1.1" + arr-flatten "^1.0.1" + arr-map "^2.0.0" + array-each "^1.0.0" + array-initial "^1.0.0" + array-last "^1.1.1" + async-done "^1.2.2" + async-settle "^1.0.0" + now-and-later "^2.0.0" + +backo2@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" + integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= + +bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== balanced-match@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base64-arraybuffer@0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" + integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= + base64-js@^1.0.2: version "1.3.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64id@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" + integrity sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY= + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -502,25 +1673,114 @@ batch@0.6.1: resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY= -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + +beeper@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" + integrity sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak= + +better-assert@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522" + integrity sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI= + dependencies: + callsite "1.0.0" big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +bin-build@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bin-build/-/bin-build-3.0.0.tgz#c5780a25a8a9f966d8244217e6c1f5082a143861" + integrity sha512-jcUOof71/TNAI2uM5uoUaDq2ePcVBQ3R/qhxAz1rX7UfvduAL/RXD3jXzvn8cVcDJdGVkiR1shal3OH0ImpuhA== + dependencies: + decompress "^4.0.0" + download "^6.2.2" + execa "^0.7.0" + p-map-series "^1.0.0" + tempfile "^2.0.0" + +bin-check@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bin-check/-/bin-check-4.1.0.tgz#fc495970bdc88bb1d5a35fc17e65c4a149fc4a49" + integrity sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA== + dependencies: + execa "^0.7.0" + executable "^4.1.0" + +bin-version-check@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/bin-version-check/-/bin-version-check-4.0.0.tgz#7d819c62496991f80d893e6e02a3032361608f71" + integrity sha512-sR631OrhC+1f8Cvs8WyVWOA33Y8tgwjETNPyyD/myRBXLkfS/vl74FmH/lFcRl9KY3zwGh7jFhvyk9vV3/3ilQ== + dependencies: + bin-version "^3.0.0" + semver "^5.6.0" + semver-truncate "^1.1.2" + +bin-version@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/bin-version/-/bin-version-3.1.0.tgz#5b09eb280752b1bd28f0c9db3f96f2f43b6c0839" + integrity sha512-Mkfm4iE1VFt4xd4vH+gx+0/71esbfus2LsnCGe8Pi4mndSPyT+NGES/Eg99jx8/lUGWfu3z2yuB/bt5UB+iVbQ== + dependencies: + execa "^1.0.0" + find-versions "^3.0.0" + +bin-wrapper@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bin-wrapper/-/bin-wrapper-4.1.0.tgz#99348f2cf85031e3ef7efce7e5300aeaae960605" + integrity sha512-hfRmo7hWIXPkbpi0ZltboCMVrU+0ClXR/JgbCKKjlDjQf6igXa7OwdqNcFWQZPZTgiY7ZpzE3+LjjkLiTN2T7Q== + dependencies: + bin-check "^4.1.0" + bin-version-check "^4.0.0" + download "^7.1.0" + import-lazy "^3.1.0" + os-filter-obj "^2.0.0" + pify "^4.0.1" + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +blob@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.5.tgz#d680eeef25f8cd91ad533f5b01eed48e64caf683" + integrity sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig== + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo= + dependencies: + inherits "~2.0.0" + bluebird@^3.5.5: - version "3.5.5" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f" - integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w== + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.8" @@ -555,7 +1815,7 @@ bonjour@^3.5.0: multicast-dns "^6.0.1" multicast-dns-service-types "^1.1.0" -boolbase@~1.0.0: +boolbase@^1.0.0, boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= @@ -584,11 +1844,76 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +braces@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + brorand@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= +browser-sync-client@^2.26.6: + version "2.26.6" + resolved "https://registry.yarnpkg.com/browser-sync-client/-/browser-sync-client-2.26.6.tgz#e5201d3ace8aee88af17656b7b0c0620b6f8e4ab" + integrity sha512-mGrkZdNzttKdf/16I+y+2dTQxoMCIpKbVIMJ/uP8ZpnKu9f9qa/2CYVtLtbjZG8nsM14EwiCrjuFTGBEnT3Gjw== + dependencies: + etag "1.8.1" + fresh "0.5.2" + mitt "^1.1.3" + rxjs "^5.5.6" + +browser-sync-ui@^2.26.4: + version "2.26.4" + resolved "https://registry.yarnpkg.com/browser-sync-ui/-/browser-sync-ui-2.26.4.tgz#3772f13c6b93f2d7d333f4be0ca1ec02aae97dba" + integrity sha512-u20P3EsZoM8Pt+puoi3BU3KlbQAH1lAcV+/O4saF26qokrBqIDotmGonfWwoRbUmdxZkM9MBmA0K39ZTG1h4sA== + dependencies: + async-each-series "0.1.1" + connect-history-api-fallback "^1" + immutable "^3" + server-destroy "1.0.1" + socket.io-client "^2.0.4" + stream-throttle "^0.1.3" + +browser-sync@^2.26.7: + version "2.26.7" + resolved "https://registry.yarnpkg.com/browser-sync/-/browser-sync-2.26.7.tgz#120287716eb405651a76cc74fe851c31350557f9" + integrity sha512-lY3emme0OyvA2ujEMpRmyRy9LY6gHLuTr2/ABxhIm3lADOiRXzP4dgekvnDrQqZ/Ec2Fz19lEjm6kglSG5766w== + dependencies: + browser-sync-client "^2.26.6" + browser-sync-ui "^2.26.4" + bs-recipes "1.3.4" + bs-snippet-injector "^2.0.1" + chokidar "^2.0.4" + connect "3.6.6" + connect-history-api-fallback "^1" + dev-ip "^1.0.1" + easy-extender "^2.3.4" + eazy-logger "^3" + etag "^1.8.1" + fresh "^0.5.2" + fs-extra "3.0.1" + http-proxy "1.15.2" + immutable "^3" + localtunnel "1.9.2" + micromatch "^3.1.10" + opn "5.3.0" + portscanner "2.1.1" + qs "6.2.3" + raw-body "^2.3.2" + resp-modifier "6.0.2" + rx "4.1.0" + send "0.16.2" + serve-index "1.9.1" + serve-static "1.13.2" + server-destroy "1.0.1" + socket.io "2.1.1" + ua-parser-js "0.7.17" + yargs "6.4.0" + browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -648,14 +1973,71 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.8.0: - version "4.8.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289" - integrity sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA== +browserslist@^1.1.3: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + integrity sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk= dependencies: - caniuse-lite "^1.0.30001015" - electron-to-chromium "^1.3.322" - node-releases "^1.1.42" + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^4.0.0, browserslist@^4.6.4: + version "4.11.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.11.0.tgz#aef4357b10a8abda00f97aac7cd587b2082ba1ad" + integrity sha512-WqEC7Yr5wUH5sg6ruR++v2SGOQYpyUdYYd4tZoAq1F7y+QXoLoYGXVbxhtaIqWmAJjtNTRjVD3HuJc1OXTel2A== + dependencies: + caniuse-lite "^1.0.30001035" + electron-to-chromium "^1.3.380" + node-releases "^1.1.52" + pkg-up "^3.1.0" + +browserslist@^4.11.1, browserslist@^4.8.2, browserslist@^4.8.5: + version "4.12.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.12.0.tgz#06c6d5715a1ede6c51fc39ff67fd647f740b656d" + integrity sha512-UH2GkcEDSI0k/lRkuDSzFl9ZZ87skSy9w2XAn1MsZnL+4c4rqbBd3e82UWHbYDpztABrPBhZsTEeuxVfHppqDg== + dependencies: + caniuse-lite "^1.0.30001043" + electron-to-chromium "^1.3.413" + node-releases "^1.1.53" + pkg-up "^2.0.0" + +bs-recipes@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/bs-recipes/-/bs-recipes-1.3.4.tgz#0d2d4d48a718c8c044769fdc4f89592dc8b69585" + integrity sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU= + +bs-snippet-injector@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz#61b5393f11f52559ed120693100343b6edb04dd5" + integrity sha1-YbU5PxH1JVntEgaTEANDtu2wTdU= + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + +buffer-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-1.0.0.tgz#59616b498304d556abd466966b22eeda3eca5fbe" + integrity sha1-WWFrSYME1Var1GaWayLu2j7KX74= + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= buffer-from@^1.0.0: version "1.1.1" @@ -673,14 +2055,22 @@ buffer-xor@^1.0.3: integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== dependencies: base64-js "^1.0.2" ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.2.1: + version "5.6.0" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786" + integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -696,31 +2086,10 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== -cacache@^12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c" - integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg== - dependencies: - bluebird "^3.5.5" - chownr "^1.1.1" - figgy-pudding "^3.5.1" - glob "^7.1.4" - graceful-fs "^4.1.15" - infer-owner "^1.0.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - mkdirp "^0.5.1" - move-concurrently "^1.0.1" - promise-inflight "^1.0.1" - rimraf "^2.6.3" - ssri "^6.0.1" - unique-filename "^1.1.1" - y18n "^4.0.0" - -cacache@^12.0.3: - version "12.0.3" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" - integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== +cacache@^12.0.2, cacache@^12.0.3: + version "12.0.4" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" + integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== dependencies: bluebird "^3.5.5" chownr "^1.1.1" @@ -753,6 +2122,19 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + call-me-maybe@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" @@ -772,6 +2154,11 @@ caller-path@^2.0.0: dependencies: caller-callsite "^2.0.0" +callsite@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" + integrity sha1-KAOY5dZkvXQDi28JBRU+borxvCA= + callsites@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" @@ -790,17 +2177,111 @@ camel-case@3.0.x: no-case "^2.2.0" upper-case "^1.1.1" -camelcase@^5.0.0, camelcase@^5.2.0: +camel-case@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" + integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== + dependencies: + pascal-case "^3.1.1" + tslib "^1.10.0" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase-keys@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" + integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= + dependencies: + camelcase "^4.1.0" + map-obj "^2.0.0" + quick-lru "^1.0.0" + +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= + +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001012, caniuse-lite@^1.0.30001015: - version "1.0.30001017" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001017.tgz#d3ad6ec18148b9bd991829958d9d7e562bb78cd6" - integrity sha512-EDnZyOJ6eYh6lHmCvCdHAFbfV4KJ9lSdfv4h/ppEhrU/Yudkl7jujwMZ1we6RX7DXqBfT04pVMQ4J+1wcTlsKA== +caniuse-api@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== + dependencies: + browserslist "^4.0.0" + caniuse-lite "^1.0.0" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" -chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: +caniuse-db@^1.0.30000639: + version "1.0.30001036" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001036.tgz#8761fb6cd423ef2d3f8d96a21d898932252dc477" + integrity sha512-plRkihXQyiDaFUXC7x/jAIXXTKiiaWvfAagsruh/vmstnRQ+a2a95HyENxiTr5WrkPSvmFUIvsRUalVFyeh2/w== + +caniuse-db@^1.0.30001017: + version "1.0.30001039" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30001039.tgz#b5e8c3bb07a144341644729fa2a5eb2c0deaf47d" + integrity sha512-XVk5KMAi8/DI28tQXKuq1PDyuPoD9Ypnda3ctF04TlB+LYIb+bgHq0ZDfNOn0+4cwLENJC0093Vuf0dhkjXQ7Q== + +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30001039, caniuse-lite@^1.0.30001043: + version "1.0.30001050" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001050.tgz#11218af4b6b85dc1089536f31e10e3181e849e71" + integrity sha512-OvGZqalCwmapci76ISq5q4kuAskb1ebqF3FEQBv1LE1kWht0pojlDDqzFlmk5jgYkuZN7MNZ1n+ULwe/7MaDNQ== + +caniuse-lite@^1.0.30001035: + version "1.0.30001036" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001036.tgz#930ea5272010d8bf190d859159d757c0b398caf0" + integrity sha512-jU8CIFIj2oR7r4W+5AKcsvWNVIb6Q6OZE3UsrXrZBHFtreT4YgTeOJtTucp+zSedEpTi3L5wASSP0LYIE3if6w== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + +caw@^2.0.0, caw@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/caw/-/caw-2.0.1.tgz#6c3ca071fc194720883c2dc5da9b074bfc7e9e95" + integrity sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA== + dependencies: + get-proxy "^2.0.0" + isurl "^1.0.0-alpha5" + tunnel-agent "^0.6.0" + url-to-options "^1.0.1" + +ccount@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.5.tgz#ac82a944905a65ce204eb03023157edf29425c17" + integrity sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw== + +chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -809,31 +2290,59 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.0.0.tgz#6e98081ed2d17faab615eb52ac66ec1fe6209e72" + integrity sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +character-entities-html4@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-1.1.4.tgz#0e64b0a3753ddbf1fdc044c5fd01d0199a02e125" + integrity sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g== + +character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + +character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + +character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chokidar@^2.0.2: - version "2.1.6" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" - integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== - dependencies: - anymatch "^2.0.0" - async-each "^1.0.1" - braces "^2.3.2" - glob-parent "^3.1.0" - inherits "^2.0.3" - is-binary-path "^1.0.0" - is-glob "^4.0.0" - normalize-path "^3.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.2.1" - upath "^1.1.1" - optionalDependencies: - fsevents "^1.2.7" - -chokidar@^2.1.8: +chokidar@^2.0.0, chokidar@^2.0.4, chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== @@ -853,9 +2362,9 @@ chokidar@^2.1.8: fsevents "^1.2.7" chownr@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6" - integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A== + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chrome-trace-event@^1.0.2: version "1.0.2" @@ -882,13 +2391,22 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -clean-css@4.2.x: - version "4.2.1" - resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" - integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g== +"classlist.js@https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz": + version "1.2.20180112" + resolved "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz#9c7ab3ccdbde5c940f6f26f8fc59bfb6bc813bc4" + +clean-css@4.2.x, clean-css@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78" + integrity sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA== dependencies: source-map "~0.6.0" +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + clean-webpack-plugin@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" @@ -897,17 +2415,26 @@ clean-webpack-plugin@^3.0.0: "@types/webpack" "^4.4.31" del "^4.1.1" -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: - restore-cursor "^2.0.0" + restore-cursor "^3.1.0" cli-width@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" - integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= + version "2.2.1" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" + integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" cliui@^4.0.0: version "4.1.0" @@ -927,11 +2454,90 @@ cliui@^5.0.0: strip-ansi "^5.2.0" wrap-ansi "^5.1.0" +clone-buffer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha1-4+JbIHrE5wGvch4staFnksrD3Fg= + +clone-regexp@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.1.tgz#051805cd33173375d82118fc0918606da39fd60f" + integrity sha512-Fcij9IwRW27XedRIJnSOEupS7RVcXtObJXbcUOX93UCLqqOdRpkvzKywOOSizmEK/Is3S/RHX9dLdfo6R1Q1mw== + dependencies: + is-regexp "^1.0.0" + is-supported-regexp-flag "^1.0.0" + +clone-regexp@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f" + integrity sha512-beMpP7BOtTipFuW8hrJvREQ2DrRu3BE7by0ZpibtfBA+qfHYvMGTc2Yb1JMYPKg/JUw0CHYvpg796aNTSW9z7Q== + dependencies: + is-regexp "^2.0.0" + +clone-response@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + +clone-stats@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-0.0.1.tgz#b88f94a82cf38b8791d58046ea4029ad88ca99d1" + integrity sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE= + +clone-stats@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-stats/-/clone-stats-1.0.0.tgz#b3782dff8bb5474e18b9b6bf0fdfe782f8777680" + integrity sha1-s3gt/4u1R04Yuba/D9/ngvh3doA= + +clone@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" + integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= + +clone@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + +cloneable-readable@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.1.3.tgz#120a00cb053bfb63a222e709f9683ea2e11d8cec" + integrity sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ== + dependencies: + inherits "^2.0.1" + process-nextick-args "^2.0.0" + readable-stream "^2.3.5" + +coa@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3" + integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA== + dependencies: + "@types/q" "^1.5.1" + chalk "^2.4.1" + q "^1.1.2" + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +collapse-white-space@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.6.tgz#e63629c0016665792060dbbeb79c42239d2c5287" + integrity sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ== + +collection-map@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-map/-/collection-map-1.0.0.tgz#aea0f06f8d26c780c2b75494385544b2255af18c" + integrity sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw= + dependencies: + arr-map "^2.0.2" + for-own "^1.0.0" + make-iterator "^1.0.0" + collection-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" @@ -940,27 +2546,72 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0: +color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color-support@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + +color@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.2.tgz#68148e7f85d41ad7649c5fa8c8106f098d229e10" + integrity sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@2.17.x: version "2.17.1" resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf" integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg== -commander@^2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" - integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== +commander@^2.2.0, commander@^2.20.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +commander@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== commander@~2.13.0: version "2.13.0" @@ -972,22 +2623,44 @@ commander@~2.19.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@~2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +component-bind@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" + integrity sha1-AMYIq33Nk4l8AAllGx06jh5zu9E= + +component-emitter@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" + integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +component-inherit@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" + integrity sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM= + compressible@~2.0.16: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== dependencies: - mime-db ">= 1.40.0 < 2" + mime-db ">= 1.43.0 < 2" compression@^1.7.4: version "1.7.4" @@ -1007,7 +2680,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@^1.5.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -1017,36 +2690,62 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concat-with-sourcemaps@^1.0.5: +concat-with-sourcemaps@^1.0.0, concat-with-sourcemaps@^1.0.5: version "1.1.0" resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== dependencies: source-map "^0.6.1" -connect-history-api-fallback@^1.6.0: +config-chain@^1.1.11: + version "1.1.12" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa" + integrity sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA== + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +connect-history-api-fallback@^1, connect-history-api-fallback@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc" integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg== -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= +connect@3.6.6: + version "3.6.6" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.6.tgz#09eff6c55af7236e137135a72574858b6786f524" + integrity sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ= dependencies: - date-now "^0.1.4" + debug "2.6.9" + finalhandler "1.1.0" + parseurl "~1.3.2" + utils-merge "1.0.1" + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= +console-stream@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/console-stream/-/console-stream-0.1.1.tgz#a095fe07b20465955f2fafd28b5d72bccd949d44" + integrity sha1-oJX+B7IEZZVfL6/Si11yvM2UnUQ= + constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -content-disposition@0.5.3: +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + integrity sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo= + +content-disposition@0.5.3, content-disposition@^0.5.2: version "0.5.3" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== @@ -1058,11 +2757,23 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== +convert-source-map@1.X, convert-source-map@^1.5.0, convert-source-map@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + cookie-signature@1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + cookie@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" @@ -1085,6 +2796,14 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= +copy-props@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.4.tgz#93bb1cadfafd31da5bb8a9d4b41f471ec3a72dfe" + integrity sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== + dependencies: + each-props "^1.3.0" + is-plain-object "^2.0.1" + copy-webpack-plugin@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88" @@ -1103,7 +2822,25 @@ copy-webpack-plugin@^5.1.1: serialize-javascript "^2.1.2" webpack-log "^2.0.0" -core-util-is@~1.0.0: +core-js-compat@^3.6.2: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" + integrity sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng== + dependencies: + browserslist "^4.8.5" + semver "7.0.0" + +core-js@^2.6.5: + version "2.6.11" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.11.tgz#38831469f9922bded8ee21c9dc46985e0399308c" + integrity sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg== + +core-js@^3.6.5: + version "3.6.5" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" + integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== + +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -1118,6 +2855,17 @@ cosmiconfig@^5.0.0: js-yaml "^3.13.1" parse-json "^4.0.0" +cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -1160,6 +2908,23 @@ cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI= + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -1177,22 +2942,64 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -css-loader@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" - integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== +css-blank-pseudo@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" + integrity sha512-LHz35Hr83dnFeipc7oqFDmsjHdljj3TQtxGGiNWSOsTLIAubSm4TEz8qCaKFpk7idaQ1GfWscF4E6mgpBysA1w== dependencies: - camelcase "^5.2.0" - icss-utils "^4.1.0" + postcss "^7.0.5" + +css-color-names@0.0.4, css-color-names@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + integrity sha1-gIrcLnnPhHOAabZGyyDsJ762KeA= + +css-declaration-sorter@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz#c198940f63a76d7e36c1e71018b001721054cb22" + integrity sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA== + dependencies: + postcss "^7.0.1" + timsort "^0.3.0" + +css-has-pseudo@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-0.10.0.tgz#3c642ab34ca242c59c41a125df9105841f6966ee" + integrity sha512-Z8hnfsZu4o/kt+AuFzeGpLVhFOGO9mluyHBaA2bA8aCGTwah5sT3WV/fTHH8UNZUytOIImuGPrl/prlb4oX4qQ== + dependencies: + postcss "^7.0.6" + postcss-selector-parser "^5.0.0-rc.4" + +css-loader@^3.4.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.5.3.tgz#95ac16468e1adcd95c844729e0bb167639eb0bcf" + integrity sha512-UEr9NH5Lmi7+dguAm+/JSPovNjYbm2k3TK58EiwQHzOHH5Jfq1Y+XoP2bQO6TMn7PptMd0opxxedAWcaSTRKHw== + dependencies: + camelcase "^5.3.1" + cssesc "^3.0.0" + icss-utils "^4.1.1" loader-utils "^1.2.3" normalize-path "^3.0.0" - postcss "^7.0.14" + postcss "^7.0.27" postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^2.0.6" - postcss-modules-scope "^2.1.0" - postcss-modules-values "^2.0.0" - postcss-value-parser "^3.3.0" - schema-utils "^1.0.0" + postcss-modules-local-by-default "^3.0.2" + postcss-modules-scope "^2.2.0" + postcss-modules-values "^3.0.0" + postcss-value-parser "^4.0.3" + schema-utils "^2.6.6" + semver "^6.3.0" + +css-prefers-color-scheme@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" + integrity sha512-MTu6+tMs9S3EUqzmqLXEcgNRbNkkD/TGFvowpeoWJn5Vfq7FMgsmRQs9X5NXAURiOBmOxm/lLjsDNXDE6k9bhg== + dependencies: + postcss "^7.0.5" + +css-select-base-adapter@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7" + integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w== css-select@^1.1.0: version "1.2.0" @@ -1204,48 +3011,225 @@ css-select@^1.1.0: domutils "1.5.1" nth-check "~1.0.1" +css-select@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef" + integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ== + dependencies: + boolbase "^1.0.0" + css-what "^3.2.1" + domutils "^1.7.0" + nth-check "^1.0.2" + +css-tree@1.0.0-alpha.37: + version "1.0.0-alpha.37" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22" + integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg== + dependencies: + mdn-data "2.0.4" + source-map "^0.6.1" + +css-tree@1.0.0-alpha.39: + version "1.0.0-alpha.39" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" + integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== + dependencies: + mdn-data "2.0.6" + source-map "^0.6.1" + css-what@2.1: version "2.1.3" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== +css-what@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.2.1.tgz#f4a8f12421064621b456755e34a03a2c22df5da1" + integrity sha512-WwOrosiQTvyms+Ti5ZC5vGEK0Vod3FTt1ca+payZqvKuGJF+dq7bG63DstxtN0dpm6FxY27a/zS3Wten+gEtGw== + +css@2.X, css@^2.2.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +cssdb@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-4.4.0.tgz#3bf2f2a68c10f5c6a08abd92378331ee803cddb0" + integrity sha512-LsTAR1JPEM9TpGhl/0p3nQecC2LJ0kD8X5YARu1hk/9I1gril5vDtMZyNxcEpxxDj34YNck/ucjuoUd66K03oQ== + +cssesc@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703" + integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg== + cssesc@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cyclist@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" - integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= +cssnano-preset-default@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz#51ec662ccfca0f88b396dcd9679cdb931be17f76" + integrity sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA== + dependencies: + css-declaration-sorter "^4.0.1" + cssnano-util-raw-cache "^4.0.1" + postcss "^7.0.0" + postcss-calc "^7.0.1" + postcss-colormin "^4.0.3" + postcss-convert-values "^4.0.1" + postcss-discard-comments "^4.0.2" + postcss-discard-duplicates "^4.0.2" + postcss-discard-empty "^4.0.1" + postcss-discard-overridden "^4.0.1" + postcss-merge-longhand "^4.0.11" + postcss-merge-rules "^4.0.3" + postcss-minify-font-values "^4.0.2" + postcss-minify-gradients "^4.0.2" + postcss-minify-params "^4.0.2" + postcss-minify-selectors "^4.0.2" + postcss-normalize-charset "^4.0.1" + postcss-normalize-display-values "^4.0.2" + postcss-normalize-positions "^4.0.2" + postcss-normalize-repeat-style "^4.0.2" + postcss-normalize-string "^4.0.2" + postcss-normalize-timing-functions "^4.0.2" + postcss-normalize-unicode "^4.0.1" + postcss-normalize-url "^4.0.1" + postcss-normalize-whitespace "^4.0.2" + postcss-ordered-values "^4.1.2" + postcss-reduce-initial "^4.0.3" + postcss-reduce-transforms "^4.0.2" + postcss-svgo "^4.0.2" + postcss-unique-selectors "^4.0.1" -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= +cssnano-util-get-arguments@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz#ed3a08299f21d75741b20f3b81f194ed49cc150f" + integrity sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8= -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +cssnano-util-get-match@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz#c0e4ca07f5386bb17ec5e52250b4f5961365156d" + integrity sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0= + +cssnano-util-raw-cache@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz#b26d5fd5f72a11dfe7a7846fb4c67260f96bf282" + integrity sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA== + dependencies: + postcss "^7.0.0" + +cssnano-util-same-parent@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz#574082fb2859d2db433855835d9a8456ea18bbf3" + integrity sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q== + +cssnano@^4.1.10: + version "4.1.10" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-4.1.10.tgz#0ac41f0b13d13d465487e111b778d42da631b8b2" + integrity sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ== + dependencies: + cosmiconfig "^5.0.0" + cssnano-preset-default "^4.0.7" + is-resolvable "^1.0.0" + postcss "^7.0.0" + +csso@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/csso/-/csso-4.0.3.tgz#0d9985dc852c7cc2b2cacfbbe1079014d1a8e903" + integrity sha512-NL3spysxUkcrOgnpsT4Xdl2aiEiBG6bXswAABQVHcMrfjjBisFOKwLDOmf4wf32aPdcJws1zds2B0Rg+jqMyHQ== + dependencies: + css-tree "1.0.0-alpha.39" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= + dependencies: + array-find-index "^1.0.1" + +cyclist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + +date-fns@^2.13.0: + version "2.13.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.13.0.tgz#d7b8a0a2d392e8d88a8024d0a46b980bbfdbd708" + integrity sha512-xm0c61mevGF7f0XpCGtDTGpzEFC/1fpLXHbmFpxZZQJuvByIK2ozm6cSYuU+nxFYOPh2EuCfzUwlTEFwKG+h5w== + +dateformat@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" + integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= + +debug-fabulous@1.X: + version "1.1.0" + resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" + integrity sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg== + dependencies: + debug "3.X" + memoizee "0.4.X" + object-assign "4.X" + +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.0.0, debug@^3.2.5, debug@^3.2.6: +debug@3.X, debug@^3.0.0, debug@^3.1.1, debug@^3.2.5: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@4.1.1, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" -decamelize@^1.2.0: +debug@=3.1.0, debug@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + +decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -1255,10 +3239,70 @@ decode-uri-component@^0.2.0: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + +decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + +decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + +decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + +decompress@^4.0.0, decompress@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + deep-equal@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.0.tgz#3103cdf8ab6d32cf4a8df7865458f2b8d33f3745" - integrity sha512-ZbfWJq/wN1Z273o7mUSjILYqehAktR2NVoSrOukDkU9kg2v/Uv89yU4Cvz8seJeAmtN5oqiefKq8FPuXOboqLw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" + integrity sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g== dependencies: is-arguments "^1.0.4" is-date-object "^1.0.1" @@ -1267,16 +3311,18 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" -deep-extend@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" - integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== - deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-gateway@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b" @@ -1285,6 +3331,11 @@ default-gateway@^4.2.0: execa "^1.0.0" ip-regex "^2.1.0" +default-resolution@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/default-resolution/-/default-resolution-2.0.0.tgz#bcb82baa72ad79b426a76732f1a81ad6df26d684" + integrity sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ= + define-properties@^1.1.2, define-properties@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1327,6 +3378,25 @@ del@^4.1.1: pify "^4.0.1" rimraf "^2.6.3" +del@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" + integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== + dependencies: + globby "^10.0.1" + graceful-fs "^4.2.2" + is-glob "^4.0.1" + is-path-cwd "^2.2.0" + is-path-inside "^3.0.1" + p-map "^3.0.0" + rimraf "^3.0.0" + slash "^3.0.0" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -1338,9 +3408,9 @@ depd@~1.1.2: integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" @@ -1355,16 +3425,21 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-libc@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" - integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-newline@2.X: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= detect-node@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c" integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw== +dev-ip@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dev-ip/-/dev-ip-1.0.1.tgz#a76a3ed1855be7a012bb8ac16cb80f3c00dc28f0" + integrity sha1-p2o+0YVb56ASu4rBbLgPPADcKPA= + diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" @@ -1382,13 +3457,20 @@ dir-glob@2.0.0: arrify "^1.0.1" path-type "^3.0.0" -dir-glob@^2.0.0: +dir-glob@^2.0.0, dir-glob@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== dependencies: path-type "^3.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dns-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" @@ -1409,6 +3491,14 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + integrity sha1-N53Ocw9hZvds76TmcHoVmwLFpvo= + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + doctrine@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" @@ -1416,10 +3506,12 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -document-register-element@^0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/document-register-element/-/document-register-element-0.5.4.tgz#df6b57fbb8e141123e5f61acf382d6bb78c02bce" - integrity sha1-32tX+7jhQRI+X2Gs84LWu3jAK84= +document-register-element@^1.14.3: + version "1.14.3" + resolved "https://registry.yarnpkg.com/document-register-element/-/document-register-element-1.14.3.tgz#3335d4578df6a1536a34595b91cca36dd5db61d7" + integrity sha512-SbJTzoQXLTcYxnpdDNRZXu/gwsGSShemXpvj6Pa6ujRwJFpJ41siil4tk4y+cQXnqylS6mc2Rtxp/PkMzfkqyQ== + dependencies: + lightercollective "^0.3.0" dom-converter@^0.2: version "0.2.0" @@ -1436,6 +3528,13 @@ dom-serializer@0: domelementtype "^2.0.1" entities "^2.0.0" +dom7@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/dom7/-/dom7-2.1.3.tgz#a736f9c3bfbc4ca039a81cd095f97d1d7f3de19c" + integrity sha512-QTxHHDox+M6ZFz1zHPAHZKI3JOHY5iY4i9BK2uctlggxKQwRhO3q3HHFq1BKsT25Bm/ySSj70K6Wk/G4bs9rMQ== + dependencies: + ssr-window "^1.0.1" + domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" @@ -1466,7 +3565,7 @@ domutils@1.5.1: dom-serializer "0" domelementtype "1" -domutils@^1.5.1: +domutils@^1.5.1, domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== @@ -1474,6 +3573,73 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +dot-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" + integrity sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + +dot-prop@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb" + integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A== + dependencies: + is-obj "^2.0.0" + +download@^6.2.2: + version "6.2.5" + resolved "https://registry.yarnpkg.com/download/-/download-6.2.5.tgz#acd6a542e4cd0bb42ca70cfc98c9e43b07039714" + integrity sha512-DpO9K1sXAST8Cpzb7kmEhogJxymyVUd5qz/vCOSyvwtp2Klj2XcDt5YUuasgxka44SxF0q5RriKIwJmQHG2AuA== + dependencies: + caw "^2.0.0" + content-disposition "^0.5.2" + decompress "^4.0.0" + ext-name "^5.0.0" + file-type "5.2.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^7.0.0" + make-dir "^1.0.0" + p-event "^1.0.0" + pify "^3.0.0" + +download@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/download/-/download-7.1.0.tgz#9059aa9d70b503ee76a132897be6dec8e5587233" + integrity sha512-xqnBTVd/E+GxJVrX5/eUJiLYjCGPwMpdL+jGhGU57BvtcA7wwhtHVbXBeUk51kOpW3S7Jn3BQbN9Q1R1Km2qDQ== + dependencies: + archive-type "^4.0.0" + caw "^2.0.1" + content-disposition "^0.5.2" + decompress "^4.2.0" + ext-name "^5.0.0" + file-type "^8.1.0" + filenamify "^2.0.0" + get-stream "^3.0.0" + got "^8.3.1" + make-dir "^1.2.0" + p-event "^2.1.0" + pify "^3.0.0" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + integrity sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds= + dependencies: + readable-stream "~1.1.9" + +duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + +duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= + duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" @@ -1484,20 +3650,65 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +duplexify@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.1.tgz#7027dc374f157b122a8ae08c2d3ea4d2d953aa61" + integrity sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA== + dependencies: + end-of-stream "^1.4.1" + inherits "^2.0.3" + readable-stream "^3.1.1" + stream-shift "^1.0.0" + +each-props@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" + integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== + dependencies: + is-plain-object "^2.0.1" + object.defaults "^1.1.0" + +easy-extender@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/easy-extender/-/easy-extender-2.3.4.tgz#298789b64f9aaba62169c77a2b3b64b4c9589b8f" + integrity sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q== + dependencies: + lodash "^4.17.10" + +eazy-logger@^3: + version "3.0.2" + resolved "https://registry.yarnpkg.com/eazy-logger/-/eazy-logger-3.0.2.tgz#a325aa5e53d13a2225889b2ac4113b2b9636f4fc" + integrity sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw= + dependencies: + tfunk "^3.0.1" + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -electron-to-chromium@^1.3.322: - version "1.3.322" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8" - integrity sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA== +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.413: + version "1.3.427" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.427.tgz#ea43d02908a8c71f47ebb46e09de5a3cf8236f04" + integrity sha512-/rG5G7Opcw68/Yrb4qYkz07h3bESVRJjUl4X/FrKLXzoUJleKm6D7K7rTTz8V5LUWnd+BbTOyxJX2XprRqHD8A== + +electron-to-chromium@^1.3.380: + version "1.3.430" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.430.tgz#33914f7c2db771bdcf30977bd4fd6258ee8a2f37" + integrity sha512-HMDYkANGhx6vfbqpOf/hc6hWEmiOipOHGDeRDeUb3HLD3XIWpvKQxFgWf0tgHcr3aNv6I/8VPecplqmQsXoZSw== elliptic@^6.0.0: - version "6.5.0" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca" - integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg== + version "6.5.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762" + integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw== dependencies: bn.js "^4.4.0" brorand "^1.0.1" @@ -1507,29 +3718,112 @@ elliptic@^6.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.0" +eme-encryption-scheme-polyfill@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eme-encryption-scheme-polyfill/-/eme-encryption-scheme-polyfill-2.0.1.tgz#b080b01bffd74c75c9cf8044c1cabedf3b83954f" + integrity sha512-Wz+Ro1c0/2Wsx2RLFvTOO0m4LvYn+7cSnq3XOvRvLLBq8jbvUACH/zpU9s0/5+mQa5oaelkU69x+q0z/iWYrFA== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= -encodeurl@~1.0.2: +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +encodeurl@~1.0.1, encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" - integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" -enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: +engine.io-client@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36" + integrity sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~3.1.0" + engine.io-parser "~2.1.1" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~3.3.1" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-client@~3.4.0: + version "3.4.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.4.1.tgz#922ddb47eecdcb541136a93aeead24718fd05461" + integrity sha512-RJNmA+A9Js+8Aoq815xpGAsgWH1VoSYM//2VgIiu9lNOaHFfLpTjH4tOzktBpjIs5lvOfiNY1dwf+NuU6D38Mw== + dependencies: + component-emitter "1.2.1" + component-inherit "0.0.3" + debug "~4.1.0" + engine.io-parser "~2.2.0" + has-cors "1.1.0" + indexof "0.0.1" + parseqs "0.0.5" + parseuri "0.0.5" + ws "~6.1.0" + xmlhttprequest-ssl "~1.5.4" + yeast "0.1.2" + +engine.io-parser@~2.1.0, engine.io-parser@~2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.3.tgz#757ab970fbf2dfb32c7b74b033216d5739ef79a6" + integrity sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io-parser@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.2.0.tgz#312c4894f57d52a02b420868da7b5c1c84af80ed" + integrity sha512-6I3qD9iUxotsC5HEMuuGsKA0cXerGz+4uGcXQEkfBidgKf0amsjrrtwcbwK/nzpZBxclXlV7gGl9dgWvu4LF6w== + dependencies: + after "0.8.2" + arraybuffer.slice "~0.0.7" + base64-arraybuffer "0.1.5" + blob "0.0.5" + has-binary2 "~1.0.2" + +engine.io@~3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.1.tgz#b60281c35484a70ee0351ea0ebff83ec8c9522a2" + integrity sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w== + dependencies: + accepts "~1.3.4" + base64id "1.0.0" + cookie "0.3.1" + debug "~3.1.0" + engine.io-parser "~2.1.0" + ws "~3.3.1" + +enhanced-resolve@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f" integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng== @@ -1538,6 +3832,15 @@ enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0: memory-fs "^0.4.0" tapable "^1.0.0" +enhanced-resolve@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" + integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.5.0" + tapable "^1.0.0" + entities@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" @@ -1555,28 +3858,29 @@ errno@^0.1.3, errno@~0.1.7: dependencies: prr "~1.0.1" -error-ex@^1.3.1: +error-ex@^1.2.0, error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.5.1: - version "1.16.2" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.2.tgz#4e874331645e9925edef141e74fc4bd144669d34" - integrity sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA== +es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: + version "1.17.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" + integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== dependencies: es-to-primitive "^1.2.1" function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" - is-callable "^1.1.4" - is-regex "^1.0.4" + is-callable "^1.1.5" + is-regex "^1.0.5" object-inspect "^1.7.0" object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" + object.assign "^4.1.0" + string.prototype.trimleft "^2.1.1" + string.prototype.trimright "^2.1.1" es-to-primitive@^1.2.1: version "1.2.1" @@ -1587,21 +3891,122 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.53" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.53.tgz#93c5a3acfdbef275220ad72644ad02ee18368de1" + integrity sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q== + dependencies: + es6-iterator "~2.0.3" + es6-symbol "~3.1.3" + next-tick "~1.0.0" + +es6-iterator@^2.0.1, es6-iterator@^2.0.3, es6-iterator@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-promise@^4.2.5: version "4.2.8" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== +es6-symbol@^3.1.1, es6-symbol@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= -escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +eslint-import-resolver-node@^0.3.2: + version "0.3.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" + integrity sha512-b8crLDo0M5RSe5YG8Pu2DYBj71tSB6OvXkfzwbJU2w7y8P4/yo0MyF8jU26IEuEuHF2K5/gcAJE3LhQGqBBbVg== + dependencies: + debug "^2.6.9" + resolve "^1.13.1" + +eslint-module-utils@^2.4.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz#579ebd094f56af7797d19c9866c9c9486629bfa6" + integrity sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA== + dependencies: + debug "^2.6.9" + pkg-dir "^2.0.0" + +eslint-plugin-compat@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-compat/-/eslint-plugin-compat-3.5.1.tgz#09f9c05dcfa9b5cd69345d7ab333749813ed8b14" + integrity sha512-dhfW12vZxxKLEVhrPoblmEopgwpYU2Sd4GdXj5OSfbQ+as9+1aY+S5pqnJYJvXXNWFFJ6aspLkCyk4NMQ/pgtA== + dependencies: + "@babel/runtime" "^7.7.7" + ast-metadata-inferer "^0.1.1" + browserslist "^4.8.2" + caniuse-db "^1.0.30001017" + lodash.memoize "4.1.2" + mdn-browser-compat-data "^1.0.3" + semver "^6.3.0" + +eslint-plugin-eslint-comments@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.1.2.tgz#4ef6c488dbe06aa1627fea107b3e5d059fc8a395" + integrity sha512-QexaqrNeteFfRTad96W+Vi4Zj1KFbkHHNMMaHZEYcovKav6gdomyGzaxSDSL3GoIyUOo078wRAdYlu1caiauIQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + +eslint-plugin-import@^2.20.2: + version "2.20.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.2.tgz#91fc3807ce08be4837141272c8b99073906e588d" + integrity sha512-FObidqpXrR8OnCh4iNsxy+WACztJLXAHBO5hK79T1Hc77PgQZkyDGA5Ag9xAvRpglvLNxhH/zSmZ70/pZ31dHg== + dependencies: + array-includes "^3.0.3" + array.prototype.flat "^1.2.1" + contains-path "^0.1.0" + debug "^2.6.9" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.2" + eslint-module-utils "^2.4.1" + has "^1.0.3" + minimatch "^3.0.4" + object.values "^1.1.0" + read-pkg-up "^2.0.0" + resolve "^1.12.0" + +eslint-plugin-promise@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a" + integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw== + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -1610,68 +4015,77 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.3.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" - integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== dependencies: - eslint-visitor-keys "^1.0.0" + esrecurse "^4.1.0" + estraverse "^4.1.1" -eslint-visitor-keys@^1.0.0: +eslint-utils@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" + integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== -eslint@^5.16.0: - version "5.16.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-5.16.0.tgz#a1e3ac1aae4a3fbd8296fcf8f7ab7314cbb6abea" - integrity sha512-S3Rz11i7c8AA5JPv7xAH+dOyq/Cu/VXHiHXBPOU1k/JAM5dXqQPt3qcrhpHSorXmrpu2g0gkIBVXAqCpzfoZIg== +eslint@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" + integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== dependencies: "@babel/code-frame" "^7.0.0" - ajv "^6.9.1" + ajv "^6.10.0" chalk "^2.1.0" cross-spawn "^6.0.5" debug "^4.0.1" doctrine "^3.0.0" - eslint-scope "^4.0.3" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^5.0.1" + eslint-scope "^5.0.0" + eslint-utils "^1.4.3" + eslint-visitor-keys "^1.1.0" + espree "^6.1.2" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" functional-red-black-tree "^1.0.1" - glob "^7.1.2" - globals "^11.7.0" + glob-parent "^5.0.0" + globals "^12.1.0" ignore "^4.0.6" import-fresh "^3.0.0" imurmurhash "^0.1.4" - inquirer "^6.2.2" - js-yaml "^3.13.0" + inquirer "^7.0.0" + is-glob "^4.0.0" + js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.17.11" + lodash "^4.17.14" minimatch "^3.0.4" mkdirp "^0.5.1" natural-compare "^1.4.0" - optionator "^0.8.2" - path-is-inside "^1.0.2" + optionator "^0.8.3" progress "^2.0.0" regexpp "^2.0.1" - semver "^5.5.1" - strip-ansi "^4.0.0" - strip-json-comments "^2.0.1" + semver "^6.1.2" + strip-ansi "^5.2.0" + strip-json-comments "^3.0.1" table "^5.2.3" text-table "^0.2.0" + v8-compile-cache "^2.0.3" -espree@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-5.0.1.tgz#5d6526fa4fc7f0788a5cf75b15f30323e2f81f7a" - integrity sha512-qWAZcWh4XE/RwzLJejfcofscgMc9CamR6Tn1+XRXNzrvUSSbiAjGOI/fggztjIi7y9VLPqnICMIPiGyr8JaZ0A== +espree@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" + integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + acorn "^7.1.1" + acorn-jsx "^5.2.0" + eslint-visitor-keys "^1.1.0" esprima@^4.0.0: version "4.0.1" @@ -1679,11 +4093,11 @@ esprima@^4.0.0: integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esquery@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708" - integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA== + version "1.3.1" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" + integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== dependencies: - estraverse "^4.0.0" + estraverse "^5.1.0" esrecurse@^4.1.0: version "4.2.1" @@ -1692,21 +4106,39 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= +estraverse@^4.1.0, estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" + integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== esutils@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: +etag@1.8.1, etag@^1.8.1, etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk= + dependencies: + d "1" + es5-ext "~0.10.14" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + integrity sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg= + eventemitter3@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" @@ -1718,9 +4150,9 @@ eventemitter3@^4.0.0: integrity sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg== events@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" - integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== + version "3.1.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.1.0.tgz#84279af1b34cb75aa88bf5ff291f6d0bd9b31a59" + integrity sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg== eventsource@^1.0.7: version "1.0.7" @@ -1737,6 +4169,30 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exec-buffer@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/exec-buffer/-/exec-buffer-3.2.0.tgz#b1686dbd904c7cf982e652c1f5a79b1e5573082b" + integrity sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA== + dependencies: + execa "^0.7.0" + p-finally "^1.0.0" + pify "^3.0.0" + rimraf "^2.5.4" + tempfile "^2.0.0" + +execa@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" + integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + execa@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" @@ -1750,6 +4206,27 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execall@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73" + integrity sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M= + dependencies: + clone-regexp "^1.0.0" + +execall@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" + integrity sha512-0FU2hZ5Hh6iQnarpRtQurM/aAvp3RIbfvgLHrcqJYzhXyV2KFruhuChf9NC6waAhiUR7FFtlugkI4p7f2Fqlow== + dependencies: + clone-regexp "^2.1.0" + +executable@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -1806,6 +4283,28 @@ express@^4.17.1: utils-merge "1.0.1" vary "~1.1.2" +ext-list@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" + integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== + dependencies: + mime-db "^1.28.0" + +ext-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" + integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== + dependencies: + ext-list "^2.0.0" + sort-keys-length "^1.0.0" + +ext@^1.1.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.4.0.tgz#89ae7a07158f79d35517882904324077e4379244" + integrity sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A== + dependencies: + type "^2.0.0" + extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -1821,6 +4320,11 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" +extend@3.0.2, extend@^3.0.0, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -1844,12 +4348,32 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= -fast-glob@^2.0.2: +extsprintf@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" + integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + +fancy-log@^1.1.0, fancy-log@^1.3.2, fancy-log@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" + integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== + dependencies: + ansi-gray "^0.1.1" + color-support "^1.1.3" + parse-node-version "^1.0.0" + time-stamp "^1.0.0" + +fast-deep-equal@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" + integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + +fast-glob@^2.0.2, fast-glob@^2.2.6: version "2.2.7" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== @@ -1861,16 +4385,40 @@ fast-glob@^2.0.2: merge2 "^1.2.3" micromatch "^3.1.10" -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= +fast-glob@^3.0.3, fast-glob@^3.1.1: + version "3.2.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" + integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" -fast-levenshtein@~2.0.4: +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-text-encoding@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.2.tgz#ff1ad5677bde049e0f8656aa6083a7ef2c5836e2" + integrity sha512-5rQdinSsycpzvAoHga2EDn+LRX1d5xLFsuNG0Kg61JrAT/tASXcLL0nf/33v+sAxlQcfYmWbTURa1mmAf55jGw== + +fastq@^1.6.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.7.0.tgz#fcd79a08c5bd7ec5b55cd3f5c4720db551929801" + integrity sha512-YOadQRnHd5q6PogvAR/x62BGituF2ufiEA6s8aavQANw5YKHERI4AREboX6KotzP8oX2klxYF2wcV/7bn1clfQ== + dependencies: + reusify "^1.0.4" + faye-websocket@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4" @@ -1885,17 +4433,39 @@ faye-websocket@~0.11.1: dependencies: websocket-driver ">=0.5.1" -figgy-pudding@^3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790" - integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w== +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= +figgy-pudding@^3.5.1: + version "3.5.2" + resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" + integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + integrity sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4= dependencies: escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-4.0.0.tgz#633567d15364aefe0b299e1e217735e8f3a9f6e8" + integrity sha512-AVSwsnbV8vH/UVbvgEhf3saVQXORNv0ZzSkvkhQIaia5Tia+JhGTaa/ePUSVoPHQyGayQNmYfkzFi3WZV5zcpA== + dependencies: + flat-cache "^2.0.1" file-entry-cache@^5.0.1: version "5.0.1" @@ -1904,13 +4474,67 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" -file-loader@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-3.0.1.tgz#f8e0ba0b599918b51adfe45d66d1e771ad560faa" - integrity sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw== +file-loader@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.0.0.tgz#97bbfaab7a2460c07bcbd72d3a6922407f67649f" + integrity sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ== dependencies: - loader-utils "^1.0.2" - schema-utils "^1.0.0" + loader-utils "^2.0.0" + schema-utils "^2.6.5" + +file-type@5.2.0, file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + +file-type@^10.4.0: + version "10.11.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-10.11.0.tgz#2961d09e4675b9fb9a3ee6b69e9cd23f43fd1890" + integrity sha512-uzk64HRpUZyTGZtVuvrjP0FYxzQrBf4rojot6J65YMEbwBLB0CWm0CLojVpwpmFmxcE/lkvYICgfcGozbBq6rw== + +file-type@^12.0.0: + version "12.4.2" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-12.4.2.tgz#a344ea5664a1d01447ee7fb1b635f72feb6169d9" + integrity sha512-UssQP5ZgIOKelfsaB5CuGAL+Y+q7EmONuiwF3N5HAH0t27rvrttgi6Ra9k/+DVaY9UF6+ybxu5pOXLUdA8N7Vg== + +file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + +file-type@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" + integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= + +file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + +file-type@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-8.1.0.tgz#244f3b7ef641bbe0cca196c7276e4b332399f68c" + integrity sha512-qyQ0pzAy78gVoJsmYeNgl8uH8yKhr1lVhW7JbzJmnlRi0I4R2eEDEJZVKG8agpDnLpacwNbDhLNG/LMdxHD2YQ== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= + +filenamify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-2.1.0.tgz#88faf495fb1b47abfd612300002a16228c677ee9" + integrity sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA== + dependencies: + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.0" + trim-repeated "^1.0.0" fill-range@^4.0.0: version "4.0.0" @@ -1922,6 +4546,26 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.0.tgz#ce0b6855b45853e791b2fcc680046d88253dd7f5" + integrity sha1-zgtoVbRYU+eRsvzGgARtiCU91/U= + dependencies: + debug "2.6.9" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.2" + statuses "~1.3.1" + unpipe "~1.0.0" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1944,6 +4588,21 @@ find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + find-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" @@ -1951,7 +4610,22 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -findup-sync@3.0.0: +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-versions@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e" + integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww== + dependencies: + semver-regex "^2.0.0" + +findup-sync@3.0.0, findup-sync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== @@ -1961,6 +4635,32 @@ findup-sync@3.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" +findup-sync@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc" + integrity sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw= + dependencies: + detect-file "^1.0.0" + is-glob "^3.1.0" + micromatch "^3.0.4" + resolve-dir "^1.0.1" + +fined@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b" + integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng== + dependencies: + expand-tilde "^2.0.2" + is-plain-object "^2.0.3" + object.defaults "^1.1.0" + object.pick "^1.2.0" + parse-filepath "^1.0.1" + +flagged-respawn@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" + integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== + flat-cache@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" @@ -1971,11 +4671,16 @@ flat-cache@^2.0.1: write "1.0.3" flatted@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" - integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg== + version "2.0.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" + integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== -flush-write-stream@^1.0.0: +flatten@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.3.tgz#c1283ac9f27b368abc1e36d1ff7b04501a30356b" + integrity sha512-dVsPA/UwQ8+2uoFe5GHtiBMu48dWLTdsuEd7CKGlZlD78r1TTWBvDuFaFGKCo/ZfEr95Uk56vZoX86OsHkUeIg== + +flush-write-stream@^1.0.0, flush-write-stream@^1.0.2: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== @@ -1991,18 +4696,51 @@ flv.js@^1.5.0: es6-promise "^4.2.5" webworkify "^1.5.0" +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + follow-redirects@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.9.0.tgz#8d5bcdc65b7108fe1508649c79c12d732dcedb4f" - integrity sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A== + version "1.11.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.11.0.tgz#afa14f08ba12a52963140fe43212658897bc0ecb" + integrity sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA== dependencies: debug "^3.0.0" -for-in@^1.0.2: +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs= + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + +fork-stream@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70" + integrity sha1-24Sfznf2cIpfjzhq5TOgkHtUrnA= + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + forwarded@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" @@ -2015,12 +4753,12 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fresh@0.5.2: +fresh@0.5.2, fresh@^0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= -from2@^2.1.0: +from2@^2.1.0, from2@^2.1.1: version "2.3.0" resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= @@ -2028,12 +4766,27 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" -fs-minipass@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07" - integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-3.0.1.tgz#3794f378c58b342ea7dbbb23095109c4b3b62291" + integrity sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE= dependencies: - minipass "^2.2.1" + graceful-fs "^4.1.2" + jsonfile "^3.0.0" + universalify "^0.1.0" + +fs-mkdirp-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz#0b7815fc3201c6a69e14db98ce098c16935259eb" + integrity sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes= + dependencies: + graceful-fs "^4.1.11" + through2 "^2.0.3" fs-write-stream-atomic@^1.0.8: version "1.0.10" @@ -2051,12 +4804,22 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: - version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" - integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== + version "1.2.12" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.12.tgz#db7e0d8ec3b0b45724fd4d83d43554a8f1f0de5c" + integrity sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q== dependencies: + bindings "^1.5.0" nan "^2.12.1" - node-pre-gyp "^0.12.0" + +fstream@^1.0.0, fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" function-bind@^1.1.1: version "1.1.1" @@ -2068,6 +4831,11 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gather-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" + integrity sha1-szmUr0V6gRVwDUEPMXczy+egkEs= + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2082,6 +4850,18 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gaze@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a" + integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g== + dependencies: + globule "^1.0.0" + +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -2092,6 +4872,41 @@ get-caller-file@^2.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-proxy@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" + integrity sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw== + dependencies: + npm-conf "^1.1.0" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= + +get-stdin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" + integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== + +get-stdin@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-7.0.0.tgz#8d5de98f15171a125c5e516643c7a6d0ea8a96f6" + integrity sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ== + +get-stream@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + +get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + get-stream@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" @@ -2104,6 +4919,30 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + +gifsicle@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gifsicle/-/gifsicle-5.0.0.tgz#d1ca7f223e949966d373eb1fb6e7ce156d257750" + integrity sha512-GZ1ym4uY12FHXsf26Kk1G06Edwago9zctqUqin69pm8ObA13jb3urgHU9PgKmtH6kHaCjEcjoRzNjxUyYvb1Bg== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + execa "^1.0.0" + logalot "^2.0.0" + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -2112,15 +4951,50 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" +glob-parent@^5.0.0, glob-parent@^5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" + integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== + dependencies: + is-glob "^4.0.1" + +glob-stream@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-6.1.0.tgz#7045c99413b3eb94888d83ab46d0b404cc7bdde4" + integrity sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ= + dependencies: + extend "^3.0.0" + glob "^7.1.1" + glob-parent "^3.1.0" + is-negated-glob "^1.0.0" + ordered-read-streams "^1.0.0" + pumpify "^1.3.5" + readable-stream "^2.1.5" + remove-trailing-separator "^1.0.1" + to-absolute-glob "^2.0.0" + unique-stream "^2.0.2" + glob-to-regexp@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" - integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== +glob-watcher@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-5.0.3.tgz#88a8abf1c4d131eb93928994bc4a593c2e5dd626" + integrity sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg== + dependencies: + anymatch "^2.0.0" + async-done "^1.2.0" + chokidar "^2.0.0" + is-negated-glob "^1.0.0" + just-debounce "^1.0.0" + object.defaults "^1.1.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2129,7 +5003,7 @@ glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" -global-modules@2.0.0: +global-modules@2.0.0, global-modules@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== @@ -2165,11 +5039,44 @@ global-prefix@^3.0.0: kind-of "^6.0.2" which "^1.3.1" -globals@^11.7.0: +globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +globals@^12.1.0: + version "12.4.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" + integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== + dependencies: + type-fest "^0.8.1" + +globby@^10.0.0, globby@^10.0.1: + version "10.0.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" + integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.0.3" + glob "^7.1.3" + ignore "^5.1.1" + merge2 "^1.2.3" + slash "^3.0.0" + +globby@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154" + integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" @@ -2206,26 +5113,401 @@ globby@^8.0.1: pify "^3.0.0" slash "^1.0.0" -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: - version "4.2.1" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.1.tgz#1c1f0c364882c868f5bff6512146328336a11b1d" - integrity sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw== +globby@^9.0.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" + integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^1.0.2" + dir-glob "^2.2.2" + fast-glob "^2.2.6" + glob "^7.1.3" + ignore "^4.0.3" + pify "^4.0.1" + slash "^2.0.0" + +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" + integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= + +globule@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.1.tgz#90a25338f22b7fbeb527cee63c629aea754d33b9" + integrity sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g== + dependencies: + glob "~7.1.1" + lodash "~4.17.12" + minimatch "~3.0.2" + +glogg@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/glogg/-/glogg-1.0.2.tgz#2d7dd702beda22eb3bffadf880696da6d846313f" + integrity sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA== + dependencies: + sparkles "^1.0.0" + +gonzales-pe@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.2.4.tgz#356ae36a312c46fe0f1026dd6cb539039f8500d2" + integrity sha512-v0Ts/8IsSbh9n1OJRnSfa7Nlxi4AkXIsWB6vPept8FDbL4bXn3FNuxjYtO/nmBGu7GDkL9MFeGebeSu6l55EPQ== + dependencies: + minimist "1.1.x" + +gonzales-pe@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" + integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== + dependencies: + minimist "^1.2.5" + +got@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + +got@^8.3.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + +graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2: + version "4.2.4" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" + integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + +group-array@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/group-array/-/group-array-1.0.0.tgz#e2e8d8890e5b46f72eb49b71e8af675173a9d0f7" + integrity sha512-PJresALe5TUzSIcdWKLdAKcdUDxv8du2EGueShgAL2xknbcTo5Bk1xbNaNhxpWxxAx/SV7N+5S0UyK7XV0+QhA== + dependencies: + arr-flatten "^1.1.0" + for-own "^1.0.0" + get-value "^3.0.1" + kind-of "^6.0.2" + split-string "^6.1.0" + union-value "^2.0.1" + +gulp-babel@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/gulp-babel/-/gulp-babel-8.0.0.tgz#e0da96f4f2ec4a88dd3a3030f476e38ab2126d87" + integrity sha512-oomaIqDXxFkg7lbpBou/gnUkX51/Y/M2ZfSjL2hdqXTAlSWZcgZtd2o0cOH0r/eE8LWD0+Q/PsLsr2DKOoqToQ== + dependencies: + plugin-error "^1.0.1" + replace-ext "^1.0.0" + through2 "^2.0.0" + vinyl-sourcemaps-apply "^0.2.0" + +gulp-cli@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.2.0.tgz#5533126eeb7fe415a7e3e84a297d334d5cf70ebc" + integrity sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA== + dependencies: + ansi-colors "^1.0.1" + archy "^1.0.0" + array-sort "^1.0.0" + color-support "^1.1.3" + concat-stream "^1.6.0" + copy-props "^2.0.1" + fancy-log "^1.3.2" + gulplog "^1.0.0" + interpret "^1.1.0" + isobject "^3.0.1" + liftoff "^3.1.0" + matchdep "^2.0.0" + mute-stdout "^1.0.0" + pretty-hrtime "^1.0.0" + replace-homedir "^1.0.0" + semver-greatest-satisfied-range "^1.1.0" + v8flags "^3.0.1" + yargs "^7.1.0" + +gulp-concat@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/gulp-concat/-/gulp-concat-2.6.1.tgz#633d16c95d88504628ad02665663cee5a4793353" + integrity sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M= + dependencies: + concat-with-sourcemaps "^1.0.0" + through2 "^2.0.0" + vinyl "^2.0.0" + +gulp-htmlmin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/gulp-htmlmin/-/gulp-htmlmin-5.0.1.tgz#90fc5e8ad0425a9e86d5d521427184e7276365e7" + integrity sha512-ASlyDPZOSKjHYUifYV0rf9JPDflN9IRIb8lw2vRqtYMC4ljU3zAmnnaVXwFQ3H+CfXxZSUesZ2x7jrnPJu93jA== + dependencies: + html-minifier "^3.5.20" + plugin-error "^1.0.1" + through2 "^2.0.3" + +gulp-if@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-3.0.0.tgz#6c3e7edc8bafadc34f2ebecb314bf43324ba1e40" + integrity sha512-fCUEngzNiEZEK2YuPm+sdMpO6ukb8+/qzbGfJBXyNOXz85bCG7yBI+pPSl+N90d7gnLvMsarthsAImx0qy7BAw== + dependencies: + gulp-match "^1.1.0" + ternary-stream "^3.0.0" + through2 "^3.0.1" + +gulp-imagemin@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/gulp-imagemin/-/gulp-imagemin-7.1.0.tgz#d1810a908fb64b4fbf15a750d303d988443e68cf" + integrity sha512-6xBTNybmPY2YrvrhhlS8Mxi0zn0ypusLon63p9XXxDtIf7U7c6KcViz94K7Skosucr3378A6IY2kJSjJyuwylQ== + dependencies: + chalk "^3.0.0" + fancy-log "^1.3.2" + imagemin "^7.0.0" + plugin-error "^1.0.1" + plur "^3.0.1" + pretty-bytes "^5.3.0" + through2-concurrent "^2.0.0" + optionalDependencies: + imagemin-gifsicle "^7.0.0" + imagemin-mozjpeg "^8.0.0" + imagemin-optipng "^7.0.0" + imagemin-svgo "^7.0.0" + +gulp-inject@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/gulp-inject/-/gulp-inject-5.0.5.tgz#c23df9cbf331447b6e13a1498cc51b63a7ceef67" + integrity sha512-5bGMjqleXUHPu4CI1pnVzHtwyMy+Zt8EMo1RFwNsOpidPxwjFwyLgmsRZWGMMI8UenJMJRjURqwznfFmqb5wgw== + dependencies: + ansi-colors "^4.1.1" + arrify "^2.0.1" + escape-string-regexp "^2.0.0" + fancy-log "^1.3.3" + group-array "^1.0.0" + plugin-error "^1.0.1" + stream-to-array "^2.3.0" + through2 "^3.0.1" + +gulp-match@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.1.0.tgz#552b7080fc006ee752c90563f9fec9d61aafdf4f" + integrity sha512-DlyVxa1Gj24DitY2OjEsS+X6tDpretuxD6wTfhXE/Rw2hweqc1f6D/XtsJmoiCwLWfXgR87W9ozEityPCVzGtQ== + dependencies: + minimatch "^3.0.3" + +gulp-mode@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/gulp-mode/-/gulp-mode-1.0.2.tgz#33c76033491fb71f47f1ebf8c67561ad9da7dfc9" + integrity sha512-i1UqW2NmBkyNirpthzbW1Na7t6JeSttuWjJyX8oY2Xve1Nx9tGhscoFgv1I/EOEsRcxGmhGyIRvpiKKL1d918A== + dependencies: + gulp-util "^3.0.8" + +gulp-postcss@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/gulp-postcss/-/gulp-postcss-8.0.0.tgz#8d3772cd4d27bca55ec8cb4c8e576e3bde4dc550" + integrity sha512-Wtl6vH7a+8IS/fU5W9IbOpcaLqKxd5L1DUOzaPmlnCbX1CrG0aWdwVnC3Spn8th0m8D59YbysV5zPUe1n/GJYg== + dependencies: + fancy-log "^1.3.2" + plugin-error "^1.0.1" + postcss "^7.0.2" + postcss-load-config "^2.0.0" + vinyl-sourcemaps-apply "^0.2.1" + +gulp-sass@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/gulp-sass/-/gulp-sass-4.1.0.tgz#486d7443c32d42bf31a6b1573ebbdaa361de7427" + integrity sha512-xIiwp9nkBLcJDpmYHbEHdoWZv+j+WtYaKD6Zil/67F3nrAaZtWYN5mDwerdo7EvcdBenSAj7Xb2hx2DqURLGdA== + dependencies: + chalk "^2.3.0" + lodash "^4.17.11" + node-sass "^4.8.3" + plugin-error "^1.0.1" + replace-ext "^1.0.0" + strip-ansi "^4.0.0" + through2 "^2.0.0" + vinyl-sourcemaps-apply "^0.2.0" + +gulp-sourcemaps@^2.6.5: + version "2.6.5" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz#a3f002d87346d2c0f3aec36af7eb873f23de8ae6" + integrity sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg== + dependencies: + "@gulp-sourcemaps/identity-map" "1.X" + "@gulp-sourcemaps/map-sources" "1.X" + acorn "5.X" + convert-source-map "1.X" + css "2.X" + debug-fabulous "1.X" + detect-newline "2.X" + graceful-fs "4.X" + source-map "~0.6.0" + strip-bom-string "1.X" + through2 "2.X" + +gulp-terser@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gulp-terser/-/gulp-terser-1.2.0.tgz#41df2a1d0257d011ba8b05efb2568432ecd0495b" + integrity sha512-lf+jE2DALg2w32p0HRiYMlFYRYelKZPNunHp2pZccCYrrdCLOs0ItbZcN63yr2pbz116IyhUG9mD/QbtRO1FKA== + dependencies: + plugin-error "^1.0.1" + terser "^4.0.0" + through2 "^3.0.1" + vinyl-sourcemaps-apply "^0.2.1" + +gulp-util@^3.0.8: + version "3.0.8" + resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" + integrity sha1-AFTh50RQLifATBh8PsxQXdVLu08= + dependencies: + array-differ "^1.0.0" + array-uniq "^1.0.2" + beeper "^1.0.0" + chalk "^1.0.0" + dateformat "^2.0.0" + fancy-log "^1.1.0" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash._reescape "^3.0.0" + lodash._reevaluate "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.template "^3.0.0" + minimist "^1.1.0" + multipipe "^0.1.2" + object-assign "^3.0.0" + replace-ext "0.0.1" + through2 "^2.0.0" + vinyl "^0.5.0" + +gulp@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp/-/gulp-4.0.2.tgz#543651070fd0f6ab0a0650c6a3e6ff5a7cb09caa" + integrity sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA== + dependencies: + glob-watcher "^5.0.3" + gulp-cli "^2.2.0" + undertaker "^1.2.1" + vinyl-fs "^3.0.0" + +gulplog@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gulplog/-/gulplog-1.0.0.tgz#e28c4d45d05ecbbed818363ce8f9c5926229ffe5" + integrity sha1-4oxNRdBey77YGDY86PnFkmIp/+U= + dependencies: + glogg "^1.0.0" handle-thing@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" + integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== + +har-schema@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754" - integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ== + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + +har-validator@~5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + dependencies: + ajv "^6.5.5" + har-schema "^2.0.0" + +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= + dependencies: + ansi-regex "^2.0.0" + +has-binary2@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.3.tgz#7776ac627f3ea77250cfc332dab7ddf5e4f5d11d" + integrity sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw== + dependencies: + isarray "2.0.1" + +has-cors@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" + integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk= + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + integrity sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -has-symbols@^1.0.1: +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-gulplog@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" + integrity sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4= + dependencies: + sparkles "^1.0.0" + +has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + +has-symbols@^1.0.0, has-symbols@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -2262,7 +5544,7 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1, has@^1.0.3: +has@^1.0.0, has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== @@ -2270,12 +5552,13 @@ has@^1.0.1, has@^1.0.3: function-bind "^1.1.1" hash-base@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" - integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" @@ -2285,15 +5568,25 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.x: +he@1.2.x, he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hls.js@^0.12.4: - version "0.12.4" - resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.12.4.tgz#c155b7b2825a11117c111b781973c0ffa759006b" - integrity sha512-e8OPxQ60dBVsdkv4atdxR21KzC1mgwspM41qpozpj3Uv1Fz4CaeQy3FWoaV2O+QKKbNRvV5hW+/LipCWdrwnMQ== +headroom.js@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/headroom.js/-/headroom.js-0.11.0.tgz#26547a932025e4243abf8ace001b4ce5e110ed20" + integrity sha512-yI4ciZRD1WH22wa5uJDg2kMtRvhJwUJWo2l41Eby0BoAD+lzXL98lf5jDFxP4Q5W3HmlrpfItSfmqc3jCtasbw== + +hex-color-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" + integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== + +hls.js@^0.13.1: + version "0.13.2" + resolved "https://registry.yarnpkg.com/hls.js/-/hls.js-0.13.2.tgz#3e7dd28e3787c69c6aba42b64b11eb2c3c8c29f1" + integrity sha512-sIg2t4uGpWQLzuK1Iid9614WOKqxj4OYg+EbFbhhTDCsxpENBN+Du3yBFnoi+a83DuOOHdiQd1ydnti9loSGXw== dependencies: eventemitter3 "3.1.0" url-toolkit "^2.1.6" @@ -2314,10 +5607,15 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -howler@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/howler/-/howler-2.1.2.tgz#8433a09d8fe84132a3e726e05cb2bd352ef8bd49" - integrity sha512-oKrTFaVXsDRoB/jik7cEpWKTj7VieoiuzMYJ7E/EU5ayvmpRhumCv3YQ3823zi9VTJkSWAhbryHnlZAionGAJg== +hosted-git-info@^2.1.4: + version "2.8.8" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" + integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + +howler@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/howler/-/howler-2.1.3.tgz#07c88618f8767e879407a4d647fe2d6d5f15f121" + integrity sha512-PSGbOi1EYgw80C5UQbxtJM7TmzD+giJunIMBYyH3RVzHZx2fZLYBoes0SpVVHi/SFa1GoNtgXj/j6I7NOKYBxQ== hpack.js@^2.1.6: version "2.1.6" @@ -2329,12 +5627,40 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-entities@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" - integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8= +hsl-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsl-regex/-/hsl-regex-1.0.0.tgz#d49330c789ed819e276a4c0d272dffa30b18fe6e" + integrity sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4= -html-minifier@^3.2.3: +hsla-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hsla-regex/-/hsla-regex-1.0.0.tgz#c1ce7a3168c8c6614033a4b5f7877f3b225f9c38" + integrity sha1-wc56MWjIxmFAM6S194d/OyJfnDg= + +html-comment-regex@^1.1.0, html-comment-regex@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.2.tgz#97d4688aeb5c81886a364faa0cad1dda14d433a7" + integrity sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ== + +html-entities@^1.2.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.3.1.tgz#fb9a1a4b5b14c5daba82d3e34c6ae4fe701a0e44" + integrity sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA== + +html-minifier-terser@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-5.1.0.tgz#95d3df037f04835e9d1a09d1767c0e361a7de916" + integrity sha512-tiYE76O1zunboByeB/nFGwUEb263Z3nkNv6Lz2oLC1s6M36bLKfTrjQ+7ssVfaucVllE+N7hh/FbpbxvnIA+LQ== + dependencies: + camel-case "^4.1.1" + clean-css "^4.2.3" + commander "^4.1.1" + he "^1.2.0" + param-case "^3.0.3" + relateurl "^0.2.7" + terser "^4.6.3" + +html-minifier@^3.5.20: version "3.5.21" resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c" integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA== @@ -2347,20 +5673,32 @@ html-minifier@^3.2.3: relateurl "0.2.x" uglify-js "3.4.x" -html-webpack-plugin@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b" - integrity sha1-sBq71yOsqqeze2r0SS69oD2d03s= +html-tags@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-2.0.0.tgz#10b30a386085f43cede353cc8fa7cb0deeea668b" + integrity sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos= + +html-tags@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.1.0.tgz#7b5e6f7e665e9fb41f30007ed9e0d41e97fb2140" + integrity sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg== + +html-webpack-plugin@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.3.0.tgz#53bf8f6d696c4637d5b656d3d9863d89ce8174fd" + integrity sha512-C0fzKN8yQoVLTelcJxZfJCE+aAvQiY2VUf3UuKrR4a9k5UMWYOtpDLsaXwATbcVCnI05hUS7L9ULQHWLZhyi3w== dependencies: - html-minifier "^3.2.3" - loader-utils "^0.2.16" - lodash "^4.17.3" - pretty-error "^2.0.2" - tapable "^1.0.0" - toposort "^1.0.0" + "@types/html-minifier-terser" "^5.0.0" + "@types/tapable" "^1.0.5" + "@types/webpack" "^4.41.8" + html-minifier-terser "^5.0.1" + loader-utils "^1.2.3" + lodash "^4.17.15" + pretty-error "^2.1.1" + tapable "^1.1.3" util.promisify "1.0.0" -htmlparser2@^3.3.0: +htmlparser2@^3.10.0, htmlparser2@^3.3.0: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -2372,6 +5710,11 @@ htmlparser2@^3.3.0: inherits "^2.0.1" readable-stream "^3.1.1" +http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -2388,17 +5731,7 @@ http-errors@1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-errors@~1.7.2: +http-errors@1.7.3, http-errors@~1.7.2: version "1.7.3" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== @@ -2409,6 +5742,16 @@ http-errors@~1.7.2: statuses ">= 1.5.0 < 2" toidentifier "1.0.0" +http-errors@~1.6.2: + version "1.6.3" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" + integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + dependencies: + depd "~1.1.2" + inherits "2.0.3" + setprototypeof "1.1.0" + statuses ">= 1.4.0 < 2" + "http-parser-js@>=0.4.0 <0.4.11": version "0.4.10" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4" @@ -2424,6 +5767,14 @@ http-proxy-middleware@0.19.1: lodash "^4.17.11" micromatch "^3.1.10" +http-proxy@1.15.2: + version "1.15.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.15.2.tgz#642fdcaffe52d3448d2bda3b0079e9409064da31" + integrity sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE= + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + http-proxy@^1.17.0: version "1.18.0" resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.0.tgz#dbe55f63e75a347db7f3d99974f2692a314a6a3a" @@ -2433,24 +5784,28 @@ http-proxy@^1.17.0: follow-redirects "^1.0.0" requires-port "^1.0.0" +http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - -icss-utils@^4.1.0: +icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA== @@ -2467,23 +5822,74 @@ iferr@^0.1.5: resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= -ignore-walk@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" - integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ== - dependencies: - minimatch "^3.0.4" - ignore@^3.3.5: version "3.3.10" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== -ignore@^4.0.6: +ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.0.4, ignore@^5.0.5, ignore@^5.1.1, ignore@^5.1.4: + version "5.1.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" + integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== + +imagemin-gifsicle@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/imagemin-gifsicle/-/imagemin-gifsicle-7.0.0.tgz#1a7ab136a144c4678657ba3b6c412f80805d26b0" + integrity sha512-LaP38xhxAwS3W8PFh4y5iQ6feoTSF+dTAXFRUEYQWYst6Xd+9L/iPk34QGgK/VO/objmIlmq9TStGfVY2IcHIA== + dependencies: + execa "^1.0.0" + gifsicle "^5.0.0" + is-gif "^3.0.0" + +imagemin-mozjpeg@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/imagemin-mozjpeg/-/imagemin-mozjpeg-8.0.0.tgz#d2ca4e8c982c7c6eda55069af89dee4c1cebcdfd" + integrity sha512-+EciPiIjCb8JWjQNr1q8sYWYf7GDCNDxPYnkD11TNIjjWNzaV+oTg4DpOPQjl5ZX/KRCPMEgS79zLYAQzLitIA== + dependencies: + execa "^1.0.0" + is-jpg "^2.0.0" + mozjpeg "^6.0.0" + +imagemin-optipng@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/imagemin-optipng/-/imagemin-optipng-7.1.0.tgz#2225c82c35e5c29b7fa98d4f9ecee1161a68e888" + integrity sha512-JNORTZ6j6untH7e5gF4aWdhDCxe3ODsSLKs/f7Grewy3ebZpl1ZsU+VUTPY4rzeHgaFA8GSWOoA8V2M3OixWZQ== + dependencies: + exec-buffer "^3.0.0" + is-png "^2.0.0" + optipng-bin "^6.0.0" + +imagemin-svgo@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/imagemin-svgo/-/imagemin-svgo-7.1.0.tgz#528a42fd3d55eff5d4af8fd1113f25fb61ad6d9a" + integrity sha512-0JlIZNWP0Luasn1HT82uB9nU9aa+vUj6kpT+MjPW11LbprXC+iC4HDwn1r4Q2/91qj4iy9tRZNsFySMlEpLdpg== + dependencies: + is-svg "^4.2.1" + svgo "^1.3.2" + +imagemin@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/imagemin/-/imagemin-7.0.1.tgz#f6441ca647197632e23db7d971fffbd530c87dbf" + integrity sha512-33AmZ+xjZhg2JMCe+vDf6a9mzWukE7l+wAtesjE7KyteqqKjzxv7aVQeWnul1Ve26mWvEQqyPwl0OctNBfSR9w== + dependencies: + file-type "^12.0.0" + globby "^10.0.0" + graceful-fs "^4.2.2" + junk "^3.1.0" + make-dir "^3.0.0" + p-pipe "^3.0.0" + replace-ext "^1.0.0" + +immutable@^3: + version "3.8.2" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" + integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -2499,10 +5905,10 @@ import-fresh@^2.0.0: caller-path "^2.0.0" resolve-from "^3.0.0" -import-fresh@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118" - integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ== +import-fresh@^3.0.0, import-fresh@^3.1.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66" + integrity sha512-6e1q1cnWP2RXD9/keSkxHScg508CdXqXWgWBaETNhyuBFz+kUZlKboh+ISK+bU++DmbHimVBrOz/zzPe0sZ3sQ== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" @@ -2514,6 +5920,16 @@ import-from@^2.1.0: dependencies: resolve-from "^3.0.0" +import-lazy@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" + integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== + +import-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + import-local@2.0.0, import-local@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" @@ -2527,11 +5943,38 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= +in-publish@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.1.tgz#948b1a535c8030561cea522f73f78f4be357e00c" + integrity sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ== + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= + dependencies: + repeating "^2.0.0" + +indent-string@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" + integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + indexes-of@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc= +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + infer-owner@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" @@ -2545,7 +5988,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2560,28 +6003,28 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: +ini@^1.3.4, ini@^1.3.5: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== -inquirer@^6.2.2: - version "6.5.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" - integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA== +inquirer@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.1.0.tgz#1298a01859883e17c7264b82870ae1034f92dd29" + integrity sha512-5fJMWEmikSYu0nv/flMc475MhGbB7TSPd/2IpFV4I4rMklboCH2rQjYY5kKiYGHqUF9gvaambupcJFFG9dvReg== dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" + ansi-escapes "^4.2.1" + chalk "^3.0.0" + cli-cursor "^3.1.0" cli-width "^2.0.0" external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" + figures "^3.0.0" + lodash "^4.17.15" + mute-stream "0.0.8" + run-async "^2.4.0" + rxjs "^6.5.3" + string-width "^4.1.0" + strip-ansi "^6.0.0" through "^2.3.6" internal-ip@^4.3.0: @@ -2592,11 +6035,36 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" -interpret@1.2.0: +interpret@1.2.0, interpret@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +intersection-observer@^0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.10.0.tgz#4d11d63c1ff67e21e62987be24d55218da1a1a69" + integrity sha512-fn4bQ0Xq8FTej09YC/jqKZwtijpvARlRp6wxL5WTA6yPe2YWSJ5RJh7Nm79rK2qB0wr6iDQzH60XGq5V/7u8YQ== + +into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + +invariant@^2.2.2, invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= + invert-kv@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" @@ -2612,21 +6080,39 @@ ip@^1.1.0, ip@^1.1.5: resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== - -ipaddr.js@^1.9.0: +ipaddr.js@1.9.1, ipaddr.js@^1.9.0: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +irregular-plurals@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.4.0.tgz#2ca9b033651111855412f16be5d77c62a458a766" + integrity sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y= + +irregular-plurals@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-2.0.0.tgz#39d40f05b00f656d0b7fa471230dd3b714af2872" + integrity sha512-Y75zBYLkh0lJ9qxeHlMjQ7bSbyiSqNW/UOPWDmzC7cXskL1hekSITh1Oc6JV0XCWWZ9DE8VYSB71xocLk3gmGw== + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + integrity sha1-UFMN+4T8yap9vnhS6Do3uTufKqY= + is-absolute-url@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== +is-absolute@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576" + integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA== + dependencies: + is-relative "^1.0.0" + is-windows "^1.0.1" + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -2641,6 +6127,24 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + +is-alphanumeric@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz#4a9cef71daf4c001c1d81d63d140cf53fd6889f4" + integrity sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ= + +is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-arguments@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" @@ -2651,6 +6155,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -2663,10 +6172,27 @@ is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-buffer@^2.0.0, is-buffer@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" + integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== + +is-callable@^1.1.4, is-callable@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" + integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== + +is-color-stop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-color-stop/-/is-color-stop-1.1.0.tgz#cfff471aee4dd5c9e158598fbe12967b5cdad345" + integrity sha1-z/9HGu5N1cnhWFmPvhKWe1za00U= + dependencies: + css-color-names "^0.0.4" + hex-color-regex "^1.1.0" + hsl-regex "^1.0.0" + hsla-regex "^1.0.0" + rgb-regex "^1.0.1" + rgba-regex "^1.0.0" is-data-descriptor@^0.1.4: version "0.1.4" @@ -2683,9 +6209,14 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" + integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + +is-decimal@^1.0.0, is-decimal@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== is-descriptor@^0.1.0: version "0.1.6" @@ -2727,6 +6258,11 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= +is-finite@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" + integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== + is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -2739,6 +6275,18 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-gif@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-gif/-/is-gif-3.0.0.tgz#c4be60b26a301d695bb833b20d9b5d66c6cf83b1" + integrity sha512-IqJ/jlbw5WJSNfwQ/lHEDXF8rxhRgF6ythk2oiEvhpG29F704eX9NO6TvPfMiq9DrbwgcEDnETYNcZDPewQoVw== + dependencies: + file-type "^10.4.0" + is-glob@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" @@ -2753,6 +6301,33 @@ is-glob@^4.0.0, is-glob@^4.0.1: dependencies: is-extglob "^2.1.1" +is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + +is-jpg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-jpg/-/is-jpg-2.0.0.tgz#2e1997fa6e9166eaac0242daae443403e4ef1d97" + integrity sha1-LhmX+m6RZuqsAkLarkQ0A+TvHZc= + +is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + +is-negated-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-negated-glob/-/is-negated-glob-1.0.0.tgz#6910bca5da8c95e784b5751b976cf5a10fee36d2" + integrity sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI= + +is-number-like@^1.0.3: + version "1.0.8" + resolved "https://registry.yarnpkg.com/is-number-like/-/is-number-like-1.0.8.tgz#2e129620b50891042e44e9bbbb30593e75cfbbe3" + integrity sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA== + dependencies: + lodash.isfinite "^3.3.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -2760,7 +6335,27 @@ is-number@^3.0.0: dependencies: kind-of "^3.0.2" -is-path-cwd@^2.0.0: +is-number@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-4.0.0.tgz#0026e37f5454d73e356dfe6564699867c6a7f0ff" + integrity sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" + integrity sha1-iVJojF7C/9awPsyF52ngKQMINHA= + +is-path-cwd@^2.0.0, is-path-cwd@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== @@ -2779,30 +6374,101 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" -is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-path-inside@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== + +is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + +is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" -is-promise@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" - integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= +is-png@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-png/-/is-png-2.0.0.tgz#ee8cbc9e9b050425cedeeb4a6fb74a649b0a4a8d" + integrity sha512-4KPGizaVGj2LK7xwJIz8o5B2ubu1D/vcQsgOGFEDlpcvgZHto4gBnyd0ig7Ws+67ixmwKoNmu0hYnpo6AaKb5g== -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= +is-promise@^2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + +is-regex@^1.0.4, is-regex@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" + integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== dependencies: - has "^1.0.1" + has "^1.0.3" -is-stream@^1.1.0: +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= + +is-regexp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" + integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== + +is-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d" + integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA== + dependencies: + is-unc-path "^1.0.0" + +is-resolvable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== + +is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + +is-stream@^1.0.0, is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= +is-string@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" + integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== + +is-supported-regexp-flag@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.1.tgz#21ee16518d2c1dd3edd3e9a0d57e50207ac364ca" + integrity sha512-3vcJecUUrpgCqc/ca0aWeNu64UGgxcvO60K/Fkr1N6RSvfGCTU60UKN68JDmKokgba0rFFJs12EnzOQa14ubKQ== + +is-svg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-3.0.0.tgz#9321dbd29c212e5ca99c4fa9794c714bcafa2f75" + integrity sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ== + dependencies: + html-comment-regex "^1.1.0" + +is-svg@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-4.2.1.tgz#095b496e345fec9211c2a7d5d021003e040d6f81" + integrity sha512-PHx3ANecKsKNl5y5+Jvt53Y4J7MfMpbNZkv384QNiswMKAWIbvcqbPz+sYbFKJI8Xv3be01GSFniPmoaP+Ai5A== + dependencies: + html-comment-regex "^1.1.2" + is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" @@ -2810,21 +6476,63 @@ is-symbol@^1.0.2: dependencies: has-symbols "^1.0.1" +is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + +is-unc-path@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d" + integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ== + dependencies: + unc-path-regex "^0.1.2" + +is-utf8@^0.2.0, is-utf8@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + +is-valid-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-valid-glob/-/is-valid-glob-1.0.0.tgz#29bf3eff701be2d4d315dbacc39bc39fe8f601aa" + integrity sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao= + +is-whitespace-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz#0858edd94a95594c7c9dd0b5c174ec6e45ee4aa7" + integrity sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w== + is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-word-character@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.4.tgz#ce0e73216f98599060592f62ff31354ddbeb0230" + integrity sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA== + is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= +isarray@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e" + integrity sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2842,17 +6550,44 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -jquery@>=1.9.1, jquery@^3.4.1: - version "3.4.1" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" - integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw== +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -js-tokens@^4.0.0: +isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + +jellyfin-apiclient@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/jellyfin-apiclient/-/jellyfin-apiclient-1.1.1.tgz#9b9e6e2f827d221ef000eb3dac09dda7623a6a06" + integrity sha512-ga+LAVxRu9LvnNI1gx53iZTvN/4VnwAdUOUX5xfq+3KJXeg8rWcPg4sdArR7efZeN9Cs60diKwDw8Y+RlnYmHA== + +"jellyfin-noto@https://github.com/jellyfin/jellyfin-noto": + version "1.0.3" + resolved "https://github.com/jellyfin/jellyfin-noto#b784602db063734c721a46563ae5d6577ec2b35d" + +jquery@>=1.9.1, jquery@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.5.1.tgz#d7b4d08e1bfdb86ad2f1a3d039ea17304717abb5" + integrity sha512-XwIBPqcMn57FxfT+Go5pzySnm4KWkT1Tv7gjrpT1srtf8Weynl6R273VJ5GjkRb51IzMp5nbaPjJXMWeju2MKg== + +js-base64@^2.1.8, js-base64@^2.1.9: + version "2.5.2" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209" + integrity sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.0, js-yaml@^3.13.1: +js-yaml@^3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -2860,6 +6595,26 @@ js-yaml@^3.13.0, js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + +json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -2870,21 +6625,26 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + json3@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -2892,13 +6652,54 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + +jsonfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-3.0.1.tgz#a5ecc6f65f53f662c4415c7675a0331d0992ec66" + integrity sha1-pezG9l9T9mLEQVx2daAzHQmS7GY= + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^1.2.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.2.3" + verror "1.10.0" + jstree@^3.3.7: - version "3.3.8" - resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.8.tgz#8d0f506028d65e5207efa7b78e6541cbe35622c1" - integrity sha512-0/nhGxVLSGfGQyVg+q59ocqSEKWRDKHoA8wNrcOIvlzCCw19tzvcMNGJ19hf+U0b7fycABowkny7fQPcLgUwwA== + version "3.3.9" + resolved "https://registry.yarnpkg.com/jstree/-/jstree-3.3.9.tgz#62b47cad3c4fda390d021e5c4f98ee5b3365198a" + integrity sha512-jRIbhg+BHrIs1Wm6oiJt3oKTVBE6sWS0PCp2/RlkIUqsLUPWUYgV3q8LfKoi1/E+YMzGtP6BuK4okk+0mwfmhQ== dependencies: jquery ">=1.9.1" +junk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" + integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== + +just-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" + integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= + +keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== + dependencies: + json-buffer "3.0.0" + killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" @@ -2918,15 +6719,54 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0: +kind-of@^5.0.0, kind-of@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051" - integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +known-css-properties@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.11.0.tgz#0da784f115ea77c76b81536d7052e90ee6c86a8a" + integrity sha512-bEZlJzXo5V/ApNNa5z375mJC6Nrz4vG43UgcSCrg2OHC+yuB6j0iDSrY7RQ/+PRofFB03wNIIt9iXIVLr4wc7w== + +known-css-properties@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.18.0.tgz#d6e00b56ee1d5b0d171fd86df1583cfb012c521f" + integrity sha512-69AgJ1rQa7VvUsd2kpvVq+VeObDuo3zrj0CzM5Slmf6yduQFAI2kXPDQJR2IE/u6MSAUOJrwSzjg5vlz8qcMiw== + +last-run@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b" + integrity sha1-RblpQsF7HHnHchmCWbqUO+v4yls= + dependencies: + default-resolution "^2.0.0" + es6-weak-map "^2.0.1" + +lazypipe@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/lazypipe/-/lazypipe-1.0.2.tgz#b66f64ed7fd8b04869f1f1bcb795dbbaa80e418c" + integrity sha512-CrU+NYdFHW8ElaeXCWz5IbmetiYVYq1fOCmpdAeZ8L+khbv1e7EnshyjlKqkO+pJbVPrsJQnHbVxEiLujG6qhQ== + dependencies: + stream-combiner "*" + +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ= + dependencies: + readable-stream "^2.0.5" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= + dependencies: + invert-kv "^1.0.0" lcid@^2.0.0: version "2.0.0" @@ -2935,6 +6775,30 @@ lcid@^2.0.0: dependencies: invert-kv "^2.0.0" +lead@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lead/-/lead-1.0.0.tgz#6f14f99a37be3a9dd784f5495690e5903466ee42" + integrity sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI= + dependencies: + flush-write-stream "^1.0.2" + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levenary@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/levenary/-/levenary-1.1.1.tgz#842a9ee98d2075aa7faeedbe32679e9205f46f77" + integrity sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ== + dependencies: + leven "^3.1.0" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -2943,22 +6807,76 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libass-wasm@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/libass-wasm/-/libass-wasm-2.1.1.tgz#f12f4fdb9579dd422dcbc348bc3bd61097f4d07d" - integrity sha512-d45bHQ7tFVsLW3QstQDrDog2m+0D6Cja4GTrkGi70R9A5+aeLunPSUz3G4CVB+sKffNgiWjK4QI5NZLHQKZ9oQ== +"libass-wasm@https://github.com/jellyfin/JavascriptSubtitlesOctopus#4.0.0-jf-smarttv": + version "4.0.0" + resolved "https://github.com/jellyfin/JavascriptSubtitlesOctopus#58e9a3f1a7f7883556ee002545f445a430120639" -libjass@^0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/libjass/-/libjass-0.11.0.tgz#bff1f464a2428c3bddfb68e4503b2d52afe3d6e6" - integrity sha1-v/H0ZKJCjDvd+2jkUDstUq/j1uY= +liftoff@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" + integrity sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog== + dependencies: + extend "^3.0.0" + findup-sync "^3.0.0" + fined "^1.0.1" + flagged-respawn "^1.0.0" + is-plain-object "^2.0.4" + object.map "^1.0.0" + rechoir "^0.6.2" + resolve "^1.1.7" + +lightercollective@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/lightercollective/-/lightercollective-0.3.0.tgz#1f07638642ec645d70bdb69ab2777676f35a28f0" + integrity sha512-RFOLSUVvwdK3xA0P8o6G7QGXLIyy1L2qv5caEI7zXN5ciaEjbAriRF182kbsoJ1S1TgvpyGcN485fMky6qxOPw== + +limiter@^1.0.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2" + integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA== + +lines-and-columns@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3: +loader-utils@1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -2967,15 +6885,41 @@ loader-utils@1.2.3, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2. emojis-list "^2.0.0" json5 "^1.0.1" -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= +loader-utils@^1.1.0, loader-utils@^1.2.3, loader-utils@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +loader-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + +localtunnel@1.9.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.9.2.tgz#0012fcabc29cf964c130a01858768aa2bb65b5af" + integrity sha512-NEKF7bDJE9U3xzJu3kbayF0WTvng6Pww7tzqNb/XtEARYwqw7CKEX7BvOMg98FtE9es2CRizl61gkV3hS8dqYg== + dependencies: + axios "0.19.0" + debug "4.1.1" + openurl "1.1.1" + yargs "6.6.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" locate-path@^3.0.0: version "3.0.0" @@ -2985,21 +6929,256 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3: +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash._basecopy@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" + integrity sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= + +lodash._basetostring@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz#d1861d877f824a52f669832dcaf3ee15566a07d5" + integrity sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U= + +lodash._basevalues@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz#5b775762802bde3d3297503e26300820fdf661b7" + integrity sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc= + +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + +lodash._isiterateecall@^3.0.0: + version "3.0.9" + resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" + integrity sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= + +lodash._reescape@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reescape/-/lodash._reescape-3.0.0.tgz#2b1d6f5dfe07c8a355753e5f27fac7f1cde1616a" + integrity sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo= + +lodash._reevaluate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz#58bc74c40664953ae0b124d806996daca431e2ed" + integrity sha1-WLx0xAZklTrgsSTYBpltrKQx4u0= + +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + +lodash._root@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash._root/-/lodash._root-3.0.1.tgz#fba1c4524c19ee9a5f8136b4609f017cf4ded692" + integrity sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI= + +lodash.clone@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" + integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= + +lodash.escape@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-3.2.0.tgz#995ee0dc18c1b48cc92effae71a10aab5b487698" + integrity sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg= + dependencies: + lodash._root "^3.0.0" + +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.isfinite@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz#fb89b65a9a80281833f0b7478b3a5104f898ebb3" + integrity sha1-+4m2WpqAKBgz8LdHizpRBPiY67M= + +lodash.keys@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + +lodash.memoize@4.1.2, lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= + +lodash.restparam@^3.0.0: + version "3.6.1" + resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" + integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= + +lodash.some@^4.2.2: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" + integrity sha1-G7nzFO9ri63tE7VJFpsqlF62jk0= + +lodash.template@^3.0.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-3.6.2.tgz#f8cdecc6169a255be9098ae8b0c53d378931d14f" + integrity sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8= + dependencies: + lodash._basecopy "^3.0.0" + lodash._basetostring "^3.0.0" + lodash._basevalues "^3.0.0" + lodash._isiterateecall "^3.0.0" + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + lodash.keys "^3.0.0" + lodash.restparam "^3.0.0" + lodash.templatesettings "^3.0.0" + +lodash.template@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz#fb307844753b66b9f1afa54e262c745307dba8e5" + integrity sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU= + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.escape "^3.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= + +lodash@^4.0.0, lodash@^4.1.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@~4.17.12: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -loglevel@^1.6.4: - version "1.6.4" - resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" - integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g== +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + integrity sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg= + dependencies: + chalk "^1.0.0" + +log-symbols@^2.0.0, log-symbols@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" + integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== + dependencies: + chalk "^2.0.1" + +log-symbols@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" + integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== + dependencies: + chalk "^2.4.2" + +logalot@^2.0.0, logalot@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/logalot/-/logalot-2.1.0.tgz#5f8e8c90d304edf12530951a5554abb8c5e3f552" + integrity sha1-X46MkNME7fElMJUaVVSruMXj9VI= + dependencies: + figures "^1.3.5" + squeak "^1.0.0" + +loglevel@^1.6.6: + version "1.6.8" + resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" + integrity sha512-bsU7+gc9AJ2SqpzxwU3+1fedl8zAntbtC5XYlt3s2j1hJcn2PsXSmgN8TaLG/J1/2mod4+cE/3vNL70/c1RNCA== + +longest-streak@^2.0.1: + version "2.0.4" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" + integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== + +longest@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= + +loose-envify@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" lower-case@^1.1.1: version "1.1.4" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= +lower-case@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" + integrity sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ== + dependencies: + tslib "^1.10.0" + +lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= + +lowercase-keys@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + +lpad-align@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/lpad-align/-/lpad-align-1.1.2.tgz#21f600ac1c3095c3c6e497ee67271ee08481fe9e" + integrity sha1-IfYArBwwlcPG5JfuZyce4ISB/p4= + dependencies: + get-stdin "^4.0.1" + indent-string "^2.1.0" + longest "^1.0.0" + meow "^3.3.0" + +lru-cache@^4.0.1: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -3007,6 +7186,20 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM= + dependencies: + es5-ext "~0.10.2" + +make-dir@^1.0.0, make-dir@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + make-dir@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" @@ -3015,10 +7208,19 @@ make-dir@^2.0.0: pify "^4.0.1" semver "^5.6.0" -mamacro@^0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4" - integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA== +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-iterator@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6" + integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw== + dependencies: + kind-of "^6.0.2" map-age-cleaner@^0.1.1: version "0.1.3" @@ -3027,11 +7229,26 @@ map-age-cleaner@^0.1.1: dependencies: p-defer "^1.0.0" -map-cache@^0.2.2: +map-cache@^0.2.0, map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + +map-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" + integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= + +map-obj@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5" + integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g== + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -3039,6 +7256,43 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +markdown-escapes@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.4.tgz#c95415ef451499d7602b91095f3c8e8975f78535" + integrity sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg== + +markdown-table@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60" + integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q== + +markdown-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" + integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== + dependencies: + repeat-string "^1.0.0" + +matchdep@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/matchdep/-/matchdep-2.0.0.tgz#c6f34834a0d8dbc3b37c27ee8bbcb27c7775582e" + integrity sha1-xvNINKDY28OzfCfui7yyfHd1WC4= + dependencies: + findup-sync "^2.0.0" + micromatch "^3.0.4" + resolve "^1.4.0" + stack-trace "0.0.10" + +material-design-icons-iconfont@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/material-design-icons-iconfont/-/material-design-icons-iconfont-5.0.1.tgz#371875ed7fe9c8c520bc7123c3231feeab731c31" + integrity sha512-Xg6rIdGrfySTqiTZ6d+nQbcFepS6R4uKbJP0oAqyeZXJY/bX6mZDnOmmUJusqLXfhIwirs0c++a6JpqVa8RFvA== + +mathml-tag-names@^2.0.1, mathml-tag-names@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" + integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== + md5.js@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" @@ -3048,6 +7302,37 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" +mdast-util-compact@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-1.0.4.tgz#d531bb7667b5123abf20859be086c4d06c894593" + integrity sha512-3YDMQHI5vRiS2uygEFYaqckibpJtKq5Sj2c8JioeOQBU6INpKbdWzfyLqFFnDwEcEnRFIdMsguzs5pC1Jp4Isg== + dependencies: + unist-util-visit "^1.1.0" + +mdast-util-compact@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz#cabc69a2f43103628326f35b1acf735d55c99490" + integrity sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA== + dependencies: + unist-util-visit "^2.0.0" + +mdn-browser-compat-data@^1.0.3: + version "1.0.19" + resolved "https://registry.yarnpkg.com/mdn-browser-compat-data/-/mdn-browser-compat-data-1.0.19.tgz#f4542aea7bce4231c95c5bdab04f999298b58903" + integrity sha512-S1i9iILAsFi/C17NADg2cBT6D6Xcd5Ub+GSMQa5ScLhuVyUrRKjCNmFEED9mQ2G/lrKtvU9SGUrpPpXB8SXhCg== + dependencies: + extend "3.0.2" + +mdn-data@2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b" + integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA== + +mdn-data@2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.6.tgz#852dc60fcaa5daa2e8cf6c9189c440ed3e042978" + integrity sha512-rQvjv71olwNHgiTbfPZFkJtjNMciWgswYeciZhtvWLO8bmX3TnhyA62I6sTWOyZssWHJJjY6/KiWwqQsWWsqOA== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -3062,6 +7347,20 @@ mem@^4.0.0: mimic-fn "^2.0.0" p-is-promise "^2.0.0" +memoizee@0.4.X: + version "0.4.14" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" + integrity sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg== + dependencies: + d "1" + es5-ext "^0.10.45" + es6-weak-map "^2.0.2" + event-emitter "^0.3.5" + is-promise "^2.1" + lru-queue "0.1" + next-tick "1" + timers-ext "^0.1.5" + memory-fs@^0.4.0, memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -3070,12 +7369,73 @@ memory-fs@^0.4.0, memory-fs@^0.4.1: errno "^0.1.3" readable-stream "^2.0.1" +memory-fs@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.3.0, meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +meow@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4" + integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig== + dependencies: + camelcase-keys "^4.0.0" + decamelize-keys "^1.0.0" + loud-rejection "^1.0.0" + minimist-options "^3.0.1" + normalize-package-data "^2.3.4" + read-pkg-up "^3.0.0" + redent "^2.0.0" + trim-newlines "^2.0.0" + yargs-parser "^10.0.0" + +meow@^6.1.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/meow/-/meow-6.1.1.tgz#1ad64c4b76b2a24dfb2f635fddcadf320d251467" + integrity sha512-3YffViIt2QWgTy6Pale5QpopX/IvU3LPL03jOTqp6pGj3VjesdO/U8CuHMKpnQr4shCNCM5fd5XFFvIIl6JBHg== + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "^4.0.2" + normalize-package-data "^2.5.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.13.1" + yargs-parser "^18.1.3" + merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= -merge2@^1.2.3: +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.2.3, merge2@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== @@ -3104,6 +7464,14 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" +micromatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" + integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== + dependencies: + braces "^3.0.1" + picomatch "^2.0.5" + miller-rabin@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" @@ -3112,22 +7480,22 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.40.0: - version "1.40.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32" - integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA== +mime-db@1.44.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: + version "1.44.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== -"mime-db@>= 1.40.0 < 2": - version "1.42.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" - integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== - -mime-types@~2.1.17, mime-types@~2.1.24: - version "2.1.24" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81" - integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ== +mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: + version "2.1.27" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== dependencies: - mime-db "1.40.0" + mime-db "1.44.0" + +mime@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" + integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== mime@1.6.0: version "1.6.0" @@ -3135,20 +7503,25 @@ mime@1.6.0: integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== mime@^2.4.4: - version "2.4.4" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5" - integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA== + version "2.4.5" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.5.tgz#d8de2ecb92982dedbb6541c9b6841d7f218ea009" + integrity sha512-3hQhEUF027BuxZjQA3s7rIv/7VCQPa27hN9u9g87sEkWaKwQPuXOkVKtOeiyUrnWqTDiOs8Ed2rwg733mB0R5w== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - -mimic-fn@^2.0.0: +mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +min-indent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" + integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -3159,37 +7532,38 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@^3.0.4: +minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minipass@^2.2.1, minipass@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== +minimist-options@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" + integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" + arrify "^1.0.1" + is-plain-obj "^1.1.0" -minizlib@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" - integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== +minimist-options@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.0.2.tgz#29c4021373ded40d546186725e57761e4b1984a7" + integrity sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w== dependencies: - minipass "^2.2.1" + arrify "^1.0.1" + is-plain-obj "^1.1.0" + +minimist@1.1.x: + version "1.1.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" + integrity sha1-O+39kaktOQFvz6ocaB6Pqhoe/ag= + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== mississippi@^3.0.0: version "3.0.0" @@ -3207,6 +7581,11 @@ mississippi@^3.0.0: stream-each "^1.1.0" through2 "^2.0.0" +mitt@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mitt/-/mitt-1.2.0.tgz#cb24e6569c806e31bd4e3995787fe38a04fdf90d" + integrity sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw== + mixin-deep@^1.2.0: version "1.3.2" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" @@ -3215,12 +7594,12 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@~0.5.1: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== dependencies: - minimist "0.0.8" + minimist "^1.2.5" move-concurrently@^1.0.1: version "1.0.1" @@ -3234,6 +7613,15 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +mozjpeg@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/mozjpeg/-/mozjpeg-6.0.1.tgz#56969dddb5741ef2bcb1af066cae21e61a91a27b" + integrity sha512-9Z59pJMi8ni+IUvSH5xQwK5tNLw7p3dwDNCZ3o1xE+of3G5Hc/yOz6Ue/YuLiBXU3ZB5oaHPURyPdqfBX/QYJA== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + logalot "^2.1.0" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3262,15 +7650,27 @@ multicast-dns@^6.0.1: dns-packet "^1.3.1" thunky "^1.0.2" -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= +multipipe@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b" + integrity sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s= + dependencies: + duplexer2 "0.0.2" -nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +mute-stdout@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" + integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nan@^2.12.1, nan@^2.13.2: + version "2.14.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== nanomatch@^1.2.9: version "1.2.13" @@ -3299,15 +7699,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== - dependencies: - debug "^3.2.6" - iconv-lite "^0.4.4" - sax "^1.2.4" - negotiator@0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" @@ -3318,6 +7709,16 @@ neo-async@^2.5.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== +next-tick@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +next-tick@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + integrity sha1-yobR/ogoFpsBICCOPchCS524NCw= + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -3330,11 +7731,37 @@ no-case@^2.2.0: dependencies: lower-case "^1.1.1" +no-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" + integrity sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw== + dependencies: + lower-case "^2.0.1" + tslib "^1.10.0" + node-forge@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== +node-gyp@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c" + integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA== + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -3364,38 +7791,80 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-pre-gyp@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" - integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== +node-releases@^1.1.52: + version "1.1.55" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.55.tgz#8af23b7c561d8e2e6e36a46637bab84633b07cee" + integrity sha512-H3R3YR/8TjT5WPin/wOoHOUPHgvj8leuU/Keta/rwelEQN9pA/S2Dx8/se4pZ2LBxSd0nAGzsNzhqwa77v7F1w== + +node-releases@^1.1.53: + version "1.1.53" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.53.tgz#2d821bfa499ed7c5dffc5e2f28c88e78a08ee3f4" + integrity sha512-wp8zyQVwef2hpZ/dJH7SfSrIPD6YoJz6BDQDpGEkcA0s3LpAQoxBIYmfIq6QAhC1DhwsyCgTaTTcONwX8qzCuQ== + +node-sass@^4.13.1: + version "4.14.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.14.1.tgz#99c87ec2efb7047ed638fb4c9db7f3a42e2217b5" + integrity sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g== dependencies: - detect-libc "^1.0.2" + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash "^4.17.15" + meow "^3.7.0" mkdirp "^0.5.1" - needle "^2.2.1" - nopt "^4.0.1" - npm-packlist "^1.1.6" - npmlog "^4.0.2" - rc "^1.2.7" - rimraf "^2.6.1" - semver "^5.3.0" - tar "^4" + nan "^2.13.2" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "2.2.5" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" -node-releases@^1.1.42: - version "1.1.44" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.44.tgz#cd66438a6eb875e3eb012b6a12e48d9f4326ffd7" - integrity sha512-NwbdvJyR7nrcGrXvKAvzc5raj/NkoJudkarh2yIpJ4t0NH4aqjUDz/486P+ynIW5eokKOfzGNRdYoLfBlomruw== +node-sass@^4.8.3: + version "4.14.0" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.14.0.tgz#a8e9d7720f8e15b4a1072719dcf04006f5648eeb" + integrity sha512-AxqU+DFpk0lEz95sI6jO0hU0Rwyw7BXVEv6o9OItoXLyeygPeaSpiV4rwQb10JiTghHaa0gZeD21sz+OsQluaw== dependencies: - semver "^6.3.0" + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash "^4.17.15" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.13.2" + node-gyp "^3.8.0" + npmlog "^4.0.0" + request "^2.88.0" + sass-graph "^2.2.4" + stdout-stream "^1.4.0" + "true-case-path" "^1.0.2" -nopt@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" - integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00= +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= dependencies: abbrev "1" - osenv "^0.1.4" -normalize-path@^2.1.1: +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= @@ -3412,18 +7881,39 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= -npm-bundled@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd" - integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g== +normalize-selector@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" + integrity sha1-0LFF62kRicY6eNIB3E/bEpPvDAM= -npm-packlist@^1.1.6: - version "1.4.4" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44" - integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw== +normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== dependencies: - ignore-walk "^3.0.1" - npm-bundled "^1.0.1" + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + +normalize-url@^3.0.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" + integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== + +now-and-later@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/now-and-later/-/now-and-later-2.0.1.tgz#8e579c8685764a7cc02cb680380e94f43ccb1f7c" + integrity sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ== + dependencies: + once "^1.3.2" + +npm-conf@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" + integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== + dependencies: + config-chain "^1.1.11" + pify "^3.0.0" npm-run-path@^2.0.0: version "2.0.2" @@ -3432,7 +7922,7 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" -npmlog@^4.0.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -3442,7 +7932,7 @@ npmlog@^4.0.2: gauge "~2.7.3" set-blocking "~2.0.0" -nth-check@~1.0.1: +nth-check@^1.0.2, nth-check@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== @@ -3459,11 +7949,26 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + +object-assign@4.X, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= +object-assign@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" + integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= + +object-component@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" + integrity sha1-8MaapQ78lbhmwYb0AKM3acsvEpE= + object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -3479,15 +7984,23 @@ object-inspect@^1.7.0: integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== object-is@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6" - integrity sha1-CqYOyZiaCz7Xlc9NBvYs8a1lObY= + version "1.1.2" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.2.tgz#c5d2e87ff9e119f78b7a088441519e2eec1573b6" + integrity sha512-5lHCz+0uufF6wZ7CRFWJN3hp8Jqblpgve06U5CMQ3f//6iDjPr2PEo9MWCjEssDsa+UZEL4PkFpr+BMop6aKzQ== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" -object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object-path@^0.9.0: + version "0.9.2" + resolved "https://registry.yarnpkg.com/object-path/-/object-path-0.9.2.tgz#0fd9a74fc5fad1ae3968b586bda5c632bd6c05a5" + integrity sha1-D9mnT8X60a45aLWGvaXGMr1sBaU= + object-visit@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" @@ -3495,21 +8008,67 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= +object.assign@^4.0.4, object.assign@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" + integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== dependencies: define-properties "^1.1.2" - es-abstract "^1.5.1" + function-bind "^1.1.1" + has-symbols "^1.0.0" + object-keys "^1.0.11" -object.pick@^1.3.0: +object.defaults@^1.0.0, object.defaults@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" + integrity sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8= + dependencies: + array-each "^1.0.1" + array-slice "^1.0.0" + for-own "^1.0.0" + isobject "^3.0.0" + +object.getownpropertydescriptors@^2.0.3, object.getownpropertydescriptors@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" + integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + +object.map@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37" + integrity sha1-z4Plncj8wK1fQlDh94s7gb2AHTc= + dependencies: + for-own "^1.0.0" + make-iterator "^1.0.0" + +object.pick@^1.2.0, object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" +object.reduce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object.reduce/-/object.reduce-1.0.1.tgz#6fe348f2ac7fa0f95ca621226599096825bb03ad" + integrity sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60= + dependencies: + for-own "^1.0.0" + make-iterator "^1.0.0" + +object.values@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.1.tgz#68a99ecde356b7e9295a3c5e0ce31dc8c953de5e" + integrity sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" + function-bind "^1.1.1" + has "^1.0.3" + obuf@^1.0.0, obuf@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" @@ -3527,19 +8086,31 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0, once@^1.3.1, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= +onetime@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" + integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== dependencies: - mimic-fn "^1.0.0" + mimic-fn "^2.1.0" + +openurl@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387" + integrity sha1-OHW0sO96UsFW8NtB1GCduw+Us4c= + +opn@5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/opn/-/opn-5.3.0.tgz#64871565c863875f052cfdf53d3e3cb5adb53b1c" + integrity sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g== + dependencies: + is-wsl "^1.1.0" opn@^5.5.0: version "5.5.0" @@ -3548,17 +8119,33 @@ opn@^5.5.0: dependencies: is-wsl "^1.1.0" -optionator@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" - integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= +optionator@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" - fast-levenshtein "~2.0.4" + fast-levenshtein "~2.0.6" levn "~0.3.0" prelude-ls "~1.1.2" type-check "~0.3.2" - wordwrap "~1.0.0" + word-wrap "~1.2.3" + +optipng-bin@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/optipng-bin/-/optipng-bin-6.0.0.tgz#376120fa79d5e71eee2f524176efdd3a5eabd316" + integrity sha512-95bB4y8IaTsa/8x6QH4bLUuyvyOoGBCLDA7wOgDL8UFqJpSUh1Hob8JRJhit+wC1ZLN3tQ7mFt7KuBj0x8F2Wg== + dependencies: + bin-build "^3.0.0" + bin-wrapper "^4.0.0" + logalot "^2.0.0" + +ordered-read-streams@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz#77c0cb37c41525d64166d990ffad7ec6a0e1363e" + integrity sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4= + dependencies: + readable-stream "^2.0.1" original@^1.0.0: version "1.0.2" @@ -3572,11 +8159,25 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= +os-filter-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/os-filter-obj/-/os-filter-obj-2.0.0.tgz#1c0b62d5f3a2442749a2d139e6dddee6e81d8d16" + integrity sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg== + dependencies: + arch "^2.1.0" + os-homedir@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= + dependencies: + lcid "^1.0.0" + os-locale@^3.0.0, os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" @@ -3591,7 +8192,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4: +osenv@0: version "0.1.5" resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -3599,34 +8200,70 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" +p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + +p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== + p-defer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= +p-event@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-1.3.0.tgz#8e6b4f4f65c72bc5b6fe28b75eda874f96a4a085" + integrity sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU= + dependencies: + p-timeout "^1.1.1" + +p-event@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" + integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== + dependencies: + p-timeout "^2.0.1" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= +p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + p-is-promise@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== -p-limit@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" - integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" -p-limit@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= dependencies: - p-try "^2.0.0" + p-limit "^1.1.0" p-locate@^3.0.0: version "3.0.0" @@ -3635,11 +8272,42 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map-series@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" + integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= + dependencies: + p-reduce "^1.0.0" + p-map@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== +p-map@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" + integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== + dependencies: + aggregate-error "^3.0.0" + +p-pipe@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.0.0.tgz#ab1fb87c0b8dd79b3bb03a8a23680fc9d054e132" + integrity sha512-gwwdRFmaxsT3IU+Tl3vYKVRdjfhg8Bbdjw7B+E0y6F7Yz6l+eaQLn0BRmGMXIhcPDONPtOkMoNwx1etZh4zPJA== + +p-reduce@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" + integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= + p-retry@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328" @@ -3647,22 +8315,48 @@ p-retry@^3.0.1: dependencies: retry "^0.12.0" +p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + +p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== + dependencies: + p-finally "^1.0.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +page@^1.11.6: + version "1.11.6" + resolved "https://registry.yarnpkg.com/page/-/page-1.11.6.tgz#5ef4efc7073749b8085ccdaa0dcd7c9e0de12fe3" + integrity sha512-P6e2JfzkBrPeFCIPplLP7vDDiU84RUUZMrWdsH4ZBGJ8OosnwFkcUkBHp1DTIjuipLliw9yQn/ZJsXZvarsO+g== + dependencies: + path-to-regexp "~1.2.1" + pako@~1.0.5: - version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" - integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== parallel-transform@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06" - integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY= + version "1.2.0" + resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== dependencies: - cyclist "~0.2.2" + cyclist "^1.0.1" inherits "^2.0.3" readable-stream "^2.1.5" @@ -3673,6 +8367,14 @@ param-case@2.1.x: dependencies: no-case "^2.2.0" +param-case@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" + integrity sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA== + dependencies: + dot-case "^3.0.3" + tslib "^1.10.0" + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -3681,9 +8383,9 @@ parent-module@^1.0.0: callsites "^3.0.0" parse-asn1@^5.0.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc" - integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw== + version "5.1.5" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== dependencies: asn1.js "^4.0.0" browserify-aes "^1.0.0" @@ -3692,6 +8394,46 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" +parse-entities@^1.0.2, parse-entities@^1.1.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50" + integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + +parse-filepath@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891" + integrity sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE= + dependencies: + is-absolute "^1.0.0" + map-cache "^0.2.0" + path-root "^0.1.1" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -3700,16 +8442,53 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" +parse-json@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + lines-and-columns "^1.1.6" + +parse-node-version@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" + integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== + parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= +parseqs@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d" + integrity sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0= + dependencies: + better-assert "~1.0.0" + +parseuri@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a" + integrity sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo= + dependencies: + better-assert "~1.0.0" + parseurl@~1.3.2, parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +pascal-case@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" + integrity sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA== + dependencies: + no-case "^3.0.3" + tslib "^1.10.0" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -3725,11 +8504,23 @@ path-dirname@^1.0.0: resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -3745,11 +8536,51 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +path-root-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" + integrity sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0= + +path-root@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7" + integrity sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc= + dependencies: + path-root-regex "^0.1.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.2.1.tgz#b33705c140234d873c8721c7b9fd8b541ed3aff9" + integrity sha1-szcFwUAjTYc8hyHHuf2LVB7Tr/k= + dependencies: + isarray "0.0.1" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= + dependencies: + pify "^2.0.0" + path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -3757,6 +8588,11 @@ path-type@^3.0.0: dependencies: pify "^3.0.0" +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -3768,7 +8604,22 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -pify@^2.0.0: +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + +picomatch@^2.0.5, picomatch@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" + integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== + +pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= @@ -3778,7 +8629,7 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= -pify@^4.0.1: +pify@^4.0.0, pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== @@ -3795,6 +8646,13 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -3802,20 +8660,293 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -portfinder@^1.0.24: - version "1.0.24" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.24.tgz#11efbc6865f12f37624b6531ead1d809ed965cfa" - integrity sha512-ekRl7zD2qxYndYflwiryJwMioBI7LI7rVXg3EnLK3sjkouT5eOuhS3gS255XxBksa30VG8UPZYZCdgfGOfkSUg== +pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f" + integrity sha1-yBmscoBZpGHKscOImivjxJoATX8= dependencies: - async "^1.5.2" - debug "^2.2.0" - mkdirp "0.5.x" + find-up "^2.1.0" + +pkg-up@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" + integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== + dependencies: + find-up "^3.0.0" + +plugin-error@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-1.0.1.tgz#77016bd8919d0ac377fdcdd0322328953ca5781c" + integrity sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA== + dependencies: + ansi-colors "^1.0.1" + arr-diff "^4.0.0" + arr-union "^3.1.0" + extend-shallow "^3.0.2" + +plur@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" + integrity sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo= + dependencies: + irregular-plurals "^1.0.0" + +plur@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/plur/-/plur-3.1.1.tgz#60267967866a8d811504fe58f2faaba237546a5b" + integrity sha512-t1Ax8KUvV3FFII8ltczPn2tJdjqbd1sIzu6t4JL7nQ3EyeL/lTrj5PWKb06ic5/6XYDr65rQ4uzQEGN70/6X5w== + dependencies: + irregular-plurals "^2.0.0" + +portfinder@^1.0.25: + version "1.0.26" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.26.tgz#475658d56ca30bed72ac7f1378ed350bd1b64e70" + integrity sha512-Xi7mKxJHHMI3rIUrnm/jjUgwhbYMkp/XKEcZX3aG4BrumLpq3nmoQMX+ClYnDZnZ/New7IatC1no5RX0zo1vXQ== + dependencies: + async "^2.6.2" + debug "^3.1.1" + mkdirp "^0.5.1" + +portscanner@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/portscanner/-/portscanner-2.1.1.tgz#eabb409e4de24950f5a2a516d35ae769343fbb96" + integrity sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y= + dependencies: + async "1.5.2" + is-number-like "^1.0.3" posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postcss-attribute-case-insensitive@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-4.0.2.tgz#d93e46b504589e94ac7277b0463226c68041a880" + integrity sha512-clkFxk/9pcdb4Vkn0hAHq3YnxBQ2p0CGD1dy24jN+reBck+EWxMbxSUqN4Yj7t0w8csl87K6p0gxBe1utkJsYA== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^6.0.2" + +postcss-calc@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-7.0.2.tgz#504efcd008ca0273120568b0792b16cdcde8aac1" + integrity sha512-rofZFHUg6ZIrvRwPeFktv06GdbDYLcGqh9EwiMutZg+a0oePCCw1zHOEiji6LCpyRcjTREtPASuUqeAvYlEVvQ== + dependencies: + postcss "^7.0.27" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.2" + +postcss-color-functional-notation@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-2.0.1.tgz#5efd37a88fbabeb00a2966d1e53d98ced93f74e0" + integrity sha512-ZBARCypjEDofW4P6IdPVTLhDNXPRn8T2s1zHbZidW6rPaaZvcnCS2soYFIQJrMZSxiePJ2XIYTlcb2ztr/eT2g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-gray@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-color-gray/-/postcss-color-gray-5.0.0.tgz#532a31eb909f8da898ceffe296fdc1f864be8547" + integrity sha512-q6BuRnAGKM/ZRpfDascZlIZPjvwsRye7UDNalqVz3s7GDxMtqPY6+Q871liNxsonUw8oC61OG+PSaysYpl1bnw== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-color-hex-alpha@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-5.0.3.tgz#a8d9ca4c39d497c9661e374b9c51899ef0f87388" + integrity sha512-PF4GDel8q3kkreVXKLAGNpHKilXsZ6xuu+mOQMHWHLPNyjiUBOr75sp5ZKJfmv1MCus5/DWUGcK9hm6qHEnXYw== + dependencies: + postcss "^7.0.14" + postcss-values-parser "^2.0.1" + +postcss-color-mod-function@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/postcss-color-mod-function/-/postcss-color-mod-function-3.0.3.tgz#816ba145ac11cc3cb6baa905a75a49f903e4d31d" + integrity sha512-YP4VG+xufxaVtzV6ZmhEtc+/aTXH3d0JLpnYfxqTvwZPbJhWqp8bSY3nfNzNRFLgB4XSaBA82OE4VjOOKpCdVQ== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-color-rebeccapurple@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-4.0.1.tgz#c7a89be872bb74e45b1e3022bfe5748823e6de77" + integrity sha512-aAe3OhkS6qJXBbqzvZth2Au4V3KieR5sRQ4ptb2b2O8wgvB3SJBsdG+jsn2BZbbwekDG8nTfcCNKcSfe/lEy8g== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-colormin@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-4.0.3.tgz#ae060bce93ed794ac71264f08132d550956bd381" + integrity sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw== + dependencies: + browserslist "^4.0.0" + color "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-convert-values@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz#ca3813ed4da0f812f9d43703584e449ebe189a7f" + integrity sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-custom-media@^7.0.8: + version "7.0.8" + resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-7.0.8.tgz#fffd13ffeffad73621be5f387076a28b00294e0c" + integrity sha512-c9s5iX0Ge15o00HKbuRuTqNndsJUbaXdiNsksnVH8H4gdc+zbLzr/UasOwNG6CTDpLFekVY4672eWdiiWu2GUg== + dependencies: + postcss "^7.0.14" + +postcss-custom-properties@^8.0.11: + version "8.0.11" + resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-8.0.11.tgz#2d61772d6e92f22f5e0d52602df8fae46fa30d97" + integrity sha512-nm+o0eLdYqdnJ5abAJeXp4CEU1c1k+eB2yMCvhgzsds/e0umabFrN6HoTy/8Q4K5ilxERdl/JD1LO5ANoYBeMA== + dependencies: + postcss "^7.0.17" + postcss-values-parser "^2.0.1" + +postcss-custom-selectors@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-5.1.2.tgz#64858c6eb2ecff2fb41d0b28c9dd7b3db4de7fba" + integrity sha512-DSGDhqinCqXqlS4R7KGxL1OSycd1lydugJ1ky4iRXPHdBRiozyMHrdu0H3o7qNOCiZwySZTUI5MV0T8QhCLu+w== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-dir-pseudo-class@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-5.0.0.tgz#6e3a4177d0edb3abcc85fdb6fbb1c26dabaeaba2" + integrity sha512-3pm4oq8HYWMZePJY+5ANriPs3P07q+LW6FAdTlkFH2XqDdP4HeeJYMOzn0HYLhRSjBO3fhiqSwwU9xEULSrPgw== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-discard-comments@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz#1fbabd2c246bff6aaad7997b2b0918f4d7af4033" + integrity sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg== + dependencies: + postcss "^7.0.0" + +postcss-discard-duplicates@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz#3fe133cd3c82282e550fc9b239176a9207b784eb" + integrity sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ== + dependencies: + postcss "^7.0.0" + +postcss-discard-empty@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz#c8c951e9f73ed9428019458444a02ad90bb9f765" + integrity sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w== + dependencies: + postcss "^7.0.0" + +postcss-discard-overridden@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz#652aef8a96726f029f5e3e00146ee7a4e755ff57" + integrity sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg== + dependencies: + postcss "^7.0.0" + +postcss-double-position-gradients@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-1.0.0.tgz#fc927d52fddc896cb3a2812ebc5df147e110522e" + integrity sha512-G+nV8EnQq25fOI8CH/B6krEohGWnF5+3A6H/+JEpOncu5dCnkS1QQ6+ct3Jkaepw1NGVqqOZH6lqrm244mCftA== + dependencies: + postcss "^7.0.5" + postcss-values-parser "^2.0.0" + +postcss-env-function@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-2.0.2.tgz#0f3e3d3c57f094a92c2baf4b6241f0b0da5365d7" + integrity sha512-rwac4BuZlITeUbiBq60h/xbLzXY43qOsIErngWa4l7Mt+RaSkT7QBjXVGTcBHupykkblHMDrBFh30zchYPaOUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-focus-visible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-4.0.0.tgz#477d107113ade6024b14128317ade2bd1e17046e" + integrity sha512-Z5CkWBw0+idJHSV6+Bgf2peDOFf/x4o+vX/pwcNYrWpXFrSfTkQ3JQ1ojrq9yS+upnAlNRHeg8uEwFTgorjI8g== + dependencies: + postcss "^7.0.2" + +postcss-focus-within@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-3.0.0.tgz#763b8788596cee9b874c999201cdde80659ef680" + integrity sha512-W0APui8jQeBKbCGZudW37EeMCjDeVxKgiYfIIEo8Bdh5SpB9sxds/Iq8SEuzS0Q4YFOlG7EPFulbbxujpkrV2w== + dependencies: + postcss "^7.0.2" + +postcss-font-variant@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-4.0.0.tgz#71dd3c6c10a0d846c5eda07803439617bbbabacc" + integrity sha512-M8BFYKOvCrI2aITzDad7kWuXXTm0YhGdP9Q8HanmN4EF1Hmcgs1KK5rSHylt/lUJe8yLxiSwWAHdScoEiIxztg== + dependencies: + postcss "^7.0.2" + +postcss-gap-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-2.0.0.tgz#431c192ab3ed96a3c3d09f2ff615960f902c1715" + integrity sha512-QZSqDaMgXCHuHTEzMsS2KfVDOq7ZFiknSpkrPJY6jmxbugUPTuSzs/vuE5I3zv0WAS+3vhrlqhijiprnuQfzmg== + dependencies: + postcss "^7.0.2" + +postcss-html@^0.36.0: + version "0.36.0" + resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.36.0.tgz#b40913f94eaacc2453fd30a1327ad6ee1f88b204" + integrity sha512-HeiOxGcuwID0AFsNAL0ox3mW6MHH5cstWN1Z3Y+n6H+g12ih7LHdYxWwEA/QmrebctLjo79xz9ouK3MroHwOJw== + dependencies: + htmlparser2 "^3.10.0" + +postcss-image-set-function@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-3.0.1.tgz#28920a2f29945bed4c3198d7df6496d410d3f288" + integrity sha512-oPTcFFip5LZy8Y/whto91L9xdRHCWEMs3e1MdJxhgt4jy2WYXfhkng59fH5qLXSCPN8k4n94p1Czrfe5IOkKUw== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-initial@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-3.0.2.tgz#f018563694b3c16ae8eaabe3c585ac6319637b2d" + integrity sha512-ugA2wKonC0xeNHgirR4D3VWHs2JcU08WAi1KFLVcnb7IN89phID6Qtg2RIctWbnvp1TM2BOmDtX8GGLCKdR8YA== + dependencies: + lodash.template "^4.5.0" + postcss "^7.0.2" + +postcss-jsx@^0.36.0: + version "0.36.4" + resolved "https://registry.yarnpkg.com/postcss-jsx/-/postcss-jsx-0.36.4.tgz#37a68f300a39e5748d547f19a747b3257240bd50" + integrity sha512-jwO/7qWUvYuWYnpOb0+4bIIgJt7003pgU3P6nETBLaOyBXuTD55ho21xnals5nBrlpTIFodyd3/jBi6UO3dHvA== + dependencies: + "@babel/core" ">=7.2.2" + +postcss-lab-function@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-2.0.1.tgz#bb51a6856cd12289ab4ae20db1e3821ef13d7d2e" + integrity sha512-whLy1IeZKY+3fYdqQFuDBf8Auw+qFuVnChWjmxm/UhHWqNHZx+B99EwxTvGYmUBqe3Fjxs4L1BoZTJmPu6usVg== + dependencies: + "@csstools/convert-colors" "^1.4.0" + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-less@^3.1.0, postcss-less@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-3.1.4.tgz#369f58642b5928ef898ffbc1a6e93c958304c5ad" + integrity sha512-7TvleQWNM2QLcHqvudt3VYjULVB49uiW6XzEUFmvwHzvsOEF5MwBrIXZDJQvJNFGjJQTzSzZnDoCJ8h/ljyGXA== + dependencies: + postcss "^7.0.14" + postcss-load-config@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-2.1.0.tgz#c84d692b7bb7b41ddced94ee62e8ab31b417b003" @@ -3834,6 +8965,95 @@ postcss-loader@^3.0.0: postcss-load-config "^2.0.0" schema-utils "^1.0.0" +postcss-logical@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-3.0.0.tgz#2495d0f8b82e9f262725f75f9401b34e7b45d5b5" + integrity sha512-1SUKdJc2vuMOmeItqGuNaC+N8MzBWFWEkAnRnLpFYj1tGGa7NqyVBujfRtgNa2gXR+6RkGUiB2O5Vmh7E2RmiA== + dependencies: + postcss "^7.0.2" + +postcss-markdown@^0.36.0: + version "0.36.0" + resolved "https://registry.yarnpkg.com/postcss-markdown/-/postcss-markdown-0.36.0.tgz#7f22849ae0e3db18820b7b0d5e7833f13a447560" + integrity sha512-rl7fs1r/LNSB2bWRhyZ+lM/0bwKv9fhl38/06gF6mKMo/NPnp55+K1dSTosSVjFZc0e1ppBlu+WT91ba0PMBfQ== + dependencies: + remark "^10.0.1" + unist-util-find-all-after "^1.0.2" + +postcss-media-minmax@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-4.0.0.tgz#b75bb6cbc217c8ac49433e12f22048814a4f5ed5" + integrity sha512-fo9moya6qyxsjbFAYl97qKO9gyre3qvbMnkOZeZwlsW6XYFsvs2DMGDlchVLfAd8LHPZDxivu/+qW2SMQeTHBw== + dependencies: + postcss "^7.0.2" + +postcss-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= + +postcss-merge-longhand@^4.0.11: + version "4.0.11" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz#62f49a13e4a0ee04e7b98f42bb16062ca2549e24" + integrity sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw== + dependencies: + css-color-names "0.0.4" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + stylehacks "^4.0.0" + +postcss-merge-rules@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz#362bea4ff5a1f98e4075a713c6cb25aefef9a650" + integrity sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + cssnano-util-same-parent "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + vendors "^1.0.0" + +postcss-minify-font-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz#cd4c344cce474343fac5d82206ab2cbcb8afd5a6" + integrity sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-gradients@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz#93b29c2ff5099c535eecda56c4aa6e665a663471" + integrity sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + is-color-stop "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-minify-params@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz#6b9cef030c11e35261f95f618c90036d680db874" + integrity sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg== + dependencies: + alphanum-sort "^1.0.0" + browserslist "^4.0.0" + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + uniqs "^2.0.0" + +postcss-minify-selectors@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz#e2e5eb40bfee500d0cd9243500f5f8ea4262fbd8" + integrity sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g== + dependencies: + alphanum-sort "^1.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + postcss-modules-extract-imports@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e" @@ -3841,32 +9061,328 @@ postcss-modules-extract-imports@^2.0.0: dependencies: postcss "^7.0.5" -postcss-modules-local-by-default@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" - integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== +postcss-modules-local-by-default@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" + integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ== dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - postcss-value-parser "^3.3.1" + icss-utils "^4.1.1" + postcss "^7.0.16" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.0.0" -postcss-modules-scope@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" - integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== +postcss-modules-scope@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz#385cae013cc7743f5a7d7602d1073a89eaae62ee" + integrity sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ== dependencies: postcss "^7.0.6" postcss-selector-parser "^6.0.0" -postcss-modules-values@^2.0.0: +postcss-modules-values@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" + integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg== + dependencies: + icss-utils "^4.0.0" + postcss "^7.0.6" + +postcss-nesting@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-7.0.1.tgz#b50ad7b7f0173e5b5e3880c3501344703e04c052" + integrity sha512-FrorPb0H3nuVq0Sff7W2rnc3SmIcruVC6YwpcS+k687VxyxO33iE1amna7wHuRVzM8vfiYofXSBHNAZ3QhLvYg== + dependencies: + postcss "^7.0.2" + +postcss-normalize-charset@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4" + integrity sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g== + dependencies: + postcss "^7.0.0" + +postcss-normalize-display-values@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz#0dbe04a4ce9063d4667ed2be476bb830c825935a" + integrity sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-positions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz#05f757f84f260437378368a91f8932d4b102917f" + integrity sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA== + dependencies: + cssnano-util-get-arguments "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-repeat-style@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz#c4ebbc289f3991a028d44751cbdd11918b17910c" + integrity sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q== + dependencies: + cssnano-util-get-arguments "^4.0.0" + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-string@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz#cd44c40ab07a0c7a36dc5e99aace1eca4ec2690c" + integrity sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA== + dependencies: + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-timing-functions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz#8e009ca2a3949cdaf8ad23e6b6ab99cb5e7d28d9" + integrity sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A== + dependencies: + cssnano-util-get-match "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-unicode@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz#841bd48fdcf3019ad4baa7493a3d363b52ae1cfb" + integrity sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-url@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz#10e437f86bc7c7e58f7b9652ed878daaa95faae1" + integrity sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA== + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-normalize-whitespace@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz#bf1d4070fe4fcea87d1348e825d8cc0c5faa7d82" + integrity sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA== + dependencies: + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-ordered-values@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz#0cf75c820ec7d5c4d280189559e0b571ebac0eee" + integrity sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw== + dependencies: + cssnano-util-get-arguments "^4.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-overflow-shorthand@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" - integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== + resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-2.0.0.tgz#31ecf350e9c6f6ddc250a78f0c3e111f32dd4c30" + integrity sha512-aK0fHc9CBNx8jbzMYhshZcEv8LtYnBIRYQD5i7w/K/wS9c2+0NSR6B3OVMu5y0hBHYLcMGjfU+dmWYNKH0I85g== dependencies: - icss-replace-symbols "^1.1.0" - postcss "^7.0.6" + postcss "^7.0.2" -postcss-selector-parser@^6.0.0: +postcss-page-break@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-2.0.0.tgz#add52d0e0a528cabe6afee8b46e2abb277df46bf" + integrity sha512-tkpTSrLpfLfD9HvgOlJuigLuk39wVTbbd8RKcy8/ugV2bNBUW3xU+AIqyxhDrQr1VUj1RmyJrBn1YWrqUm9zAQ== + dependencies: + postcss "^7.0.2" + +postcss-place@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-4.0.1.tgz#e9f39d33d2dc584e46ee1db45adb77ca9d1dcc62" + integrity sha512-Zb6byCSLkgRKLODj/5mQugyuj9bvAAw9LqJJjgwz5cYryGeXfFZfSXoP1UfveccFmeq0b/2xxwcTEVScnqGxBg== + dependencies: + postcss "^7.0.2" + postcss-values-parser "^2.0.0" + +postcss-preset-env@^6.7.0: + version "6.7.0" + resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-6.7.0.tgz#c34ddacf8f902383b35ad1e030f178f4cdf118a5" + integrity sha512-eU4/K5xzSFwUFJ8hTdTQzo2RBLbDVt83QZrAvI07TULOkmyQlnYlpwep+2yIK+K+0KlZO4BvFcleOCCcUtwchg== + dependencies: + autoprefixer "^9.6.1" + browserslist "^4.6.4" + caniuse-lite "^1.0.30000981" + css-blank-pseudo "^0.1.4" + css-has-pseudo "^0.10.0" + css-prefers-color-scheme "^3.1.1" + cssdb "^4.4.0" + postcss "^7.0.17" + postcss-attribute-case-insensitive "^4.0.1" + postcss-color-functional-notation "^2.0.1" + postcss-color-gray "^5.0.0" + postcss-color-hex-alpha "^5.0.3" + postcss-color-mod-function "^3.0.3" + postcss-color-rebeccapurple "^4.0.1" + postcss-custom-media "^7.0.8" + postcss-custom-properties "^8.0.11" + postcss-custom-selectors "^5.1.2" + postcss-dir-pseudo-class "^5.0.0" + postcss-double-position-gradients "^1.0.0" + postcss-env-function "^2.0.2" + postcss-focus-visible "^4.0.0" + postcss-focus-within "^3.0.0" + postcss-font-variant "^4.0.0" + postcss-gap-properties "^2.0.0" + postcss-image-set-function "^3.0.1" + postcss-initial "^3.0.0" + postcss-lab-function "^2.0.1" + postcss-logical "^3.0.0" + postcss-media-minmax "^4.0.0" + postcss-nesting "^7.0.0" + postcss-overflow-shorthand "^2.0.0" + postcss-page-break "^2.0.0" + postcss-place "^4.0.1" + postcss-pseudo-class-any-link "^6.0.0" + postcss-replace-overflow-wrap "^3.0.0" + postcss-selector-matches "^4.0.0" + postcss-selector-not "^4.0.0" + +postcss-pseudo-class-any-link@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-6.0.0.tgz#2ed3eed393b3702879dec4a87032b210daeb04d1" + integrity sha512-lgXW9sYJdLqtmw23otOzrtbDXofUdfYzNm4PIpNE322/swES3VU9XlXHeJS46zT2onFO7V1QFdD4Q9LiZj8mew== + dependencies: + postcss "^7.0.2" + postcss-selector-parser "^5.0.0-rc.3" + +postcss-reduce-initial@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz#7fd42ebea5e9c814609639e2c2e84ae270ba48df" + integrity sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA== + dependencies: + browserslist "^4.0.0" + caniuse-api "^3.0.0" + has "^1.0.0" + postcss "^7.0.0" + +postcss-reduce-transforms@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz#17efa405eacc6e07be3414a5ca2d1074681d4e29" + integrity sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg== + dependencies: + cssnano-util-get-match "^4.0.0" + has "^1.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + +postcss-replace-overflow-wrap@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-3.0.0.tgz#61b360ffdaedca84c7c918d2b0f0d0ea559ab01c" + integrity sha512-2T5hcEHArDT6X9+9dVSPQdo7QHzG4XKclFT8rU5TzJPDN7RIRTbO9c4drUISOVemLj03aezStHCR2AIcr8XLpw== + dependencies: + postcss "^7.0.2" + +postcss-reporter@^1.3.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-1.4.1.tgz#c136f0a5b161915f379dd3765c61075f7e7b9af2" + integrity sha1-wTbwpbFhkV83ndN2XGEHX357mvI= + dependencies: + chalk "^1.0.0" + lodash "^4.1.0" + log-symbols "^1.0.2" + postcss "^5.0.0" + +postcss-reporter@^6.0.0, postcss-reporter@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-6.0.1.tgz#7c055120060a97c8837b4e48215661aafb74245f" + integrity sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw== + dependencies: + chalk "^2.4.1" + lodash "^4.17.11" + log-symbols "^2.2.0" + postcss "^7.0.7" + +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" + integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= + +postcss-safe-parser@^4.0.0, postcss-safe-parser@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-4.0.2.tgz#a6d4e48f0f37d9f7c11b2a581bf00f8ba4870b96" + integrity sha512-Uw6ekxSWNLCPesSv/cmqf2bY/77z11O7jZGPax3ycZMFU/oi2DMH9i89AdHc1tRwFg/arFoEwX0IS3LCUxJh1g== + dependencies: + postcss "^7.0.26" + +postcss-sass@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.3.5.tgz#6d3e39f101a53d2efa091f953493116d32beb68c" + integrity sha512-B5z2Kob4xBxFjcufFnhQ2HqJQ2y/Zs/ic5EZbCywCkxKd756Q40cIQ/veRDwSrw1BF6+4wUgmpm0sBASqVi65A== + dependencies: + gonzales-pe "^4.2.3" + postcss "^7.0.1" + +postcss-sass@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/postcss-sass/-/postcss-sass-0.4.4.tgz#91f0f3447b45ce373227a98b61f8d8f0785285a3" + integrity sha512-BYxnVYx4mQooOhr+zer0qWbSPYnarAy8ZT7hAQtbxtgVf8gy+LSLT/hHGe35h14/pZDTw1DsxdbrwxBN++H+fg== + dependencies: + gonzales-pe "^4.3.0" + postcss "^7.0.21" + +postcss-scss@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-2.0.0.tgz#248b0a28af77ea7b32b1011aba0f738bda27dea1" + integrity sha512-um9zdGKaDZirMm+kZFKKVsnKPF7zF7qBAtIfTSnZXD1jZ0JNZIxdB6TxQOjCnlSzLRInVl2v3YdBh/M881C4ug== + dependencies: + postcss "^7.0.0" + +postcss-selector-matches@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-matches/-/postcss-selector-matches-4.0.0.tgz#71c8248f917ba2cc93037c9637ee09c64436fcff" + integrity sha512-LgsHwQR/EsRYSqlwdGzeaPKVT0Ml7LAT6E75T8W8xLJY62CE4S/l03BWIt3jT8Taq22kXP08s2SfTSzaraoPww== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-not@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-4.0.0.tgz#c68ff7ba96527499e832724a2674d65603b645c0" + integrity sha512-W+bkBZRhqJaYN8XAnbbZPLWMvZD1wKTu0UxtFKdhtGjWYmxhkUneoeOhRJKdAE5V7ZTlnbHfCR+6bNwK9e1dTQ== + dependencies: + balanced-match "^1.0.0" + postcss "^7.0.2" + +postcss-selector-parser@^2.0.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + integrity sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A= + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^3.0.0, postcss-selector-parser@^3.1.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz#b310f5c4c0fdaf76f94902bbaa30db6aa84f5270" + integrity sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA== + dependencies: + dot-prop "^5.2.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^5.0.0-rc.3, postcss-selector-parser@^5.0.0-rc.4: + version "5.0.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c" + integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ== + dependencies: + cssesc "^2.0.0" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c" integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg== @@ -3875,29 +9391,79 @@ postcss-selector-parser@^6.0.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: +postcss-sorting@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-4.1.0.tgz#a107f0bf3852977fa64e4442bc340c88d5aacdb3" + integrity sha512-r4T2oQd1giURJdHQ/RMb72dKZCuLOdWx2B/XhXN1Y1ZdnwXsKH896Qz6vD4tFy9xSjpKNYhlZoJmWyhH/7JUQw== + dependencies: + lodash "^4.17.4" + postcss "^7.0.0" + +postcss-sorting@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-5.0.1.tgz#10d5d0059eea8334dacc820c0121864035bc3f11" + integrity sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA== + dependencies: + lodash "^4.17.14" + postcss "^7.0.17" + +postcss-svgo@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-4.0.2.tgz#17b997bc711b333bab143aaed3b8d3d6e3d38258" + integrity sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw== + dependencies: + is-svg "^3.0.0" + postcss "^7.0.0" + postcss-value-parser "^3.0.0" + svgo "^1.0.0" + +postcss-syntax@^0.36.2: + version "0.36.2" + resolved "https://registry.yarnpkg.com/postcss-syntax/-/postcss-syntax-0.36.2.tgz#f08578c7d95834574e5593a82dfbfa8afae3b51c" + integrity sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w== + +postcss-unique-selectors@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz#9446911f3289bfd64c6d680f073c03b1f9ee4bac" + integrity sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg== + dependencies: + alphanum-sort "^1.0.0" + postcss "^7.0.0" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.0, postcss-value-parser@^3.3.0: version "3.3.1" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== -postcss-value-parser@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz#482282c09a42706d1fc9a069b73f44ec08391dc9" - integrity sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ== +postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== -postcss@^7.0.0, postcss@^7.0.23: - version "7.0.25" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.25.tgz#dd2a2a753d50b13bed7a2009b4a18ac14d9db21e" - integrity sha512-NXXVvWq9icrm/TgQC0O6YVFi4StfJz46M1iNd/h6B26Nvh/HKI+q4YZtFN/EjcInZliEscO/WL10BXnc1E5nwg== +postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/postcss-values-parser/-/postcss-values-parser-2.0.1.tgz#da8b472d901da1e205b47bdc98637b9e9e550e5f" + integrity sha512-2tLuBsA6P4rYTNKCXYG/71C7j1pU6pK503suYOmn4xYrQIzW+opD+7FAFNuGSdZC/3Qfy334QbeMu7MEb8gOxg== dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" -postcss@^7.0.14, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.17" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" - integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== +postcss@^5.0.0, postcss@^5.0.18: + version "5.2.18" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.18.tgz#badfa1497d46244f6390f58b319830d9107853c5" + integrity sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg== + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.13, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.21, postcss@^7.0.26, postcss@^7.0.27, postcss@^7.0.5, postcss@^7.0.6, postcss@^7.0.7: + version "7.0.28" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.28.tgz#d349ced7743475717ba91f6810efb58c51fb5dbb" + integrity sha512-YU6nVhyWIsVtlNlnAj1fHTsUKW5qxm3KEgzq2Jj6KTEFOTK8QWR12eIDvrlWhiSTK8WIBFTBhOJV4DY6dUuEbw== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -3908,7 +9474,22 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= -pretty-error@^2.0.2: +prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + +prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + +pretty-bytes@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2" + integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg== + +pretty-error@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM= @@ -3916,7 +9497,17 @@ pretty-error@^2.0.2: renderkid "^2.0.1" utila "~0.4" -process-nextick-args@~2.0.0: +pretty-hrtime@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" + integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= + +private@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" + integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg== + +process-nextick-args@^2.0.0, process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== @@ -3936,19 +9527,34 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= + proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" + integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== dependencies: forwarded "~0.1.2" - ipaddr.js "1.9.0" + ipaddr.js "1.9.1" prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + +psl@^1.1.28: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + public-encrypt@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" @@ -3977,7 +9583,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pumpify@^1.3.3: +pumpify@^1.3.3, pumpify@^1.3.5: version "1.5.1" resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== @@ -3996,16 +9602,49 @@ punycode@^1.2.4: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +q@^1.1.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" + integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= + +qs@6.2.3: + version "6.2.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.3.tgz#1cfcb25c10a9b2b483053ff39f5dfc9233908cfe" + integrity sha1-HPyyXBCpsrSDBT/zn138kjOQjP4= + qs@6.7.0: version "6.7.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== +qs@~6.5.2: + version "6.5.2" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +query-string@^6.11.1: + version "6.12.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.12.1.tgz#2ae4d272db4fba267141665374e49a1de09e8a7c" + integrity sha512-OHj+zzfRMyj3rmo/6G8a5Ifvw3AleL/EbcHMD27YA31Q+cO5lfmQxECkImuNVjcskLcvBRVHNAB3w6udMs1eAA== + dependencies: + decode-uri-component "^0.2.0" + split-on-first "^1.0.0" + strict-uri-encode "^2.0.0" + querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -4021,6 +9660,16 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== +quick-lru@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" + integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= + +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -4036,7 +9685,7 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.2.1, range-parser@~1.2.1: +range-parser@^1.2.1, range-parser@~1.2.0, range-parser@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== @@ -4051,20 +9700,97 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" -rc@^1.2.7: - version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" - integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== +raw-body@^2.3.2: + version "2.4.1" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.1.tgz#30ac82f98bb5ae8c152e67149dac8d55153b168c" + integrity sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA== dependencies: - deep-extend "^0.6.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" + bytes "3.1.0" + http-errors "1.7.3" + iconv-lite "0.4.24" + unpipe "1.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: - version "2.3.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" - integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== +read-file-stdin@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/read-file-stdin/-/read-file-stdin-0.2.1.tgz#25eccff3a153b6809afacb23ee15387db9e0ee61" + integrity sha1-JezP86FTtoCa+ssj7hU4fbng7mE= + dependencies: + gather-stream "^1.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" + integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= + dependencies: + find-up "^2.0.0" + read-pkg "^3.0.0" + +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" inherits "~2.0.3" @@ -4074,15 +9800,25 @@ rc@^1.2.7: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.1.1: - version "3.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" - integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== +"readable-stream@2 || 3", readable-stream@^3.0.6, readable-stream@^3.1.1, readable-stream@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -4092,6 +9828,62 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +redent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" + integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= + dependencies: + indent-string "^3.0.0" + strip-indent "^2.0.0" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + +regenerate-unicode-properties@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz#e5de7111d655e7ba60c057dbe9ff37c87e65cdec" + integrity sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA== + dependencies: + regenerate "^1.4.0" + +regenerate@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" + integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== + +regenerator-runtime@^0.13.4: + version "0.13.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== + +regenerator-transform@^0.14.2: + version "0.14.4" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.4.tgz#5266857896518d1616a78a0479337a30ea974cc7" + integrity sha512-EaJaKPBI9GvKpvUz2mz4fhx7WPgvwRLY9v3hlNHWmAuJHI13T4nwKnNvm5RWJzEdnI5g5UwtOww+S8IdoUC2bw== + dependencies: + "@babel/runtime" "^7.8.4" + private "^0.1.8" + regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" @@ -4101,23 +9893,166 @@ regex-not@^1.0.0, regex-not@^1.0.2: safe-regex "^1.1.0" regexp.prototype.flags@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.2.0.tgz#6b30724e306a27833eeb171b66ac8890ba37e41c" - integrity sha512-ztaw4M1VqgMwl9HlPpOuiYgItcHlunW0He2fE6eNfT6E/CF2FtYi9ofOYe4mKntstYk0Fyh/rDRBdS3AnxjlrA== + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" + integrity sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ== dependencies: - define-properties "^1.1.2" + define-properties "^1.1.3" + es-abstract "^1.17.0-next.1" regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== -relateurl@0.2.x: +regexpu-core@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.7.0.tgz#fcbf458c50431b0bb7b45d6967b8192d91f3d938" + integrity sha512-TQ4KXRnIn6tz6tjnrXEkD/sshygKH/j5KzK86X8MkeHyZ8qst/LZ89j3X4/8HEIfHANTFIP/AbXakeRhWIl5YQ== + dependencies: + regenerate "^1.4.0" + regenerate-unicode-properties "^8.2.0" + regjsgen "^0.5.1" + regjsparser "^0.6.4" + unicode-match-property-ecmascript "^1.0.4" + unicode-match-property-value-ecmascript "^1.2.0" + +regjsgen@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.1.tgz#48f0bf1a5ea205196929c0d9798b42d1ed98443c" + integrity sha512-5qxzGZjDs9w4tzT3TPhCJqWdCc3RLYwy9J2NB0nm5Lz+S273lvWcpjaTGHsT1dc6Hhfq41uSEOw8wBmxrKOuyg== + +regjsparser@^0.6.4: + version "0.6.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.4.tgz#a769f8684308401a66e9b529d2436ff4d0666272" + integrity sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw== + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x, relateurl@^0.2.7: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk= -remove-trailing-separator@^1.0.1: +remark-parse@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-6.0.3.tgz#c99131052809da482108413f87b0ee7f52180a3a" + integrity sha512-QbDXWN4HfKTUC0hHa4teU463KclLAnwpn/FBn87j9cKYJWWawbiLgMfP2Q4XwhxxuuuOxHlw+pSN0OKuJwyVvg== + dependencies: + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^1.1.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^1.0.0" + vfile-location "^2.0.0" + xtend "^4.0.1" + +remark-parse@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-8.0.2.tgz#5999bc0b9c2e3edc038800a64ff103d0890b318b" + integrity sha512-eMI6kMRjsAGpMXXBAywJwiwAse+KNpmt+BK55Oofy4KvBZEqUDj6mWbGLJZrujoPIPPxDXzn3T9baRlpsm2jnQ== + dependencies: + ccount "^1.0.0" + collapse-white-space "^1.0.2" + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + is-word-character "^1.0.0" + markdown-escapes "^1.0.0" + parse-entities "^2.0.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + trim "0.0.1" + trim-trailing-lines "^1.0.0" + unherit "^1.0.4" + unist-util-remove-position "^2.0.0" + vfile-location "^3.0.0" + xtend "^4.0.1" + +remark-stringify@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-6.0.4.tgz#16ac229d4d1593249018663c7bddf28aafc4e088" + integrity sha512-eRWGdEPMVudijE/psbIDNcnJLRVx3xhfuEsTDGgH4GsFF91dVhw5nhmnBppafJ7+NWINW6C7ZwWbi30ImJzqWg== + dependencies: + ccount "^1.0.0" + is-alphanumeric "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + longest-streak "^2.0.1" + markdown-escapes "^1.0.0" + markdown-table "^1.1.0" + mdast-util-compact "^1.0.0" + parse-entities "^1.0.2" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + stringify-entities "^1.0.1" + unherit "^1.0.4" + xtend "^4.0.1" + +remark-stringify@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-8.0.0.tgz#33423ab8bf3076fb197f4cf582aaaf866b531625" + integrity sha512-cABVYVloFH+2ZI5bdqzoOmemcz/ZuhQSH6W6ZNYnLojAUUn3xtX7u+6BpnYp35qHoGr2NFBsERV14t4vCIeW8w== + dependencies: + ccount "^1.0.0" + is-alphanumeric "^1.0.0" + is-decimal "^1.0.0" + is-whitespace-character "^1.0.0" + longest-streak "^2.0.1" + markdown-escapes "^1.0.0" + markdown-table "^2.0.0" + mdast-util-compact "^2.0.0" + parse-entities "^2.0.0" + repeat-string "^1.5.4" + state-toggle "^1.0.0" + stringify-entities "^3.0.0" + unherit "^1.0.4" + xtend "^4.0.1" + +remark@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark/-/remark-10.0.1.tgz#3058076dc41781bf505d8978c291485fe47667df" + integrity sha512-E6lMuoLIy2TyiokHprMjcWNJ5UxfGQjaMSMhV+f4idM625UjjK4j798+gPs5mfjzDE6vL0oFKVeZM6gZVSVrzQ== + dependencies: + remark-parse "^6.0.0" + remark-stringify "^6.0.0" + unified "^7.0.0" + +remark@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/remark/-/remark-12.0.0.tgz#d1c145c07341c9232f93b2f8539d56da15a2548c" + integrity sha512-oX4lMIS0csgk8AEbzY0h2jdR0ngiCHOpwwpxjmRa5TqAkeknY+tkhjRJGZqnCmvyuWh55/0SW5WY3R3nn3PH9A== + dependencies: + remark-parse "^8.0.0" + remark-stringify "^8.0.0" + unified "^9.0.0" + +remove-bom-buffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" + integrity sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ== + dependencies: + is-buffer "^1.1.5" + is-utf8 "^0.2.1" + +remove-bom-stream@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz#05f1a593f16e42e1fb90ebf59de8e569525f9523" + integrity sha1-BfGlk/FuQuH7kOv1nejlaVJflSM= + dependencies: + remove-bom-buffer "^3.0.0" + safe-buffer "^5.1.0" + through2 "^2.0.3" + +remove-trailing-separator@^1.0.1, remove-trailing-separator@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= @@ -4138,11 +10073,68 @@ repeat-element@^1.1.2: resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== -repeat-string@^1.6.1: +repeat-string@^1.0.0, repeat-string@^1.5.4, repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= + dependencies: + is-finite "^1.0.0" + +replace-ext@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" + integrity sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ= + +replace-ext@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb" + integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs= + +replace-ext@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.1.tgz#2d6d996d04a15855d967443631dd5f77825b016a" + integrity sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw== + +replace-homedir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/replace-homedir/-/replace-homedir-1.0.0.tgz#e87f6d513b928dde808260c12be7fec6ff6e798c" + integrity sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw= + dependencies: + homedir-polyfill "^1.0.1" + is-absolute "^1.0.0" + remove-trailing-separator "^1.1.0" + +request@^2.87.0, request@^2.88.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -4158,12 +10150,7 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -requirejs@^2.3.5: - version "2.3.6" - resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.6.tgz#e5093d9601c2829251258c0b9445d4d19fa9e7c9" - integrity sha512-ipEzlWQe6RK3jkzikgCupiTbTvm4S0/CAU5GlgptkN5SO6F3u0UD0K18wy6ErDqiCyP4J4YYe1HuAShvsxePLg== - -requires-port@^1.0.0: +requires-port@1.x.x, requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= @@ -4198,17 +10185,51 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-options@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve-options/-/resolve-options-1.1.0.tgz#32bb9e39c06d67338dc9378c0d6d6074566ad131" + integrity sha1-MrueOcBtZzONyTeMDW1gdFZq0TE= + dependencies: + value-or-function "^3.0.0" + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.3.2, resolve@^1.4.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: - onetime "^2.0.0" + path-parse "^1.0.6" + +resp-modifier@6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/resp-modifier/-/resp-modifier-6.0.2.tgz#b124de5c4fbafcba541f48ffa73970f4aa456b4f" + integrity sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08= + dependencies: + debug "^2.2.0" + minimatch "^3.0.2" + +responselike@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" signal-exit "^3.0.2" ret@~0.1.10: @@ -4221,13 +10242,42 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rgb-regex@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/rgb-regex/-/rgb-regex-1.0.1.tgz#c0e0d6882df0e23be254a475e8edd41915feaeb1" + integrity sha1-wODWiC3w4jviVKR16O3UGRX+rrE= + +rgba-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" + integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= + +rimraf@2, rimraf@^2.5.4, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -4236,12 +10286,15 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -run-async@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" - integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA= - dependencies: - is-promise "^2.1.0" +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" @@ -4250,10 +10303,22 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.4.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7" - integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg== +rx@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" + integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= + +rxjs@^5.5.6: + version "5.5.12" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" + integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== + dependencies: + symbol-observable "1.0.1" + +rxjs@^6.5.3: + version "6.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.5.tgz#c5c884e3094c8cfee31bf27eb87e54ccfc87f9ec" + integrity sha512-WfQI+1gohdf0Dai/Bbmk5L5ItH5tYqm3ki2c5GdWhKjalzjg93N3avFjVStyZZz+A2Em+ZxKH5bNghw9UeylGQ== dependencies: tslib "^1.9.0" @@ -4262,7 +10327,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== @@ -4274,12 +10339,32 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@^1.2.4: +sass-graph@2.2.5: + version "2.2.5" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.5.tgz#a981c87446b8319d96dce0671e487879bd24c2e8" + integrity sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag== + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^13.3.2" + +sass-graph@^2.2.4: + version "2.2.6" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.6.tgz#09fda0e4287480e3e4967b72a2d133ba09b8d827" + integrity sha512-MKuEYXFSGuRSi8FZ3A7imN1CeVn9Gpw0/SFJKdL1ejXJneI9a5rwlEZrKejhEFAA3O6yr3eIyl/WuvASvlT36g== + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -4301,6 +10386,34 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" +schema-utils@^2.6.5, schema-utils@^2.6.6: + version "2.6.6" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.6.tgz#299fe6bd4a3365dc23d99fd446caff8f1d6c330c" + integrity sha512-wHutF/WPSbIi9x6ctjGGk2Hvl0VOz5l3EKEuKbjPlB30mKZUzb9A5k9yEXRX3pwyqVLPvpfZZEllaFq/M718hA== + dependencies: + ajv "^6.12.0" + ajv-keywords "^3.4.1" + +screenfull@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.2.tgz#b9acdcf1ec676a948674df5cd0ff66b902b0bed7" + integrity sha512-cCF2b+L/mnEiORLN5xSAz6H3t18i2oHh9BA8+CQlAh5DRw2+NFAGQJOSYbcGw8B2k04g/lVvFcfZ83b3ysH5UQ== + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE= + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +seek-bzip@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.5.tgz#cfe917cb3d274bcffac792758af53173eb1fabdc" + integrity sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w= + dependencies: + commander "~2.8.1" + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -4313,16 +10426,64 @@ selfsigned@^1.10.7: dependencies: node-forge "0.9.0" -semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: - version "5.7.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" - integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== +semver-greatest-satisfied-range@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz#13e8c2658ab9691cb0cd71093240280d36f77a5b" + integrity sha1-E+jCZYq5aRywzXEJMkAoDTb3els= + dependencies: + sver-compat "^1.5.0" -semver@^6.3.0: +semver-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338" + integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw== + +semver-truncate@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/semver-truncate/-/semver-truncate-1.1.2.tgz#57f41de69707a62709a7e0104ba2117109ea47e8" + integrity sha1-V/Qd5pcHpicJp+AQS6IRcQnqR+g= + dependencies: + semver "^5.3.0" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + +semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + +semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + +send@0.16.2: + version "0.16.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" + integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "~1.6.2" + mime "1.4.1" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.4.0" + send@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -4342,17 +10503,12 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" -serialize-javascript@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== - serialize-javascript@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.2.tgz#ecec53b0e0317bdc95ef76ab7074b7384785fa61" integrity sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ== -serve-index@^1.9.1: +serve-index@1.9.1, serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk= @@ -4365,6 +10521,16 @@ serve-index@^1.9.1: mime-types "~2.1.17" parseurl "~1.3.2" +serve-static@1.13.2: + version "1.13.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1" + integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.2" + send "0.16.2" + serve-static@1.14.1: version "1.14.1" resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" @@ -4375,6 +10541,11 @@ serve-static@1.14.1: parseurl "~1.3.3" send "0.17.1" +server-destroy@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/server-destroy/-/server-destroy-1.0.1.tgz#f13bf928e42b9c3e79383e61cc3998b5d14e6cdd" + integrity sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0= + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -4390,6 +10561,13 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +set-value@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-3.0.2.tgz#74e8ecd023c33d0f77199d415409a40f21e61b90" + integrity sha512-npjkVoz+ank0zjlV9F47Fdbjfj/PfXyVhZvGALWsyIYU/qrMzpi6avjKW3/7KeSU2Df3I46BrN1xOI1+6vW0hA== + dependencies: + is-plain-object "^2.0.4" + setimmediate@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" @@ -4413,10 +10591,12 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -shaka-player@^2.5.5: - version "2.5.5" - resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.5.tgz#81e7265f28f631afd3837c06ec6637824bda71e4" - integrity sha512-YEWBFapWKjwy2+wIgH9NqoFW9A14LIYNAoJ9cQr3c9BGS7qjqxeiYM/H1BJ8so1FQexpsWUdyjwHvcspdc7/nw== +shaka-player@^2.5.11: + version "2.5.11" + resolved "https://registry.yarnpkg.com/shaka-player/-/shaka-player-2.5.11.tgz#af550a0ee3aadf7be4e64e1a4d615c8d728e0b0f" + integrity sha512-SiZd/vCUPeKXNPnfWcBdraskdUYLtm+DITWceCZvRP4eoxxQuRI0MekVJTGqu5d7B2yW9TdQh5ojyRAjbQPFGA== + dependencies: + eme-encryption-scheme-polyfill "^2.0.1" shebang-command@^1.2.0: version "1.2.0" @@ -4431,15 +10611,32 @@ shebang-regex@^1.0.0: integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= + version "3.0.3" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" + integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slice-ansi@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -4479,6 +10676,81 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +socket.io-adapter@~1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz#ab3f0d6f66b8fc7fca3959ab5991f82221789be9" + integrity sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g== + +socket.io-client@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f" + integrity sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~3.1.0" + engine.io-client "~3.2.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.2.0" + to-array "0.1.4" + +socket.io-client@^2.0.4: + version "2.3.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.3.0.tgz#14d5ba2e00b9bcd145ae443ab96b3f86cbcc1bb4" + integrity sha512-cEQQf24gET3rfhxZ2jJ5xzAOo/xhZwK+mOqtGRg5IowZsMgwvHwnf/mCRapAAkadhM26y+iydgwsXGObBB5ZdA== + dependencies: + backo2 "1.0.2" + base64-arraybuffer "0.1.5" + component-bind "1.0.0" + component-emitter "1.2.1" + debug "~4.1.0" + engine.io-client "~3.4.0" + has-binary2 "~1.0.2" + has-cors "1.1.0" + indexof "0.0.1" + object-component "0.0.3" + parseqs "0.0.5" + parseuri "0.0.5" + socket.io-parser "~3.3.0" + to-array "0.1.4" + +socket.io-parser@~3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077" + integrity sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io-parser@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.3.0.tgz#2b52a96a509fdf31440ba40fed6094c7d4f1262f" + integrity sha512-hczmV6bDgdaEbVqhAeVMM/jfUfzuEZHsQg6eOmLgJht6G3mPKMxYm75w2+qhAQZ+4X+1+ATZ+QFKeOZD5riHng== + dependencies: + component-emitter "1.2.1" + debug "~3.1.0" + isarray "2.0.1" + +socket.io@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980" + integrity sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA== + dependencies: + debug "~3.1.0" + engine.io "~3.2.0" + has-binary2 "~1.0.2" + socket.io-adapter "~1.1.0" + socket.io-client "2.1.1" + socket.io-parser "~3.2.0" + sockjs-client@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.4.0.tgz#c9f2568e19c8fd8173b4997ea3420e0bb306c7d5" @@ -4499,31 +10771,52 @@ sockjs@0.3.19: faye-websocket "^0.10.0" uuid "^3.0.1" -sortablejs@^1.9.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.0.tgz#0ebc054acff2486569194a2f975b2b145dd5e7d6" - integrity sha512-+e0YakK1BxgEZpf9l9UiFaiQ8ZOBn1p/4qkkXr8QDVmYyCrUDTyDRRGm0AgW4E4cD0wtgxJ6yzIRkSPUwqhuhg== +sort-keys-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" + integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= + dependencies: + sort-keys "^1.0.0" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + +sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + +sortablejs@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sortablejs/-/sortablejs-1.10.2.tgz#6e40364d913f98b85a14f6678f92b5c1221f5290" + integrity sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A== source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-resolve@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" - integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA== +source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: - atob "^2.1.1" + atob "^2.1.2" decode-uri-component "^0.2.0" resolve-url "^0.2.1" source-map-url "^0.4.0" urix "^0.1.0" source-map-support@~0.5.12: - version "0.5.13" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" - integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + version "0.5.19" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" + integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -4533,7 +10826,14 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.6: +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + integrity sha1-66T12pwNyZneaAMti092FzZSA2s= + dependencies: + amdefine ">=0.0.4" + +source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -4543,6 +10843,37 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sparkles@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.1.tgz#008db65edce6c50eec0c5e228e1945061dd0437c" + integrity sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw== + +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -4556,9 +10887,9 @@ spdy-transport@^3.0.0: wbuf "^1.7.3" spdy@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.1.tgz#6f12ed1c5db7ea4f24ebb8b89ba58c87c08257f2" - integrity sha512-HeZS3PBdMA+sZSu0qwpCxl3DeALD5ASx8pAX0jZdKXSpPWbQ6SYGnlg3BBmYLx5LtiZrmkAZfErCm2oECBcioA== + version "4.0.2" + resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" + integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== dependencies: debug "^4.1.0" handle-thing "^2.0.0" @@ -4566,6 +10897,16 @@ spdy@^4.0.1: select-hose "^2.0.0" spdy-transport "^3.0.0" +specificity@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" + integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== + +split-on-first@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" + integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -4573,11 +10914,45 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split-string@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-6.1.0.tgz#e9cedcf94cdab077d9b5528927894dec4b0f42ab" + integrity sha512-9UBdnmnvx2NLLd4bMs7CEKK+wSzbujVv3ONyorkP1o8M3pVJQtXDO1cN19xD1JJs6ltOrtPrkUND0HzLSinUcA== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +squeak@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/squeak/-/squeak-1.3.0.tgz#33045037b64388b567674b84322a6521073916c3" + integrity sha1-MwRQN7ZDiLVnZ0uEMiplIQc5FsM= + dependencies: + chalk "^1.0.0" + console-stream "^0.1.1" + lpad-align "^1.0.1" + +sshpk@^1.7.0: + version "1.16.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +ssr-window@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ssr-window/-/ssr-window-1.0.1.tgz#30752a6a4666e7767f0b7e6aa6fc2fdbd0d9b369" + integrity sha512-dgFqB+f00LJTEgb6UXhx0h+SrG50LJvti2yMKMqAgzfUmUXZrLSv2fjULF7AWGwK25EXu8+smLR3jYsJQChPsg== + ssri@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" @@ -4585,6 +10960,21 @@ ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" +stable@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== + +stack-trace@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + +state-toggle@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe" + integrity sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -4598,6 +10988,23 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + integrity sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4= + +statuses@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087" + integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + +stdout-stream@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de" + integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA== + dependencies: + readable-stream "^2.0.1" + stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -4606,6 +11013,14 @@ stream-browserify@^2.0.1: inherits "~2.0.1" readable-stream "^2.0.2" +stream-combiner@*: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + integrity sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg= + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + stream-each@^1.1.0: version "1.2.3" resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" @@ -4614,6 +11029,11 @@ stream-each@^1.1.0: end-of-stream "^1.1.0" stream-shift "^1.0.0" +stream-exhaust@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stream-exhaust/-/stream-exhaust-1.0.2.tgz#acdac8da59ef2bc1e17a2c0ccf6c320d120e555d" + integrity sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw== + stream-http@^2.7.2: version "2.8.3" resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" @@ -4626,11 +11046,36 @@ stream-http@^2.7.2: xtend "^4.0.0" stream-shift@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" - integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= + version "1.0.1" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" + integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -string-width@^1.0.1: +stream-throttle@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/stream-throttle/-/stream-throttle-0.1.3.tgz#add57c8d7cc73a81630d31cd55d3961cfafba9c3" + integrity sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM= + dependencies: + commander "^2.2.0" + limiter "^1.0.5" + +stream-to-array@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/stream-to-array/-/stream-to-array-2.3.0.tgz#bbf6b39f5f43ec30bc71babcb37557acecf34353" + integrity sha1-u/azn19D7DC8cbq8s3VXrOzzQ1M= + dependencies: + any-promise "^1.1.0" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + +strict-uri-encode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" + integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= + +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= @@ -4639,7 +11084,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -4656,36 +11101,61 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" + integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.0" + +string.prototype.trimend@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" + integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== +string.prototype.trimleft@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" + integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== dependencies: define-properties "^1.1.3" - function-bind "^1.1.1" + es-abstract "^1.17.5" + string.prototype.trimstart "^1.0.0" -string_decoder@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d" - integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w== +string.prototype.trimright@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" + integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== dependencies: - safe-buffer "~5.1.0" + define-properties "^1.1.3" + es-abstract "^1.17.5" + string.prototype.trimend "^1.0.0" -string_decoder@^1.1.1: +string.prototype.trimstart@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" + integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -4693,6 +11163,27 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +stringify-entities@^1.0.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-1.3.2.tgz#a98417e5471fd227b3e45d3db1861c11caf668f7" + integrity sha512-nrBAQClJAPN2p+uGCVJRPIPakKeKWZ9GtBCmormE7pWOSlHat7+x5A8gx85M7HM5Dt0BP3pP5RhVW77WdbJJ3A== + dependencies: + character-entities-html4 "^1.0.0" + character-entities-legacy "^1.0.0" + is-alphanumerical "^1.0.0" + is-hexadecimal "^1.0.0" + +stringify-entities@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-3.0.0.tgz#455abe501f8b7859ba5726a25a8872333c65b0a7" + integrity sha512-h7NJJIssprqlyjHT2eQt2W1F+MCcNmwPGlKb0bWEdET/3N44QN3QbUF/ueKCgAssyKRZ3Br9rQ7FcXjHr0qLHw== + dependencies: + character-entities-html4 "^1.0.0" + character-entities-legacy "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.2" + is-hexadecimal "^1.0.0" + strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -4714,23 +11205,259 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== + dependencies: + ansi-regex "^5.0.0" + +strip-bom-string@1.X: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= - -style-loader@^0.23.1: - version "0.23.1" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" - integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= dependencies: - loader-utils "^1.1.0" - schema-utils "^1.0.0" + get-stdin "^4.0.1" + +strip-indent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" + integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.0.tgz#7638d31422129ecf4457440009fba03f9f9ac180" + integrity sha512-e6/d0eBu7gHtdCqFt0xJr642LdToM5/cN4Qb9DbHjVx1CP5RyeM+zH7pbecEmDv/lBqb0QH+6Uqq75rxFPkM0w== + +strip-outer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + +style-loader@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.2.1.tgz#c5cbbfbf1170d076cfdd86e0109c5bba114baa1a" + integrity sha512-ByHSTQvHLkWE9Ir5+lGbVOXhxX10fbprhLvdg96wedFZb4NDekDPxVKv5Fwmio+QcMlkkNfuK+5W1peQ5CUhZg== + dependencies: + loader-utils "^2.0.0" + schema-utils "^2.6.6" + +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" + integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= + +stylehacks@^2.3: + version "2.3.2" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-2.3.2.tgz#64c83e0438a68c9edf449e8c552a7d9ab6009b0b" + integrity sha1-ZMg+BDimjJ7fRJ6MVSp9mrYAmws= + dependencies: + browserslist "^1.1.3" + chalk "^1.1.1" + log-symbols "^1.0.2" + minimist "^1.2.0" + plur "^2.1.2" + postcss "^5.0.18" + postcss-reporter "^1.3.3" + postcss-selector-parser "^2.0.0" + read-file-stdin "^0.2.1" + text-table "^0.2.0" + write-file-stdout "0.0.2" + +stylehacks@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" + integrity sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g== + dependencies: + browserslist "^4.0.0" + postcss "^7.0.0" + postcss-selector-parser "^3.0.0" + +stylelint-config-rational-order@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/stylelint-config-rational-order/-/stylelint-config-rational-order-0.1.2.tgz#4e98e390783d437f0ec41fb73bc41992e78d02a0" + integrity sha512-Qo7ZQaihCwTqijfZg4sbdQQHtugOX/B1/fYh018EiDZHW+lkqH9uHOnsDwDPGZrYJuB6CoyI7MZh2ecw2dOkew== + dependencies: + stylelint "^9.10.1" + stylelint-order "^2.2.1" + +stylelint-no-browser-hacks@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/stylelint-no-browser-hacks/-/stylelint-no-browser-hacks-1.2.1.tgz#c6ae1a53d04d3a8d32de40b6e9b6dec3ec607dea" + integrity sha512-lPcqHx3e/WnrXdw0wdnKtcjcSCAYEXjwSitXRw0OQ2qPF+iLyDFoarbn4qcw38Uuu7q29fhj+w2mECLM0fUOlw== + dependencies: + stylehacks "^2.3" + stylelint "^9.1" + +stylelint-order@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-2.2.1.tgz#cd2d4a0d81d91c705f1d275a58487e5ad5aa5828" + integrity sha512-019KBV9j8qp1MfBjJuotse6MgaZqGVtXMc91GU9MsS9Feb+jYUvUU3Z8XiClqPdqJZQ0ryXQJGg3U3PcEjXwfg== + dependencies: + lodash "^4.17.10" + postcss "^7.0.2" + postcss-sorting "^4.1.0" + +stylelint-order@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-4.0.0.tgz#2a945c2198caac3ff44687d7c8582c81d044b556" + integrity sha512-bXV0v+jfB0+JKsqIn3mLglg1Dj2QCYkFHNfL1c+rVMEmruZmW5LUqT/ARBERfBm8SFtCuXpEdatidw/3IkcoiA== + dependencies: + lodash "^4.17.15" + postcss "^7.0.26" + postcss-sorting "^5.0.1" + +stylelint@^13.3.3: + version "13.3.3" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.3.3.tgz#e267a628ebfc1adad6f5a1fe818724c34171402b" + integrity sha512-j8Oio2T1YNiJc6iXDaPYd74Jg4zOa1bByNm/g9/Nvnq4tDPsIjMi46jhRZyPPktGPwjJ5FwcmCqIRlH6PVP8mA== + dependencies: + "@stylelint/postcss-css-in-js" "^0.37.1" + "@stylelint/postcss-markdown" "^0.36.1" + autoprefixer "^9.7.6" + balanced-match "^1.0.0" + chalk "^4.0.0" + cosmiconfig "^6.0.0" + debug "^4.1.1" + execall "^2.0.0" + file-entry-cache "^5.0.1" + get-stdin "^7.0.0" + global-modules "^2.0.0" + globby "^11.0.0" + globjoin "^0.1.4" + html-tags "^3.1.0" + ignore "^5.1.4" + import-lazy "^4.0.0" + imurmurhash "^0.1.4" + known-css-properties "^0.18.0" + leven "^3.1.0" + lodash "^4.17.15" + log-symbols "^3.0.0" + mathml-tag-names "^2.1.3" + meow "^6.1.0" + micromatch "^4.0.2" + normalize-selector "^0.2.0" + postcss "^7.0.27" + postcss-html "^0.36.0" + postcss-less "^3.1.4" + postcss-media-query-parser "^0.2.3" + postcss-reporter "^6.0.1" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^4.0.2" + postcss-sass "^0.4.4" + postcss-scss "^2.0.0" + postcss-selector-parser "^6.0.2" + postcss-syntax "^0.36.2" + postcss-value-parser "^4.0.3" + resolve-from "^5.0.0" + slash "^3.0.0" + specificity "^0.4.1" + string-width "^4.2.0" + strip-ansi "^6.0.0" + style-search "^0.1.0" + sugarss "^2.0.0" + svg-tags "^1.0.0" + table "^5.4.6" + v8-compile-cache "^2.1.0" + write-file-atomic "^3.0.3" + +stylelint@^9.1, stylelint@^9.10.1: + version "9.10.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.10.1.tgz#5f0ee3701461dff1d68284e1386efe8f0677a75d" + integrity sha512-9UiHxZhOAHEgeQ7oLGwrwoDR8vclBKlSX7r4fH0iuu0SfPwFaLkb1c7Q2j1cqg9P7IDXeAV2TvQML/fRQzGBBQ== + dependencies: + autoprefixer "^9.0.0" + balanced-match "^1.0.0" + chalk "^2.4.1" + cosmiconfig "^5.0.0" + debug "^4.0.0" + execall "^1.0.0" + file-entry-cache "^4.0.0" + get-stdin "^6.0.0" + global-modules "^2.0.0" + globby "^9.0.0" + globjoin "^0.1.4" + html-tags "^2.0.0" + ignore "^5.0.4" + import-lazy "^3.1.0" + imurmurhash "^0.1.4" + known-css-properties "^0.11.0" + leven "^2.1.0" + lodash "^4.17.4" + log-symbols "^2.0.0" + mathml-tag-names "^2.0.1" + meow "^5.0.0" + micromatch "^3.1.10" + normalize-selector "^0.2.0" + pify "^4.0.0" + postcss "^7.0.13" + postcss-html "^0.36.0" + postcss-jsx "^0.36.0" + postcss-less "^3.1.0" + postcss-markdown "^0.36.0" + postcss-media-query-parser "^0.2.3" + postcss-reporter "^6.0.0" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^4.0.0" + postcss-sass "^0.3.5" + postcss-scss "^2.0.0" + postcss-selector-parser "^3.1.0" + postcss-syntax "^0.36.2" + postcss-value-parser "^3.3.0" + resolve-from "^4.0.0" + signal-exit "^3.0.2" + slash "^2.0.0" + specificity "^0.4.1" + string-width "^3.0.0" + style-search "^0.1.0" + sugarss "^2.0.0" + svg-tags "^1.0.0" + table "^5.0.0" + +sugarss@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-2.0.0.tgz#ddd76e0124b297d40bf3cca31c8b22ecb43bc61d" + integrity sha512-WfxjozUk0UVA4jm+U1d736AUpzSrNsQcIbyOkoE364GrtWmIrFdk5lksEupgWMD4VaT/0kVx1dobpiDumSgmJQ== + dependencies: + postcss "^7.0.2" supports-color@6.1.0, supports-color@^6.1.0: version "6.1.0" @@ -4739,22 +11466,81 @@ supports-color@6.1.0, supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^5.3.0: +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= + +supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= + dependencies: + has-flag "^1.0.0" + +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" -swiper@^3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/swiper/-/swiper-3.4.2.tgz#39d6b410b1a39833e1f72d3b72999df5f5e38392" - integrity sha1-Oda0ELGjmDPh9y07cpmd9fXjg5I= +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" -table@^5.2.3: - version "5.4.5" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.5.tgz#c8f4ea2d8fee08c0027fac27b0ec0a4fe01dfa42" - integrity sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA== +sver-compat@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/sver-compat/-/sver-compat-1.5.0.tgz#3cf87dfeb4d07b4a3f14827bc186b3fd0c645cd8" + integrity sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg= + dependencies: + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + +svgo@^1.0.0, svgo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" + integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== + dependencies: + chalk "^2.4.1" + coa "^2.0.2" + css-select "^2.0.0" + css-select-base-adapter "^0.1.1" + css-tree "1.0.0-alpha.37" + csso "^4.0.2" + js-yaml "^3.13.1" + mkdirp "~0.5.1" + object.values "^1.1.0" + sax "~1.2.4" + stable "^0.1.8" + unquote "~1.1.1" + util.promisify "~1.0.0" + +swiper@^5.3.7: + version "5.3.8" + resolved "https://registry.yarnpkg.com/swiper/-/swiper-5.3.8.tgz#25c555d73787d35aa56418b904cb3ed4423bade8" + integrity sha512-bCxrayTgzC2bZBRuFwAx7T4exWeHqMADBpcuTQ7PNCOIIzJRPqNh4ySIvW06LEEU3Q0KncaNre4hrn+jXcWivQ== + dependencies: + dom7 "^2.1.3" + ssr-window "^1.0.1" + +symbol-observable@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" + integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= + +table@^5.0.0, table@^5.2.3, table@^5.4.6: + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== dependencies: ajv "^6.10.2" lodash "^4.17.14" @@ -4766,38 +11552,70 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== -tar@^4: - version "4.4.10" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1" - integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA== +tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== dependencies: - chownr "^1.1.1" - fs-minipass "^1.2.5" - minipass "^2.3.5" - minizlib "^1.2.1" - mkdirp "^0.5.0" - safe-buffer "^5.1.2" - yallist "^3.0.3" + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" -terser-webpack-plugin@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" - integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== +tar@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== + dependencies: + block-stream "*" + fstream "^1.0.12" + inherits "2" + +temp-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" + integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= + +tempfile@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tempfile/-/tempfile-2.0.0.tgz#6b0446856a9b1114d1856ffcbe509cccb0977265" + integrity sha1-awRGhWqbERTRhW/8vlCczLCXcmU= + dependencies: + temp-dir "^1.0.0" + uuid "^3.0.1" + +ternary-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-3.0.0.tgz#7951930ea9e823924d956f03d516151a2d516253" + integrity sha512-oIzdi+UL/JdktkT+7KU5tSIQjj8pbShj3OASuvDEhm0NT5lppsm7aXWAmAq4/QMaBIyfuEcNLbAQA+HpaISobQ== + dependencies: + duplexify "^4.1.1" + fork-stream "^0.0.4" + merge-stream "^2.0.0" + through2 "^3.0.1" + +terser-webpack-plugin@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" + integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== dependencies: cacache "^12.0.2" find-cache-dir "^2.1.0" is-wsl "^1.1.0" schema-utils "^1.0.0" - serialize-javascript "^1.7.0" + serialize-javascript "^2.1.2" source-map "^0.6.1" terser "^4.1.2" webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser@^4.1.2: - version "4.1.3" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.3.tgz#6074fbcf3517561c3272ea885f422c7a8c32d689" - integrity sha512-on13d+cnpn5bMouZu+J8tPYQecsdRJCJuxFJ+FVoPBoLJgk5bCBkp+Uen2hWyi0KIUm6eDarnlAlH+KgIx/PuQ== +terser@^4.0.0, terser@^4.1.2, terser@^4.6.3: + version "4.6.13" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.13.tgz#e879a7364a5e0db52ba4891ecde007422c56a916" + integrity sha512-wMvqukYgVpQlymbnNbabVZbtM6PN63AzqexpwJL8tbh/mRT9LE5o+ruVduAGL7D6Fpjl+Q+06U5I9Ul82odAhw== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -4808,7 +11626,30 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -through2@^2.0.0: +tfunk@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/tfunk/-/tfunk-3.1.0.tgz#38e4414fc64977d87afdaa72facb6d29f82f7b5b" + integrity sha1-OORBT8ZJd9h6/apy+sttKfgve1s= + dependencies: + chalk "^1.1.1" + object-path "^0.9.0" + +through2-concurrent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/through2-concurrent/-/through2-concurrent-2.0.0.tgz#c9dd2c146504ec9962dbc86a5168b63d662669fa" + integrity sha512-R5/jLkfMvdmDD+seLwN7vB+mhbqzWop5fAjx5IX8/yQq7VhBhzDmhXgaHAOnhnWkCpRMM7gToYHycB0CS/pd+A== + dependencies: + through2 "^2.0.0" + +through2-filter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" + integrity sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA== + dependencies: + through2 "~2.0.0" + xtend "~4.0.0" + +through2@2.X, through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -4816,23 +11657,53 @@ through2@^2.0.0: readable-stream "~2.3.6" xtend "~4.0.1" -through@^2.3.6: +through2@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.1.tgz#39276e713c3302edf9e388dd9c812dd3b825bd5a" + integrity sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww== + dependencies: + readable-stream "2 || 3" + +through@^2.3.6, through@^2.3.8, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= thunky@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826" - integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow== + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + +time-stamp@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" + integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= + +timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= timers-browserify@^2.0.4: - version "2.0.10" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" - integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg== + version "2.0.11" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" + integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== dependencies: setimmediate "^1.0.4" +timers-ext@^0.1.5: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + +timsort@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -4840,11 +11711,34 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-absolute-glob@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1865f43d9e74b0822db9f145b78cff7d0f7c849b" + integrity sha1-GGX0PZ50sIItufFFt4z/fQ98hJs= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + +to-array@0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890" + integrity sha1-F+bBH3PdTz10zaek/zI46a2b+JA= + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -4860,6 +11754,13 @@ to-regex-range@^2.1.0: is-number "^3.0.0" repeat-string "^1.6.1" +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" @@ -4870,26 +11771,92 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-through@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-through/-/to-through-2.0.0.tgz#fc92adaba072647bc0b67d6b03664aa195093af6" + integrity sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY= + dependencies: + through2 "^2.0.3" + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -toposort@^1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" - integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk= +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" -tslib@^1.9.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= + +trim-newlines@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" + integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= + +trim-newlines@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" + integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== + +trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= + dependencies: + escape-string-regexp "^1.0.2" + +trim-trailing-lines@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz#7f0739881ff76657b7776e10874128004b625a94" + integrity sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA== + +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0= + +trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + +"true-case-path@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d" + integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew== + dependencies: + glob "^7.1.2" + +tslib@^1.10.0, tslib@^1.9.0: + version "1.11.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" + integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== tty-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -4897,6 +11864,26 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-fest@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== + +type-fest@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" + integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -4905,11 +11892,33 @@ type-is@~1.6.17, type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.0.0.tgz#5f16ff6ef2eb44f260494dae271033b29c09a9c3" + integrity sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +ua-parser-js@0.7.17: + version "0.7.17" + resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.17.tgz#e9ec5f9498b9ec910e7ae3ac626a805c4d09ecac" + integrity sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g== + uglify-es@^3.3.9: version "3.3.9" resolved "https://registry.yarnpkg.com/uglify-es/-/uglify-es-3.3.9.tgz#0c1c4f0700bed8dbc124cdb304d2592ca203e677" @@ -4926,6 +11935,101 @@ uglify-js@3.4.x: commander "~2.19.0" source-map "~0.6.1" +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + +unbzip2-stream@^1.0.9: + version "1.4.2" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.2.tgz#84eb9e783b186d8fb397515fbb656f312f1a7dbf" + integrity sha512-pZMVAofMrrHX6Ik39hCk470kulCbmZ2SWfQLPmTWqfJV/oUm0gn1CblvHdUu4+54Je6Jq34x8kY6XjTy6dMkOg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + +unc-path-regex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + integrity sha1-5z3T17DXxe2G+6xrCufYxqadUPo= + +undertaker-registry@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50" + integrity sha1-XkvaMI5KiirlhPm5pDWaSZglzFA= + +undertaker@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/undertaker/-/undertaker-1.2.1.tgz#701662ff8ce358715324dfd492a4f036055dfe4b" + integrity sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA== + dependencies: + arr-flatten "^1.0.1" + arr-map "^2.0.0" + bach "^1.0.0" + collection-map "^1.0.0" + es6-weak-map "^2.0.1" + last-run "^1.1.0" + object.defaults "^1.0.0" + object.reduce "^1.0.0" + undertaker-registry "^1.0.0" + +unherit@^1.0.4: + version "1.1.3" + resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" + integrity sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ== + dependencies: + inherits "^2.0.0" + xtend "^4.0.0" + +unicode-canonical-property-names-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" + integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ== + +unicode-match-property-ecmascript@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c" + integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg== + dependencies: + unicode-canonical-property-names-ecmascript "^1.0.4" + unicode-property-aliases-ecmascript "^1.0.4" + +unicode-match-property-value-ecmascript@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz#0d91f600eeeb3096aa962b1d6fc88876e64ea531" + integrity sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ== + +unicode-property-aliases-ecmascript@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz#dd57a99f6207bedff4628abefb94c50db941c8f4" + integrity sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg== + +unified@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-7.1.0.tgz#5032f1c1ee3364bd09da12e27fdd4a7553c7be13" + integrity sha512-lbk82UOIGuCEsZhPj8rNAkXSDXd6p0QLzIuSsCdxrqnqU56St4eyOB+AlXsVgVeRmetPTYydIuvFfpDIed8mqw== + dependencies: + "@types/unist" "^2.0.0" + "@types/vfile" "^3.0.0" + bail "^1.0.0" + extend "^3.0.0" + is-plain-obj "^1.1.0" + trough "^1.0.0" + vfile "^3.0.0" + x-is-string "^0.1.0" + +unified@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/unified/-/unified-9.0.0.tgz#12b099f97ee8b36792dbad13d278ee2f696eed1d" + integrity sha512-ssFo33gljU3PdlWLjNp15Inqb77d6JnJSfyplGJPT/a+fNRNyCBeveBAYJdO5khKdF6WVHa/yYCC7Xl6BDwZUQ== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + union-value@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" @@ -4936,11 +12040,24 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^2.0.1" +union-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-2.0.1.tgz#4e1ab0f99ab52c52a53e14d8039b5130fef682b8" + integrity sha512-NmcRHHhUy1qWmp6yYWsaURV2qwfS24TmTtO9S9x0L41wCNNVBQFD3toOzO0cd8SsNrFhbw/O0iYO5uffXGYocw== + dependencies: + get-value "^3.0.1" + set-value "^3.0.0" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8= +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= + unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -4955,11 +12072,110 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +unique-stream@^2.0.2: + version "2.3.1" + resolved "https://registry.yarnpkg.com/unique-stream/-/unique-stream-2.3.1.tgz#c65d110e9a4adf9a6c5948b28053d9a8d04cbeac" + integrity sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A== + dependencies: + json-stable-stringify-without-jsonify "^1.0.1" + through2-filter "^3.0.0" + +unist-util-find-all-after@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-1.0.5.tgz#5751a8608834f41d117ad9c577770c5f2f1b2899" + integrity sha512-lWgIc3rrTMTlK1Y0hEuL+k+ApzFk78h+lsaa2gHf63Gp5Ww+mt11huDniuaoq1H+XMK2lIIjjPkncxXcDp3QDw== + dependencies: + unist-util-is "^3.0.0" + +unist-util-find-all-after@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/unist-util-find-all-after/-/unist-util-find-all-after-3.0.1.tgz#95cc62f48812d879b4685a0512bf1b838da50e9a" + integrity sha512-0GICgc++sRJesLwEYDjFVJPJttBpVQaTNgc6Jw0Jhzvfs+jtKePEMu+uD+PqkRUrAvGQqwhpDwLGWo1PK8PDEw== + dependencies: + unist-util-is "^4.0.0" + +unist-util-is@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd" + integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A== + +unist-util-is@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.0.2.tgz#c7d1341188aa9ce5b3cff538958de9895f14a5de" + integrity sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ== + +unist-util-remove-position@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.4.tgz#ec037348b6102c897703eee6d0294ca4755a2020" + integrity sha512-tLqd653ArxJIPnKII6LMZwH+mb5q+n/GtXQZo6S6csPRs5zB0u79Yw8ouR3wTw8wxvdJFhpP6Y7jorWdCgLO0A== + dependencies: + unist-util-visit "^1.1.0" + +unist-util-remove-position@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz#5d19ca79fdba712301999b2b73553ca8f3b352cc" + integrity sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA== + dependencies: + unist-util-visit "^2.0.0" + +unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6" + integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ== + +unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + +unist-util-visit-parents@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9" + integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g== + dependencies: + unist-util-is "^3.0.0" + +unist-util-visit-parents@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.0.2.tgz#d4076af3011739c71d2ce99d05de37d545f4351d" + integrity sha512-yJEfuZtzFpQmg1OSCyS9M5NJRrln/9FbYosH3iW0MG402QbdbaB8ZESwUv9RO6nRfLAKvWcMxCwdLWOov36x/g== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + +unist-util-visit@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3" + integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw== + dependencies: + unist-util-visit-parents "^2.0.0" + +unist-util-visit@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-2.0.2.tgz#3843782a517de3d2357b4c193b24af2d9366afb7" + integrity sha512-HoHNhGnKj6y+Sq+7ASo2zpVdfdRifhTgX2KTU3B/sO/TTlZchp7E3S4vjRzDJ7L60KmrCPsQkVK3lEF3cz36XQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + unist-util-visit-parents "^3.0.0" + +universalify@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= +unquote@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" + integrity sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ= + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -4968,16 +12184,11 @@ unset-value@^1.0.0: has-value "^0.3.1" isobject "^3.0.0" -upath@^1.1.0: +upath@^1.1.0, upath@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -upath@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068" - integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q== - upper-case@^1.1.1: version "1.1.3" resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" @@ -4995,6 +12206,20 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + +url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + url-parse@^1.4.3: version "1.4.7" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278" @@ -5003,6 +12228,11 @@ url-parse@^1.4.3: querystringify "^2.1.1" requires-port "^1.0.0" +url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + url-toolkit@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/url-toolkit/-/url-toolkit-2.1.6.tgz#6d03246499e519aad224c44044a4ae20544154f2" @@ -5034,6 +12264,16 @@ util.promisify@1.0.0: define-properties "^1.1.2" object.getownpropertydescriptors "^2.0.3" +util.promisify@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" + integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.2" + has-symbols "^1.0.1" + object.getownpropertydescriptors "^2.1.0" + util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -5058,37 +12298,189 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.0.1: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== - -uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== +uuid@^3.0.1, uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== v8-compile-cache@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== +v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" + integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== + +v8flags@^3.0.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.1.3.tgz#fc9dc23521ca20c5433f81cc4eb9b3033bb105d8" + integrity sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w== + dependencies: + homedir-polyfill "^1.0.1" + +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + +value-or-function@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/value-or-function/-/value-or-function-3.0.0.tgz#1c243a50b595c1be54a754bfece8563b9ff8d813" + integrity sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM= + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -vm-browserify@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" - integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== +vendors@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== -watchpack@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" - integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: - chokidar "^2.0.2" + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +vfile-location@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.6.tgz#8a274f39411b8719ea5728802e10d9e0dff1519e" + integrity sha512-sSFdyCP3G6Ka0CEmN83A2YCMKIieHx0EDaj5IDP4g1pa5ZJ4FJDvpO0WODLxo4LUX4oe52gmSCK7Jw4SBghqxA== + +vfile-location@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.0.1.tgz#d78677c3546de0f7cd977544c367266764d31bb3" + integrity sha512-yYBO06eeN/Ki6Kh1QAkgzYpWT1d3Qln+ZCtSbJqFExPl1S3y2qqotJQXoh6qEvl/jDlgpUJolBn3PItVnnZRqQ== + +vfile-message@*: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.3.tgz#0dd4f6879fb240a8099b22bd3755536c92e59ba5" + integrity sha512-qQg/2z8qnnBHL0psXyF72kCjb9YioIynvyltuNKFaUhRtqTIcIMP3xnBaPzirVZNuBrUe1qwFciSx2yApa4byw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile-message@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1" + integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA== + dependencies: + unist-util-stringify-position "^1.1.1" + +vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + +vfile@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-3.0.1.tgz#47331d2abe3282424f4a4bb6acd20a44c4121803" + integrity sha512-y7Y3gH9BsUSdD4KzHsuMaCzRjglXN0W2EcMf0gpvu6+SbsGhMje7xDc8AEoeXy6mIwCKMI6BkjMsRjzQbhMEjQ== + dependencies: + is-buffer "^2.0.0" + replace-ext "1.0.0" + unist-util-stringify-position "^1.0.0" + vfile-message "^1.0.0" + +vfile@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.1.0.tgz#d79248957f43225d57ff67a56effc67bef08946e" + integrity sha512-BaTPalregj++64xbGK6uIlsurN3BCRNM/P2Pg8HezlGzKd1O9PrwIac6bd9Pdx2uTb0QHoioZ+rXKolbVXEgJg== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + replace-ext "1.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + +vinyl-fs@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/vinyl-fs/-/vinyl-fs-3.0.3.tgz#c85849405f67428feabbbd5c5dbdd64f47d31bc7" + integrity sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng== + dependencies: + fs-mkdirp-stream "^1.0.0" + glob-stream "^6.1.0" + graceful-fs "^4.0.0" + is-valid-glob "^1.0.0" + lazystream "^1.0.0" + lead "^1.0.0" + object.assign "^4.0.4" + pumpify "^1.3.5" + readable-stream "^2.3.3" + remove-bom-buffer "^3.0.0" + remove-bom-stream "^1.2.0" + resolve-options "^1.1.0" + through2 "^2.0.0" + to-through "^2.0.0" + value-or-function "^3.0.0" + vinyl "^2.0.0" + vinyl-sourcemap "^1.1.0" + +vinyl-sourcemap@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz#92a800593a38703a8cdb11d8b300ad4be63b3e16" + integrity sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY= + dependencies: + append-buffer "^1.0.2" + convert-source-map "^1.5.0" + graceful-fs "^4.1.6" + normalize-path "^2.1.1" + now-and-later "^2.0.0" + remove-bom-buffer "^3.0.0" + vinyl "^2.0.0" + +vinyl-sourcemaps-apply@^0.2.0, vinyl-sourcemaps-apply@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz#ab6549d61d172c2b1b87be5c508d239c8ef87705" + integrity sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU= + dependencies: + source-map "^0.5.1" + +vinyl@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.5.3.tgz#b0455b38fc5e0cf30d4325132e461970c2091cde" + integrity sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4= + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + +vinyl@^2.0.0, vinyl@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.2.0.tgz#d85b07da96e458d25b2ffe19fece9f2caa13ed86" + integrity sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg== + dependencies: + clone "^2.1.1" + clone-buffer "^1.0.0" + clone-stats "^1.0.0" + cloneable-readable "^1.0.0" + remove-trailing-separator "^1.0.1" + replace-ext "^1.0.0" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +watchpack@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.1.tgz#280da0a8718592174010c078c7585a74cd8cd0e2" + integrity sha512-+IF9hfUFOrYOOaKyfaI7h7dquUIOgyEMoQMLA7OP5FxegKA2+XdXThAZ9TU2kucfhDH7rfMHs1oPYziVGWRnZA== + dependencies: + chokidar "^2.1.8" graceful-fs "^4.1.2" neo-async "^2.5.0" @@ -5104,10 +12496,10 @@ webcomponents.js@^0.7.24: resolved "https://registry.yarnpkg.com/webcomponents.js/-/webcomponents.js-0.7.24.tgz#2116fbfa1468ec416a7befdaa333e1d118f69c04" integrity sha1-IRb7+hRo7EFqe+/aozPh0Rj2nAQ= -webpack-cli@^3.3.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" - integrity sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A== +webpack-cli@^3.3.10: + version "3.3.11" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.11.tgz#3bf21889bf597b5d82c38f215135a411edfdc631" + integrity sha512-dXlfuml7xvAFwYUPsrtQAA9e4DOe58gnzSxhgrO/ZM/gyXTBowrsYeubyN4mqGhYdpXMFNyQ6emjJS9M7OBd4g== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -5143,10 +12535,10 @@ webpack-dev-middleware@^3.7.2: range-parser "^1.2.1" webpack-log "^2.0.0" -webpack-dev-server@^3.8.1: - version "3.8.2" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.8.2.tgz#3292427bf6510da9a3ac2d500b924a4197667ff9" - integrity sha512-0xxogS7n5jHDQWy0WST0q6Ykp7UGj4YvWh+HVN71JoE7BwPxMZrwgraBvmdEMbDVMBzF0u+mEzn8TQzBm5NYJQ== +webpack-dev-server@^3.10.3: + version "3.10.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.10.3.tgz#f35945036813e57ef582c2420ef7b470e14d3af0" + integrity sha512-e4nWev8YzEVNdOMcNzNeCN947sWJNd43E5XvsJzbAL08kGc2frm1tQ32hTJslRS+H65LCb/AaUCYU7fjHCpDeQ== dependencies: ansi-html "0.0.7" bonjour "^3.5.0" @@ -5163,10 +12555,10 @@ webpack-dev-server@^3.8.1: ip "^1.1.5" is-absolute-url "^3.0.3" killable "^1.0.1" - loglevel "^1.6.4" + loglevel "^1.6.6" opn "^5.5.0" p-retry "^3.0.1" - portfinder "^1.0.24" + portfinder "^1.0.25" schema-utils "^1.0.0" selfsigned "^1.10.7" semver "^6.3.0" @@ -5205,16 +12597,31 @@ webpack-sources@^1.4.0, webpack-sources@^1.4.1: source-list-map "^2.0.0" source-map "~0.6.1" -webpack@^4.41.0: - version "4.41.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b" - integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g== +webpack-stream@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/webpack-stream/-/webpack-stream-5.2.1.tgz#35c992161399fe8cad9c10d4a5c258f022629b39" + integrity sha512-WvyVU0K1/VB1NZ7JfsaemVdG0PXAQUqbjUNW4A58th4pULvKMQxG+y33HXTL02JvD56ko2Cub+E2NyPwrLBT/A== dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/wasm-edit" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - acorn "^6.2.1" + fancy-log "^1.3.3" + lodash.clone "^4.3.2" + lodash.some "^4.2.2" + memory-fs "^0.4.1" + plugin-error "^1.0.1" + supports-color "^5.5.0" + through "^2.3.8" + vinyl "^2.1.0" + webpack "^4.26.1" + +webpack@^4.26.1, webpack@^4.41.5: + version "4.43.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.43.0.tgz#c48547b11d563224c561dad1172c8aa0b8a678e6" + integrity sha512-GW1LjnPipFW2Y78OOab8NJlCflB7EFskMih2AHdvjbpKMeDJqEgSx24cXXXiPS65+WSwVyxtDsJH6jGX2czy+g== + dependencies: + "@webassemblyjs/ast" "1.9.0" + "@webassemblyjs/helper-module-context" "1.9.0" + "@webassemblyjs/wasm-edit" "1.9.0" + "@webassemblyjs/wasm-parser" "1.9.0" + acorn "^6.4.1" ajv "^6.10.2" ajv-keywords "^3.4.1" chrome-trace-event "^1.0.2" @@ -5225,13 +12632,13 @@ webpack@^4.41.0: loader-utils "^1.2.3" memory-fs "^0.4.1" micromatch "^3.1.10" - mkdirp "^0.5.1" + mkdirp "^0.5.3" neo-async "^2.6.1" node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" - watchpack "^1.6.0" + terser-webpack-plugin "^1.4.3" + watchpack "^1.6.1" webpack-sources "^1.4.1" websocket-driver@>=0.5.1: @@ -5253,17 +12660,22 @@ webworkify@^1.5.0: resolved "https://registry.yarnpkg.com/webworkify/-/webworkify-1.5.0.tgz#734ad87a774de6ebdd546e1d3e027da5b8f4a42c" integrity sha512-AMcUeyXAhbACL8S2hqqdqOLqvJ8ylmIbNwUIqQujRSouf4+eUFaXbG6F1Rbu+srlJMmxQWsiU7mOJi0nMBfM1g== -whatwg-fetch@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-1.1.1.tgz#ac3c9d39f320c6dce5339969d054ef43dd333319" - integrity sha1-rDydOfMgxtzlM5lp0FTvQ90zMxk= +whatwg-fetch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz#fc804e458cc460009b1a2b966bc8817d2578aefb" + integrity sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q== + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8= which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -5277,10 +12689,15 @@ wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" -wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= +window-size@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" + integrity sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU= + +word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== worker-farm@^1.7.0: version "1.7.0" @@ -5311,6 +12728,21 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + +write-file-stdout@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1" + integrity sha1-wlLXx8WxtAKJdjDjRTx7/mkNnKE= + write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" @@ -5325,20 +12757,70 @@ ws@^6.2.1: dependencies: async-limiter "~1.0.0" -xtend@^4.0.0, xtend@~4.0.1: +ws@~3.3.1: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + +ws@~6.1.0: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== + dependencies: + async-limiter "~1.0.0" + +x-is-string@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82" + integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI= + +xmlhttprequest-ssl@~1.5.4: + version "1.5.5" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz#c2876b06168aadc40e57d97e81191ac8f4398b3e" + integrity sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4= + +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= + "y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" - integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A== +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yaml@^1.7.2: + version "1.9.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.9.2.tgz#f0cfa865f003ab707663e4f04b3956957ea564ed" + integrity sha512-HPT7cGGI0DuRcsO51qC1j9O16Dh1mZ2bnXwsi0jrSpsLz0WxOLSLXfkABVl6bZO629py3CU+OMJtpNHDLB97kg== + dependencies: + "@babel/runtime" "^7.9.2" + +yargs-parser@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" + integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== + dependencies: + camelcase "^4.1.0" yargs-parser@^11.1.1: version "11.1.1" @@ -5348,14 +12830,36 @@ yargs-parser@^11.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^13.1.0: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== +yargs-parser@^13.1.0, yargs-parser@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" + integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^18.1.3: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + +yargs-parser@^4.1.0, yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + integrity sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw= + dependencies: + camelcase "^3.0.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo= + dependencies: + camelcase "^3.0.0" + yargs@12.0.5: version "12.0.5" resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" @@ -5390,3 +12894,90 @@ yargs@13.2.4: which-module "^2.0.0" y18n "^4.0.0" yargs-parser "^13.1.0" + +yargs@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.4.0.tgz#816e1a866d5598ccf34e5596ddce22d92da490d4" + integrity sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + window-size "^0.2.0" + y18n "^3.2.1" + yargs-parser "^4.1.0" + +yargs@6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + integrity sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@^13.3.2: + version "13.3.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" + integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== + dependencies: + cliui "^5.0.0" + find-up "^3.0.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^3.0.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^13.1.2" + +yargs@^7.0.0, yargs@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg= + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0" + +yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + +yeast@0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" + integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
${ApiKeysCaption}
${HeaderApiKey}${HeaderApp}${HeaderDateIssued}${HeaderApiKey}${HeaderApp}${HeaderDateIssued}
'; - html += '"; - html += "'; - html += item.AccessToken; - html += "'; - html += item.AppName || ""; - html += "'; - var date = datetime.parseISO8601Date(item.DateCreated, true); - html += datetime.toLocaleDateString(date) + " " + datetime.getDisplayTime(date); - html += "
'; + html += ''; + html += ''; + html += item.AccessToken; + html += ''; + html += item.AppName || ''; + html += ''; + var date = datetime.parseISO8601Date(item.DateCreated, true); + html += datetime.toLocaleDateString(date) + ' ' + datetime.getDisplayTime(date); + html += '