Compare commits
21 Commits
release-10
...
release-10
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc66fadb0e | ||
|
|
298d8d7929 | ||
|
|
bdf8553728 | ||
|
|
8ac155fb7a | ||
|
|
54dee197fd | ||
|
|
7a3eb3ffad | ||
|
|
15b987e0de | ||
|
|
54b05ab27d | ||
|
|
e1308f01b6 | ||
|
|
c596c19bfd | ||
|
|
087d06debf | ||
|
|
0b4402b642 | ||
|
|
b36369b562 | ||
|
|
78a2ba73e7 | ||
|
|
1be5e20363 | ||
|
|
9a130f5869 | ||
|
|
d6cec24d9e | ||
|
|
2044efc0c3 | ||
|
|
e12a8bc39d | ||
|
|
a885964e46 | ||
|
|
efdc07e032 |
@@ -1,63 +0,0 @@
|
||||
jobs:
|
||||
- job: Build
|
||||
displayName: 'Build'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
Development:
|
||||
BuildConfiguration: development
|
||||
Production:
|
||||
BuildConfiguration: production
|
||||
Standalone:
|
||||
BuildConfiguration: standalone
|
||||
|
||||
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 build:development'
|
||||
displayName: 'Build Development'
|
||||
condition: eq(variables['BuildConfiguration'], 'development')
|
||||
|
||||
- script: 'yarn build:production'
|
||||
displayName: 'Build Production'
|
||||
condition: eq(variables['BuildConfiguration'], 'production')
|
||||
|
||||
- script: 'yarn build:standalone'
|
||||
displayName: 'Build Standalone'
|
||||
condition: eq(variables['BuildConfiguration'], 'standalone')
|
||||
|
||||
- script: 'test -d dist'
|
||||
displayName: 'Check Build'
|
||||
|
||||
- script: 'mv dist jellyfin-web'
|
||||
displayName: 'Rename Directory'
|
||||
|
||||
- task: ArchiveFiles@2
|
||||
displayName: 'Archive Directory'
|
||||
inputs:
|
||||
rootFolderOrFile: 'jellyfin-web'
|
||||
includeRootFolder: true
|
||||
archiveFile: 'jellyfin-web-$(BuildConfiguration)'
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish Release'
|
||||
inputs:
|
||||
targetPath: '$(Build.SourcesDirectory)/jellyfin-web-$(BuildConfiguration).zip'
|
||||
artifactName: 'jellyfin-web-$(BuildConfiguration)'
|
||||
@@ -1,29 +0,0 @@
|
||||
jobs:
|
||||
- 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'
|
||||
@@ -1,122 +0,0 @@
|
||||
jobs:
|
||||
- job: BuildPackage
|
||||
displayName: 'Build Packages'
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
CentOS:
|
||||
BuildConfiguration: centos
|
||||
Debian:
|
||||
BuildConfiguration: debian
|
||||
Fedora:
|
||||
BuildConfiguration: fedora
|
||||
Portable:
|
||||
BuildConfiguration: portable
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- script: 'docker build -f deployment/Dockerfile.$(BuildConfiguration) -t jellyfin-web-$(BuildConfiguration) deployment'
|
||||
displayName: 'Build Dockerfile'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
|
||||
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="yes" -e BUILD_ID=$(Build.BuildNumber) jellyfin-web-$(BuildConfiguration)'
|
||||
displayName: 'Run Dockerfile (unstable)'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
|
||||
- script: 'docker image ls -a && docker run -v $(pwd)/deployment/dist:/dist -v $(pwd):/jellyfin -e IS_UNSTABLE="no" -e BUILD_ID=$(Build.BuildNumber) jellyfin-web-$(BuildConfiguration)'
|
||||
displayName: 'Run Dockerfile (stable)'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish Release'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
inputs:
|
||||
targetPath: '$(Build.SourcesDirectory)/deployment/dist'
|
||||
artifactName: 'jellyfin-web-$(BuildConfiguration)'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Create target directory on repository server'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'mkdir -p /srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
||||
|
||||
- task: CopyFilesOverSSH@0
|
||||
displayName: 'Upload artifacts to repository server'
|
||||
condition: or(startsWith(variables['Build.SourceBranch'], 'refs/tags'), startsWith(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
sourceFolder: '$(Build.SourcesDirectory)/deployment/dist'
|
||||
contents: '**'
|
||||
targetFolder: '/srv/repository/incoming/azure/$(Build.BuildNumber)/$(BuildConfiguration)'
|
||||
|
||||
- job: BuildDocker
|
||||
displayName: 'Build Docker'
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
variables:
|
||||
- name: JellyfinVersion
|
||||
value: 0.0.0
|
||||
|
||||
steps:
|
||||
- script: echo "##vso[task.setvariable variable=JellyfinVersion]$( awk -F '/' '{ print $NF }' <<<'$(Build.SourceBranch)' | sed 's/^v//' )"
|
||||
displayName: Set release version (stable)
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Unstable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
repository: 'jellyfin/jellyfin-web'
|
||||
command: buildAndPush
|
||||
buildContext: '.'
|
||||
Dockerfile: 'deployment/Dockerfile.docker'
|
||||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
unstable-$(Build.BuildNumber)
|
||||
unstable
|
||||
|
||||
- task: Docker@2
|
||||
displayName: 'Push Stable Image'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
inputs:
|
||||
repository: 'jellyfin/jellyfin-web'
|
||||
command: buildAndPush
|
||||
buildContext: '.'
|
||||
Dockerfile: 'deployment/Dockerfile.docker'
|
||||
containerRegistry: Docker Hub
|
||||
tags: |
|
||||
stable-$(Build.BuildNumber)
|
||||
$(JellyfinVersion)
|
||||
|
||||
- job: CollectArtifacts
|
||||
displayName: 'Collect Artifacts'
|
||||
dependsOn:
|
||||
- BuildPackage
|
||||
- BuildDocker
|
||||
condition: and(succeeded('BuildPackage'), succeeded('BuildDocker'))
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: SSH@0
|
||||
displayName: 'Update Unstable Repository'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/heads/master')
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber) unstable'
|
||||
|
||||
- task: SSH@0
|
||||
displayName: 'Update Stable Repository'
|
||||
condition: startsWith(variables['Build.SourceBranch'], 'refs/tags')
|
||||
inputs:
|
||||
sshEndpoint: repository
|
||||
runOptions: 'inline'
|
||||
inline: 'sudo /srv/repository/collect-server.azure.sh /srv/repository/incoming/azure $(Build.BuildNumber)'
|
||||
@@ -2,16 +2,63 @@ trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
- master
|
||||
- release-*
|
||||
tags:
|
||||
include:
|
||||
- '*'
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- '*'
|
||||
|
||||
jobs:
|
||||
- template: azure-pipelines-build.yml
|
||||
- template: azure-pipelines-lint.yml
|
||||
- template: azure-pipelines-package.yml
|
||||
- job: main_build
|
||||
displayName: 'Main Build'
|
||||
|
||||
dependsOn: lint
|
||||
condition: succeeded()
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- script: |
|
||||
yarn install
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: |
|
||||
test -d dist
|
||||
displayName: 'Check dist directory'
|
||||
|
||||
- script: |
|
||||
yarn pack --filename jellyfin-web.tgz
|
||||
displayName: 'Build package'
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
displayName: 'Publish package'
|
||||
condition: succeeded()
|
||||
inputs:
|
||||
targetPath: '$(Build.SourcesDirectory)/jellyfin-web.tgz'
|
||||
artifactName: 'jellyfin-web'
|
||||
|
||||
- job: lint
|
||||
displayName: 'Lint'
|
||||
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- task: NodeTool@0
|
||||
displayName: 'Install Node.js'
|
||||
inputs:
|
||||
versionSpec: '10.x'
|
||||
|
||||
- script: |
|
||||
yarn install
|
||||
displayName: 'Install dependencies'
|
||||
|
||||
- script: |
|
||||
yarn run lint
|
||||
displayName: 'Run ESLint'
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../fedora/Makefile
|
||||
@@ -1,5 +0,0 @@
|
||||
version: 1
|
||||
update_configs:
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
@@ -7,6 +7,3 @@ charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
|
||||
[json]
|
||||
indent_size = 2
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.idea
|
||||
.vscode
|
||||
src/libraries
|
||||
196
.eslintrc.js
196
.eslintrc.js
@@ -1,196 +0,0 @@
|
||||
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'],
|
||||
'space-infix-ops': 'error'
|
||||
},
|
||||
overrides: [
|
||||
{
|
||||
files: [
|
||||
'./src/**/*.js'
|
||||
],
|
||||
parser: 'babel-eslint',
|
||||
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.entries',
|
||||
'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'
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
4
.eslintrc.yml
Normal file
4
.eslintrc.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
env:
|
||||
es6: true
|
||||
browser: true
|
||||
amd: true
|
||||
36
.gitattributes
vendored
36
.gitattributes
vendored
@@ -1,35 +1 @@
|
||||
* 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
|
||||
/CONTRIBUTORS.md merge=union
|
||||
|
||||
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@@ -1,4 +0,0 @@
|
||||
.ci @dkanada @EraYaN
|
||||
.github @jellyfin/core
|
||||
build.sh @joshuaboniface
|
||||
deployment @joshuaboniface
|
||||
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -8,7 +8,6 @@ exemptLabels:
|
||||
- future
|
||||
- feature
|
||||
- enhancement
|
||||
- confirmed
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
|
||||
582
.gitignore
vendored
582
.gitignore
vendored
@@ -1,11 +1,575 @@
|
||||
# npm
|
||||
dist
|
||||
web
|
||||
node_modules
|
||||
|
||||
# ide
|
||||
.idea
|
||||
.vscode
|
||||
# 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
|
||||
|
||||
# log
|
||||
yarn-error.log
|
||||
### 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/
|
||||
|
||||
# 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
|
||||
143
.stylelintrc
143
.stylelintrc
@@ -1,143 +0,0 @@
|
||||
{
|
||||
"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,
|
||||
}
|
||||
}
|
||||
@@ -32,10 +32,6 @@
|
||||
- [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)
|
||||
- [Andrei Oanca](https://github.com/OancaAndrei)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
||||
78
README.md
78
README.md
@@ -1,81 +1,15 @@
|
||||
<h1 align="center">Jellyfin Web</h1>
|
||||
<h3 align="center">Part of the <a href="https://jellyfin.org">Jellyfin Project</a></h3>
|
||||
<h3 align="center">The Free Software Media System</h3>
|
||||
|
||||
---
|
||||
|
||||
<p align="center">
|
||||
<img alt="Logo Banner" src="https://raw.githubusercontent.com/jellyfin/jellyfin-ux/master/branding/SVG/banner-logo-solid.svg?sanitize=true"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web">
|
||||
<img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin-web.svg"/>
|
||||
</a>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web/releases">
|
||||
<img alt="Current Release" src="https://img.shields.io/github/release/jellyfin/jellyfin-web.svg"/>
|
||||
</a>
|
||||
<a href="https://translate.jellyfin.org/projects/jellyfin/jellyfin-web/?utm_source=widget">
|
||||
<img src="https://translate.jellyfin.org/widgets/jellyfin/-/jellyfin-web/svg-badge.svg" alt="Translation Status"/>
|
||||
</a>
|
||||
<br/>
|
||||
<a href="https://opencollective.com/jellyfin">
|
||||
<img alt="Donate" src="https://img.shields.io/opencollective/all/jellyfin.svg?label=backers"/>
|
||||
</a>
|
||||
<a href="https://features.jellyfin.org">
|
||||
<img alt="Feature Requests" src="https://img.shields.io/badge/fider-vote%20on%20features-success.svg"/>
|
||||
</a>
|
||||
<a href="https://forum.jellyfin.org">
|
||||
<img alt="Discuss on our Forum" src="https://img.shields.io/discourse/https/forum.jellyfin.org/users.svg"/>
|
||||
</a>
|
||||
<a href="https://matrix.to/#/+jellyfin:matrix.org">
|
||||
<img alt="Chat on Matrix" src="https://img.shields.io/matrix/jellyfin:matrix.org.svg?logo=matrix"/>
|
||||
</a>
|
||||
<a href="https://www.reddit.com/r/jellyfin">
|
||||
<img alt="Join our Subreddit" src="https://img.shields.io/badge/reddit-r%2Fjellyfin-%23FF5700.svg"/>
|
||||
</a>
|
||||
<br/><br/>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web"><img alt="GPL 2.0 License" src="https://img.shields.io/github/license/jellyfin/jellyfin-web.svg"/></a>
|
||||
<a href="https://github.com/jellyfin/jellyfin-web/releases"><img alt="Current Release" src="https://img.shields.io/github/release/jellyfin/jellyfin-web.svg"/></a>
|
||||
</p>
|
||||
|
||||
Jellyfin Web is the frontend used for most of the clients available for end users, such as desktop browsers, Android, and iOS. We welcome all contributions and pull requests! If you have a larger feature in mind please open an issue so we can discuss the implementation before you start. Translations can be improved very easily from our <a href="https://translate.jellyfin.org/projects/jellyfin/jellyfin-web">Weblate</a> instance. Look through the following graphic to see if your native language could use some work!
|
||||
---
|
||||
|
||||
<a href="https://translate.jellyfin.org/engage/jellyfin/?utm_source=widget">
|
||||
<img src="https://translate.jellyfin.org/widgets/jellyfin/-/jellyfin-web/multi-auto.svg" alt="Detailed Translation Status"/>
|
||||
</a>
|
||||
|
||||
## Build Process
|
||||
|
||||
### Dependencies
|
||||
|
||||
- [Yarn 1.22.4](https://classic.yarnpkg.com/en/docs/install)
|
||||
- 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
|
||||
```
|
||||
Jellyfin is a free software media system that puts you in control of managing and streaming your media.
|
||||
|
||||
110
build.sh
110
build.sh
@@ -1,110 +0,0 @@
|
||||
#!/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 <BUILD_TYPE> -p/--platform <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
|
||||
@@ -1,9 +0,0 @@
|
||||
---
|
||||
# We just wrap `build` so this is really it
|
||||
name: "jellyfin-web"
|
||||
version: "10.6.4"
|
||||
packages:
|
||||
- debian.all
|
||||
- fedora.all
|
||||
- centos.all
|
||||
- portable
|
||||
91
bump_version
91
bump_version
@@ -1,91 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# bump_version - increase the shared version and generate changelogs
|
||||
|
||||
set -o errexit
|
||||
set -o pipefail
|
||||
set -o xtrace
|
||||
|
||||
usage() {
|
||||
echo -e "bump_version - increase the shared version and generate changelogs"
|
||||
echo -e ""
|
||||
echo -e "Usage:"
|
||||
echo -e " $ bump_version <new_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/" | tr -d '[:space:]' )"
|
||||
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-web (${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 <packaging@jellyfin.org> $( 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-web.spec"
|
||||
fedora_changelog_temp="$( mktemp )"
|
||||
fedora_spec_temp_dir="$( mktemp -d )"
|
||||
fedora_spec_temp="${fedora_spec_temp_dir}/jellyfin-web.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-web.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 <packaging@jellyfin.org>
|
||||
- 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}
|
||||
git status
|
||||
29
debian/changelog
vendored
29
debian/changelog
vendored
@@ -1,29 +0,0 @@
|
||||
jellyfin-web (10.6.4-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.4
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 30 Aug 2020 16:45:08 -0400
|
||||
|
||||
jellyfin-web (10.6.3-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.3
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 16 Aug 2020 19:48:03 -0400
|
||||
|
||||
jellyfin-web (10.6.2-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.2
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Sun, 02 Aug 2020 20:25:58 -0400
|
||||
|
||||
jellyfin-web (10.6.1-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.1
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> Mon, 27 Jul 2020 18:29:54 -0400
|
||||
|
||||
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 <packaging@jellyfin.org> Mon, 16 Mar 2020 11:15:00 -0400
|
||||
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
||||
8
|
||||
16
debian/control
vendored
16
debian/control
vendored
@@ -1,16 +0,0 @@
|
||||
Source: jellyfin-web
|
||||
Section: misc
|
||||
Priority: optional
|
||||
Maintainer: Jellyfin Team <team@jellyfin.org>
|
||||
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.
|
||||
28
debian/copyright
vendored
28
debian/copyright
vendored
@@ -1,28 +0,0 @@
|
||||
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 <joshua@boniface.me>
|
||||
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 <http://www.gnu.org/licenses/>
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
||||
6
debian/gbp.conf
vendored
6
debian/gbp.conf
vendored
@@ -1,6 +0,0 @@
|
||||
[DEFAULT]
|
||||
pristine-tar = False
|
||||
cleaner = fakeroot debian/rules clean
|
||||
|
||||
[import-orig]
|
||||
filter = [ ".git*", ".hg*", ".vs*", ".vscode*" ]
|
||||
1
debian/install
vendored
1
debian/install
vendored
@@ -1 +0,0 @@
|
||||
web usr/share/jellyfin/
|
||||
1
debian/po/POTFILES.in
vendored
1
debian/po/POTFILES.in
vendored
@@ -1 +0,0 @@
|
||||
[type: gettext/rfc822deb] templates
|
||||
57
debian/po/templates.pot
vendored
57
debian/po/templates.pot
vendored
@@ -1,57 +0,0 @@
|
||||
# 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 <EMAIL@ADDRESS>, 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 <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\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 ""
|
||||
20
debian/rules
vendored
20
debian/rules
vendored
@@ -1,20 +0,0 @@
|
||||
#! /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
|
||||
1
debian/source/format
vendored
1
debian/source/format
vendored
@@ -1 +0,0 @@
|
||||
1.0
|
||||
7
debian/source/options
vendored
7
debian/source/options
vendored
@@ -1,7 +0,0 @@
|
||||
tar-ignore='.git*'
|
||||
tar-ignore='**/.git'
|
||||
tar-ignore='**/.hg'
|
||||
tar-ignore='**/.vs'
|
||||
tar-ignore='**/.vscode'
|
||||
tar-ignore='deployment'
|
||||
tar-ignore='*.deb'
|
||||
@@ -1,29 +0,0 @@
|
||||
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 /build.sh
|
||||
|
||||
VOLUME ${SOURCE_DIR}
|
||||
|
||||
VOLUME ${ARTIFACT_DIR}
|
||||
|
||||
ENTRYPOINT ["/build.sh"]
|
||||
@@ -1,27 +0,0 @@
|
||||
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 /build.sh
|
||||
|
||||
VOLUME ${SOURCE_DIR}
|
||||
|
||||
VOLUME ${ARTIFACT_DIR}
|
||||
|
||||
ENTRYPOINT ["/build.sh"]
|
||||
@@ -1,11 +0,0 @@
|
||||
FROM node:alpine
|
||||
|
||||
ARG SOURCE_DIR=/src
|
||||
ARG ARTIFACT_DIR=/jellyfin-web
|
||||
|
||||
RUN apk add autoconf g++ make libpng-dev gifsicle alpine-sdk automake libtool make gcc musl-dev nasm python
|
||||
|
||||
WORKDIR ${SOURCE_DIR}
|
||||
COPY . .
|
||||
|
||||
RUN yarn install && mv dist ${ARTIFACT_DIR}
|
||||
@@ -1,23 +0,0 @@
|
||||
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 /build.sh
|
||||
|
||||
VOLUME ${SOURCE_DIR}
|
||||
|
||||
VOLUME ${ARTIFACT_DIR}
|
||||
|
||||
ENTRYPOINT ["/build.sh"]
|
||||
@@ -1,26 +0,0 @@
|
||||
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 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"]
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
# move to source directory
|
||||
pushd ${SOURCE_DIR}
|
||||
|
||||
cp -a yarn.lock /tmp/yarn.lock
|
||||
|
||||
# modify changelog to unstable configuration if IS_UNSTABLE
|
||||
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
|
||||
pushd fedora
|
||||
|
||||
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
|
||||
|
||||
sed -i "s/Version:.*/Version: ${BUILD_ID}/" jellyfin-web.spec
|
||||
sed -i "/%changelog/q" jellyfin-web.spec
|
||||
|
||||
cat <<EOF >>jellyfin-web.spec
|
||||
* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
|
||||
EOF
|
||||
popd
|
||||
fi
|
||||
|
||||
# build rpm
|
||||
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
|
||||
rpmbuild --rebuild -bb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
|
||||
|
||||
# move the artifacts
|
||||
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
|
||||
@@ -1,39 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
# move to source directory
|
||||
pushd ${SOURCE_DIR}
|
||||
|
||||
cp -a yarn.lock /tmp/yarn.lock
|
||||
|
||||
# modify changelog to unstable configuration if IS_UNSTABLE
|
||||
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
|
||||
pushd debian
|
||||
|
||||
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
|
||||
|
||||
cat <<EOF >changelog
|
||||
jellyfin-web (${BUILD_ID}-unstable) unstable; urgency=medium
|
||||
|
||||
* Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
|
||||
|
||||
-- Jellyfin Packaging Team <packaging@jellyfin.org> $( date --rfc-2822 )
|
||||
EOF
|
||||
popd
|
||||
fi
|
||||
|
||||
# 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
|
||||
@@ -1,41 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
# move to source directory
|
||||
pushd ${SOURCE_DIR}
|
||||
|
||||
cp -a yarn.lock /tmp/yarn.lock
|
||||
|
||||
# modify changelog to unstable configuration if IS_UNSTABLE
|
||||
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
|
||||
pushd fedora
|
||||
|
||||
PR_ID=$( git log --grep 'Merge pull request' --oneline --single-worktree --first-parent | head -1 | grep --color=none -Eo '#[0-9]+' | tr -d '#' )
|
||||
|
||||
sed -i "s/Version:.*/Version: ${BUILD_ID}/" jellyfin-web.spec
|
||||
sed -i "/%changelog/q" jellyfin-web.spec
|
||||
|
||||
cat <<EOF >>jellyfin-web.spec
|
||||
* $( LANG=C date '+%a %b %d %Y' ) Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Jellyfin Web unstable build ${BUILD_ID} for merged PR #${PR_ID}
|
||||
EOF
|
||||
popd
|
||||
fi
|
||||
|
||||
# build rpm
|
||||
make -f fedora/Makefile srpm outdir=/root/rpmbuild/SRPMS
|
||||
rpmbuild -rb /root/rpmbuild/SRPMS/jellyfin-*.src.rpm
|
||||
|
||||
# move the artifacts
|
||||
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
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
set -o xtrace
|
||||
|
||||
# move to source directory
|
||||
pushd ${SOURCE_DIR}
|
||||
|
||||
# get version
|
||||
if [[ ${IS_UNSTABLE} == 'yes' ]]; then
|
||||
version="${BUILD_ID}"
|
||||
else
|
||||
version="$( grep "version:" ./build.yaml | sed -E 's/version: "([0-9\.]+.*)"/\1/' )"
|
||||
fi
|
||||
|
||||
# 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
|
||||
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
|
||||
@@ -1,21 +0,0 @@
|
||||
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)"
|
||||
@@ -1,53 +0,0 @@
|
||||
%global debug_package %{nil}
|
||||
|
||||
Name: jellyfin-web
|
||||
Version: 10.6.4
|
||||
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
|
||||
# sadly the yarn RPM at https://dl.yarnpkg.com/rpm/ uses git but doesn't Requires: it
|
||||
BuildRequires: git
|
||||
%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
|
||||
* Sun Aug 30 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.4; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.4
|
||||
* Sun Aug 16 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.3; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.3
|
||||
* Sun Aug 02 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.2; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.2
|
||||
* Mon Jul 27 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- New upstream version 10.6.1; release changelog at https://github.com/jellyfin/jellyfin-web/releases/tag/v10.6.1
|
||||
* Mon Mar 23 2020 Jellyfin Packaging Team <packaging@jellyfin.org>
|
||||
- Forthcoming stable release
|
||||
204
gulpfile.js
204
gulpfile.js
@@ -1,204 +0,0 @@
|
||||
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', 'src/**/*.mp3']
|
||||
},
|
||||
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 injectBundle() {
|
||||
return src(options.injectBundle.query, { base: './src/' })
|
||||
.pipe(inject(
|
||||
src(['src/scripts/apploader.js'], { read: false }, { base: './src/' }), {
|
||||
relative: true,
|
||||
transform: function (filepath) {
|
||||
return `<script src="${filepath}" defer></script>`;
|
||||
}
|
||||
}
|
||||
))
|
||||
.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), injectBundle);
|
||||
exports.standalone = series(build(true), injectBundle);
|
||||
exports.serve = series(exports.standalone, serve);
|
||||
181
package.json
181
package.json
@@ -5,170 +5,31 @@
|
||||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.3",
|
||||
"@babel/plugin-proposal-class-properties": "^7.10.1",
|
||||
"@babel/plugin-proposal-private-methods": "^7.10.1",
|
||||
"@babel/plugin-transform-modules-amd": "^7.9.6",
|
||||
"@babel/polyfill": "^7.8.7",
|
||||
"@babel/preset-env": "^7.10.3",
|
||||
"autoprefixer": "^9.8.5",
|
||||
"babel-eslint": "^11.0.0-beta.2",
|
||||
"babel-loader": "^8.0.6",
|
||||
"browser-sync": "^2.26.7",
|
||||
"copy-webpack-plugin": "^5.1.1",
|
||||
"css-loader": "^3.6.0",
|
||||
"cssnano": "^4.1.10",
|
||||
"del": "^5.1.0",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-compat": "^3.5.1",
|
||||
"eslint-plugin-eslint-comments": "^3.2.0",
|
||||
"eslint-plugin-import": "^2.21.2",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"file-loader": "^6.0.0",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-babel": "^8.0.0",
|
||||
"gulp-cli": "^2.3.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",
|
||||
"postcss-preset-env": "^6.7.0",
|
||||
"style-loader": "^1.1.3",
|
||||
"stylelint": "^13.6.1",
|
||||
"stylelint-config-rational-order": "^0.1.2",
|
||||
"stylelint-no-browser-hacks": "^1.2.1",
|
||||
"stylelint-order": "^4.1.0",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-merge": "^4.2.2",
|
||||
"webpack-stream": "^5.2.1"
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"css-loader": "^2.1.0",
|
||||
"eslint": "^5.16.0",
|
||||
"file-loader": "^3.0.1",
|
||||
"style-loader": "^0.23.1",
|
||||
"webpack": "^4.41.0",
|
||||
"webpack-cli": "^3.3.9",
|
||||
"webpack-dev-server": "^3.8.1",
|
||||
"webpack-merge": "^4.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"alameda": "^1.4.0",
|
||||
"blurhash": "^1.1.3",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
"core-js": "^3.6.5",
|
||||
"date-fns": "^2.14.0",
|
||||
"epubjs": "^0.3.85",
|
||||
"fast-text-encoding": "^1.0.3",
|
||||
"flv.js": "^1.5.0",
|
||||
"headroom.js": "^0.11.0",
|
||||
"hls.js": "^0.14.0",
|
||||
"howler": "^2.2.0",
|
||||
"intersection-observer": "^0.11.0",
|
||||
"jellyfin-apiclient": "^1.4.1",
|
||||
"jellyfin-noto": "https://github.com/jellyfin/jellyfin-noto",
|
||||
"jquery": "^3.5.1",
|
||||
"jstree": "^3.3.10",
|
||||
"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",
|
||||
"page": "^1.11.6",
|
||||
"query-string": "^6.13.1",
|
||||
"resize-observer-polyfill": "^1.5.1",
|
||||
"screenfull": "^5.0.2",
|
||||
"shaka-player": "^2.5.13",
|
||||
"sortablejs": "^1.10.2",
|
||||
"swiper": "^5.4.5",
|
||||
"webcomponents.js": "^0.7.24",
|
||||
"whatwg-fetch": "^3.2.0"
|
||||
"hls.js": "^0.12.4",
|
||||
"howler": "^2.1.2",
|
||||
"jquery": "^3.4.1",
|
||||
"jstree": "^3.3.7",
|
||||
"libjass": "^0.11.0",
|
||||
"shaka-player": "^2.5.5",
|
||||
"sortablejs": "^1.9.0",
|
||||
"swiper": "^3.4.2"
|
||||
},
|
||||
"babel": {
|
||||
"presets": [
|
||||
"@babel/preset-env"
|
||||
],
|
||||
"overrides": [
|
||||
{
|
||||
"test": [
|
||||
"src/components/accessSchedule/accessSchedule.js",
|
||||
"src/components/actionSheet/actionSheet.js",
|
||||
"src/components/autoFocuser.js",
|
||||
"src/components/cardbuilder/cardBuilder.js",
|
||||
"src/components/cardbuilder/chaptercardbuilder.js",
|
||||
"src/components/cardbuilder/peoplecardbuilder.js",
|
||||
"src/components/images/imageLoader.js",
|
||||
"src/components/indicators/indicators.js",
|
||||
"src/components/lazyLoader/lazyLoaderIntersectionObserver.js",
|
||||
"src/components/playback/brightnessosd.js",
|
||||
"src/components/playback/mediasession.js",
|
||||
"src/components/playback/nowplayinghelper.js",
|
||||
"src/components/playback/playbackorientation.js",
|
||||
"src/components/playback/playerSelectionMenu.js",
|
||||
"src/components/playback/playersettingsmenu.js",
|
||||
"src/components/playback/playmethodhelper.js",
|
||||
"src/components/playback/remotecontrolautoplay.js",
|
||||
"src/components/playback/volumeosd.js",
|
||||
"src/components/playmenu.js",
|
||||
"src/components/sanatizefilename.js",
|
||||
"src/components/scrollManager.js",
|
||||
"src/components/syncPlay/groupSelectionMenu.js",
|
||||
"src/components/syncPlay/playbackPermissionManager.js",
|
||||
"src/components/syncPlay/syncPlayManager.js",
|
||||
"src/components/syncPlay/timeSyncManager.js",
|
||||
"src/controllers/dashboard/logs.js",
|
||||
"src/controllers/dashboard/plugins/repositories.js",
|
||||
"src/controllers/user/display.js",
|
||||
"src/controllers/user/home.js",
|
||||
"src/controllers/user/playback.js",
|
||||
"src/controllers/user/subtitles.js",
|
||||
"src/plugins/bookPlayer/plugin.js",
|
||||
"src/plugins/bookPlayer/tableOfContents.js",
|
||||
"src/plugins/photoPlayer/plugin.js",
|
||||
"src/scripts/deleteHelper.js",
|
||||
"src/scripts/dfnshelper.js",
|
||||
"src/scripts/dom.js",
|
||||
"src/scripts/fileDownloader.js",
|
||||
"src/scripts/filesystem.js",
|
||||
"src/scripts/imagehelper.js",
|
||||
"src/scripts/inputManager.js",
|
||||
"src/plugins/backdropScreensaver/plugin.js",
|
||||
"src/components/filterdialog/filterdialog.js",
|
||||
"src/components/fetchhelper.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",
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
"@babel/plugin-proposal-private-methods"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 Firefox versions",
|
||||
"last 2 Chrome versions",
|
||||
"last 2 ChromeAndroid versions",
|
||||
"last 2 Safari versions",
|
||||
"iOS > 10",
|
||||
"last 2 Edge versions",
|
||||
"Chrome 27",
|
||||
"Chrome 38",
|
||||
"Chrome 47",
|
||||
"Chrome 53",
|
||||
"Chrome 56",
|
||||
"Chrome 63",
|
||||
"Edge 18",
|
||||
"Firefox ESR"
|
||||
],
|
||||
"scripts": {
|
||||
"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\""
|
||||
"serve": "webpack-dev-server --config webpack.dev.js --open",
|
||||
"build": "webpack --config webpack.prod.js",
|
||||
"lint": "eslint \"src\"",
|
||||
"prepare": "webpack --config webpack.prod.js"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const packageConfig = require('./package.json');
|
||||
const postcssPresetEnv = require('postcss-preset-env');
|
||||
const autoprefixer = require('autoprefixer');
|
||||
const cssnano = require('cssnano');
|
||||
|
||||
const config = () => ({
|
||||
plugins: [
|
||||
// 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;
|
||||
@@ -1,52 +0,0 @@
|
||||
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 = []
|
||||
missing = []
|
||||
|
||||
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]
|
||||
elif key not in missing:
|
||||
missing.append(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(missing)
|
||||
print('LENGTH: ' + str(len(missing)))
|
||||
with open('missing.txt', 'w') as out:
|
||||
for item in missing:
|
||||
out.write(item + '\n')
|
||||
out.close()
|
||||
|
||||
print('DONE')
|
||||
@@ -1,40 +0,0 @@
|
||||
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('unused.txt', 'w') as out:
|
||||
for item in dep:
|
||||
out.write(item + '\n')
|
||||
out.close()
|
||||
@@ -1,34 +0,0 @@
|
||||
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')
|
||||
@@ -1,15 +1,21 @@
|
||||
<div id="addPluginPage" data-role="page" class="page type-interior pluginConfigurationPage" data-backbutton="true">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
|
||||
<div class="readOnlyContent">
|
||||
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h1 class="sectionTitle pluginName"></h1>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/plugins/index.html">${Help}</a>
|
||||
<a is="emby-linkbutton" class="raised button-alt headerHelpButton" target="_blank" href="https://docs.jellyfin.org/general/server/plugins/index.html">${Help}</a>
|
||||
</div>
|
||||
|
||||
<p id="overview" style="font-style: italic;"></p>
|
||||
<p id="description"></p>
|
||||
<p id="tagline" style="font-style: italic;"></p>
|
||||
<p id="pPreviewImage"></p>
|
||||
|
||||
<p id="overview"></p>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="verticalSection">
|
||||
@@ -21,12 +27,13 @@
|
||||
<select id="selectVersion" name="selectVersion" is="emby-select" label="${LabelSelectVersionToInstall}"></select>
|
||||
</div>
|
||||
|
||||
<div id="btnInstallDiv" class="hide">
|
||||
<p id="btnInstallDiv" class="hide">
|
||||
<button is="emby-button" type="submit" id="btnInstall" class="raised button-submit block">
|
||||
<span>${Install}</span>
|
||||
</button>
|
||||
<div class="fieldDescription">${ServerRestartNeededAfterPluginInstall}</div>
|
||||
</div>
|
||||
</p>
|
||||
<p id="nonServerMsg"></p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -35,6 +42,9 @@
|
||||
<div is="emby-collapse" title="${HeaderDeveloperInfo}">
|
||||
<div class="collapseContent">
|
||||
<p id="developer"></p>
|
||||
<p id="pViewWebsite" style="display: none;">
|
||||
<a is="emby-linkbutton" class="button-link" href="#" target="_blank">${ButtonViewWebsite}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div data-role="page" class="page standalonePage">
|
||||
<div class="padded-left padded-right padded-bottom-page">
|
||||
<form class="addServerForm" style="margin: 0 auto;" novalidate>
|
||||
<form class="addServerForm" style="margin: 0 auto;">
|
||||
<h1>${HeaderConnectToServer}</h1>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="url" id="txtServerHost" required="required" label="${LabelServerHost}"/>
|
||||
<input is="emby-input" type="text" id="txtServerHost" required="required" label="${LabelServerHost}" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off" />
|
||||
<div class="fieldDescription">${LabelServerHostHelp}</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
@@ -2,25 +2,26 @@
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
<div class="detailSectionHeader">
|
||||
<h2 style="margin:.6em 0;vertical-align:middle;display:inline-block;">${HeaderApiKeys}</h2>
|
||||
<h2 style="margin:.6em 0;vertical-align:middle;display:inline-block;">
|
||||
${HeaderApiKeys}
|
||||
</h2>
|
||||
<button is="emby-button" type="button" class="fab btnNewKey submit" style="margin-left:1em;" title="${ButtonAdd}">
|
||||
<span class="material-icons add" aria-hidden="true"></span>
|
||||
<i class="md-icon">add</i>
|
||||
</button>
|
||||
</div>
|
||||
<p>${HeaderApiKeysHelp}</p>
|
||||
<br />
|
||||
<table class="tblApiKeys detailTable">
|
||||
<caption class="clipForScreenReader">${ApiKeysCaption}</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" class="detailTableHeaderCell"></th>
|
||||
<th scope="col" class="detailTableHeaderCell">${HeaderApiKey}</th>
|
||||
<th scope="col" class="detailTableHeaderCell">${HeaderApp}</th>
|
||||
<th scope="col" class="detailTableHeaderCell">${HeaderDateIssued}</th>
|
||||
<th class="detailTableHeaderCell"></th>
|
||||
<th class="detailTableHeaderCell">${HeaderApiKey}</th>
|
||||
<th class="detailTableHeaderCell">${HeaderApp}</th>
|
||||
<th class="detailTableHeaderCell">${HeaderDateIssued}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="resultBody"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Binary file not shown.
@@ -1,37 +0,0 @@
|
||||
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 {
|
||||
font-family: "Noto Sans", sans-serif;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 400;
|
||||
font-size: 1.8em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 400;
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 400;
|
||||
font-size: 1.17em;
|
||||
}
|
||||
|
||||
.layout-tv {
|
||||
font-size: 130%;
|
||||
}
|
||||
|
||||
.layout-mobile {
|
||||
font-size: 90%;
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
html {
|
||||
font-size: 82% !important;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,9 +0,0 @@
|
||||
.guideVerticalScroller {
|
||||
padding-bottom: 15em;
|
||||
}
|
||||
|
||||
@media all and (min-width: 62.5em) {
|
||||
#guideTab {
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
body,
|
||||
html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.layout-mobile,
|
||||
.layout-tv {
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.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 */
|
||||
font-feature-settings: "liga";
|
||||
}
|
||||
|
||||
.backgroundContainer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
html {
|
||||
line-height: 1.35;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
background-color: transparent !important;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
.mainAnimatedPage {
|
||||
contain: style size !important;
|
||||
}
|
||||
|
||||
.pageContainer {
|
||||
overflow-x: visible !important;
|
||||
}
|
||||
|
||||
.bodyWithPopupOpen {
|
||||
overflow-y: hidden !important;
|
||||
}
|
||||
|
||||
div[data-role=page] {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.pageTitle {
|
||||
margin-top: 0;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.fieldDescription {
|
||||
padding-left: 0.15em;
|
||||
font-weight: 400;
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
.fieldDescription + .fieldDescription {
|
||||
margin-top: 0.3em;
|
||||
}
|
||||
|
||||
.content-primary,
|
||||
.padded-bottom-page,
|
||||
.page,
|
||||
.pageWithAbsoluteTabs .pageTabContent {
|
||||
/* provides room for the music controls */
|
||||
padding-bottom: 5em !important;
|
||||
}
|
||||
|
||||
@media all and (min-width: 50em) {
|
||||
.readOnlyContent,
|
||||
form {
|
||||
max-width: 54em;
|
||||
}
|
||||
}
|
||||
|
||||
.headerHelpButton {
|
||||
margin-left: 1.25em !important;
|
||||
padding-bottom: 0.4em !important;
|
||||
padding-top: 0.4em !important;
|
||||
}
|
||||
|
||||
.mediaInfoContent {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
.headroom {
|
||||
will-change: transform;
|
||||
transition: transform 200ms linear;
|
||||
}
|
||||
|
||||
.headroom--pinned {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
|
||||
.headroom--unpinned {
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.drawerContent {
|
||||
/* make sure the bottom of the drawer is visible when music is playing */
|
||||
padding-bottom: 4em;
|
||||
}
|
||||
|
||||
.force-scroll {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.hide-scroll {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M24 19H0a13.6 13.6 0 0 1 2.21-6.07A11.2 11.2 0 0 1 5.87 9.4l.41-.23-2.02-3.41a.51.51 0 0 1 .17-.7.5.5 0 0 1 .69.18l2.08 3.5a12.62 12.62 0 0 1 4.84-.9 12.2 12.2 0 0 1 4.75.9l2.07-3.5a.5.5 0 0 1 .7-.17.51.51 0 0 1 .16.7L17.7 9.19l.5.28a11.38 11.38 0 0 1 3.63 3.62A14.48 14.48 0 0 1 24 19zm-7.5-4.48a1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1 1 1 0 0 0-1 1zm-11 0a1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0-1-1 1 1 0 0 0-1 1z" fill="#fff"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 563 B |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" role="img" viewBox="0 0 24 24"><title>Microsoft Edge icon</title><path d="M21.86 17.86q.14 0 .25.12.1.13.1.25t-.11.33l-.32.46-.43.53-.44.5q-.21.25-.38.42l-.22.23q-.58.53-1.34 1.04-.76.51-1.6.91-.86.4-1.74.64t-1.67.24q-.9 0-1.69-.28-.8-.28-1.48-.78-.68-.5-1.22-1.17-.53-.66-.92-1.44-.38-.77-.58-1.6-.2-.83-.2-1.67 0-1 .32-1.96.33-.97.87-1.8.14.95.55 1.77.41.82 1.02 1.5.6.68 1.38 1.21.78.54 1.64.9.86.36 1.77.56.92.2 1.8.2 1.12 0 2.18-.24 1.06-.23 2.06-.72l.2-.1.2-.05zm-15.5-1.27q0 1.1.27 2.15.27 1.06.78 2.03.51.96 1.24 1.77.74.82 1.66 1.4-1.47-.2-2.8-.74-1.33-.55-2.48-1.37-1.15-.83-2.08-1.9-.92-1.07-1.58-2.33T.36 14.94Q0 13.54 0 12.06q0-.81.32-1.49.31-.68.83-1.23.53-.55 1.2-.96.66-.4 1.35-.66.74-.27 1.5-.39.78-.12 1.55-.12.7 0 1.42.1.72.12 1.4.35.68.23 1.32.57.63.35 1.16.83-.35 0-.7.07-.33.07-.65.23v-.02q-.63.28-1.2.74-.57.46-1.05 1.04-.48.58-.87 1.26-.38.67-.65 1.39-.27.71-.42 1.44-.15.72-.15 1.38zM11.96.06q1.7 0 3.33.39 1.63.38 3.07 1.15 1.43.77 2.62 1.93 1.18 1.16 1.98 2.7.49.94.76 1.96.28 1 .28 2.08 0 .89-.23 1.7-.24.8-.69 1.48-.45.68-1.1 1.22-.64.53-1.45.88-.54.24-1.11.36-.58.13-1.16.13-.42 0-.97-.03-.54-.03-1.1-.12-.55-.1-1.05-.28-.5-.19-.84-.5-.12-.09-.23-.24-.1-.16-.1-.33 0-.15.16-.35.16-.2.35-.5.2-.28.36-.68.16-.4.16-.95 0-1.06-.4-1.96-.4-.91-1.06-1.64-.66-.74-1.52-1.28-.86-.55-1.79-.89-.84-.3-1.72-.44-.87-.14-1.76-.14-1.55 0-3.06.45T.94 7.55q.71-1.74 1.81-3.13 1.1-1.38 2.52-2.35Q6.68 1.1 8.37.58q1.7-.52 3.58-.52Z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,11 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<g transform="translate(-36.173 -93.796)">
|
||||
<g transform="matrix(.08 0 0 .08 40.527 88.485)">
|
||||
<path d="m53.295 119.35v-39.688h79.375v79.375h-79.375z" fill="#fcfdfd" stroke-width=".26458"/>
|
||||
</g>
|
||||
<g transform="matrix(1.3761 0 0 1.3825 -26.63 -38.456)" fill="#fff">
|
||||
<path transform="matrix(.08 0 0 .08 40.527 88.485)" d="m86.822 141.89c-4.738-4.7596-5.2168-5.3235-5.2168-6.1442 0-0.82158 0.47505-1.3787 5.2329-6.1365 4.7552-4.7552 5.3153-5.2329 6.1353-5.2329 0.81617 0 1.3676 0.46161 5.7678 4.8286 4.8692 4.8324 5.6182 5.7452 5.6182 6.8466 0 0.41218-1.5697 2.1641-5.2274 5.834-4.8206 4.8367-5.3 5.2449-6.1603 5.2449-0.86046 0-1.3378-0.40681-6.1497-5.2406zm22.168-12.455c-0.43656-0.27248-2.9071-2.6371-5.4901-5.2547-4.1957-4.2519-4.6964-4.8534-4.6964-5.6418 0-0.7938 0.52954-1.414 5.2644-6.1655 4.6582-4.6746 5.362-5.2829 6.1127-5.2829 0.75071 0 1.4546 0.60829 6.1127 5.2829 4.7729 4.7898 5.2644 5.3668 5.2644 6.1818 0 0.81542-0.48628 1.3851-5.2394 6.1382-5.6104 5.6104-5.7707 5.7142-7.3283 4.742zm-40.16-5.2731c-3.5636-3.5816-4.9518-5.1483-4.9518-5.5886 0-0.75745 9.3384-10.601 10.057-10.601 0.2584 0 0.54208 0.18833 0.63041 0.41851s0.1606 4.7624 0.1606 10.072c0 9.1098-0.10948 10.677-0.74606 10.677-0.10905 0-2.4266-2.2396-5.1501-4.9768zm13.2-1.5272c-0.08833-0.23018-0.1606-5.3558-0.1606-11.39 0-8.9734 0.06852-11.102 0.37621-11.686 0.20691-0.39296 2.447-2.7683 4.9781-5.2785 4.3226-4.2871 4.6624-4.5641 5.5987-4.5641 0.94583 0 1.2591 0.26717 6.1277 5.2255 4.658 4.7439 5.1315 5.3102 5.1376 6.1439 6e-3 0.85888-0.67407 1.6-10.506 11.443-5.782 5.7887-10.71 10.525-10.952 10.525s-0.51144-0.18833-0.59977-0.41852z" fill="#fff" stroke-width=".26458"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.8 KiB |
@@ -1,20 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg id="svg3390" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="141.25" viewBox="0 0 138.75 141.25" width="138.75" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<metadata id="metadata3396">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="layer1" fill="#f93208">
|
||||
<path id="path3412" d="m20.154 40.829c-28.149 27.622-13.657 61.011-5.734 71.931 35.254 41.954 92.792 25.339 111.89-5.9071 4.7608-8.2027 22.554-53.467-23.976-78.009z"/>
|
||||
<path id="path3471" d="m39.613 39.265 4.7778-8.8607 28.406-5.0384 11.119 9.2082z"/>
|
||||
</g>
|
||||
<g id="layer2">
|
||||
<path id="path3437" d="m39.436 8.5696 8.9682-5.2826 6.7569 15.479c3.7925-6.3226 13.79-16.316 24.939-4.6684-4.7281 1.2636-7.5161 3.8553-7.7397 8.4768 15.145-4.1697 31.343 3.2127 33.539 9.0911-10.951-4.314-27.695 10.377-41.771 2.334 0.009 15.045-12.617 16.636-19.902 17.076 2.077-4.996 5.591-9.994 1.474-14.987-7.618 8.171-13.874 10.668-33.17 4.668 4.876-1.679 14.843-11.39 24.448-11.425-6.775-2.467-12.29-2.087-17.814-1.475 2.917-3.961 12.149-15.197 28.625-8.476z" fill="#02902e"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="145" height="140"><path fill="#0fc755" d="M47.4 35.342c-13.607-7.935-12.32-25.203 2.097-31.88 26.124-6.531 29.117 13.78 22.652 30.412-6.542 24.11 18.095 23.662 19.925 10.067 3.605-18.412 19.394-26.695 31.67-16.359 12.598 12.135 7.074 36.581-17.827 34.187-16.03-1.545-19.552 19.585.839 21.183 32.228 1.915 42.49 22.167 31.04 35.865-15.993 15.15-37.691-4.439-45.512-19.505-6.8-9.307-17.321.11-13.423 6.502 12.983 19.465 2.923 31.229-10.906 30.62-13.37-.85-20.96-9.06-13.214-29.15 3.897-12.481-8.595-15.386-16.57-5.45-11.707 19.61-28.865 13.68-33.976 4.19-3.243-7.621-2.921-25.846 24.119-23.696 16.688 4.137 11.776-12.561-.63-13.633-9.245-.443-30.501-7.304-22.86-24.54 7.34-11.056 24.958-11.768 33.348 6.293 3.037 4.232 8.361 11.042 18.037 5.033 3.51-5.197 1.21-13.9-8.809-20.135z"/></svg>
|
||||
|
Before Width: | Height: | Size: 833 B |
@@ -5,4 +5,4 @@
|
||||
<div id="pluginTiles" style="text-align:left;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
419
src/bower_components/alameda/alameda.js
vendored
Normal file
419
src/bower_components/alameda/alameda.js
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
var requirejs, require, define;
|
||||
! function(global, Promise, undef) {
|
||||
function commentReplace(match, singlePrefix) {
|
||||
return singlePrefix || ""
|
||||
}
|
||||
|
||||
function hasProp(obj, prop) {
|
||||
return hasOwn.call(obj, prop)
|
||||
}
|
||||
|
||||
function getOwn(obj, prop) {
|
||||
return obj && hasProp(obj, prop) && obj[prop]
|
||||
}
|
||||
|
||||
function obj() {
|
||||
return Object.create(null)
|
||||
}
|
||||
|
||||
function eachProp(obj, func) {
|
||||
var prop;
|
||||
for (prop in obj)
|
||||
if (hasProp(obj, prop) && func(obj[prop], prop)) break
|
||||
}
|
||||
|
||||
function mixin(target, source, force, deepStringMixin) {
|
||||
return source && eachProp(source, function(value, prop) {
|
||||
!force && hasProp(target, prop) || (!deepStringMixin || "object" != typeof value || !value || Array.isArray(value) || "function" == typeof value || value instanceof RegExp ? target[prop] = value : (target[prop] || (target[prop] = {}), mixin(target[prop], value, force, deepStringMixin)))
|
||||
}), target
|
||||
}
|
||||
|
||||
function getGlobal(value) {
|
||||
if (!value) return value;
|
||||
var g = global;
|
||||
return value.split(".").forEach(function(part) {
|
||||
g = g[part]
|
||||
}), g
|
||||
}
|
||||
|
||||
function newContext(contextName) {
|
||||
function trimDots(ary) {
|
||||
var i, part, length = ary.length;
|
||||
for (i = 0; i < length; i++)
|
||||
if ("." === (part = ary[i])) ary.splice(i, 1), i -= 1;
|
||||
else if (".." === part) {
|
||||
if (0 === i || 1 === i && ".." === ary[2] || ".." === ary[i - 1]) continue;
|
||||
i > 0 && (ary.splice(i - 1, 2), i -= 2)
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(name, baseName, applyMap) {
|
||||
var mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, baseParts = baseName && baseName.split("/"),
|
||||
normalizedBaseParts = baseParts,
|
||||
map = config.map,
|
||||
starMap = map && map["*"];
|
||||
if (name && (name = name.split("/"), lastIndex = name.length - 1, config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex]) && (name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, "")), "." === name[0].charAt(0) && baseParts && (normalizedBaseParts = baseParts.slice(0, baseParts.length - 1), name = normalizedBaseParts.concat(name)), trimDots(name), name = name.join("/")), applyMap && map && (baseParts || starMap)) {
|
||||
nameParts = name.split("/");
|
||||
outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
|
||||
if (nameSegment = nameParts.slice(0, i).join("/"), baseParts)
|
||||
for (j = baseParts.length; j > 0; j -= 1)
|
||||
if ((mapValue = getOwn(map, baseParts.slice(0, j).join("/"))) && (mapValue = getOwn(mapValue, nameSegment))) {
|
||||
foundMap = mapValue, foundI = i;
|
||||
break outerLoop
|
||||
}! foundStarMap && starMap && getOwn(starMap, nameSegment) && (foundStarMap = getOwn(starMap, nameSegment), starI = i)
|
||||
}!foundMap && foundStarMap && (foundMap = foundStarMap, foundI = starI), foundMap && (nameParts.splice(0, foundI, foundMap), name = nameParts.join("/"))
|
||||
}
|
||||
return getOwn(config.pkgs, name) || name
|
||||
}
|
||||
|
||||
function makeShimExports(value) {
|
||||
function fn() {
|
||||
var ret;
|
||||
return value.init && (ret = value.init.apply(global, arguments)), ret || value.exports && getGlobal(value.exports)
|
||||
}
|
||||
return fn
|
||||
}
|
||||
|
||||
function takeQueue(anonId) {
|
||||
var i, id, args, shim;
|
||||
for (i = 0; i < queue.length; i += 1) {
|
||||
if ("string" != typeof queue[i][0]) {
|
||||
if (!anonId) break;
|
||||
queue[i].unshift(anonId), anonId = undef
|
||||
}
|
||||
args = queue.shift(), id = args[0], i -= 1, id in defined || id in waiting || (id in deferreds ? main.apply(undef, args) : waiting[id] = args)
|
||||
}
|
||||
anonId && (shim = getOwn(config.shim, anonId) || {}, main(anonId, shim.deps || [], shim.exportsFn))
|
||||
}
|
||||
|
||||
function makeRequire(relName, topLevel) {
|
||||
var req = function(deps, callback, errback, alt) {
|
||||
var name, cfg;
|
||||
if (topLevel && takeQueue(), "string" == typeof deps) {
|
||||
if (handlers[deps]) return handlers[deps](relName);
|
||||
if (!((name = makeMap(deps, relName, !0).id) in defined)) throw new Error("Not loaded: " + name);
|
||||
return defined[name]
|
||||
}
|
||||
return deps && !Array.isArray(deps) && (cfg = deps, deps = undef, Array.isArray(callback) && (deps = callback, callback = errback, errback = alt), topLevel) ? req.config(cfg)(deps, callback, errback) : (callback = callback || function() {
|
||||
return slice.call(arguments, 0)
|
||||
}, asyncResolve.then(function() {
|
||||
return takeQueue(), main(undef, deps || [], callback, errback, relName)
|
||||
}))
|
||||
};
|
||||
return req.isBrowser = "undefined" != typeof document && "undefined" != typeof navigator, req.nameToUrl = function(moduleName, ext, skipExt) {
|
||||
var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName);
|
||||
if (pkgMain && (moduleName = pkgMain), bundleId = getOwn(bundlesMap, moduleName)) return req.nameToUrl(bundleId, ext, skipExt);
|
||||
if (urlRegExp.test(moduleName)) url = moduleName + (ext || "");
|
||||
else {
|
||||
for (paths = config.paths, syms = moduleName.split("/"), i = syms.length; i > 0; i -= 1)
|
||||
if (parentModule = syms.slice(0, i).join("/"), parentPath = getOwn(paths, parentModule)) {
|
||||
Array.isArray(parentPath) && (parentPath = parentPath[0]), syms.splice(0, i, parentPath);
|
||||
break
|
||||
} url = syms.join("/"), url += ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? "" : ".js"), url = ("/" === url.charAt(0) || url.match(/^[\w\+\.\-]+:/) ? "" : config.baseUrl) + url
|
||||
}
|
||||
return config.urlArgs && !/^blob\:/.test(url) ? url + config.urlArgs(moduleName, url) : url
|
||||
}, req.toUrl = function(moduleNamePlusExt) {
|
||||
var ext, index = moduleNamePlusExt.lastIndexOf("."),
|
||||
segment = moduleNamePlusExt.split("/")[0],
|
||||
isRelative = "." === segment || ".." === segment;
|
||||
return -1 !== index && (!isRelative || index > 1) && (ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length), moduleNamePlusExt = moduleNamePlusExt.substring(0, index)), req.nameToUrl(normalize(moduleNamePlusExt, relName), ext, !0)
|
||||
}, req.defined = function(id) {
|
||||
return makeMap(id, relName, !0).id in defined
|
||||
}, req.specified = function(id) {
|
||||
return (id = makeMap(id, relName, !0).id) in defined || id in deferreds
|
||||
}, req
|
||||
}
|
||||
|
||||
function resolve(name, d, value) {
|
||||
name && (defined[name] = value, requirejs.onResourceLoad && requirejs.onResourceLoad(context, d.map, d.deps)), d.finished = !0, d.resolve(value)
|
||||
}
|
||||
|
||||
function reject(d, err) {
|
||||
d.finished = !0, d.rejected = !0, d.reject(err)
|
||||
}
|
||||
|
||||
function makeNormalize(relName) {
|
||||
return function(name) {
|
||||
return normalize(name, relName, !0)
|
||||
}
|
||||
}
|
||||
|
||||
function defineModule(d) {
|
||||
d.factoryCalled = !0;
|
||||
var ret, name = d.map.id;
|
||||
try {
|
||||
ret = context.execCb(name, d.factory, d.values, defined[name])
|
||||
} catch (err) {
|
||||
return reject(d, err)
|
||||
}
|
||||
name ? ret === undef && (d.cjsModule ? ret = d.cjsModule.exports : d.usingExports && (ret = defined[name])) : requireDeferreds.splice(requireDeferreds.indexOf(d), 1), resolve(name, d, ret)
|
||||
}
|
||||
|
||||
function depFinished(val, i) {
|
||||
this.rejected || this.depDefined[i] || (this.depDefined[i] = !0, this.depCount += 1, this.values[i] = val, this.depending || this.depCount !== this.depMax || defineModule(this))
|
||||
}
|
||||
|
||||
function makeDefer(name, calculatedMap) {
|
||||
var d = {};
|
||||
return d.promise = new Promise(function(resolve, reject) {
|
||||
d.resolve = resolve, d.reject = function(err) {
|
||||
name || requireDeferreds.splice(requireDeferreds.indexOf(d), 1), reject(err)
|
||||
}
|
||||
}), d.map = name ? calculatedMap || makeMap(name) : {}, d.depCount = 0, d.depMax = 0, d.values = [], d.depDefined = [], d.depFinished = depFinished, d.map.pr && (d.deps = [makeMap(d.map.pr)]), d
|
||||
}
|
||||
|
||||
function getDefer(name, calculatedMap) {
|
||||
var d;
|
||||
return name ? (d = name in deferreds && deferreds[name]) || (d = deferreds[name] = makeDefer(name, calculatedMap)) : (d = makeDefer(), requireDeferreds.push(d)), d
|
||||
}
|
||||
|
||||
function makeErrback(d, name) {
|
||||
return function(err) {
|
||||
d.rejected || (err.dynaId || (err.dynaId = "id" + (errCount += 1), err.requireModules = [name]), reject(d, err))
|
||||
}
|
||||
}
|
||||
|
||||
function waitForDep(depMap, relName, d, i) {
|
||||
d.depMax += 1, callDep(depMap, relName).then(function(val) {
|
||||
d.depFinished(val, i)
|
||||
}, makeErrback(d, depMap.id)).catch(makeErrback(d, d.map.id))
|
||||
}
|
||||
|
||||
function makeLoad(id) {
|
||||
function load(value) {
|
||||
fromTextCalled || resolve(id, getDefer(id), value)
|
||||
}
|
||||
var fromTextCalled;
|
||||
return load.error = function(err) {
|
||||
reject(getDefer(id), err)
|
||||
}, load.fromText = function(text, textAlt) {
|
||||
var execError, d = getDefer(id),
|
||||
map = makeMap(makeMap(id).n),
|
||||
plainId = map.id;
|
||||
fromTextCalled = !0, d.factory = function(p, val) {
|
||||
return val
|
||||
}, textAlt && (text = textAlt), hasProp(config.config, id) && (config.config[plainId] = config.config[id]);
|
||||
try {
|
||||
req.exec(text)
|
||||
} catch (e) {
|
||||
execError = new Error("fromText eval for " + plainId + " failed: " + e), execError.requireType = "fromtexteval", reject(d, execError)
|
||||
}
|
||||
takeQueue(plainId), d.deps = [map], waitForDep(map, null, d, d.deps.length)
|
||||
}, load
|
||||
}
|
||||
|
||||
function callPlugin(plugin, map, relName) {
|
||||
plugin.load(map.n, makeRequire(relName), makeLoad(map.id), config)
|
||||
}
|
||||
|
||||
function splitPrefix(name) {
|
||||
var prefix, index = name ? name.indexOf("!") : -1;
|
||||
return index > -1 && (prefix = name.substring(0, index), name = name.substring(index + 1, name.length)), [prefix, name]
|
||||
}
|
||||
|
||||
function breakCycle(d, traced, processed) {
|
||||
var id = d.map.id;
|
||||
traced[id] = !0, !d.finished && d.deps && d.deps.forEach(function(depMap) {
|
||||
var depId = depMap.id,
|
||||
dep = !hasProp(handlers, depId) && getDefer(depId, depMap);
|
||||
!dep || dep.finished || processed[depId] || (hasProp(traced, depId) ? d.deps.forEach(function(depMap, i) {
|
||||
depMap.id === depId && d.depFinished(defined[depId], i)
|
||||
}) : breakCycle(dep, traced, processed))
|
||||
}), processed[id] = !0
|
||||
}
|
||||
|
||||
function check(d) {
|
||||
var err, mid, dfd, notFinished = [],
|
||||
waitInterval = 1e3 * config.waitSeconds,
|
||||
expired = waitInterval && startTime + waitInterval < (new Date).getTime();
|
||||
if (0 === loadCount && (d ? d.finished || breakCycle(d, {}, {}) : requireDeferreds.length && requireDeferreds.forEach(function(d) {
|
||||
breakCycle(d, {}, {})
|
||||
})), expired) {
|
||||
for (mid in deferreds) dfd = deferreds[mid], dfd.finished || notFinished.push(dfd.map.id);
|
||||
err = new Error("Timeout for modules: " + notFinished), err.requireModules = notFinished, err.requireType = "timeout", notFinished.forEach(function(id) {
|
||||
reject(getDefer(id), err)
|
||||
})
|
||||
} else(loadCount || requireDeferreds.length) && (checkingLater || (checkingLater = !0, setTimeout(function() {
|
||||
checkingLater = !1, check()
|
||||
}, 70)))
|
||||
}
|
||||
|
||||
function delayedError(e) {
|
||||
console.log(e.stack);
|
||||
return setTimeout(function() {
|
||||
e.dynaId && trackedErrors[e.dynaId] || (trackedErrors[e.dynaId] = !0, req.onError(e))
|
||||
}), e
|
||||
}
|
||||
var req, main, makeMap, callDep, handlers, checkingLater, load, context, defined = obj(),
|
||||
waiting = obj(),
|
||||
config = {
|
||||
waitSeconds: 7,
|
||||
baseUrl: "./",
|
||||
paths: {},
|
||||
bundles: {},
|
||||
pkgs: {},
|
||||
shim: {},
|
||||
config: {}
|
||||
},
|
||||
mapCache = obj(),
|
||||
requireDeferreds = [],
|
||||
deferreds = obj(),
|
||||
calledDefine = obj(),
|
||||
calledPlugin = obj(),
|
||||
loadCount = 0,
|
||||
startTime = (new Date).getTime(),
|
||||
errCount = 0,
|
||||
trackedErrors = obj(),
|
||||
urlFetched = obj(),
|
||||
bundlesMap = obj(),
|
||||
asyncResolve = Promise.resolve(undefined);
|
||||
return load = "function" == typeof importScripts ? function(map) {
|
||||
var url = map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, getDefer(map.id), importScripts(url), takeQueue(map.id))
|
||||
} : function(map) {
|
||||
var script, id = map.id,
|
||||
url = map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, script = document.createElement("script"), script.setAttribute("data-requiremodule", id), script.type = config.scriptType || "text/javascript", script.charset = "utf-8", script.async = !0, loadCount += 1, script.addEventListener("load", function() {
|
||||
loadCount -= 1, takeQueue(id)
|
||||
}, !1), script.addEventListener("error", function() {
|
||||
loadCount -= 1;
|
||||
var err, pathConfig = getOwn(config.paths, id);
|
||||
if (pathConfig && Array.isArray(pathConfig) && pathConfig.length > 1) {
|
||||
script.parentNode.removeChild(script), pathConfig.shift();
|
||||
var d = getDefer(id);
|
||||
d.map = makeMap(id), d.map.url = req.nameToUrl(id), load(d.map)
|
||||
} else err = new Error("Load failed: " + id + ": " + script.src), err.requireModules = [id], err.requireType = "scripterror", reject(getDefer(id), err)
|
||||
}, !1), script.src = url, 10 === document.documentMode ? asap.then(function() {
|
||||
document.head.appendChild(script)
|
||||
}) : document.head.appendChild(script))
|
||||
}, callDep = function(map, relName) {
|
||||
var args, bundleId, name = map.id,
|
||||
shim = config.shim[name];
|
||||
if (name in waiting) args = waiting[name], delete waiting[name], main.apply(undef, args);
|
||||
else if (!(name in deferreds))
|
||||
if (map.pr) {
|
||||
if (!(bundleId = getOwn(bundlesMap, name))) return callDep(makeMap(map.pr)).then(function(plugin) {
|
||||
var newMap = map.prn ? map : makeMap(name, relName, !0),
|
||||
newId = newMap.id,
|
||||
shim = getOwn(config.shim, newId);
|
||||
return newId in calledPlugin || (calledPlugin[newId] = !0, shim && shim.deps ? req(shim.deps, function() {
|
||||
callPlugin(plugin, newMap, relName)
|
||||
}) : callPlugin(plugin, newMap, relName)), getDefer(newId).promise
|
||||
});
|
||||
map.url = req.nameToUrl(bundleId), load(map)
|
||||
} else shim && shim.deps ? req(shim.deps, function() {
|
||||
load(map)
|
||||
}) : load(map);
|
||||
return getDefer(name).promise
|
||||
}, makeMap = function(name, relName, applyMap) {
|
||||
if ("string" != typeof name) return name;
|
||||
var plugin, url, parts, prefix, result, prefixNormalized, cacheKey = name + " & " + (relName || "") + " & " + !!applyMap;
|
||||
return parts = splitPrefix(name), prefix = parts[0], name = parts[1], !prefix && cacheKey in mapCache ? mapCache[cacheKey] : (prefix && (prefix = normalize(prefix, relName, applyMap), plugin = prefix in defined && defined[prefix]), prefix ? plugin && plugin.normalize ? (name = plugin.normalize(name, makeNormalize(relName)), prefixNormalized = !0) : name = -1 === name.indexOf("!") ? normalize(name, relName, applyMap) : name : (name = normalize(name, relName, applyMap), parts = splitPrefix(name), prefix = parts[0], name = parts[1], url = req.nameToUrl(name)), result = {
|
||||
id: prefix ? prefix + "!" + name : name,
|
||||
n: name,
|
||||
pr: prefix,
|
||||
url: url,
|
||||
prn: prefix && prefixNormalized
|
||||
}, prefix || (mapCache[cacheKey] = result), result)
|
||||
}, handlers = {
|
||||
require: function(name) {
|
||||
return makeRequire(name)
|
||||
},
|
||||
exports: function(name) {
|
||||
var e = defined[name];
|
||||
return void 0 !== e ? e : defined[name] = {}
|
||||
},
|
||||
module: function(name) {
|
||||
return {
|
||||
id: name,
|
||||
uri: "",
|
||||
exports: handlers.exports(name),
|
||||
config: function() {
|
||||
return getOwn(config.config, name) || {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, main = function(name, deps, factory, errback, relName) {
|
||||
if (name) {
|
||||
if (name in calledDefine) return;
|
||||
calledDefine[name] = !0
|
||||
}
|
||||
var d = getDefer(name);
|
||||
return deps && !Array.isArray(deps) && (factory = deps, deps = []), deps = deps ? slice.call(deps, 0) : null, errback || (hasProp(config, "defaultErrback") ? config.defaultErrback && (errback = config.defaultErrback) : errback = delayedError), errback && d.promise.catch(errback), relName = relName || name, "function" == typeof factory ? (!deps.length && factory.length && (factory.toString().replace(commentRegExp, commentReplace).replace(cjsRequireRegExp, function(match, dep) {
|
||||
deps.push(dep)
|
||||
}), deps = (1 === factory.length ? ["require"] : ["require", "exports", "module"]).concat(deps)), d.factory = factory, d.deps = deps, d.depending = !0, deps.forEach(function(depName, i) {
|
||||
var depMap;
|
||||
deps[i] = depMap = makeMap(depName, relName, !0), depName = depMap.id, "require" === depName ? d.values[i] = handlers.require(name) : "exports" === depName ? (d.values[i] = handlers.exports(name), d.usingExports = !0) : "module" === depName ? d.values[i] = d.cjsModule = handlers.module(name) : void 0 === depName ? d.values[i] = void 0 : waitForDep(depMap, relName, d, i)
|
||||
}), d.depending = !1, d.depCount === d.depMax && defineModule(d)) : name && resolve(name, d, factory), startTime = (new Date).getTime(), name || check(d), d.promise
|
||||
}, req = makeRequire(null, !0), req.config = function(cfg) {
|
||||
if (cfg.context && cfg.context !== contextName) {
|
||||
var existingContext = getOwn(contexts, cfg.context);
|
||||
return existingContext ? existingContext.req.config(cfg) : newContext(cfg.context).config(cfg)
|
||||
}
|
||||
if (mapCache = obj(), cfg.baseUrl && "/" !== cfg.baseUrl.charAt(cfg.baseUrl.length - 1) && (cfg.baseUrl += "/"), "string" == typeof cfg.urlArgs) {
|
||||
var urlArgs = cfg.urlArgs;
|
||||
cfg.urlArgs = function(id, url) {
|
||||
return (-1 === url.indexOf("?") ? "?" : "&") + urlArgs
|
||||
}
|
||||
}
|
||||
var shim = config.shim,
|
||||
objs = {
|
||||
paths: !0,
|
||||
bundles: !0,
|
||||
config: !0,
|
||||
map: !0
|
||||
};
|
||||
return eachProp(cfg, function(value, prop) {
|
||||
objs[prop] ? (config[prop] || (config[prop] = {}), mixin(config[prop], value, !0, !0)) : config[prop] = value
|
||||
}), cfg.bundles && eachProp(cfg.bundles, function(value, prop) {
|
||||
value.forEach(function(v) {
|
||||
v !== prop && (bundlesMap[v] = prop)
|
||||
})
|
||||
}), cfg.shim && (eachProp(cfg.shim, function(value, id) {
|
||||
Array.isArray(value) && (value = {
|
||||
deps: value
|
||||
}), !value.exports && !value.init || value.exportsFn || (value.exportsFn = makeShimExports(value)), shim[id] = value
|
||||
}), config.shim = shim), cfg.packages && cfg.packages.forEach(function(pkgObj) {
|
||||
var location, name;
|
||||
pkgObj = "string" == typeof pkgObj ? {
|
||||
name: pkgObj
|
||||
} : pkgObj, name = pkgObj.name, location = pkgObj.location, location && (config.paths[name] = pkgObj.location), config.pkgs[name] = pkgObj.name + "/" + (pkgObj.main || "main").replace(currDirRegExp, "").replace(jsSuffixRegExp, "")
|
||||
}), (cfg.deps || cfg.callback) && req(cfg.deps, cfg.callback), req
|
||||
}, req.onError = function(err) {
|
||||
throw err
|
||||
}, context = {
|
||||
id: contextName,
|
||||
defined: defined,
|
||||
waiting: waiting,
|
||||
config: config,
|
||||
deferreds: deferreds,
|
||||
req: req,
|
||||
execCb: function(name, callback, args, exports) {
|
||||
return callback.apply(exports, args)
|
||||
}
|
||||
}, contexts[contextName] = context, req
|
||||
}
|
||||
if (!Promise) throw new Error("No Promise implementation available");
|
||||
var topReq, dataMain, src, subPath, bootstrapConfig = requirejs || require,
|
||||
hasOwn = Object.prototype.hasOwnProperty,
|
||||
contexts = {},
|
||||
queue = [],
|
||||
currDirRegExp = /^\.\//,
|
||||
urlRegExp = /^\/|\:|\?|\.js$/,
|
||||
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,
|
||||
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
|
||||
jsSuffixRegExp = /\.js$/,
|
||||
slice = Array.prototype.slice;
|
||||
if ("function" != typeof requirejs) {
|
||||
var asap = Promise.resolve(void 0);
|
||||
requirejs = topReq = newContext("_"), "function" != typeof require && (require = topReq), topReq.exec = function(text) {
|
||||
return eval(text)
|
||||
}, topReq.contexts = contexts, define = function() {
|
||||
queue.push(slice.call(arguments, 0))
|
||||
}, define.amd = {
|
||||
jQuery: !0
|
||||
}, bootstrapConfig && topReq.config(bootstrapConfig), topReq.isBrowser && !contexts._.config.skipDataMain && (dataMain = document.querySelectorAll("script[data-main]")[0], (dataMain = dataMain && dataMain.getAttribute("data-main")) && (dataMain = dataMain.replace(jsSuffixRegExp, ""), bootstrapConfig && bootstrapConfig.baseUrl || -1 !== dataMain.indexOf("!") || (src = dataMain.split("/"), dataMain = src.pop(), subPath = src.length ? src.join("/") + "/" : "./", topReq.config({
|
||||
baseUrl: subPath
|
||||
})), topReq([dataMain])))
|
||||
}
|
||||
}(this, "undefined" != typeof Promise ? Promise : void 0);
|
||||
236
src/bower_components/apiclient/apiclient.js
vendored
Normal file
236
src/bower_components/apiclient/apiclient.js
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
//TODO: (vitorsemeano) modify this lines for webpack
|
||||
define(["bower_components/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
|
||||
});
|
||||
1548
src/bower_components/apiclient/apiclientcore.js
vendored
Normal file
1548
src/bower_components/apiclient/apiclientcore.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
53
src/bower_components/apiclient/appStorage.js
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
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;
|
||||
});
|
||||
747
src/bower_components/apiclient/connectionmanager.js
vendored
Normal file
747
src/bower_components/apiclient/connectionmanager.js
vendored
Normal file
@@ -0,0 +1,747 @@
|
||||
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];
|
||||
null !== value && void 0 !== value && "" !== value && values.push(encodeURIComponent(key) + "=" + encodeURIComponent(value))
|
||||
}
|
||||
return values.join("&")
|
||||
}
|
||||
|
||||
function resolveFailure(instance, resolve) {
|
||||
resolve({
|
||||
State: "Unavailable",
|
||||
ConnectUser: instance.connectUser()
|
||||
})
|
||||
}
|
||||
|
||||
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, systemInfo.Id && (server.Id = systemInfo.Id), systemInfo.LocalAddress && (server.LocalAddress = systemInfo.LocalAddress)
|
||||
}
|
||||
|
||||
function getEmbyServerUrl(baseUrl, handler) {
|
||||
return baseUrl + "/" + handler
|
||||
}
|
||||
|
||||
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 fetchWithTimeout(url, options, timeoutMs) {
|
||||
return console.log("fetchWithTimeout: timeoutMs: " + timeoutMs + ", url: " + url), 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");
|
||||
return request.headers = request.headers || {}, console.log("ConnectionManager requesting url: " + request.url), getFetchPromise(request).then(function(response) {
|
||||
return console.log("ConnectionManager response status: " + response.status + ", url: " + request.url), response.status < 400 ? "json" === request.dataType || "application/json" === request.headers.accept ? response.json() : response : Promise.reject(response)
|
||||
}, function(err) {
|
||||
throw console.log("ConnectionManager request failed to url: " + request.url), err
|
||||
})
|
||||
}
|
||||
|
||||
function getConnectUrl(handler) {
|
||||
return "https://connect.emby.media/service/" + handler
|
||||
}
|
||||
|
||||
function replaceAll(originalString, strReplace, strWith) {
|
||||
var reg = new RegExp(strReplace, "ig");
|
||||
return originalString.replace(reg, strWith)
|
||||
}
|
||||
|
||||
function normalizeAddress(address) {
|
||||
return address = address.trim(), 0 !== address.toLowerCase().indexOf("http") && (address = "http://" + address), address = replaceAll(address, "Http:", "http:"), address = replaceAll(address, "Https:", "https:")
|
||||
}
|
||||
|
||||
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"),
|
||||
bVal = parseInt(b[i] || "0");
|
||||
if (aVal < bVal) return -1;
|
||||
if (aVal > bVal) return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
var defaultTimeout = 2e4,
|
||||
ConnectionMode = {
|
||||
Local: 0,
|
||||
Remote: 1,
|
||||
Manual: 2
|
||||
},
|
||||
ConnectionManager = function(credentialProvider, appName, appVersion, deviceName, deviceId, capabilities, devicePixelRatio) {
|
||||
function onConnectUserSignIn(user) {
|
||||
connectUser = user, events.trigger(self, "connectusersignedin", [user])
|
||||
}
|
||||
|
||||
function onAuthenticated(apiClient, result, options, saveCredentials) {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
servers = credentials.Servers.filter(function(s) {
|
||||
return s.Id === result.ServerId
|
||||
}),
|
||||
server = servers.length ? servers[0] : apiClient.serverInfo();
|
||||
return !1 !== options.updateDateLastAccessed && (server.DateLastAccessed = (new Date).getTime()), server.Id = result.ServerId, saveCredentials ? (server.UserId = result.User.Id, server.AccessToken = result.AccessToken) : (server.UserId = null, server.AccessToken = null), credentialProvider.addOrUpdateServer(credentials.Servers, server), credentialProvider.credentials(credentials), apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection, apiClient.serverInfo(server), afterConnected(apiClient, options), onLocalUserSignIn(server, apiClient.serverAddress(), result.User)
|
||||
}
|
||||
|
||||
function afterConnected(apiClient, options) {
|
||||
options = options || {}, !1 !== options.reportCapabilities && apiClient.reportCapabilities(capabilities), apiClient.enableAutomaticBitrateDetection = options.enableAutomaticBitrateDetection, !1 !== options.enableWebSocket && (console.log("calling apiClient.ensureWebSocket"), apiClient.ensureWebSocket())
|
||||
}
|
||||
|
||||
function onLocalUserSignIn(server, serverUrl, user) {
|
||||
return self._getOrAddApiClient(server, serverUrl), (self.onLocalUserSignedIn ? self.onLocalUserSignedIn.call(self, user) : Promise.resolve()).then(function() {
|
||||
events.trigger(self, "localusersignedin", [user])
|
||||
})
|
||||
}
|
||||
|
||||
function ensureConnectUser(credentials) {
|
||||
return connectUser && connectUser.Id === credentials.ConnectUserId ? Promise.resolve() : credentials.ConnectUserId && credentials.ConnectAccessToken ? (connectUser = null, getConnectUser(credentials.ConnectUserId, credentials.ConnectAccessToken).then(function(user) {
|
||||
return onConnectUserSignIn(user), Promise.resolve()
|
||||
}, function() {
|
||||
return Promise.resolve()
|
||||
})) : Promise.resolve()
|
||||
}
|
||||
|
||||
function getConnectUser(userId, accessToken) {
|
||||
if (!userId) throw new Error("null userId");
|
||||
if (!accessToken) throw new Error("null accessToken");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/user?id=" + userId,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": accessToken
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function addAuthenticationInfoFromConnect(server, serverUrl, credentials) {
|
||||
if (!server.ExchangeToken) throw new Error("server.ExchangeToken cannot be null");
|
||||
if (!credentials.ConnectUserId) throw new Error("credentials.ConnectUserId cannot be null");
|
||||
var url = getEmbyServerUrl(serverUrl, "Connect/Exchange?format=json&ConnectUserId=" + credentials.ConnectUserId),
|
||||
auth = 'MediaBrowser Client="' + appName + '", Device="' + deviceName + '", DeviceId="' + deviceId + '", Version="' + appVersion + '"';
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: url,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-MediaBrowser-Token": server.ExchangeToken,
|
||||
"X-Emby-Authorization": auth
|
||||
}
|
||||
}).then(function(auth) {
|
||||
return server.UserId = auth.LocalUserId, server.AccessToken = auth.AccessToken, auth
|
||||
}, function() {
|
||||
return server.UserId = null, server.AccessToken = null, Promise.reject()
|
||||
})
|
||||
}
|
||||
|
||||
function validateAuthentication(server, serverUrl) {
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: getEmbyServerUrl(serverUrl, "System/Info"),
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-MediaBrowser-Token": server.AccessToken
|
||||
}
|
||||
}).then(function(systemInfo) {
|
||||
return updateServerInfo(server, systemInfo), Promise.resolve()
|
||||
}, function() {
|
||||
return server.UserId = null, server.AccessToken = null, Promise.resolve()
|
||||
})
|
||||
}
|
||||
|
||||
function getImageUrl(localUser) {
|
||||
if (connectUser && connectUser.ImageUrl) return {
|
||||
url: connectUser.ImageUrl
|
||||
};
|
||||
if (localUser && localUser.PrimaryImageTag) {
|
||||
return {
|
||||
url: self.getApiClient(localUser).getUserImageUrl(localUser.Id, {
|
||||
tag: localUser.PrimaryImageTag,
|
||||
type: "Primary"
|
||||
}),
|
||||
supportsParams: !0
|
||||
}
|
||||
}
|
||||
return {
|
||||
url: null,
|
||||
supportsParams: !1
|
||||
}
|
||||
}
|
||||
|
||||
function logoutOfServer(apiClient) {
|
||||
var serverInfo = apiClient.serverInfo() || {},
|
||||
logoutInfo = {
|
||||
serverId: serverInfo.Id
|
||||
};
|
||||
return apiClient.logout().then(function() {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo])
|
||||
}, function() {
|
||||
events.trigger(self, "localusersignedout", [logoutInfo])
|
||||
})
|
||||
}
|
||||
|
||||
function getConnectServers(credentials) {
|
||||
return console.log("Begin getConnectServers"), credentials.ConnectAccessToken && credentials.ConnectUserId ? ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/servers?userId=" + credentials.ConnectUserId,
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-Connect-UserToken": credentials.ConnectAccessToken
|
||||
}
|
||||
}).then(function(servers) {
|
||||
return servers.map(function(i) {
|
||||
return {
|
||||
ExchangeToken: i.AccessKey,
|
||||
ConnectServerId: i.Id,
|
||||
Id: i.SystemId,
|
||||
Name: i.Name,
|
||||
RemoteAddress: i.Url,
|
||||
LocalAddress: i.LocalAddress,
|
||||
UserLinkType: "guest" === (i.UserType || "").toLowerCase() ? "Guest" : "LinkedUser"
|
||||
}
|
||||
})
|
||||
}, function() {
|
||||
return credentials.Servers.slice(0).filter(function(s) {
|
||||
return s.ExchangeToken
|
||||
})
|
||||
}) : Promise.resolve([])
|
||||
}
|
||||
|
||||
function filterServers(servers, connectServers) {
|
||||
return servers.filter(function(server) {
|
||||
return !server.ExchangeToken || connectServers.filter(function(connectServer) {
|
||||
return server.Id === connectServer.Id
|
||||
}).length > 0
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
};
|
||||
return info.LastConnectionMode = info.ManualAddress ? ConnectionMode.Manual : ConnectionMode.Local, 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],
|
||||
parts = info.Address.split(":");
|
||||
if (parts.length > 1) {
|
||||
var portString = parts[parts.length - 1];
|
||||
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) {
|
||||
state.resolved || (state.resolved = !0, console.log("Reconnect succeeded to " + url), resolve({
|
||||
url: url,
|
||||
connectionMode: connectionMode,
|
||||
data: result
|
||||
}))
|
||||
}, function() {
|
||||
state.resolved || (console.log("Reconnect failed to " + url), ++state.rejects >= state.numAddresses && reject())
|
||||
})
|
||||
}
|
||||
|
||||
function tryReconnect(serverInfo) {
|
||||
var addresses = [],
|
||||
addressesStrings = [];
|
||||
return !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)), serverInfo.ManualAddress && -1 === addressesStrings.indexOf(serverInfo.ManualAddress) && (addresses.push({
|
||||
url: serverInfo.ManualAddress,
|
||||
mode: ConnectionMode.Manual,
|
||||
timeout: 100
|
||||
}), addressesStrings.push(addresses[addresses.length - 1].url)), !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("|")), new Promise(function(resolve, reject) {
|
||||
var state = {};
|
||||
state.numAddresses = addresses.length, state.rejects = 0, addresses.map(function(url) {
|
||||
setTimeout(function() {
|
||||
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 || {}, credentials.ConnectAccessToken && !1 !== options.enableAutoLogin ? ensureConnectUser(credentials).then(function() {
|
||||
server.ExchangeToken ? addAuthenticationInfoFromConnect(server, serverUrl, credentials).then(function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}, function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}) : afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}) : afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !0, options, resolve)
|
||||
}
|
||||
|
||||
function afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, verifyLocalAuthentication, options, resolve) {
|
||||
if (options = options || {}, !1 === options.enableAutoLogin) server.UserId = null, server.AccessToken = null;
|
||||
else if (verifyLocalAuthentication && server.AccessToken && !1 !== options.enableAutoLogin) return void validateAuthentication(server, serverUrl).then(function() {
|
||||
afterConnectValidated(server, credentials, systemInfo, connectionMode, serverUrl, !1, options, resolve)
|
||||
});
|
||||
updateServerInfo(server, systemInfo), server.LastConnectionMode = connectionMode, !1 !== 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 && !1 !== 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])
|
||||
};
|
||||
"SignedIn" === result.State ? (afterConnected(result.ApiClient, options), result.ApiClient.getCurrentUser().then(function(user) {
|
||||
onLocalUserSignIn(server, serverUrl, user).then(resolveActions, resolveActions)
|
||||
}, resolveActions)) : resolveActions()
|
||||
}
|
||||
|
||||
function getCacheKey(feature, apiClient, options) {
|
||||
options = options || {};
|
||||
var viewOnly = options.viewOnly,
|
||||
cacheKey = "regInfo-" + apiClient.serverId();
|
||||
return viewOnly && (cacheKey += "-viewonly"), cacheKey
|
||||
}
|
||||
|
||||
function addAppInfoToConnectRequest(request) {
|
||||
request.headers = request.headers || {}, request.headers["X-Application"] = appName + "/" + appVersion
|
||||
}
|
||||
|
||||
function exchangePin(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
var request = {
|
||||
type: "POST",
|
||||
url: getConnectUrl("pin/authenticate"),
|
||||
data: {
|
||||
deviceId: pinInfo.DeviceId,
|
||||
pin: pinInfo.Pin
|
||||
},
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}
|
||||
console.log("Begin ConnectionManager constructor");
|
||||
var self = this;
|
||||
this._apiClients = [];
|
||||
var connectUser;
|
||||
self.connectUser = function() {
|
||||
return connectUser
|
||||
}, 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.connectUserId = function() {
|
||||
return credentialProvider.credentials().ConnectUserId
|
||||
}, self.connectToken = function() {
|
||||
return credentialProvider.credentials().ConnectAccessToken
|
||||
}, self.getServerInfo = function(id) {
|
||||
return credentialProvider.credentials().Servers.filter(function(s) {
|
||||
return s.Id === id
|
||||
})[0]
|
||||
}, self.getLastUsedServer = function() {
|
||||
var servers = credentialProvider.credentials().Servers;
|
||||
return servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), servers.length ? servers[0] : 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())
|
||||
}),
|
||||
existingServer = existingServers.length ? existingServers[0] : apiClient.serverInfo();
|
||||
if (existingServer.DateLastAccessed = (new Date).getTime(), existingServer.LastConnectionMode = ConnectionMode.Manual, existingServer.ManualAddress = apiClient.serverAddress(), apiClient.manualAddressOnly && (existingServer.manualAddressOnly = !0), apiClient.serverInfo(existingServer), apiClient.onAuthenticated = function(instance, result) {
|
||||
return onAuthenticated(instance, result, {}, !0)
|
||||
}, !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"), connectUser = null;
|
||||
var credentials = credentialProvider.credentials();
|
||||
credentials.ConnectAccessToken = null, credentials.ConnectUserId = null, credentials.Servers = [], credentialProvider.credentials(credentials)
|
||||
}, self._getOrAddApiClient = function(server, serverUrl) {
|
||||
var apiClient = self.getApiClient(server.Id);
|
||||
return 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, {}, !0)
|
||||
}, events.trigger(self, "apiclientcreated", [apiClient])), console.log("returning instance from getOrAddApiClient"), apiClient
|
||||
}, self.getOrCreateApiClient = function(serverId) {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
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) {
|
||||
var image = getImageUrl(localUser);
|
||||
resolve({
|
||||
localUser: localUser,
|
||||
name: connectUser ? connectUser.Name : localUser ? localUser.Name : null,
|
||||
imageUrl: image.url,
|
||||
supportsImageParams: image.supportsParams,
|
||||
connectUser: connectUser
|
||||
})
|
||||
}
|
||||
|
||||
function onEnsureConnectUserDone() {
|
||||
apiClient && apiClient.getCurrentUserId() ? apiClient.getCurrentUser().then(function(u) {
|
||||
localUser = u, onLocalUserDone()
|
||||
}, onLocalUserDone) : onLocalUserDone()
|
||||
}
|
||||
var localUser, credentials = credentialProvider.credentials();
|
||||
!credentials.ConnectUserId || !credentials.ConnectAccessToken || apiClient && apiClient.getCurrentUserId() ? onEnsureConnectUserDone() : ensureConnectUser(credentials).then(onEnsureConnectUserDone, onEnsureConnectUserDone)
|
||||
})
|
||||
}, self.logout = function() {
|
||||
console.log("begin connectionManager loguot");
|
||||
for (var promises = [], i = 0, length = self._apiClients.length; i < length; i++) {
|
||||
var apiClient = self._apiClients[i];
|
||||
apiClient.accessToken() && promises.push(logoutOfServer(apiClient))
|
||||
}
|
||||
return Promise.all(promises).then(function() {
|
||||
for (var credentials = credentialProvider.credentials(), servers = credentials.Servers.filter(function(u) {
|
||||
return "Guest" !== u.UserLinkType
|
||||
}), j = 0, numServers = servers.length; j < numServers; j++) {
|
||||
var server = servers[j];
|
||||
server.UserId = null, server.AccessToken = null, server.ExchangeToken = null
|
||||
}
|
||||
credentials.Servers = servers, credentials.ConnectAccessToken = null, credentials.ConnectUserId = null, credentialProvider.credentials(credentials), connectUser && (connectUser = null, events.trigger(self, "connectusersignedout"))
|
||||
})
|
||||
}, self.getSavedServers = function() {
|
||||
var credentials = credentialProvider.credentials(),
|
||||
servers = credentials.Servers.slice(0);
|
||||
return servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), servers
|
||||
}, self.getAvailableServers = function() {
|
||||
console.log("Begin getAvailableServers");
|
||||
var credentials = credentialProvider.credentials();
|
||||
return Promise.all([getConnectServers(credentials), findServers()]).then(function(responses) {
|
||||
var connectServers = responses[0],
|
||||
foundServers = responses[1],
|
||||
servers = credentials.Servers.slice(0);
|
||||
return mergeServers(credentialProvider, servers, foundServers), mergeServers(credentialProvider, servers, connectServers), servers = filterServers(servers, connectServers), servers.sort(function(a, b) {
|
||||
return (b.DateLastAccessed || 0) - (a.DateLastAccessed || 0)
|
||||
}), credentials.Servers = servers, credentialProvider.credentials(credentials), servers
|
||||
})
|
||||
}, self.connectToServers = function(servers, options) {
|
||||
console.log("Begin connectToServers, with " + servers.length + " servers");
|
||||
var firstServer = servers.length ? servers[0] : null;
|
||||
return firstServer ? self.connectToServer(firstServer, options).then(function(result) {
|
||||
return "Unavailable" === result.State && (result.State = "ServerSelection"), console.log("resolving connectToServers with result.State: " + result.State), result
|
||||
}) : Promise.resolve({
|
||||
Servers: servers,
|
||||
State: servers.length || self.connectUser() ? "ServerSelection" : "ConnectSignIn",
|
||||
ConnectUser: self.connectUser()
|
||||
})
|
||||
}, self.connectToServer = function(server, options) {
|
||||
return console.log("begin connectToServer"), new Promise(function(resolve, reject) {
|
||||
options = options || {}, tryReconnect(server).then(function(result) {
|
||||
var serverUrl = result.url,
|
||||
connectionMode = result.connectionMode;
|
||||
result = result.data, 1 === compareVersions(self.minServerVersion(), result.Version) ? (console.log("minServerVersion requirement not met. Server version: " + result.Version), resolve({
|
||||
State: "ServerUpdateNeeded",
|
||||
Servers: [server]
|
||||
})) : server.Id && result.Id !== server.Id ? (console.log("http request succeeded, but found a different server Id than what was expected"), resolveFailure(self, resolve)) : onSuccessfulConnection(server, result, connectionMode, serverUrl, options, resolve)
|
||||
}, function() {
|
||||
resolveFailure(self, resolve)
|
||||
})
|
||||
})
|
||||
}, self.connectToAddress = function(address, options) {
|
||||
function onFail() {
|
||||
return console.log("connectToAddress " + address + " failed"), Promise.resolve({
|
||||
State: "Unavailable",
|
||||
ConnectUser: instance.connectUser()
|
||||
})
|
||||
}
|
||||
if (!address) return Promise.reject();
|
||||
address = normalizeAddress(address);
|
||||
var instance = this,
|
||||
server = {
|
||||
ManualAddress: address,
|
||||
LastConnectionMode: ConnectionMode.Manual
|
||||
};
|
||||
return self.connectToServer(server, options).catch(onFail)
|
||||
}, self.loginToConnect = function(username, password) {
|
||||
return username && password ? ajax({
|
||||
type: "POST",
|
||||
url: "https://connect.emby.media/service/user/authenticate",
|
||||
data: {
|
||||
nameOrEmail: username,
|
||||
rawpw: password
|
||||
},
|
||||
dataType: "json",
|
||||
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
}).then(function(result) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
return credentials.ConnectAccessToken = result.AccessToken, credentials.ConnectUserId = result.User.Id, credentialProvider.credentials(credentials), onConnectUserSignIn(result.User), result
|
||||
}) : Promise.reject()
|
||||
}, self.signupForConnect = function(options) {
|
||||
var email = options.email,
|
||||
username = options.username,
|
||||
password = options.password,
|
||||
passwordConfirm = options.passwordConfirm;
|
||||
if (!email) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!username) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!password) return Promise.reject({
|
||||
errorCode: "invalidinput"
|
||||
});
|
||||
if (!passwordConfirm) return Promise.reject({
|
||||
errorCode: "passwordmatch"
|
||||
});
|
||||
if (password !== passwordConfirm) return Promise.reject({
|
||||
errorCode: "passwordmatch"
|
||||
});
|
||||
var data = {
|
||||
email: email,
|
||||
userName: username,
|
||||
rawpw: password
|
||||
};
|
||||
return options.grecaptcha && (data.grecaptcha = options.grecaptcha), ajax({
|
||||
type: "POST",
|
||||
url: "https://connect.emby.media/service/register",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
|
||||
headers: {
|
||||
"X-Application": appName + "/" + appVersion,
|
||||
"X-CONNECT-TOKEN": "CONNECT-REGISTER"
|
||||
}
|
||||
}).catch(function(response) {
|
||||
try {
|
||||
return response.json()
|
||||
} catch (err) {
|
||||
throw err
|
||||
}
|
||||
}).then(function(result) {
|
||||
if (result && result.Status) return "SUCCESS" === result.Status ? Promise.resolve(result) : Promise.reject({
|
||||
errorCode: result.Status
|
||||
});
|
||||
Promise.reject()
|
||||
})
|
||||
}, self.getUserInvitations = function() {
|
||||
var connectToken = self.connectToken();
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/servers?userId=" + self.connectUserId() + "&status=Waiting",
|
||||
dataType: "json",
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.deleteServer = function(serverId) {
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
var server = credentialProvider.credentials().Servers.filter(function(s) {
|
||||
return s.Id === serverId
|
||||
});
|
||||
return server = server.length ? server[0] : null, 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();
|
||||
var connectToken = self.connectToken(),
|
||||
connectUserId = self.connectUserId();
|
||||
if (!connectToken || !connectUserId) return void onDone();
|
||||
ajax({
|
||||
type: "DELETE",
|
||||
url: "https://connect.emby.media/service/serverAuthorizations?serverId=" + server.ConnectServerId + "&userId=" + connectUserId,
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
}).then(onDone, onDone)
|
||||
})
|
||||
}, self.rejectServer = function(serverId) {
|
||||
var connectToken = self.connectToken();
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
var url = "https://connect.emby.media/service/serverAuthorizations?serverId=" + serverId + "&userId=" + self.connectUserId();
|
||||
return fetch(url, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.acceptServer = function(serverId) {
|
||||
var connectToken = self.connectToken();
|
||||
if (!serverId) throw new Error("null serverId");
|
||||
if (!connectToken) throw new Error("null connectToken");
|
||||
if (!self.connectUserId()) throw new Error("null connectUserId");
|
||||
return ajax({
|
||||
type: "GET",
|
||||
url: "https://connect.emby.media/service/ServerAuthorizations/accept?serverId=" + serverId + "&userId=" + self.connectUserId(),
|
||||
headers: {
|
||||
"X-Connect-UserToken": connectToken,
|
||||
"X-Application": appName + "/" + appVersion
|
||||
}
|
||||
})
|
||||
}, self.resetRegistrationInfo = function(apiClient) {
|
||||
var cacheKey = getCacheKey("themes", apiClient, {
|
||||
viewOnly: !0
|
||||
});
|
||||
appStorage.removeItem(cacheKey), cacheKey = getCacheKey("themes", apiClient, {
|
||||
viewOnly: !1
|
||||
}), appStorage.removeItem(cacheKey)
|
||||
}, self.getRegistrationInfo = function(feature, apiClient, options) {
|
||||
var cacheKey = getCacheKey(feature, apiClient, options);
|
||||
appStorage.setItem(cacheKey, JSON.stringify({
|
||||
lastValidDate: new Date().getTime(),
|
||||
deviceId: self.deviceId()
|
||||
}));
|
||||
return Promise.resolve();
|
||||
}, self.createPin = function() {
|
||||
var request = {
|
||||
type: "POST",
|
||||
url: getConnectUrl("pin"),
|
||||
data: {
|
||||
deviceId: deviceId
|
||||
},
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}, self.getPinStatus = function(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
var queryString = {
|
||||
deviceId: pinInfo.DeviceId,
|
||||
pin: pinInfo.Pin
|
||||
},
|
||||
request = {
|
||||
type: "GET",
|
||||
url: getConnectUrl("pin") + "?" + paramsToString(queryString),
|
||||
dataType: "json"
|
||||
};
|
||||
return addAppInfoToConnectRequest(request), ajax(request)
|
||||
}, self.exchangePin = function(pinInfo) {
|
||||
if (!pinInfo) throw new Error("pinInfo cannot be null");
|
||||
return exchangePin(pinInfo).then(function(result) {
|
||||
var credentials = credentialProvider.credentials();
|
||||
return credentials.ConnectAccessToken = result.AccessToken, credentials.ConnectUserId = result.UserId, credentialProvider.credentials(credentials), ensureConnectUser(credentials)
|
||||
})
|
||||
}
|
||||
};
|
||||
return 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.isLoggedIntoConnect = function() {
|
||||
return !(!this.connectToken() || !this.connectUserId())
|
||||
}, ConnectionManager.prototype.getApiClients = function() {
|
||||
for (var servers = this.getSavedServers(), i = 0, length = servers.length; i < length; i++) {
|
||||
var server = servers[i];
|
||||
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");
|
||||
return item.ServerId && (item = item.ServerId), this._apiClients.filter(function(a) {
|
||||
var serverInfo = a.serverInfo();
|
||||
return !serverInfo || serverInfo.Id === item
|
||||
})[0]
|
||||
}, ConnectionManager.prototype.minServerVersion = function(val) {
|
||||
return val && (this._minServerVersion = val), 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)
|
||||
}
|
||||
}
|
||||
}, ConnectionManager
|
||||
});
|
||||
29
src/bower_components/apiclient/credentialprovider.js
vendored
Normal file
29
src/bower_components/apiclient/credentialprovider.js
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
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
|
||||
});
|
||||
30
src/bower_components/apiclient/events.js
vendored
Normal file
30
src/bower_components/apiclient/events.js
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
406
src/bower_components/apiclient/localassetmanager.js
vendored
Normal file
406
src/bower_components/apiclient/localassetmanager.js
vendored
Normal file
@@ -0,0 +1,406 @@
|
||||
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
|
||||
}
|
||||
});
|
||||
3
src/bower_components/apiclient/package.json
vendored
Normal file
3
src/bower_components/apiclient/package.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "apiclient.js"
|
||||
}
|
||||
45
src/bower_components/apiclient/sync/filerepository.js
vendored
Normal file
45
src/bower_components/apiclient/sync/filerepository.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
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
|
||||
}
|
||||
});
|
||||
123
src/bower_components/apiclient/sync/itemrepository.js
vendored
Normal file
123
src/bower_components/apiclient/sync/itemrepository.js
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
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
|
||||
}
|
||||
});
|
||||
17
src/bower_components/apiclient/sync/localsync.js
vendored
Normal file
17
src/bower_components/apiclient/sync/localsync.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
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)
|
||||
})
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
});
|
||||
368
src/bower_components/apiclient/sync/mediasync.js
vendored
Normal file
368
src/bower_components/apiclient/sync/mediasync.js
vendored
Normal file
@@ -0,0 +1,368 @@
|
||||
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())
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
22
src/bower_components/apiclient/sync/multiserversync.js
vendored
Normal file
22
src/bower_components/apiclient/sync/multiserversync.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
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
|
||||
});
|
||||
42
src/bower_components/apiclient/sync/serversync.js
vendored
Normal file
42
src/bower_components/apiclient/sync/serversync.js
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
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
|
||||
});
|
||||
30
src/bower_components/apiclient/sync/transfermanager.js
vendored
Normal file
30
src/bower_components/apiclient/sync/transfermanager.js
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
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
|
||||
}
|
||||
});
|
||||
108
src/bower_components/apiclient/sync/useractionrepository.js
vendored
Normal file
108
src/bower_components/apiclient/sync/useractionrepository.js
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
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
|
||||
}
|
||||
});
|
||||
12
src/bower_components/document-register-element/basic.html
vendored
Normal file
12
src/bower_components/document-register-element/basic.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>testing my-element</title>
|
||||
<script src="build/document-register-element.js"></script>
|
||||
<script src="test/my-element.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<my-element>
|
||||
some content
|
||||
</my-element>
|
||||
</body>
|
||||
246
src/bower_components/document-register-element/build/document-register-element.js
vendored
Normal file
246
src/bower_components/document-register-element/build/document-register-element.js
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
/*! (C) WebReflection Mit Style License */
|
||||
(function(e, t, n, r) {
|
||||
"use strict";
|
||||
|
||||
function rt(e, t) {
|
||||
for (var n = 0, r = e.length; n < r; n++) vt(e[n], t)
|
||||
}
|
||||
|
||||
function it(e) {
|
||||
for (var t = 0, n = e.length, r; t < n; t++) r = e[t], nt(r, b[ot(r)])
|
||||
}
|
||||
|
||||
function st(e) {
|
||||
return function(t) {
|
||||
j(t) && (vt(t, e), rt(t.querySelectorAll(w), e))
|
||||
}
|
||||
}
|
||||
|
||||
function ot(e) {
|
||||
var t = e.getAttribute("is"),
|
||||
n = e.nodeName.toUpperCase(),
|
||||
r = S.call(y, t ? v + t.toUpperCase() : d + n);
|
||||
return t && -1 < r && !ut(n, t) ? -1 : r
|
||||
}
|
||||
|
||||
function ut(e, t) {
|
||||
return -1 < w.indexOf(e + '[is="' + t + '"]')
|
||||
}
|
||||
|
||||
function at(e) {
|
||||
var t = e.currentTarget,
|
||||
n = e.attrChange,
|
||||
r = e.attrName,
|
||||
i = e.target;
|
||||
Q && (!i || i === t) && t.attributeChangedCallback && r !== "style" && e.prevValue !== e.newValue && t.attributeChangedCallback(r, n === e[a] ? null : e.prevValue, n === e[l] ? null : e.newValue)
|
||||
}
|
||||
|
||||
function ft(e) {
|
||||
var t = st(e);
|
||||
return function(e) {
|
||||
X.push(t, e.target)
|
||||
}
|
||||
}
|
||||
|
||||
function lt(e) {
|
||||
K && (K = !1, e.currentTarget.removeEventListener(h, lt)), rt((e.target || t).querySelectorAll(w), e.detail === o ? o : s), B && pt()
|
||||
}
|
||||
|
||||
function ct(e, t) {
|
||||
var n = this;
|
||||
q.call(n, e, t), G.call(n, {
|
||||
target: n
|
||||
})
|
||||
}
|
||||
|
||||
function ht(e, t) {
|
||||
D(e, t), et ? et.observe(e, z) : (J && (e.setAttribute = ct, e[i] = Z(e), e.addEventListener(p, G)), e.addEventListener(c, at)), e.createdCallback && Q && (e.created = !0, e.createdCallback(), e.created = !1)
|
||||
}
|
||||
|
||||
function pt() {
|
||||
for (var e, t = 0, n = F.length; t < n; t++) e = F[t], E.contains(e) || (n--, F.splice(t--, 1), vt(e, o))
|
||||
}
|
||||
|
||||
function dt(e) {
|
||||
throw new Error("A " + e + " type is already registered")
|
||||
}
|
||||
|
||||
function vt(e, t) {
|
||||
var n, r = ot(e); - 1 < r && (tt(e, b[r]), r = 0, t === s && !e[s] ? (e[o] = !1, e[s] = !0, r = 1, B && S.call(F, e) < 0 && F.push(e)) : t === o && !e[o] && (e[s] = !1, e[o] = !0, r = 1), r && (n = e[t + "Callback"]) && n.call(e))
|
||||
}
|
||||
if (r in t) return;
|
||||
var i = "__" + r + (Math.random() * 1e5 >> 0),
|
||||
s = "attached",
|
||||
o = "detached",
|
||||
u = "extends",
|
||||
a = "ADDITION",
|
||||
f = "MODIFICATION",
|
||||
l = "REMOVAL",
|
||||
c = "DOMAttrModified",
|
||||
h = "DOMContentLoaded",
|
||||
p = "DOMSubtreeModified",
|
||||
d = "<",
|
||||
v = "=",
|
||||
m = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,
|
||||
g = ["ANNOTATION-XML", "COLOR-PROFILE", "FONT-FACE", "FONT-FACE-SRC", "FONT-FACE-URI", "FONT-FACE-FORMAT", "FONT-FACE-NAME", "MISSING-GLYPH"],
|
||||
y = [],
|
||||
b = [],
|
||||
w = "",
|
||||
E = t.documentElement,
|
||||
S = y.indexOf || function(e) {
|
||||
for (var t = this.length; t-- && this[t] !== e;);
|
||||
return t
|
||||
},
|
||||
x = n.prototype,
|
||||
T = x.hasOwnProperty,
|
||||
N = x.isPrototypeOf,
|
||||
C = n.defineProperty,
|
||||
k = n.getOwnPropertyDescriptor,
|
||||
L = n.getOwnPropertyNames,
|
||||
A = n.getPrototypeOf,
|
||||
O = n.setPrototypeOf,
|
||||
M = !!n.__proto__,
|
||||
_ = n.create || function mt(e) {
|
||||
return e ? (mt.prototype = e, new mt) : this
|
||||
},
|
||||
D = O || (M ? function(e, t) {
|
||||
return e.__proto__ = t, e
|
||||
} : L && k ? function() {
|
||||
function e(e, t) {
|
||||
for (var n, r = L(t), i = 0, s = r.length; i < s; i++) n = r[i], T.call(e, n) || C(e, n, k(t, n))
|
||||
}
|
||||
return function(t, n) {
|
||||
do e(t, n); while ((n = A(n)) && !N.call(n, t));
|
||||
return t
|
||||
}
|
||||
}() : function(e, t) {
|
||||
for (var n in t) e[n] = t[n];
|
||||
return e
|
||||
}),
|
||||
P = e.MutationObserver || e.WebKitMutationObserver,
|
||||
H = (e.HTMLElement || e.Element || e.Node).prototype,
|
||||
B = !N.call(H, E),
|
||||
j = B ? function(e) {
|
||||
return e.nodeType === 1
|
||||
} : function(e) {
|
||||
return N.call(H, e)
|
||||
},
|
||||
F = B && [],
|
||||
I = H.cloneNode,
|
||||
q = H.setAttribute,
|
||||
R = H.removeAttribute,
|
||||
U = t.createElement,
|
||||
z = P && {
|
||||
attributes: !0,
|
||||
characterData: !0,
|
||||
attributeOldValue: !0
|
||||
},
|
||||
W = P || function(e) {
|
||||
J = !1, E.removeEventListener(c, W)
|
||||
},
|
||||
X, V = e.requestAnimationFrame || e.webkitRequestAnimationFrame || e.mozRequestAnimationFrame || e.msRequestAnimationFrame || function(e) {
|
||||
setTimeout(e, 10)
|
||||
},
|
||||
$ = !1,
|
||||
J = !0,
|
||||
K = !0,
|
||||
Q = !0,
|
||||
G, Y, Z, et, tt, nt;
|
||||
O || M ? (tt = function(e, t) {
|
||||
N.call(t, e) || ht(e, t)
|
||||
}, nt = ht) : (tt = function(e, t) {
|
||||
e[i] || (e[i] = n(!0), ht(e, t))
|
||||
}, nt = tt), B ? (J = !1, function() {
|
||||
var e = k(H, "addEventListener"),
|
||||
t = e.value,
|
||||
n = function(e) {
|
||||
var t = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
});
|
||||
t.attrName = e, t.prevValue = this.getAttribute(e), t.newValue = null, t[l] = t.attrChange = 2, R.call(this, e), this.dispatchEvent(t)
|
||||
},
|
||||
r = function(e, t) {
|
||||
var n = this.hasAttribute(e),
|
||||
r = n && this.getAttribute(e),
|
||||
i = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
});
|
||||
q.call(this, e, t), i.attrName = e, i.prevValue = n ? r : null, i.newValue = t, n ? i[f] = i.attrChange = 1 : i[a] = i.attrChange = 0, this.dispatchEvent(i)
|
||||
},
|
||||
s = function(e) {
|
||||
var t = e.currentTarget,
|
||||
n = t[i],
|
||||
r = e.propertyName,
|
||||
s;
|
||||
n.hasOwnProperty(r) && (n = n[r], s = new CustomEvent(c, {
|
||||
bubbles: !0
|
||||
}), s.attrName = n.name, s.prevValue = n.value || null, s.newValue = n.value = t[r] || null, s.prevValue == null ? s[a] = s.attrChange = 0 : s[f] = s.attrChange = 1, t.dispatchEvent(s))
|
||||
};
|
||||
e.value = function(e, o, u) {
|
||||
e === c && this.attributeChangedCallback && this.setAttribute !== r && (this[i] = {
|
||||
className: {
|
||||
name: "class",
|
||||
value: this.className
|
||||
}
|
||||
}, this.setAttribute = r, this.removeAttribute = n, t.call(this, "propertychange", s)), t.call(this, e, o, u)
|
||||
}, C(H, "addEventListener", e)
|
||||
}()) : P || (E.addEventListener(c, W), E.setAttribute(i, 1), E.removeAttribute(i), J && (G = function(e) {
|
||||
var t = this,
|
||||
n, r, s;
|
||||
if (t === e.target) {
|
||||
n = t[i], t[i] = r = Z(t);
|
||||
for (s in r) {
|
||||
if (!(s in n)) return Y(0, t, s, n[s], r[s], a);
|
||||
if (r[s] !== n[s]) return Y(1, t, s, n[s], r[s], f)
|
||||
}
|
||||
for (s in n)
|
||||
if (!(s in r)) return Y(2, t, s, n[s], r[s], l)
|
||||
}
|
||||
}, Y = function(e, t, n, r, i, s) {
|
||||
var o = {
|
||||
attrChange: e,
|
||||
currentTarget: t,
|
||||
attrName: n,
|
||||
prevValue: r,
|
||||
newValue: i
|
||||
};
|
||||
o[s] = e, at(o)
|
||||
}, Z = function(e) {
|
||||
for (var t, n, r = {}, i = e.attributes, s = 0, o = i.length; s < o; s++) t = i[s], n = t.name, n !== "setAttribute" && (r[n] = t.value);
|
||||
return r
|
||||
})), t[r] = function(n, r) {
|
||||
c = n.toUpperCase(), $ || ($ = !0, P ? (et = function(e, t) {
|
||||
function n(e, t) {
|
||||
for (var n = 0, r = e.length; n < r; t(e[n++]));
|
||||
}
|
||||
return new P(function(r) {
|
||||
for (var i, s, o, u = 0, a = r.length; u < a; u++) i = r[u], i.type === "childList" ? (n(i.addedNodes, e), n(i.removedNodes, t)) : (s = i.target, Q && s.attributeChangedCallback && i.attributeName !== "style" && (o = s.getAttribute(i.attributeName), o !== i.oldValue && s.attributeChangedCallback(i.attributeName, i.oldValue, o)))
|
||||
})
|
||||
}(st(s), st(o)), et.observe(t, {
|
||||
childList: !0,
|
||||
subtree: !0
|
||||
})) : (X = [], V(function E() {
|
||||
while (X.length) X.shift().call(null, X.shift());
|
||||
V(E)
|
||||
}), t.addEventListener("DOMNodeInserted", ft(s)), t.addEventListener("DOMNodeRemoved", ft(o))), t.addEventListener(h, lt), t.addEventListener("readystatechange", lt), t.createElement = function(e, n) {
|
||||
var r = U.apply(t, arguments),
|
||||
i = "" + e,
|
||||
s = S.call(y, (n ? v : d) + (n || i).toUpperCase()),
|
||||
o = -1 < s;
|
||||
return n && (r.setAttribute("is", n = n.toLowerCase()), o && (o = ut(i.toUpperCase(), n))), Q = !t.createElement.innerHTMLHelper, o && nt(r, b[s]), r
|
||||
}, H.cloneNode = function(e) {
|
||||
var t = I.call(this, !!e),
|
||||
n = ot(t);
|
||||
return -1 < n && nt(t, b[n]), e && it(t.querySelectorAll(w)), t
|
||||
}), -2 < S.call(y, v + c) + S.call(y, d + c) && dt(n);
|
||||
if (!m.test(c) || -1 < S.call(g, c)) throw new Error("The type " + n + " is invalid");
|
||||
var i = function() {
|
||||
return f ? t.createElement(l, c) : t.createElement(l)
|
||||
},
|
||||
a = r || x,
|
||||
f = T.call(a, u),
|
||||
l = f ? r[u].toUpperCase() : c,
|
||||
c, p;
|
||||
return f && -1 < S.call(y, d + l) && dt(l), p = y.push((f ? v : d) + c) - 1, w = w.concat(w.length ? "," : "", f ? l + '[is="' + n.toLowerCase() + '"]' : l), i.prototype = b[p] = T.call(a, "prototype") ? a.prototype : _(H), rt(t.querySelectorAll(w), s), i
|
||||
}
|
||||
})(window, document, Object, "registerElement");
|
||||
263
src/bower_components/fetch/fetch.js
vendored
Normal file
263
src/bower_components/fetch/fetch.js
vendored
Normal file
@@ -0,0 +1,263 @@
|
||||
! function(self) {
|
||||
"use strict";
|
||||
|
||||
function normalizeName(name) {
|
||||
if ("string" != typeof name && (name = String(name)), /[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) throw new TypeError("Invalid character in header field name");
|
||||
return name.toLowerCase()
|
||||
}
|
||||
|
||||
function normalizeValue(value) {
|
||||
return "string" != typeof value && (value = String(value)), value
|
||||
}
|
||||
|
||||
function iteratorFor(items) {
|
||||
var iterator = {
|
||||
next: function() {
|
||||
var value = items.shift();
|
||||
return {
|
||||
done: void 0 === value,
|
||||
value: value
|
||||
}
|
||||
}
|
||||
};
|
||||
return support.iterable && (iterator[Symbol.iterator] = function() {
|
||||
return iterator
|
||||
}), iterator
|
||||
}
|
||||
|
||||
function Headers(headers) {
|
||||
this.map = {}, headers instanceof Headers ? headers.forEach(function(value, name) {
|
||||
this.append(name, value)
|
||||
}, this) : headers && Object.getOwnPropertyNames(headers).forEach(function(name) {
|
||||
this.append(name, headers[name])
|
||||
}, this)
|
||||
}
|
||||
|
||||
function consumed(body) {
|
||||
if (body.bodyUsed) return Promise.reject(new TypeError("Already read"));
|
||||
body.bodyUsed = !0
|
||||
}
|
||||
|
||||
function fileReaderReady(reader) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
reader.onload = function() {
|
||||
resolve(reader.result)
|
||||
}, reader.onerror = function() {
|
||||
reject(reader.error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function readBlobAsArrayBuffer(blob) {
|
||||
var reader = new FileReader,
|
||||
promise = fileReaderReady(reader);
|
||||
return reader.readAsArrayBuffer(blob), promise
|
||||
}
|
||||
|
||||
function readBlobAsText(blob) {
|
||||
var reader = new FileReader,
|
||||
promise = fileReaderReady(reader);
|
||||
return reader.readAsText(blob), promise
|
||||
}
|
||||
|
||||
function readArrayBufferAsText(buf) {
|
||||
for (var view = new Uint8Array(buf), chars = new Array(view.length), i = 0; i < view.length; i++) chars[i] = String.fromCharCode(view[i]);
|
||||
return chars.join("")
|
||||
}
|
||||
|
||||
function bufferClone(buf) {
|
||||
if (buf.slice) return buf.slice(0);
|
||||
var view = new Uint8Array(buf.byteLength);
|
||||
return view.set(new Uint8Array(buf)), view.buffer
|
||||
}
|
||||
|
||||
function Body() {
|
||||
return this.bodyUsed = !1, this._initBody = function(body) {
|
||||
if (this._bodyInit = body, body)
|
||||
if ("string" == typeof body) this._bodyText = body;
|
||||
else if (support.blob && Blob.prototype.isPrototypeOf(body)) this._bodyBlob = body;
|
||||
else if (support.formData && FormData.prototype.isPrototypeOf(body)) this._bodyFormData = body;
|
||||
else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) this._bodyText = body.toString();
|
||||
else if (support.arrayBuffer && support.blob && isDataView(body)) this._bodyArrayBuffer = bufferClone(body.buffer), this._bodyInit = new Blob([this._bodyArrayBuffer]);
|
||||
else {
|
||||
if (!support.arrayBuffer || !ArrayBuffer.prototype.isPrototypeOf(body) && !isArrayBufferView(body)) throw new Error("unsupported BodyInit type");
|
||||
this._bodyArrayBuffer = bufferClone(body)
|
||||
} else this._bodyText = "";
|
||||
this.headers.get("content-type") || ("string" == typeof body ? this.headers.set("content-type", "text/plain;charset=UTF-8") : this._bodyBlob && this._bodyBlob.type ? this.headers.set("content-type", this._bodyBlob.type) : support.searchParams && URLSearchParams.prototype.isPrototypeOf(body) && this.headers.set("content-type", "application/x-www-form-urlencoded;charset=UTF-8"))
|
||||
}, support.blob && (this.blob = function() {
|
||||
var rejected = consumed(this);
|
||||
if (rejected) return rejected;
|
||||
if (this._bodyBlob) return Promise.resolve(this._bodyBlob);
|
||||
if (this._bodyArrayBuffer) return Promise.resolve(new Blob([this._bodyArrayBuffer]));
|
||||
if (this._bodyFormData) throw new Error("could not read FormData body as blob");
|
||||
return Promise.resolve(new Blob([this._bodyText]))
|
||||
}, this.arrayBuffer = function() {
|
||||
return this._bodyArrayBuffer ? consumed(this) || Promise.resolve(this._bodyArrayBuffer) : this.blob().then(readBlobAsArrayBuffer)
|
||||
}), this.text = function() {
|
||||
var rejected = consumed(this);
|
||||
if (rejected) return rejected;
|
||||
if (this._bodyBlob) return readBlobAsText(this._bodyBlob);
|
||||
if (this._bodyArrayBuffer) return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
|
||||
if (this._bodyFormData) throw new Error("could not read FormData body as text");
|
||||
return Promise.resolve(this._bodyText)
|
||||
}, support.formData && (this.formData = function() {
|
||||
return this.text().then(decode)
|
||||
}), this.json = function() {
|
||||
return this.text().then(JSON.parse)
|
||||
}, this
|
||||
}
|
||||
|
||||
function normalizeMethod(method) {
|
||||
var upcased = method.toUpperCase();
|
||||
return methods.indexOf(upcased) > -1 ? upcased : method
|
||||
}
|
||||
|
||||
function Request(input, options) {
|
||||
options = options || {};
|
||||
var body = options.body;
|
||||
if ("string" == typeof input) this.url = input;
|
||||
else {
|
||||
if (input.bodyUsed) throw new TypeError("Already read");
|
||||
this.url = input.url, this.credentials = input.credentials, options.headers || (this.headers = new Headers(input.headers)), this.method = input.method, this.mode = input.mode, body || null == input._bodyInit || (body = input._bodyInit, input.bodyUsed = !0)
|
||||
}
|
||||
if (this.credentials = options.credentials || this.credentials || "omit", !options.headers && this.headers || (this.headers = new Headers(options.headers)), this.method = normalizeMethod(options.method || this.method || "GET"), this.mode = options.mode || this.mode || null, this.referrer = null, ("GET" === this.method || "HEAD" === this.method) && body) throw new TypeError("Body not allowed for GET or HEAD requests");
|
||||
this._initBody(body)
|
||||
}
|
||||
|
||||
function decode(body) {
|
||||
var form = new FormData;
|
||||
return body.trim().split("&").forEach(function(bytes) {
|
||||
if (bytes) {
|
||||
var split = bytes.split("="),
|
||||
name = split.shift().replace(/\+/g, " "),
|
||||
value = split.join("=").replace(/\+/g, " ");
|
||||
form.append(decodeURIComponent(name), decodeURIComponent(value))
|
||||
}
|
||||
}), form
|
||||
}
|
||||
|
||||
function parseHeaders(rawHeaders) {
|
||||
var headers = new Headers;
|
||||
return rawHeaders.split("\r\n").forEach(function(line) {
|
||||
var parts = line.split(":"),
|
||||
key = parts.shift().trim();
|
||||
if (key) {
|
||||
var value = parts.join(":").trim();
|
||||
headers.append(key, value)
|
||||
}
|
||||
}), headers
|
||||
}
|
||||
|
||||
function Response(bodyInit, options) {
|
||||
options || (options = {}), this.type = "default", this.status = "status" in options ? options.status : 200, this.ok = this.status >= 200 && this.status < 300, this.statusText = "statusText" in options ? options.statusText : "OK", this.headers = new Headers(options.headers), this.url = options.url || "", this._initBody(bodyInit)
|
||||
}
|
||||
if (!self.fetch) {
|
||||
var support = {
|
||||
searchParams: "URLSearchParams" in self,
|
||||
iterable: "Symbol" in self && "iterator" in Symbol,
|
||||
blob: "FileReader" in self && "Blob" in self && function() {
|
||||
try {
|
||||
return new Blob, !0
|
||||
} catch (e) {
|
||||
return !1
|
||||
}
|
||||
}(),
|
||||
formData: "FormData" in self,
|
||||
arrayBuffer: "ArrayBuffer" in self
|
||||
};
|
||||
if (support.arrayBuffer) var viewClasses = ["[object Int8Array]", "[object Uint8Array]", "[object Uint8ClampedArray]", "[object Int16Array]", "[object Uint16Array]", "[object Int32Array]", "[object Uint32Array]", "[object Float32Array]", "[object Float64Array]"],
|
||||
isDataView = function(obj) {
|
||||
return obj && DataView.prototype.isPrototypeOf(obj)
|
||||
},
|
||||
isArrayBufferView = ArrayBuffer.isView || function(obj) {
|
||||
return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
|
||||
};
|
||||
Headers.prototype.append = function(name, value) {
|
||||
name = normalizeName(name), value = normalizeValue(value);
|
||||
var list = this.map[name];
|
||||
list || (list = [], this.map[name] = list), list.push(value)
|
||||
}, Headers.prototype.delete = function(name) {
|
||||
delete this.map[normalizeName(name)]
|
||||
}, Headers.prototype.get = function(name) {
|
||||
var values = this.map[normalizeName(name)];
|
||||
return values ? values[0] : null
|
||||
}, Headers.prototype.getAll = function(name) {
|
||||
return this.map[normalizeName(name)] || []
|
||||
}, Headers.prototype.has = function(name) {
|
||||
return this.map.hasOwnProperty(normalizeName(name))
|
||||
}, Headers.prototype.set = function(name, value) {
|
||||
this.map[normalizeName(name)] = [normalizeValue(value)]
|
||||
}, Headers.prototype.forEach = function(callback, thisArg) {
|
||||
Object.getOwnPropertyNames(this.map).forEach(function(name) {
|
||||
this.map[name].forEach(function(value) {
|
||||
callback.call(thisArg, value, name, this)
|
||||
}, this)
|
||||
}, this)
|
||||
}, Headers.prototype.keys = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value, name) {
|
||||
items.push(name)
|
||||
}), iteratorFor(items)
|
||||
}, Headers.prototype.values = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value) {
|
||||
items.push(value)
|
||||
}), iteratorFor(items)
|
||||
}, Headers.prototype.entries = function() {
|
||||
var items = [];
|
||||
return this.forEach(function(value, name) {
|
||||
items.push([name, value])
|
||||
}), iteratorFor(items)
|
||||
}, support.iterable && (Headers.prototype[Symbol.iterator] = Headers.prototype.entries);
|
||||
var methods = ["DELETE", "GET", "HEAD", "OPTIONS", "POST", "PUT"];
|
||||
Request.prototype.clone = function() {
|
||||
return new Request(this, {
|
||||
body: this._bodyInit
|
||||
})
|
||||
}, Body.call(Request.prototype), Body.call(Response.prototype), Response.prototype.clone = function() {
|
||||
return new Response(this._bodyInit, {
|
||||
status: this.status,
|
||||
statusText: this.statusText,
|
||||
headers: new Headers(this.headers),
|
||||
url: this.url
|
||||
})
|
||||
}, Response.error = function() {
|
||||
var response = new Response(null, {
|
||||
status: 0,
|
||||
statusText: ""
|
||||
});
|
||||
return response.type = "error", response
|
||||
};
|
||||
var redirectStatuses = [301, 302, 303, 307, 308];
|
||||
Response.redirect = function(url, status) {
|
||||
if (-1 === redirectStatuses.indexOf(status)) throw new RangeError("Invalid status code");
|
||||
return new Response(null, {
|
||||
status: status,
|
||||
headers: {
|
||||
location: url
|
||||
}
|
||||
})
|
||||
}, self.Headers = Headers, self.Request = Request, self.Response = Response, self.fetch = function(input, init) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var request = new Request(input, init),
|
||||
xhr = new XMLHttpRequest;
|
||||
xhr.onload = function() {
|
||||
var options = {
|
||||
status: xhr.status,
|
||||
statusText: xhr.statusText,
|
||||
headers: parseHeaders(xhr.getAllResponseHeaders() || "")
|
||||
};
|
||||
options.url = "responseURL" in xhr ? xhr.responseURL : options.headers.get("X-Request-URL");
|
||||
var body = "response" in xhr ? xhr.response : xhr.responseText;
|
||||
resolve(new Response(body, options))
|
||||
}, xhr.onerror = function() {
|
||||
reject(new TypeError("Network request failed"))
|
||||
}, xhr.ontimeout = function() {
|
||||
reject(new TypeError("Network request failed"))
|
||||
}, xhr.open(request.method, request.url, !0), "include" === request.credentials && (xhr.withCredentials = !0), "responseType" in xhr && support.blob && (xhr.responseType = "blob"), request.headers.forEach(function(value, name) {
|
||||
xhr.setRequestHeader(name, value)
|
||||
}), xhr.send(void 0 === request._bodyInit ? null : request._bodyInit)
|
||||
})
|
||||
}, self.fetch.polyfill = !0
|
||||
}
|
||||
}("undefined" != typeof self ? self : this);
|
||||
18
src/bower_components/query-string/index.js
vendored
Normal file
18
src/bower_components/query-string/index.js
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"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("&") : ""
|
||||
};
|
||||
83
src/bower_components/query-string/test.js
vendored
Normal file
83
src/bower_components/query-string/test.js
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
"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)
|
||||
})
|
||||
});
|
||||
607
src/bower_components/requirejs/require.js
vendored
Normal file
607
src/bower_components/requirejs/require.js
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
var requirejs, require, define;
|
||||
! function(global, setTimeout) {
|
||||
function commentReplace(match, singlePrefix) {
|
||||
return singlePrefix || ""
|
||||
}
|
||||
|
||||
function isFunction(it) {
|
||||
return "[object Function]" === ostring.call(it)
|
||||
}
|
||||
|
||||
function isArray(it) {
|
||||
return "[object Array]" === ostring.call(it)
|
||||
}
|
||||
|
||||
function each(ary, func) {
|
||||
if (ary) {
|
||||
var i;
|
||||
for (i = 0; i < ary.length && (!ary[i] || !func(ary[i], i, ary)); i += 1);
|
||||
}
|
||||
}
|
||||
|
||||
function eachReverse(ary, func) {
|
||||
if (ary) {
|
||||
var i;
|
||||
for (i = ary.length - 1; i > -1 && (!ary[i] || !func(ary[i], i, ary)); i -= 1);
|
||||
}
|
||||
}
|
||||
|
||||
function hasProp(obj, prop) {
|
||||
return hasOwn.call(obj, prop)
|
||||
}
|
||||
|
||||
function getOwn(obj, prop) {
|
||||
return hasProp(obj, prop) && obj[prop]
|
||||
}
|
||||
|
||||
function eachProp(obj, func) {
|
||||
var prop;
|
||||
for (prop in obj)
|
||||
if (hasProp(obj, prop) && func(obj[prop], prop)) break
|
||||
}
|
||||
|
||||
function mixin(target, source, force, deepStringMixin) {
|
||||
return source && eachProp(source, function(value, prop) {
|
||||
!force && hasProp(target, prop) || (!deepStringMixin || "object" != typeof value || !value || isArray(value) || isFunction(value) || value instanceof RegExp ? target[prop] = value : (target[prop] || (target[prop] = {}), mixin(target[prop], value, force, deepStringMixin)))
|
||||
}), target
|
||||
}
|
||||
|
||||
function bind(obj, fn) {
|
||||
return function() {
|
||||
return fn.apply(obj, arguments)
|
||||
}
|
||||
}
|
||||
|
||||
function scripts() {
|
||||
return document.getElementsByTagName("script")
|
||||
}
|
||||
|
||||
function defaultOnError(err) {
|
||||
throw err
|
||||
}
|
||||
|
||||
function getGlobal(value) {
|
||||
if (!value) return value;
|
||||
var g = global;
|
||||
return each(value.split("."), function(part) {
|
||||
g = g[part]
|
||||
}), g
|
||||
}
|
||||
|
||||
function makeError(id, msg, err, requireModules) {
|
||||
var e = new Error(msg + "\nhttp://requirejs.org/docs/errors.html#" + id);
|
||||
return e.requireType = id, e.requireModules = requireModules, err && (e.originalError = err), e
|
||||
}
|
||||
|
||||
function newContext(contextName) {
|
||||
function trimDots(ary) {
|
||||
var i, part;
|
||||
for (i = 0; i < ary.length; i++)
|
||||
if ("." === (part = ary[i])) ary.splice(i, 1), i -= 1;
|
||||
else if (".." === part) {
|
||||
if (0 === i || 1 === i && ".." === ary[2] || ".." === ary[i - 1]) continue;
|
||||
i > 0 && (ary.splice(i - 1, 2), i -= 2)
|
||||
}
|
||||
}
|
||||
|
||||
function normalize(name, baseName, applyMap) {
|
||||
var mapValue, nameParts, i, j, nameSegment, lastIndex, foundMap, foundI, foundStarMap, starI, normalizedBaseParts, baseParts = baseName && baseName.split("/"),
|
||||
map = config.map,
|
||||
starMap = map && map["*"];
|
||||
if (name && (name = name.split("/"), lastIndex = name.length - 1, config.nodeIdCompat && jsSuffixRegExp.test(name[lastIndex]) && (name[lastIndex] = name[lastIndex].replace(jsSuffixRegExp, "")), "." === name[0].charAt(0) && baseParts && (normalizedBaseParts = baseParts.slice(0, baseParts.length - 1), name = normalizedBaseParts.concat(name)), trimDots(name), name = name.join("/")), applyMap && map && (baseParts || starMap)) {
|
||||
nameParts = name.split("/");
|
||||
outerLoop: for (i = nameParts.length; i > 0; i -= 1) {
|
||||
if (nameSegment = nameParts.slice(0, i).join("/"), baseParts)
|
||||
for (j = baseParts.length; j > 0; j -= 1)
|
||||
if ((mapValue = getOwn(map, baseParts.slice(0, j).join("/"))) && (mapValue = getOwn(mapValue, nameSegment))) {
|
||||
foundMap = mapValue, foundI = i;
|
||||
break outerLoop
|
||||
}! foundStarMap && starMap && getOwn(starMap, nameSegment) && (foundStarMap = getOwn(starMap, nameSegment), starI = i)
|
||||
}!foundMap && foundStarMap && (foundMap = foundStarMap, foundI = starI), foundMap && (nameParts.splice(0, foundI, foundMap), name = nameParts.join("/"))
|
||||
}
|
||||
return getOwn(config.pkgs, name) || name
|
||||
}
|
||||
|
||||
function removeScript(name) {
|
||||
isBrowser && each(scripts(), function(scriptNode) {
|
||||
if (scriptNode.getAttribute("data-requiremodule") === name && scriptNode.getAttribute("data-requirecontext") === context.contextName) return scriptNode.parentNode.removeChild(scriptNode), !0
|
||||
})
|
||||
}
|
||||
|
||||
function hasPathFallback(id) {
|
||||
var pathConfig = getOwn(config.paths, id);
|
||||
if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) return pathConfig.shift(), context.require.undef(id), context.makeRequire(null, {
|
||||
skipMap: !0
|
||||
})([id]), !0
|
||||
}
|
||||
|
||||
function splitPrefix(name) {
|
||||
var prefix, index = name ? name.indexOf("!") : -1;
|
||||
return index > -1 && (prefix = name.substring(0, index), name = name.substring(index + 1, name.length)), [prefix, name]
|
||||
}
|
||||
|
||||
function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) {
|
||||
var url, pluginModule, suffix, nameParts, prefix = null,
|
||||
parentName = parentModuleMap ? parentModuleMap.name : null,
|
||||
originalName = name,
|
||||
isDefine = !0,
|
||||
normalizedName = "";
|
||||
return name || (isDefine = !1, name = "_@r" + (requireCounter += 1)), nameParts = splitPrefix(name), prefix = nameParts[0], name = nameParts[1], prefix && (prefix = normalize(prefix, parentName, applyMap), pluginModule = getOwn(defined, prefix)), name && (prefix ? normalizedName = isNormalized ? name : pluginModule && pluginModule.normalize ? pluginModule.normalize(name, function(name) {
|
||||
return normalize(name, parentName, applyMap)
|
||||
}) : -1 === name.indexOf("!") ? normalize(name, parentName, applyMap) : name : (normalizedName = normalize(name, parentName, applyMap), nameParts = splitPrefix(normalizedName), prefix = nameParts[0], normalizedName = nameParts[1], isNormalized = !0, url = context.nameToUrl(normalizedName))), suffix = !prefix || pluginModule || isNormalized ? "" : "_unnormalized" + (unnormalizedCounter += 1), {
|
||||
prefix: prefix,
|
||||
name: normalizedName,
|
||||
parentMap: parentModuleMap,
|
||||
unnormalized: !!suffix,
|
||||
url: url,
|
||||
originalName: originalName,
|
||||
isDefine: isDefine,
|
||||
id: (prefix ? prefix + "!" + normalizedName : normalizedName) + suffix
|
||||
}
|
||||
}
|
||||
|
||||
function getModule(depMap) {
|
||||
var id = depMap.id,
|
||||
mod = getOwn(registry, id);
|
||||
return mod || (mod = registry[id] = new context.Module(depMap)), mod
|
||||
}
|
||||
|
||||
function on(depMap, name, fn) {
|
||||
var id = depMap.id,
|
||||
mod = getOwn(registry, id);
|
||||
!hasProp(defined, id) || mod && !mod.defineEmitComplete ? (mod = getModule(depMap), mod.error && "error" === name ? fn(mod.error) : mod.on(name, fn)) : "defined" === name && fn(defined[id])
|
||||
}
|
||||
|
||||
function onError(err, errback) {
|
||||
var ids = err.requireModules,
|
||||
notified = !1;
|
||||
errback ? errback(err) : (each(ids, function(id) {
|
||||
var mod = getOwn(registry, id);
|
||||
mod && (mod.error = err, mod.events.error && (notified = !0, mod.emit("error", err)))
|
||||
}), notified || req.onError(err))
|
||||
}
|
||||
|
||||
function takeGlobalQueue() {
|
||||
globalDefQueue.length && (each(globalDefQueue, function(queueItem) {
|
||||
var id = queueItem[0];
|
||||
"string" == typeof id && (context.defQueueMap[id] = !0), defQueue.push(queueItem)
|
||||
}), globalDefQueue = [])
|
||||
}
|
||||
|
||||
function cleanRegistry(id) {
|
||||
delete registry[id], delete enabledRegistry[id]
|
||||
}
|
||||
|
||||
function breakCycle(mod, traced, processed) {
|
||||
var id = mod.map.id;
|
||||
mod.error ? mod.emit("error", mod.error) : (traced[id] = !0, each(mod.depMaps, function(depMap, i) {
|
||||
var depId = depMap.id,
|
||||
dep = getOwn(registry, depId);
|
||||
!dep || mod.depMatched[i] || processed[depId] || (getOwn(traced, depId) ? (mod.defineDep(i, defined[depId]), mod.check()) : breakCycle(dep, traced, processed))
|
||||
}), processed[id] = !0)
|
||||
}
|
||||
|
||||
function checkLoaded() {
|
||||
var err, usingPathFallback, waitInterval = 1e3 * config.waitSeconds,
|
||||
expired = waitInterval && context.startTime + waitInterval < (new Date).getTime(),
|
||||
noLoads = [],
|
||||
reqCalls = [],
|
||||
stillLoading = !1,
|
||||
needCycleCheck = !0;
|
||||
if (!inCheckLoaded) {
|
||||
if (inCheckLoaded = !0, eachProp(enabledRegistry, function(mod) {
|
||||
var map = mod.map,
|
||||
modId = map.id;
|
||||
if (mod.enabled && (map.isDefine || reqCalls.push(mod), !mod.error))
|
||||
if (!mod.inited && expired) hasPathFallback(modId) ? (usingPathFallback = !0, stillLoading = !0) : (noLoads.push(modId), removeScript(modId));
|
||||
else if (!mod.inited && mod.fetched && map.isDefine && (stillLoading = !0, !map.prefix)) return needCycleCheck = !1
|
||||
}), expired && noLoads.length) return err = makeError("timeout", "Load timeout for modules: " + noLoads, null, noLoads), err.contextName = context.contextName, onError(err);
|
||||
needCycleCheck && each(reqCalls, function(mod) {
|
||||
breakCycle(mod, {}, {})
|
||||
}), expired && !usingPathFallback || !stillLoading || !isBrowser && !isWebWorker || checkLoadedTimeoutId || (checkLoadedTimeoutId = setTimeout(function() {
|
||||
checkLoadedTimeoutId = 0, checkLoaded()
|
||||
}, 50)), inCheckLoaded = !1
|
||||
}
|
||||
}
|
||||
|
||||
function callGetModule(args) {
|
||||
hasProp(defined, args[0]) || getModule(makeModuleMap(args[0], null, !0)).init(args[1], args[2])
|
||||
}
|
||||
|
||||
function removeListener(node, func, name, ieName) {
|
||||
node.detachEvent && !isOpera ? ieName && node.detachEvent(ieName, func) : node.removeEventListener(name, func, !1)
|
||||
}
|
||||
|
||||
function getScriptData(evt) {
|
||||
var node = evt.currentTarget || evt.srcElement;
|
||||
return removeListener(node, context.onScriptLoad, "load", "onreadystatechange"), removeListener(node, context.onScriptError, "error"), {
|
||||
node: node,
|
||||
id: node && node.getAttribute("data-requiremodule")
|
||||
}
|
||||
}
|
||||
|
||||
function intakeDefines() {
|
||||
var args;
|
||||
for (takeGlobalQueue(); defQueue.length;) {
|
||||
if (args = defQueue.shift(), null === args[0]) return onError(makeError("mismatch", "Mismatched anonymous define() module: " + args[args.length - 1]));
|
||||
callGetModule(args)
|
||||
}
|
||||
context.defQueueMap = {}
|
||||
}
|
||||
var inCheckLoaded, Module, context, handlers, checkLoadedTimeoutId, config = {
|
||||
waitSeconds: 7,
|
||||
baseUrl: "./",
|
||||
paths: {},
|
||||
bundles: {},
|
||||
pkgs: {},
|
||||
shim: {},
|
||||
config: {}
|
||||
},
|
||||
registry = {},
|
||||
enabledRegistry = {},
|
||||
undefEvents = {},
|
||||
defQueue = [],
|
||||
defined = {},
|
||||
urlFetched = {},
|
||||
bundlesMap = {},
|
||||
requireCounter = 1,
|
||||
unnormalizedCounter = 1;
|
||||
return handlers = {
|
||||
require: function(mod) {
|
||||
return mod.require ? mod.require : mod.require = context.makeRequire(mod.map)
|
||||
},
|
||||
exports: function(mod) {
|
||||
if (mod.usingExports = !0, mod.map.isDefine) return mod.exports ? defined[mod.map.id] = mod.exports : mod.exports = defined[mod.map.id] = {}
|
||||
},
|
||||
module: function(mod) {
|
||||
return mod.module ? mod.module : mod.module = {
|
||||
id: mod.map.id,
|
||||
uri: mod.map.url,
|
||||
config: function() {
|
||||
return getOwn(config.config, mod.map.id) || {}
|
||||
},
|
||||
exports: mod.exports || (mod.exports = {})
|
||||
}
|
||||
}
|
||||
}, Module = function(map) {
|
||||
this.events = getOwn(undefEvents, map.id) || {}, this.map = map, this.shim = getOwn(config.shim, map.id), this.depExports = [], this.depMaps = [], this.depMatched = [], this.pluginMaps = {}, this.depCount = 0
|
||||
}, Module.prototype = {
|
||||
init: function(depMaps, factory, errback, options) {
|
||||
options = options || {}, this.inited || (this.factory = factory, errback ? this.on("error", errback) : this.events.error && (errback = bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
})), this.depMaps = depMaps && depMaps.slice(0), this.errback = errback, this.inited = !0, this.ignore = options.ignore, options.enabled || this.enabled ? this.enable() : this.check())
|
||||
},
|
||||
defineDep: function(i, depExports) {
|
||||
this.depMatched[i] || (this.depMatched[i] = !0, this.depCount -= 1, this.depExports[i] = depExports)
|
||||
},
|
||||
fetch: function() {
|
||||
if (!this.fetched) {
|
||||
this.fetched = !0, context.startTime = (new Date).getTime();
|
||||
var map = this.map;
|
||||
if (!this.shim) return map.prefix ? this.callPlugin() : this.load();
|
||||
context.makeRequire(this.map, {
|
||||
enableBuildCallback: !0
|
||||
})(this.shim.deps || [], bind(this, function() {
|
||||
return map.prefix ? this.callPlugin() : this.load()
|
||||
}))
|
||||
}
|
||||
},
|
||||
load: function() {
|
||||
var url = this.map.url;
|
||||
urlFetched[url] || (urlFetched[url] = !0, context.load(this.map.id, url))
|
||||
},
|
||||
check: function() {
|
||||
if (this.enabled && !this.enabling) {
|
||||
var err, cjsModule, id = this.map.id,
|
||||
depExports = this.depExports,
|
||||
exports = this.exports,
|
||||
factory = this.factory;
|
||||
if (this.inited) {
|
||||
if (this.error) this.emit("error", this.error);
|
||||
else if (!this.defining) {
|
||||
if (this.defining = !0, this.depCount < 1 && !this.defined) {
|
||||
if (isFunction(factory)) {
|
||||
if (this.events.error && this.map.isDefine || req.onError !== defaultOnError) try {
|
||||
exports = context.execCb(id, factory, depExports, exports)
|
||||
} catch (e) {
|
||||
err = e
|
||||
} else exports = context.execCb(id, factory, depExports, exports);
|
||||
if (this.map.isDefine && void 0 === exports && (cjsModule = this.module, cjsModule ? exports = cjsModule.exports : this.usingExports && (exports = this.exports)), err) return err.requireMap = this.map, err.requireModules = this.map.isDefine ? [this.map.id] : null, err.requireType = this.map.isDefine ? "define" : "require", onError(this.error = err)
|
||||
} else exports = factory;
|
||||
if (this.exports = exports, this.map.isDefine && !this.ignore && (defined[id] = exports, req.onResourceLoad)) {
|
||||
var resLoadMaps = [];
|
||||
each(this.depMaps, function(depMap) {
|
||||
resLoadMaps.push(depMap.normalizedMap || depMap)
|
||||
}), req.onResourceLoad(context, this.map, resLoadMaps)
|
||||
}
|
||||
cleanRegistry(id), this.defined = !0
|
||||
}
|
||||
this.defining = !1, this.defined && !this.defineEmitted && (this.defineEmitted = !0, this.emit("defined", this.exports), this.defineEmitComplete = !0)
|
||||
}
|
||||
} else hasProp(context.defQueueMap, id) || this.fetch()
|
||||
}
|
||||
},
|
||||
callPlugin: function() {
|
||||
var map = this.map,
|
||||
id = map.id,
|
||||
pluginMap = makeModuleMap(map.prefix);
|
||||
this.depMaps.push(pluginMap), on(pluginMap, "defined", bind(this, function(plugin) {
|
||||
var load, normalizedMap, normalizedMod, bundleId = getOwn(bundlesMap, this.map.id),
|
||||
name = this.map.name,
|
||||
parentName = this.map.parentMap ? this.map.parentMap.name : null,
|
||||
localRequire = context.makeRequire(map.parentMap, {
|
||||
enableBuildCallback: !0
|
||||
});
|
||||
return this.map.unnormalized ? (plugin.normalize && (name = plugin.normalize(name, function(name) {
|
||||
return normalize(name, parentName, !0)
|
||||
}) || ""), normalizedMap = makeModuleMap(map.prefix + "!" + name, this.map.parentMap, !0), on(normalizedMap, "defined", bind(this, function(value) {
|
||||
this.map.normalizedMap = normalizedMap, this.init([], function() {
|
||||
return value
|
||||
}, null, {
|
||||
enabled: !0,
|
||||
ignore: !0
|
||||
})
|
||||
})), void((normalizedMod = getOwn(registry, normalizedMap.id)) && (this.depMaps.push(normalizedMap), this.events.error && normalizedMod.on("error", bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
})), normalizedMod.enable()))) : bundleId ? (this.map.url = context.nameToUrl(bundleId), void this.load()) : (load = bind(this, function(value) {
|
||||
this.init([], function() {
|
||||
return value
|
||||
}, null, {
|
||||
enabled: !0
|
||||
})
|
||||
}), load.error = bind(this, function(err) {
|
||||
this.inited = !0, this.error = err, err.requireModules = [id], eachProp(registry, function(mod) {
|
||||
0 === mod.map.id.indexOf(id + "_unnormalized") && cleanRegistry(mod.map.id)
|
||||
}), onError(err)
|
||||
}), load.fromText = bind(this, function(text, textAlt) {
|
||||
var moduleName = map.name,
|
||||
moduleMap = makeModuleMap(moduleName),
|
||||
hasInteractive = useInteractive;
|
||||
textAlt && (text = textAlt), hasInteractive && (useInteractive = !1), getModule(moduleMap), hasProp(config.config, id) && (config.config[moduleName] = config.config[id]);
|
||||
try {
|
||||
req.exec(text)
|
||||
} catch (e) {
|
||||
return onError(makeError("fromtexteval", "fromText eval for " + id + " failed: " + e, e, [id]))
|
||||
}
|
||||
hasInteractive && (useInteractive = !0), this.depMaps.push(moduleMap), context.completeLoad(moduleName), localRequire([moduleName], load)
|
||||
}), void plugin.load(map.name, localRequire, load, config))
|
||||
})), context.enable(pluginMap, this), this.pluginMaps[pluginMap.id] = pluginMap
|
||||
},
|
||||
enable: function() {
|
||||
enabledRegistry[this.map.id] = this, this.enabled = !0, this.enabling = !0, each(this.depMaps, bind(this, function(depMap, i) {
|
||||
var id, mod, handler;
|
||||
if ("string" == typeof depMap) {
|
||||
if (depMap = makeModuleMap(depMap, this.map.isDefine ? this.map : this.map.parentMap, !1, !this.skipMap), this.depMaps[i] = depMap, handler = getOwn(handlers, depMap.id)) return void(this.depExports[i] = handler(this));
|
||||
this.depCount += 1, on(depMap, "defined", bind(this, function(depExports) {
|
||||
this.undefed || (this.defineDep(i, depExports), this.check())
|
||||
})), this.errback ? on(depMap, "error", bind(this, this.errback)) : this.events.error && on(depMap, "error", bind(this, function(err) {
|
||||
this.emit("error", err)
|
||||
}))
|
||||
}
|
||||
id = depMap.id, mod = registry[id], hasProp(handlers, id) || !mod || mod.enabled || context.enable(depMap, this)
|
||||
})), eachProp(this.pluginMaps, bind(this, function(pluginMap) {
|
||||
var mod = getOwn(registry, pluginMap.id);
|
||||
mod && !mod.enabled && context.enable(pluginMap, this)
|
||||
})), this.enabling = !1, this.check()
|
||||
},
|
||||
on: function(name, cb) {
|
||||
var cbs = this.events[name];
|
||||
cbs || (cbs = this.events[name] = []), cbs.push(cb)
|
||||
},
|
||||
emit: function(name, evt) {
|
||||
each(this.events[name], function(cb) {
|
||||
cb(evt)
|
||||
}), "error" === name && delete this.events[name]
|
||||
}
|
||||
}, context = {
|
||||
config: config,
|
||||
contextName: contextName,
|
||||
registry: registry,
|
||||
defined: defined,
|
||||
urlFetched: urlFetched,
|
||||
defQueue: defQueue,
|
||||
defQueueMap: {},
|
||||
Module: Module,
|
||||
makeModuleMap: makeModuleMap,
|
||||
nextTick: req.nextTick,
|
||||
onError: onError,
|
||||
configure: function(cfg) {
|
||||
if (cfg.baseUrl && "/" !== cfg.baseUrl.charAt(cfg.baseUrl.length - 1) && (cfg.baseUrl += "/"), "string" == typeof cfg.urlArgs) {
|
||||
var urlArgs = cfg.urlArgs;
|
||||
cfg.urlArgs = function(id, url) {
|
||||
return (-1 === url.indexOf("?") ? "?" : "&") + urlArgs
|
||||
}
|
||||
}
|
||||
var shim = config.shim,
|
||||
objs = {
|
||||
paths: !0,
|
||||
bundles: !0,
|
||||
config: !0,
|
||||
map: !0
|
||||
};
|
||||
eachProp(cfg, function(value, prop) {
|
||||
objs[prop] ? (config[prop] || (config[prop] = {}), mixin(config[prop], value, !0, !0)) : config[prop] = value
|
||||
}), cfg.bundles && eachProp(cfg.bundles, function(value, prop) {
|
||||
each(value, function(v) {
|
||||
v !== prop && (bundlesMap[v] = prop)
|
||||
})
|
||||
}), cfg.shim && (eachProp(cfg.shim, function(value, id) {
|
||||
isArray(value) && (value = {
|
||||
deps: value
|
||||
}), !value.exports && !value.init || value.exportsFn || (value.exportsFn = context.makeShimExports(value)), shim[id] = value
|
||||
}), config.shim = shim), cfg.packages && each(cfg.packages, function(pkgObj) {
|
||||
var location, name;
|
||||
pkgObj = "string" == typeof pkgObj ? {
|
||||
name: pkgObj
|
||||
} : pkgObj, name = pkgObj.name, location = pkgObj.location, location && (config.paths[name] = pkgObj.location), config.pkgs[name] = pkgObj.name + "/" + (pkgObj.main || "main").replace(currDirRegExp, "").replace(jsSuffixRegExp, "")
|
||||
}), eachProp(registry, function(mod, id) {
|
||||
mod.inited || mod.map.unnormalized || (mod.map = makeModuleMap(id, null, !0))
|
||||
}), (cfg.deps || cfg.callback) && context.require(cfg.deps || [], cfg.callback)
|
||||
},
|
||||
makeShimExports: function(value) {
|
||||
function fn() {
|
||||
var ret;
|
||||
return value.init && (ret = value.init.apply(global, arguments)), ret || value.exports && getGlobal(value.exports)
|
||||
}
|
||||
return fn
|
||||
},
|
||||
makeRequire: function(relMap, options) {
|
||||
function localRequire(deps, callback, errback) {
|
||||
var id, map, requireMod;
|
||||
return options.enableBuildCallback && callback && isFunction(callback) && (callback.__requireJsBuild = !0), "string" == typeof deps ? isFunction(callback) ? onError(makeError("requireargs", "Invalid require call"), errback) : relMap && hasProp(handlers, deps) ? handlers[deps](registry[relMap.id]) : req.get ? req.get(context, deps, relMap, localRequire) : (map = makeModuleMap(deps, relMap, !1, !0), id = map.id, hasProp(defined, id) ? defined[id] : onError(makeError("notloaded", 'Module name "' + id + '" has not been loaded yet for context: ' + contextName + (relMap ? "" : ". Use require([])")))) : (intakeDefines(), context.nextTick(function() {
|
||||
intakeDefines(), requireMod = getModule(makeModuleMap(null, relMap)), requireMod.skipMap = options.skipMap, requireMod.init(deps, callback, errback, {
|
||||
enabled: !0
|
||||
}), checkLoaded()
|
||||
}), localRequire)
|
||||
}
|
||||
return options = options || {}, mixin(localRequire, {
|
||||
isBrowser: isBrowser,
|
||||
toUrl: function(moduleNamePlusExt) {
|
||||
var ext, index = moduleNamePlusExt.lastIndexOf("."),
|
||||
segment = moduleNamePlusExt.split("/")[0],
|
||||
isRelative = "." === segment || ".." === segment;
|
||||
return -1 !== index && (!isRelative || index > 1) && (ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length), moduleNamePlusExt = moduleNamePlusExt.substring(0, index)), context.nameToUrl(normalize(moduleNamePlusExt, relMap && relMap.id, !0), ext, !0)
|
||||
},
|
||||
defined: function(id) {
|
||||
return hasProp(defined, makeModuleMap(id, relMap, !1, !0).id)
|
||||
},
|
||||
specified: function(id) {
|
||||
return id = makeModuleMap(id, relMap, !1, !0).id, hasProp(defined, id) || hasProp(registry, id)
|
||||
}
|
||||
}), relMap || (localRequire.undef = function(id) {
|
||||
takeGlobalQueue();
|
||||
var map = makeModuleMap(id, relMap, !0),
|
||||
mod = getOwn(registry, id);
|
||||
mod.undefed = !0, removeScript(id), delete defined[id], delete urlFetched[map.url], delete undefEvents[id], eachReverse(defQueue, function(args, i) {
|
||||
args[0] === id && defQueue.splice(i, 1)
|
||||
}), delete context.defQueueMap[id], mod && (mod.events.defined && (undefEvents[id] = mod.events), cleanRegistry(id))
|
||||
}), localRequire
|
||||
},
|
||||
enable: function(depMap) {
|
||||
getOwn(registry, depMap.id) && getModule(depMap).enable()
|
||||
},
|
||||
completeLoad: function(moduleName) {
|
||||
var found, args, mod, shim = getOwn(config.shim, moduleName) || {},
|
||||
shExports = shim.exports;
|
||||
for (takeGlobalQueue(); defQueue.length;) {
|
||||
if (args = defQueue.shift(), null === args[0]) {
|
||||
if (args[0] = moduleName, found) break;
|
||||
found = !0
|
||||
} else args[0] === moduleName && (found = !0);
|
||||
callGetModule(args)
|
||||
}
|
||||
if (context.defQueueMap = {}, mod = getOwn(registry, moduleName), !found && !hasProp(defined, moduleName) && mod && !mod.inited) {
|
||||
if (!(!config.enforceDefine || shExports && getGlobal(shExports))) return hasPathFallback(moduleName) ? void 0 : onError(makeError("nodefine", "No define call for " + moduleName, null, [moduleName]));
|
||||
callGetModule([moduleName, shim.deps || [], shim.exportsFn])
|
||||
}
|
||||
checkLoaded()
|
||||
},
|
||||
nameToUrl: function(moduleName, ext, skipExt) {
|
||||
var paths, syms, i, parentModule, url, parentPath, bundleId, pkgMain = getOwn(config.pkgs, moduleName);
|
||||
if (pkgMain && (moduleName = pkgMain), bundleId = getOwn(bundlesMap, moduleName)) return context.nameToUrl(bundleId, ext, skipExt);
|
||||
if (req.jsExtRegExp.test(moduleName)) url = moduleName + (ext || "");
|
||||
else {
|
||||
for (paths = config.paths, syms = moduleName.split("/"), i = syms.length; i > 0; i -= 1)
|
||||
if (parentModule = syms.slice(0, i).join("/"), parentPath = getOwn(paths, parentModule)) {
|
||||
isArray(parentPath) && (parentPath = parentPath[0]), syms.splice(0, i, parentPath);
|
||||
break
|
||||
} url = syms.join("/"), url += ext || (/^data\:|^blob\:|\?/.test(url) || skipExt ? "" : ".js"), url = ("/" === url.charAt(0) || url.match(/^[\w\+\.\-]+:/) ? "" : config.baseUrl) + url
|
||||
}
|
||||
return config.urlArgs && !/^blob\:/.test(url) ? url + config.urlArgs(moduleName, url) : url
|
||||
},
|
||||
load: function(id, url) {
|
||||
req.load(context, id, url)
|
||||
},
|
||||
execCb: function(name, callback, args, exports) {
|
||||
return callback.apply(exports, args)
|
||||
},
|
||||
onScriptLoad: function(evt) {
|
||||
if ("load" === evt.type || readyRegExp.test((evt.currentTarget || evt.srcElement).readyState)) {
|
||||
interactiveScript = null;
|
||||
var data = getScriptData(evt);
|
||||
context.completeLoad(data.id)
|
||||
}
|
||||
},
|
||||
onScriptError: function(evt) {
|
||||
var data = getScriptData(evt);
|
||||
if (!hasPathFallback(data.id)) {
|
||||
var parents = [];
|
||||
return eachProp(registry, function(value, key) {
|
||||
0 !== key.indexOf("_@r") && each(value.depMaps, function(depMap) {
|
||||
if (depMap.id === data.id) return parents.push(key), !0
|
||||
})
|
||||
}), onError(makeError("scripterror", 'Script error for "' + data.id + (parents.length ? '", needed by: ' + parents.join(", ") : '"'), evt, [data.id]))
|
||||
}
|
||||
}
|
||||
}, context.require = context.makeRequire(), context
|
||||
}
|
||||
|
||||
function getInteractiveScript() {
|
||||
return interactiveScript && "interactive" === interactiveScript.readyState ? interactiveScript : (eachReverse(scripts(), function(script) {
|
||||
if ("interactive" === script.readyState) return interactiveScript = script
|
||||
}), interactiveScript)
|
||||
}
|
||||
var req, s, head, baseElement, dataMain, src, interactiveScript, currentlyAddingScript, mainScript, subPath, version = "2.3.5",
|
||||
commentRegExp = /\/\*[\s\S]*?\*\/|([^:"'=]|^)\/\/.*$/gm,
|
||||
cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,
|
||||
jsSuffixRegExp = /\.js$/,
|
||||
currDirRegExp = /^\.\//,
|
||||
op = Object.prototype,
|
||||
ostring = op.toString,
|
||||
hasOwn = op.hasOwnProperty,
|
||||
isBrowser = !("undefined" == typeof window || "undefined" == typeof navigator || !window.document),
|
||||
isWebWorker = !isBrowser && "undefined" != typeof importScripts,
|
||||
readyRegExp = isBrowser && "PLAYSTATION 3" === navigator.platform ? /^complete$/ : /^(complete|loaded)$/,
|
||||
defContextName = "_",
|
||||
isOpera = "undefined" != typeof opera && "[object Opera]" === opera.toString(),
|
||||
contexts = {},
|
||||
cfg = {},
|
||||
globalDefQueue = [],
|
||||
useInteractive = !1;
|
||||
if (void 0 === define) {
|
||||
if (void 0 !== requirejs) {
|
||||
if (isFunction(requirejs)) return;
|
||||
cfg = requirejs, requirejs = void 0
|
||||
}
|
||||
void 0 === require || isFunction(require) || (cfg = require, require = void 0), req = requirejs = function(deps, callback, errback, optional) {
|
||||
var context, config, contextName = defContextName;
|
||||
return isArray(deps) || "string" == typeof deps || (config = deps, isArray(callback) ? (deps = callback, callback = errback, errback = optional) : deps = []), config && config.context && (contextName = config.context), context = getOwn(contexts, contextName), context || (context = contexts[contextName] = req.s.newContext(contextName)), config && context.configure(config), context.require(deps, callback, errback)
|
||||
}, req.config = function(config) {
|
||||
return req(config)
|
||||
}, req.nextTick = void 0 !== setTimeout ? function(fn) {
|
||||
setTimeout(fn, 4)
|
||||
} : function(fn) {
|
||||
fn()
|
||||
}, require || (require = req), req.version = version, req.jsExtRegExp = /^\/|:|\?|\.js$/, req.isBrowser = isBrowser, s = req.s = {
|
||||
contexts: contexts,
|
||||
newContext: newContext
|
||||
}, req({}), each(["toUrl", "undef", "defined", "specified"], function(prop) {
|
||||
req[prop] = function() {
|
||||
var ctx = contexts[defContextName];
|
||||
return ctx.require[prop].apply(ctx, arguments)
|
||||
}
|
||||
}), isBrowser && (head = s.head = document.getElementsByTagName("head")[0], (baseElement = document.getElementsByTagName("base")[0]) && (head = s.head = baseElement.parentNode)), req.onError = defaultOnError, req.createNode = function(config, moduleName, url) {
|
||||
var node = config.xhtml ? document.createElementNS("http://www.w3.org/1999/xhtml", "html:script") : document.createElement("script");
|
||||
return node.type = config.scriptType || "text/javascript", node.charset = "utf-8", node.async = !0, node
|
||||
}, req.load = function(context, moduleName, url) {
|
||||
var node, config = context && context.config || {};
|
||||
if (isBrowser) return node = req.createNode(config, moduleName, url), node.setAttribute("data-requirecontext", context.contextName), node.setAttribute("data-requiremodule", moduleName), !node.attachEvent || node.attachEvent.toString && node.attachEvent.toString().indexOf("[native code") < 0 || isOpera ? (node.addEventListener("load", context.onScriptLoad, !1), node.addEventListener("error", context.onScriptError, !1)) : (useInteractive = !0, node.attachEvent("onreadystatechange", context.onScriptLoad)), node.src = url, config.onNodeCreated && config.onNodeCreated(node, config, moduleName, url), currentlyAddingScript = node, baseElement ? head.insertBefore(node, baseElement) : head.appendChild(node), currentlyAddingScript = null, node;
|
||||
if (isWebWorker) try {
|
||||
setTimeout(function() {}, 0), importScripts(url), context.completeLoad(moduleName)
|
||||
} catch (e) {
|
||||
context.onError(makeError("importscripts", "importScripts failed for " + moduleName + " at " + url, e, [moduleName]))
|
||||
}
|
||||
}, isBrowser && !cfg.skipDataMain && eachReverse(scripts(), function(script) {
|
||||
if (head || (head = script.parentNode), dataMain = script.getAttribute("data-main")) return mainScript = dataMain, cfg.baseUrl || -1 !== mainScript.indexOf("!") || (src = mainScript.split("/"), mainScript = src.pop(), subPath = src.length ? src.join("/") + "/" : "./", cfg.baseUrl = subPath), mainScript = mainScript.replace(jsSuffixRegExp, ""), req.jsExtRegExp.test(mainScript) && (mainScript = dataMain), cfg.deps = cfg.deps ? cfg.deps.concat(mainScript) : [mainScript], !0
|
||||
}), define = function(name, deps, callback) {
|
||||
var node, context;
|
||||
"string" != typeof name && (callback = deps, deps = name, name = null), isArray(deps) || (callback = deps, deps = null), !deps && isFunction(callback) && (deps = [], callback.length && (callback.toString().replace(commentRegExp, commentReplace).replace(cjsRequireRegExp, function(match, dep) {
|
||||
deps.push(dep)
|
||||
}), deps = (1 === callback.length ? ["require"] : ["require", "exports", "module"]).concat(deps))), useInteractive && (node = currentlyAddingScript || getInteractiveScript()) && (name || (name = node.getAttribute("data-requiremodule")), context = contexts[node.getAttribute("data-requirecontext")]), context ? (context.defQueue.push([name, deps, callback]), context.defQueueMap[name] = !0) : globalDefQueue.push([name, deps, callback])
|
||||
}, define.amd = {
|
||||
jQuery: !0
|
||||
}, req.exec = function(text) {
|
||||
return eval(text)
|
||||
}, req(cfg)
|
||||
}
|
||||
}(this, "undefined" == typeof setTimeout ? void 0 : setTimeout);
|
||||
1571
src/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
1571
src/bower_components/webcomponentsjs/webcomponents-lite.min.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
183
src/bundle.js
183
src/bundle.js
@@ -4,180 +4,33 @@
|
||||
// Use define from require.js not webpack's define
|
||||
var _define = window.define;
|
||||
|
||||
// fetch
|
||||
var fetch = require('whatwg-fetch');
|
||||
_define('fetch', function() {
|
||||
return fetch;
|
||||
});
|
||||
|
||||
// Blurhash
|
||||
var blurhash = require('blurhash');
|
||||
_define('blurhash', function() {
|
||||
return blurhash;
|
||||
});
|
||||
|
||||
// query-string
|
||||
var query = require('query-string');
|
||||
_define('queryString', function() {
|
||||
return query;
|
||||
});
|
||||
|
||||
// flvjs
|
||||
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() {
|
||||
return jstree;
|
||||
});
|
||||
var jstree = require("jstree");
|
||||
require("jstree/dist/themes/default/style.css");
|
||||
_define("jstree", function() { return jstree; });
|
||||
|
||||
// jquery
|
||||
var jquery = require('jquery');
|
||||
_define('jQuery', function() {
|
||||
return jquery;
|
||||
});
|
||||
var jquery = require("jquery");
|
||||
_define("jQuery", function() { return jquery; });
|
||||
|
||||
// hlsjs
|
||||
var hlsjs = require('hls.js');
|
||||
_define('hlsjs', function() {
|
||||
return hlsjs;
|
||||
});
|
||||
var hlsjs = require("hls.js");
|
||||
_define("hlsjs", function() { return hlsjs; });
|
||||
|
||||
// howler
|
||||
var howler = require('howler');
|
||||
_define('howler', function() {
|
||||
return howler;
|
||||
});
|
||||
|
||||
// resize-observer-polyfill
|
||||
var resize = require('resize-observer-polyfill').default;
|
||||
_define('resize-observer-polyfill', function() {
|
||||
return resize;
|
||||
});
|
||||
var howler = require("howler");
|
||||
_define("howler", function() { return howler; });
|
||||
|
||||
// swiper
|
||||
var swiper = require('swiper/js/swiper');
|
||||
require('swiper/css/swiper.min.css');
|
||||
_define('swiper', function() {
|
||||
return swiper;
|
||||
});
|
||||
var swiper = require("swiper");
|
||||
require("swiper/dist/css/swiper.min.css");
|
||||
_define("swiper", function() { return swiper; });
|
||||
|
||||
// sortable
|
||||
var sortable = require('sortablejs').default;
|
||||
_define('sortable', function() {
|
||||
return sortable;
|
||||
});
|
||||
var sortable = require("sortablejs");
|
||||
_define("sortable", function() { return sortable; });
|
||||
|
||||
// webcomponents
|
||||
var webcomponents = require('webcomponents.js/webcomponents-lite');
|
||||
_define('webcomponents', function() {
|
||||
return webcomponents;
|
||||
});
|
||||
|
||||
// shaka
|
||||
var shaka = require('shaka-player');
|
||||
_define('shaka', function() {
|
||||
return shaka;
|
||||
});
|
||||
|
||||
// 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;
|
||||
});
|
||||
|
||||
var epubjs = require('epubjs');
|
||||
_define('epubjs', function () {
|
||||
return epubjs;
|
||||
});
|
||||
|
||||
// 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;
|
||||
});
|
||||
// libjass
|
||||
var libjass = require("libjass");
|
||||
require("libjass/libjass.css");
|
||||
_define("libjass", function() { return libjass; });
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for controlling user parental control from.
|
||||
* @module components/accessSchedule/accessSchedule
|
||||
*/
|
||||
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import datetime from 'datetime';
|
||||
import globalize from 'globalize';
|
||||
import 'emby-select';
|
||||
import 'paper-icon-button-light';
|
||||
import 'formDialogStyle';
|
||||
|
||||
function getDisplayTime(hours) {
|
||||
let minutes = 0;
|
||||
const pct = hours % 1;
|
||||
|
||||
if (pct) {
|
||||
minutes = parseInt(60 * pct);
|
||||
}
|
||||
|
||||
return datetime.getDisplayTime(new Date(2000, 1, 1, hours, minutes, 0, 0));
|
||||
}
|
||||
|
||||
function populateHours(context) {
|
||||
let html = '';
|
||||
|
||||
for (let i = 0; i < 24; i++) {
|
||||
html += `<option value="${i}">${getDisplayTime(i)}</option>`;
|
||||
}
|
||||
|
||||
html += `<option value="24">${getDisplayTime(0)}</option>`;
|
||||
context.querySelector('#selectStart').innerHTML = html;
|
||||
context.querySelector('#selectEnd').innerHTML = html;
|
||||
}
|
||||
|
||||
function loadSchedule(context, {DayOfWeek, StartHour, EndHour}) {
|
||||
context.querySelector('#selectDay').value = DayOfWeek || 'Sunday';
|
||||
context.querySelector('#selectStart').value = StartHour || 0;
|
||||
context.querySelector('#selectEnd').value = EndHour || 0;
|
||||
}
|
||||
|
||||
function submitSchedule(context, options) {
|
||||
const updatedSchedule = {
|
||||
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'));
|
||||
}
|
||||
|
||||
context.submitted = true;
|
||||
options.schedule = Object.assign(options.schedule, updatedSchedule);
|
||||
dialogHelper.close(context);
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// TODO: remove require
|
||||
require(['text!./components/accessSchedule/accessSchedule.template.html'], template => {
|
||||
const dlg = dialogHelper.createDialog({
|
||||
removeOnClose: true,
|
||||
size: 'small'
|
||||
});
|
||||
dlg.classList.add('formDialog');
|
||||
let html = '';
|
||||
html += globalize.translateDocument(template);
|
||||
dlg.innerHTML = html;
|
||||
populateHours(dlg);
|
||||
loadSchedule(dlg, options.schedule);
|
||||
dialogHelper.open(dlg);
|
||||
dlg.addEventListener('close', () => {
|
||||
if (dlg.submitted) {
|
||||
resolve(options.schedule);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
dlg.querySelector('.btnCancel').addEventListener('click', () => {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
dlg.querySelector('form').addEventListener('submit', event => {
|
||||
submitSchedule(dlg, options);
|
||||
event.preventDefault();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
51
src/components/accessschedule/accessschedule.js
Normal file
51
src/components/accessschedule/accessschedule.js
Normal file
@@ -0,0 +1,51 @@
|
||||
define(["dialogHelper", "datetime", "emby-select", "paper-icon-button-light", "formDialogStyle"], function(dialogHelper, datetime) {
|
||||
"use strict";
|
||||
|
||||
function getDisplayTime(hours) {
|
||||
var minutes = 0,
|
||||
pct = hours % 1;
|
||||
return pct && (minutes = parseInt(60 * pct)), datetime.getDisplayTime(new Date(2e3, 1, 1, hours, minutes, 0, 0))
|
||||
}
|
||||
|
||||
function populateHours(context) {
|
||||
for (var html = "", i = 0; i < 24; i++) html += '<option value="' + i + '">' + getDisplayTime(i) + "</option>";
|
||||
html += '<option value="24">' + getDisplayTime(0) + "</option>", 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
|
||||
}
|
||||
|
||||
function submitSchedule(context, options) {
|
||||
var updatedSchedule = {
|
||||
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"));
|
||||
context.submitted = !0, options.schedule = Object.assign(options.schedule, updatedSchedule), dialogHelper.close(context)
|
||||
}
|
||||
return {
|
||||
show: function(options) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var xhr = new XMLHttpRequest;
|
||||
xhr.open("GET", "components/accessschedule/accessschedule.template.html", !0), xhr.onload = function(e) {
|
||||
var template = this.response,
|
||||
dlg = dialogHelper.createDialog({
|
||||
removeOnClose: !0,
|
||||
size: "small"
|
||||
});
|
||||
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.submitted ? resolve(options.schedule) : reject()
|
||||
}), dlg.querySelector(".btnCancel").addEventListener("click", function(e) {
|
||||
dialogHelper.close(dlg)
|
||||
}), dlg.querySelector("form").addEventListener("submit", function(e) {
|
||||
return submitSchedule(dlg, options), e.preventDefault(), !1
|
||||
})
|
||||
}, xhr.send()
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,7 +1,5 @@
|
||||
<div class="formDialogHeader">
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" title="${LabelPrevious}" tabindex="-1">
|
||||
<span class="material-icons arrow_back" aria-hidden="true"></span>
|
||||
</button>
|
||||
<button is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1"><i class="md-icon"></i></button>
|
||||
<h3 class="formDialogHeaderTitle">
|
||||
${HeaderAccessSchedule}
|
||||
</h3>
|
||||
@@ -38,4 +36,4 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,340 +0,0 @@
|
||||
import dialogHelper from 'dialogHelper';
|
||||
import layoutManager from 'layoutManager';
|
||||
import globalize from 'globalize';
|
||||
import dom from 'dom';
|
||||
import 'emby-button';
|
||||
import 'css!./actionSheet';
|
||||
import 'material-icons';
|
||||
import 'scrollStyles';
|
||||
import 'listViewStyle';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
||||
let results = [];
|
||||
|
||||
if (!document) {
|
||||
return results;
|
||||
}
|
||||
|
||||
for (const elem of elems) {
|
||||
let box = elem.getBoundingClientRect();
|
||||
|
||||
results.push({
|
||||
top: box.top,
|
||||
left: box.left,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
});
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
|
||||
const windowSize = dom.getWindowSize();
|
||||
const windowHeight = windowSize.innerHeight;
|
||||
const windowWidth = windowSize.innerWidth;
|
||||
|
||||
let pos = getOffsets([options.positionTo])[0];
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
}
|
||||
|
||||
pos.left += (pos.width || 0) / 2;
|
||||
|
||||
const height = dlg.offsetHeight || 300;
|
||||
const width = dlg.offsetWidth || 160;
|
||||
|
||||
// Account for popup size
|
||||
pos.top -= height / 2;
|
||||
pos.left -= width / 2;
|
||||
|
||||
// Avoid showing too close to the bottom
|
||||
const overflowX = pos.left + width - windowWidth;
|
||||
const overflowY = pos.top + height - windowHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
pos.left -= (overflowX + 20);
|
||||
}
|
||||
if (overflowY > 0) {
|
||||
pos.top -= (overflowY + 20);
|
||||
}
|
||||
|
||||
pos.top += (options.offsetTop || 0);
|
||||
pos.left += (options.offsetLeft || 0);
|
||||
|
||||
// Do some boundary checking
|
||||
pos.top = Math.max(pos.top, 10);
|
||||
pos.left = Math.max(pos.left, 10);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
const fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
export function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
let dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
let isFullscreen;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
isFullscreen = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
|
||||
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
|
||||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
|
||||
let dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
} else {
|
||||
dlg.classList.add('actionsheet-not-fullscreen');
|
||||
}
|
||||
|
||||
dlg.classList.add('actionSheet');
|
||||
|
||||
if (options.dialogClass) {
|
||||
dlg.classList.add(options.dialogClass);
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
const scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
|
||||
let style = '';
|
||||
|
||||
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
|
||||
if (options.items.length > 20) {
|
||||
const minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
|
||||
style += 'min-width:' + minWidth + 'px;';
|
||||
}
|
||||
|
||||
let renderIcon = false;
|
||||
let icons = [];
|
||||
let itemIcon;
|
||||
for (const item of options.items) {
|
||||
|
||||
itemIcon = item.icon || (item.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
renderIcon = true;
|
||||
}
|
||||
icons.push(itemIcon || '');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
html += `<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1">
|
||||
<span class="material-icons arrow_back"></span>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
|
||||
const center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
|
||||
|
||||
if (center || layoutManager.tv) {
|
||||
html += '<div class="actionSheetContent actionSheetContent-centered">';
|
||||
} else {
|
||||
html += '<div class="actionSheetContent">';
|
||||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">' + options.title + '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
html += '<p class="actionSheetText">' + options.text + '</p>';
|
||||
}
|
||||
|
||||
let scrollerClassName = 'actionSheetScroller';
|
||||
if (layoutManager.tv) {
|
||||
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
|
||||
}
|
||||
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
|
||||
|
||||
let menuItemClass = 'listItem listItem-button actionSheetMenuItem';
|
||||
|
||||
if (options.border || options.shaded) {
|
||||
menuItemClass += ' listItem-border';
|
||||
}
|
||||
|
||||
if (options.menuItemClass) {
|
||||
menuItemClass += ' ' + options.menuItemClass;
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
menuItemClass += ' listItem-focusscale';
|
||||
}
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
menuItemClass += ' actionsheet-xlargeFont';
|
||||
}
|
||||
|
||||
// 'options.items' is HTMLOptionsCollection, so no fancy loops
|
||||
for (let i = 0; i < options.items.length; i++) {
|
||||
const item = options.items[i];
|
||||
|
||||
if (item.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
const autoFocus = item.selected && layoutManager.tv ? ' autoFocus' : '';
|
||||
|
||||
// Check for null in case int 0 was passed in
|
||||
const optionId = item.id == null || item.id === '' ? item.value : item.id;
|
||||
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
|
||||
|
||||
itemIcon = icons[i];
|
||||
|
||||
if (itemIcon) {
|
||||
html += `<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons ${itemIcon}"></span>`;
|
||||
} else if (renderIcon && !center) {
|
||||
html += '<span class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent material-icons check" style="visibility:hidden;"></span>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody actionsheetListItemBody">';
|
||||
|
||||
html += '<div class="listItemBodyText actionSheetItemText">';
|
||||
html += (item.name || item.textContent || item.innerText);
|
||||
html += '</div>';
|
||||
|
||||
if (item.secondaryText) {
|
||||
html += `<div class="listItemBodyText secondary">${item.secondaryText}</div>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (item.asideText) {
|
||||
html += `<div class="listItemAside actionSheetItemAsideText">${item.asideText}</div>`;
|
||||
}
|
||||
|
||||
html += '</button>';
|
||||
}
|
||||
|
||||
if (options.showCancel) {
|
||||
html += '<div class="buttons">';
|
||||
html += `<button is="emby-button" type="button" class="btnCloseActionSheet">${globalize.translate('ButtonCancel')}</button>`;
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
let btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
btnCloseActionSheet.addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
let selectedId;
|
||||
|
||||
let timeout;
|
||||
if (options.timeout) {
|
||||
timeout = setTimeout(function () {
|
||||
dialogHelper.close(dlg);
|
||||
}, options.timeout);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
let isResolved;
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
const actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
|
||||
if (!isResolved) {
|
||||
if (selectedId != null) {
|
||||
if (options.callback) {
|
||||
options.callback(selectedId);
|
||||
}
|
||||
|
||||
resolve(selectedId);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
const pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
|
||||
|
||||
if (pos) {
|
||||
dlg.style.position = 'fixed';
|
||||
dlg.style.margin = 0;
|
||||
dlg.style.left = pos.left + 'px';
|
||||
dlg.style.top = pos.top + 'px';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
@@ -4,7 +4,7 @@
|
||||
padding: 0;
|
||||
border: none;
|
||||
max-height: 84%;
|
||||
border-radius: 0.1em !important;
|
||||
border-radius: .1em !important;
|
||||
}
|
||||
|
||||
.actionsheet-not-fullscreen {
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
.actionSheetContent {
|
||||
margin: 0 !important;
|
||||
padding: 0.4em 0 !important;
|
||||
padding: .4em 0 !important;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@@ -37,15 +37,14 @@
|
||||
box-shadow: none;
|
||||
flex-shrink: 0;
|
||||
border-radius: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.actionSheetMenuItem:focus {
|
||||
transform: none !important;
|
||||
}
|
||||
.actionSheetMenuItem:focus {
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.actionsheetListItemBody {
|
||||
padding: 0.4em 1em 0.4em 0.6em !important;
|
||||
padding: .4em 1em .4em .6em !important;
|
||||
}
|
||||
|
||||
.actionSheetItemText {
|
||||
@@ -59,13 +58,13 @@
|
||||
}
|
||||
|
||||
.actionSheetItemAsideText {
|
||||
opacity: 0.7;
|
||||
opacity: .7;
|
||||
font-size: 90%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
flex-shrink: 0;
|
||||
margin-left: 5em;
|
||||
margin-right: 0.5em;
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.actionSheetScroller {
|
||||
@@ -83,14 +82,14 @@
|
||||
}
|
||||
|
||||
.actionsheetDivider {
|
||||
height: 0.07em;
|
||||
margin: 0.25em 0;
|
||||
height: .07em;
|
||||
margin: .25em 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.actionSheetTitle {
|
||||
margin: 0.6em 0 0.7em !important;
|
||||
padding: 0 0.9em;
|
||||
margin: .6em 0 .7em !important;
|
||||
padding: 0 .9em;
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
@@ -100,16 +99,16 @@
|
||||
}
|
||||
|
||||
.actionsheetMenuItemIcon {
|
||||
margin: 0 0.85em 0 0.45em !important;
|
||||
margin: 0 .85em 0 .45em !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.actionsheet-xlargeFont {
|
||||
font-size: 112% !important;
|
||||
font-size: 112%!important;
|
||||
}
|
||||
|
||||
.btnCloseActionSheet {
|
||||
position: fixed;
|
||||
top: 0.75em;
|
||||
left: 0.5em;
|
||||
top: .75em;
|
||||
left: .5em;
|
||||
}
|
||||
359
src/components/actionsheet/actionsheet.js
Normal file
359
src/components/actionsheet/actionsheet.js
Normal file
@@ -0,0 +1,359 @@
|
||||
define(['dialogHelper', 'layoutManager', 'globalize', 'browser', 'dom', 'emby-button', 'css!./actionsheet', 'material-icons', 'scrollStyles', 'listViewStyle'], function (dialogHelper, layoutManager, globalize, browser, dom) {
|
||||
'use strict';
|
||||
|
||||
function getOffsets(elems) {
|
||||
|
||||
var doc = document;
|
||||
var results = [];
|
||||
|
||||
if (!doc) {
|
||||
return results;
|
||||
}
|
||||
|
||||
var box;
|
||||
var elem;
|
||||
|
||||
for (var i = 0, length = elems.length; i < length; i++) {
|
||||
|
||||
elem = elems[i];
|
||||
// Support: BlackBerry 5, iOS 3 (original iPhone)
|
||||
// If we don't have gBCR, just use 0,0 rather than error
|
||||
if (elem.getBoundingClientRect) {
|
||||
box = elem.getBoundingClientRect();
|
||||
} else {
|
||||
box = { top: 0, left: 0 };
|
||||
}
|
||||
|
||||
results[i] = {
|
||||
top: box.top,
|
||||
left: box.left,
|
||||
width: box.width,
|
||||
height: box.height
|
||||
};
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function getPosition(options, dlg) {
|
||||
|
||||
var windowSize = dom.getWindowSize();
|
||||
var windowHeight = windowSize.innerHeight;
|
||||
var windowWidth = windowSize.innerWidth;
|
||||
|
||||
var pos = getOffsets([options.positionTo])[0];
|
||||
|
||||
if (options.positionY !== 'top') {
|
||||
pos.top += (pos.height || 0) / 2;
|
||||
}
|
||||
|
||||
pos.left += (pos.width || 0) / 2;
|
||||
|
||||
var height = dlg.offsetHeight || 300;
|
||||
var width = dlg.offsetWidth || 160;
|
||||
|
||||
// Account for popup size
|
||||
pos.top -= height / 2;
|
||||
pos.left -= width / 2;
|
||||
|
||||
// Avoid showing too close to the bottom
|
||||
var overflowX = pos.left + width - windowWidth;
|
||||
var overflowY = pos.top + height - windowHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
pos.left -= (overflowX + 20);
|
||||
}
|
||||
if (overflowY > 0) {
|
||||
pos.top -= (overflowY + 20);
|
||||
}
|
||||
|
||||
pos.top += (options.offsetTop || 0);
|
||||
pos.left += (options.offsetLeft || 0);
|
||||
|
||||
// Do some boundary checking
|
||||
pos.top = Math.max(pos.top, 10);
|
||||
pos.left = Math.max(pos.left, 10);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
require(['scrollHelper'], function (scrollHelper) {
|
||||
var fn = on ? 'on' : 'off';
|
||||
scrollHelper.centerFocus[fn](elem, horiz);
|
||||
});
|
||||
}
|
||||
|
||||
function show(options) {
|
||||
|
||||
// items
|
||||
// positionTo
|
||||
// showCancel
|
||||
// title
|
||||
var dialogOptions = {
|
||||
removeOnClose: true,
|
||||
enableHistory: options.enableHistory,
|
||||
scrollY: false
|
||||
};
|
||||
|
||||
var backButton = false;
|
||||
var isFullscreen;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
dialogOptions.size = 'fullscreen';
|
||||
isFullscreen = true;
|
||||
backButton = true;
|
||||
dialogOptions.autoFocus = true;
|
||||
} else {
|
||||
|
||||
dialogOptions.modal = false;
|
||||
dialogOptions.entryAnimation = options.entryAnimation;
|
||||
dialogOptions.exitAnimation = options.exitAnimation;
|
||||
dialogOptions.entryAnimationDuration = options.entryAnimationDuration || 140;
|
||||
dialogOptions.exitAnimationDuration = options.exitAnimationDuration || 100;
|
||||
dialogOptions.autoFocus = false;
|
||||
}
|
||||
|
||||
var dlg = dialogHelper.createDialog(dialogOptions);
|
||||
|
||||
if (isFullscreen) {
|
||||
dlg.classList.add('actionsheet-fullscreen');
|
||||
} else {
|
||||
dlg.classList.add('actionsheet-not-fullscreen');
|
||||
}
|
||||
|
||||
dlg.classList.add('actionSheet');
|
||||
|
||||
if (options.dialogClass) {
|
||||
dlg.classList.add(options.dialogClass);
|
||||
}
|
||||
|
||||
var html = '';
|
||||
|
||||
var scrollClassName = layoutManager.tv ? 'scrollY smoothScrollY hiddenScrollY' : 'scrollY';
|
||||
var style = '';
|
||||
|
||||
// Admittedly a hack but right now the scrollbar is being factored into the width which is causing truncation
|
||||
if (options.items.length > 20) {
|
||||
var minWidth = dom.getWindowSize().innerWidth >= 300 ? 240 : 200;
|
||||
style += "min-width:" + minWidth + "px;";
|
||||
}
|
||||
|
||||
var i, length, option;
|
||||
var renderIcon = false;
|
||||
var icons = [];
|
||||
var itemIcon;
|
||||
for (i = 0, length = options.items.length; i < length; i++) {
|
||||
|
||||
option = options.items[i];
|
||||
|
||||
itemIcon = option.icon || (option.selected ? 'check' : null);
|
||||
|
||||
if (itemIcon) {
|
||||
renderIcon = true;
|
||||
}
|
||||
icons.push(itemIcon || '');
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
html += '<button is="paper-icon-button-light" class="btnCloseActionSheet hide-mouse-idle-tv" tabindex="-1"><i class="md-icon"></i></button>';
|
||||
}
|
||||
|
||||
// If any items have an icon, give them all an icon just to make sure they're all lined up evenly
|
||||
var center = options.title && (!renderIcon /*|| itemsWithIcons.length != options.items.length*/);
|
||||
|
||||
if (center || layoutManager.tv) {
|
||||
html += '<div class="actionSheetContent actionSheetContent-centered">';
|
||||
} else {
|
||||
html += '<div class="actionSheetContent">';
|
||||
}
|
||||
|
||||
if (options.title) {
|
||||
|
||||
html += '<h1 class="actionSheetTitle">';
|
||||
html += options.title;
|
||||
html += '</h1>';
|
||||
}
|
||||
if (options.text) {
|
||||
html += '<p class="actionSheetText">';
|
||||
html += options.text;
|
||||
html += '</p>';
|
||||
}
|
||||
|
||||
var scrollerClassName = 'actionSheetScroller';
|
||||
if (layoutManager.tv) {
|
||||
scrollerClassName += ' actionSheetScroller-tv focuscontainer-x focuscontainer-y';
|
||||
}
|
||||
html += '<div class="' + scrollerClassName + ' ' + scrollClassName + '" style="' + style + '">';
|
||||
|
||||
var menuItemClass = 'listItem listItem-button actionSheetMenuItem';
|
||||
|
||||
if (options.border || options.shaded) {
|
||||
menuItemClass += ' listItem-border';
|
||||
}
|
||||
|
||||
if (options.menuItemClass) {
|
||||
menuItemClass += ' ' + options.menuItemClass;
|
||||
}
|
||||
|
||||
if (layoutManager.tv) {
|
||||
menuItemClass += ' listItem-focusscale';
|
||||
}
|
||||
|
||||
if (layoutManager.mobile) {
|
||||
menuItemClass += ' actionsheet-xlargeFont';
|
||||
}
|
||||
|
||||
for (i = 0, length = options.items.length; i < length; i++) {
|
||||
|
||||
option = options.items[i];
|
||||
|
||||
if (option.divider) {
|
||||
|
||||
html += '<div class="actionsheetDivider"></div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
var autoFocus = option.selected && layoutManager.tv ? ' autoFocus' : '';
|
||||
|
||||
// Check for null in case int 0 was passed in
|
||||
var optionId = option.id == null || option.id === '' ? option.value : option.id;
|
||||
html += '<button' + autoFocus + ' is="emby-button" type="button" class="' + menuItemClass + '" data-id="' + optionId + '">';
|
||||
|
||||
itemIcon = icons[i];
|
||||
|
||||
if (itemIcon) {
|
||||
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon">' + itemIcon + '</i>';
|
||||
}
|
||||
else if (renderIcon && !center) {
|
||||
html += '<i class="actionsheetMenuItemIcon listItemIcon listItemIcon-transparent md-icon" style="visibility:hidden;">check</i>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody actionsheetListItemBody">';
|
||||
|
||||
html += '<div class="listItemBodyText actionSheetItemText">';
|
||||
html += (option.name || option.textContent || option.innerText);
|
||||
html += '</div>';
|
||||
|
||||
if (option.secondaryText) {
|
||||
html += '<div class="listItemBodyText secondary">';
|
||||
html += option.secondaryText;
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
if (option.asideText) {
|
||||
html += '<div class="listItemAside actionSheetItemAsideText">';
|
||||
html += option.asideText;
|
||||
html += '</div>';
|
||||
}
|
||||
|
||||
html += '</button>';
|
||||
}
|
||||
|
||||
if (options.showCancel) {
|
||||
html += '<div class="buttons">';
|
||||
html += '<button is="emby-button" type="button" class="btnCloseActionSheet">' + globalize.translate('ButtonCancel') + '</button>';
|
||||
html += '</div>';
|
||||
}
|
||||
html += '</div>';
|
||||
|
||||
dlg.innerHTML = html;
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, true);
|
||||
}
|
||||
|
||||
var btnCloseActionSheet = dlg.querySelector('.btnCloseActionSheet');
|
||||
if (btnCloseActionSheet) {
|
||||
dlg.querySelector('.btnCloseActionSheet').addEventListener('click', function () {
|
||||
dialogHelper.close(dlg);
|
||||
});
|
||||
}
|
||||
|
||||
// Seeing an issue in some non-chrome browsers where this is requiring a double click
|
||||
//var eventName = browser.firefox ? 'mousedown' : 'click';
|
||||
var selectedId;
|
||||
|
||||
var timeout;
|
||||
if (options.timeout) {
|
||||
timeout = setTimeout(function () {
|
||||
dialogHelper.close(dlg);
|
||||
}, options.timeout);
|
||||
}
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
|
||||
var isResolved;
|
||||
|
||||
dlg.addEventListener('click', function (e) {
|
||||
|
||||
var actionSheetMenuItem = dom.parentWithClass(e.target, 'actionSheetMenuItem');
|
||||
|
||||
if (actionSheetMenuItem) {
|
||||
selectedId = actionSheetMenuItem.getAttribute('data-id');
|
||||
|
||||
if (options.resolveOnClick) {
|
||||
|
||||
if (options.resolveOnClick.indexOf) {
|
||||
|
||||
if (options.resolveOnClick.indexOf(selectedId) !== -1) {
|
||||
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
resolve(selectedId);
|
||||
isResolved = true;
|
||||
}
|
||||
}
|
||||
|
||||
dialogHelper.close(dlg);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
dlg.addEventListener('close', function () {
|
||||
|
||||
if (layoutManager.tv) {
|
||||
centerFocus(dlg.querySelector('.actionSheetScroller'), false, false);
|
||||
}
|
||||
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
|
||||
if (!isResolved) {
|
||||
if (selectedId != null) {
|
||||
if (options.callback) {
|
||||
options.callback(selectedId);
|
||||
}
|
||||
|
||||
resolve(selectedId);
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogHelper.open(dlg);
|
||||
|
||||
var pos = options.positionTo && dialogOptions.size !== 'fullscreen' ? getPosition(options, dlg) : null;
|
||||
|
||||
if (pos) {
|
||||
dlg.style.position = 'fixed';
|
||||
dlg.style.margin = 0;
|
||||
dlg.style.left = pos.left + 'px';
|
||||
dlg.style.top = pos.top + 'px';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
show: show
|
||||
};
|
||||
});
|
||||
3
src/components/actionsheet/package.json
Normal file
3
src/components/actionsheet/package.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"main": "actionsheet.js"
|
||||
}
|
||||
@@ -1,160 +1,96 @@
|
||||
define(['events', 'globalize', 'dom', 'date-fns', 'dfnshelper', 'userSettings', 'serverNotifications', 'connectionManager', 'emby-button', 'listViewStyle'], function (events, globalize, dom, datefns, dfnshelper, userSettings, serverNotifications, connectionManager) {
|
||||
'use strict';
|
||||
define(["events", "globalize", "dom", "datetime", "userSettings", "serverNotifications", "connectionManager", "emby-button", "listViewStyle"], function(events, globalize, dom, datetime, userSettings, serverNotifications, connectionManager) {
|
||||
"use strict";
|
||||
|
||||
function getEntryHtml(entry, apiClient) {
|
||||
var html = '';
|
||||
var html = "";
|
||||
html += '<div class="listItem listItem-border">';
|
||||
var color = '#00a4dc';
|
||||
var icon = 'notifications';
|
||||
|
||||
if ('Error' == entry.Severity || 'Fatal' == entry.Severity || 'Warn' == entry.Severity) {
|
||||
color = '#cc0000';
|
||||
icon = 'notification_important';
|
||||
var color = "#00a4dc";
|
||||
var icon = "notifications";
|
||||
if ("Error" == entry.Severity || "Fatal" == entry.Severity || "Warn" == entry.Severity) {
|
||||
color = "#cc0000";
|
||||
icon = "notification_important";
|
||||
}
|
||||
|
||||
if (entry.UserId && entry.UserPrimaryImageTag) {
|
||||
html += '<span class="listItemIcon material-icons dvr" style="width:2em!important;height:2em!important;padding:0;color:transparent;background-color:' + color + ";background-image:url('" + apiClient.getUserImageUrl(entry.UserId, {
|
||||
type: 'Primary',
|
||||
tag: entry.UserPrimaryImageTag
|
||||
}) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\"></span>";
|
||||
html += '<i class="listItemIcon md-icon" style="width:2em!important;height:2em!important;padding:0;color:transparent;background-color:' + color + ";background-image:url('" + apiClient.getUserImageUrl(entry.UserId, {
|
||||
type: "Primary",
|
||||
tag: entry.UserPrimaryImageTag,
|
||||
height: 40
|
||||
}) + "');background-repeat:no-repeat;background-position:center center;background-size: cover;\">dvr</i>"
|
||||
} else {
|
||||
html += '<span class="listItemIcon material-icons ' + icon + '" style="background-color:' + color + '"></span>';
|
||||
html += '<i class="listItemIcon md-icon" style="background-color:' + color + '">' + icon + '</i>';
|
||||
}
|
||||
|
||||
html += '<div class="listItemBody three-line">';
|
||||
html += '<div class="listItemBodyText">';
|
||||
html += entry.Name;
|
||||
html += '</div>';
|
||||
html += '<div class="listItemBodyText secondary">';
|
||||
html += datefns.formatRelative(Date.parse(entry.Date), Date.parse(new Date()), { locale: dfnshelper.getLocale() });
|
||||
html += '</div>';
|
||||
html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">';
|
||||
html += entry.ShortOverview || '';
|
||||
html += '</div>';
|
||||
html += '</div>';
|
||||
|
||||
if (entry.Overview) {
|
||||
html += `<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="${entry.Id}" title="${globalize.translate('Info')}">
|
||||
<span class="material-icons info"></span>
|
||||
</button>`;
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
html += '<div class="listItemBody three-line">', html += '<div class="listItemBodyText">', html += entry.Name, html += "</div>", html += '<div class="listItemBodyText secondary">';
|
||||
var date = datetime.parseISO8601Date(entry.Date, !0);
|
||||
return html += datetime.toLocaleString(date).toLowerCase(), html += "</div>", html += '<div class="listItemBodyText secondary listItemBodyText-nowrap">', html += entry.ShortOverview || "", html += "</div>", html += "</div>", entry.Overview && (html += '<button type="button" is="paper-icon-button-light" class="btnEntryInfo" data-id="' + entry.Id + '" title="' + globalize.translate("Info") + '"><i class="md-icon">info</i></button>'), html += "</div>"
|
||||
}
|
||||
|
||||
function renderList(elem, apiClient, result, startIndex, limit) {
|
||||
elem.innerHTML = result.Items.map(function (i) {
|
||||
return getEntryHtml(i, apiClient);
|
||||
}).join('');
|
||||
elem.innerHTML = result.Items.map(function(i) {
|
||||
return getEntryHtml(i, apiClient)
|
||||
}).join("")
|
||||
}
|
||||
|
||||
function reloadData(instance, elem, apiClient, startIndex, limit) {
|
||||
if (null == startIndex) {
|
||||
startIndex = parseInt(elem.getAttribute('data-activitystartindex') || '0');
|
||||
}
|
||||
|
||||
limit = limit || parseInt(elem.getAttribute('data-activitylimit') || '7');
|
||||
var minDate = new Date();
|
||||
var hasUserId = 'false' !== elem.getAttribute('data-useractivity');
|
||||
|
||||
if (hasUserId) {
|
||||
minDate.setTime(minDate.getTime() - 24 * 60 * 60 * 1000); // one day back
|
||||
} else {
|
||||
minDate.setTime(minDate.getTime() - 7 * 24 * 60 * 60 * 1000); // one week back
|
||||
}
|
||||
|
||||
ApiClient.getJSON(ApiClient.getUrl('System/ActivityLog/Entries', {
|
||||
null == startIndex && (startIndex = parseInt(elem.getAttribute("data-activitystartindex") || "0")), limit = limit || parseInt(elem.getAttribute("data-activitylimit") || "7");
|
||||
var minDate = new Date,
|
||||
hasUserId = "false" !== elem.getAttribute("data-useractivity");
|
||||
hasUserId ? minDate.setTime(minDate.getTime() - 864e5) : minDate.setTime(minDate.getTime() - 6048e5), 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);
|
||||
if (!startIndex) {
|
||||
var activityContainer = dom.parentWithClass(elem, 'activityContainer');
|
||||
|
||||
if (activityContainer) {
|
||||
if (result.Items.length) {
|
||||
activityContainer.classList.remove('hide');
|
||||
} else {
|
||||
activityContainer.classList.add('hide');
|
||||
}
|
||||
}
|
||||
})).then(function(result) {
|
||||
if (elem.setAttribute("data-activitystartindex", startIndex), elem.setAttribute("data-activitylimit", limit), !startIndex) {
|
||||
var activityContainer = dom.parentWithClass(elem, "activityContainer");
|
||||
activityContainer && (result.Items.length ? activityContainer.classList.remove("hide") : activityContainer.classList.add("hide"))
|
||||
}
|
||||
|
||||
instance.items = result.Items;
|
||||
renderList(elem, apiClient, result, startIndex, limit);
|
||||
});
|
||||
instance.items = result.Items, renderList(elem, apiClient, result, startIndex, limit)
|
||||
})
|
||||
}
|
||||
|
||||
function onActivityLogUpdate(e, apiClient, data) {
|
||||
var options = this.options;
|
||||
|
||||
if (options && options.serverId === apiClient.serverId()) {
|
||||
reloadData(this, options.element, apiClient);
|
||||
}
|
||||
options && options.serverId === apiClient.serverId() && reloadData(this, options.element, apiClient)
|
||||
}
|
||||
|
||||
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 items = this.items;
|
||||
|
||||
var id = btnEntryInfo.getAttribute("data-id"),
|
||||
items = this.items;
|
||||
if (items) {
|
||||
var item = items.filter(function (i) {
|
||||
return i.Id.toString() === id;
|
||||
var item = items.filter(function(i) {
|
||||
return i.Id.toString() === id
|
||||
})[0];
|
||||
|
||||
if (item) {
|
||||
showItemOverview(item);
|
||||
}
|
||||
item && showItemOverview(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showItemOverview(item) {
|
||||
require(['alert'], function (alert) {
|
||||
require(["alert"], function(alert) {
|
||||
alert({
|
||||
text: item.Overview
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
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');
|
||||
this.updateFn = onUpdate, events.on(serverNotifications, "ActivityLogEntry", onUpdate), apiClient.sendMessage("ActivityLogEntryStart", "0,1500")
|
||||
}
|
||||
|
||||
ActivityLog.prototype.destroy = function () {
|
||||
return 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);
|
||||
}
|
||||
|
||||
this.items = null;
|
||||
this.options = null;
|
||||
};
|
||||
|
||||
return ActivityLog;
|
||||
onUpdate && events.off(serverNotifications, "ActivityLogEntry", onUpdate), this.items = null, this.options = null
|
||||
}, ActivityLog
|
||||
});
|
||||
|
||||
@@ -35,11 +35,11 @@ define(['browser', 'dialog', 'globalize'], function (browser, dialog, globalize)
|
||||
if (result === 'ok') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
|
||||
return Promise.reject();
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
});
|
||||
});
|
||||
@@ -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;
|
||||
});
|
||||
});
|
||||
@@ -50,7 +50,9 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
|
||||
var vertical = element.classList.contains('alphaPicker-vertical');
|
||||
|
||||
if (!vertical) {
|
||||
if (vertical) {
|
||||
|
||||
} else {
|
||||
element.classList.add('focuscontainer-x');
|
||||
}
|
||||
|
||||
@@ -67,7 +69,8 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
|
||||
html += '<div class="' + rowClassName + '">';
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon space_bar"></span></button>';
|
||||
// space_bar icon
|
||||
html += '<button data-value=" " is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
} else {
|
||||
letters = ['#'];
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
@@ -77,7 +80,8 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
html += mapLetters(letters, vertical).join('');
|
||||
|
||||
if (options.mode === 'keyboard') {
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><span class="material-icons alphaPickerButtonIcon backspace"></span></button>';
|
||||
// backspace icon
|
||||
html += '<button data-value="backspace" is="paper-icon-button-light" class="' + alphaPickerButtonClassName + '"><i class="md-icon alphaPickerButtonIcon"></i></button>';
|
||||
html += '</div>';
|
||||
|
||||
letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
|
||||
@@ -132,7 +136,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
|
||||
@@ -226,8 +230,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
AlphaPicker.prototype.value = function (value, applyValue) {
|
||||
|
||||
var element = this.options.element;
|
||||
var btn;
|
||||
var selected;
|
||||
var btn, selected;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (value != null) {
|
||||
@@ -241,7 +244,7 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
try {
|
||||
btn = element.querySelector('.alphaPickerButton[data-value=\'' + value + '\']');
|
||||
} catch (err) {
|
||||
console.error('error in querySelector: ' + err);
|
||||
console.log('Error in querySelector: ' + err);
|
||||
}
|
||||
|
||||
if (btn && btn !== selected) {
|
||||
@@ -262,7 +265,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
|
||||
@@ -318,4 +321,4 @@ define(['focusManager', 'layoutManager', 'dom', 'css!./style.css', 'paper-icon-b
|
||||
};
|
||||
|
||||
return AlphaPicker;
|
||||
});
|
||||
});
|
||||
@@ -35,15 +35,16 @@
|
||||
font-size: inherit;
|
||||
min-width: initial;
|
||||
margin: 0;
|
||||
padding: 0.1em 0.4em;
|
||||
padding: .1em .4em;
|
||||
width: auto;
|
||||
border-radius: 0.1em;
|
||||
border-radius: .1em;
|
||||
font-weight: normal;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
@media all and (max-height: 50em) {
|
||||
|
||||
.alphaPicker-fixed {
|
||||
bottom: 5em;
|
||||
}
|
||||
@@ -55,12 +56,14 @@
|
||||
}
|
||||
|
||||
@media all and (max-height: 49em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 94%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height: 44em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 90%;
|
||||
}
|
||||
@@ -72,12 +75,14 @@
|
||||
}
|
||||
|
||||
@media all and (max-height: 37em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 82%;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (max-height: 32em) {
|
||||
|
||||
.alphaPicker-vertical {
|
||||
font-size: 74%;
|
||||
}
|
||||
@@ -107,17 +112,27 @@
|
||||
bottom: 1%;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-left {
|
||||
left: .4em;
|
||||
}
|
||||
|
||||
.alphaPicker-fixed-right {
|
||||
right: 0.4em;
|
||||
right: .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;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user