mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge branch 'master' into audio-normalization
This commit is contained in:
commit
8bfc387b85
320 changed files with 55219 additions and 49479 deletions
|
@ -6,7 +6,6 @@
|
|||
"./dist/libraries/pdf.worker.js",
|
||||
"./dist/libraries/worker-bundle.js",
|
||||
"./dist/libraries/wasm-gen/libarchive.js",
|
||||
"./dist/node_modules.@jellyfin.libass-wasm.*.chunk.js",
|
||||
"./dist/serviceworker.js"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -64,7 +64,9 @@ module.exports = {
|
|||
'no-var': ['error'],
|
||||
'no-void': ['error', { 'allowAsStatement': true }],
|
||||
'no-warning-comments': ['warn', { 'terms': ['fixme', 'hack', 'xxx'] }],
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'one-var': ['error', 'never'],
|
||||
'operator-linebreak': ['error', 'before', { overrides: { '?': 'after', ':': 'after', '=': 'after' } }],
|
||||
'padded-blocks': ['error', 'never'],
|
||||
'prefer-const': ['error', { 'destructuring': 'all' }],
|
||||
'quotes': ['error', 'single', { 'avoidEscape': true, 'allowTemplateLiterals': false }],
|
||||
|
@ -267,7 +269,6 @@ module.exports = {
|
|||
'no-useless-constructor': ['off'],
|
||||
'@typescript-eslint/no-useless-constructor': ['error'],
|
||||
|
||||
'max-params': ['error', 7],
|
||||
'sonarjs/cognitive-complexity': ['warn']
|
||||
}
|
||||
}
|
||||
|
|
6
.github/CODEOWNERS
vendored
6
.github/CODEOWNERS
vendored
|
@ -1,6 +1,2 @@
|
|||
.ci @dkanada @EraYaN
|
||||
* @jellyfin/web
|
||||
.github @jellyfin/core
|
||||
fedora @joshuaboniface
|
||||
debian @joshuaboniface
|
||||
.copr @joshuaboniface
|
||||
deployment @joshuaboniface
|
||||
|
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
|
@ -19,13 +19,13 @@ jobs:
|
|||
language: [ 'javascript' ]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2.2.7
|
||||
uses: github/codeql-action/init@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
queries: +security-extended
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2.2.7
|
||||
uses: github/codeql-action/autobuild@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@168b99b3c22180941ae7dbdd5f5c9678ede476ba # v2.2.7
|
||||
uses: github/codeql-action/analyze@b2c19fb9a2a485599ccf4ed5d65527d94bc57226 # v2.3.0
|
||||
|
|
12
.github/workflows/commands.yml
vendored
12
.github/workflows/commands.yml
vendored
|
@ -12,13 +12,13 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Notify as seen
|
||||
uses: peter-evans/create-or-update-comment@67dcc547d311b736a8e6c5c236542148a47adc3d # v2.1.1
|
||||
uses: peter-evans/create-or-update-comment@3383acd359705b10cb1eeef05c0e88c056ea4666 # v3.0.0
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
comment-id: ${{ github.event.comment.id }}
|
||||
reactions: '+1'
|
||||
- name: Checkout the latest code
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
fetch-depth: 0
|
||||
|
@ -26,3 +26,11 @@ jobs:
|
|||
uses: cirrus-actions/rebase@b87d48154a87a85666003575337e27b8cd65f691 # 1.8
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.JF_BOT_TOKEN }}
|
||||
- name: Comment on failure
|
||||
if: failure()
|
||||
uses: peter-evans/create-or-update-comment@3383acd359705b10cb1eeef05c0e88c056ea4666 # v3.0.0
|
||||
with:
|
||||
token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
issue-number: ${{ github.event.issue.number }}
|
||||
body: |
|
||||
I'm sorry @${{ github.event.comment.user.login }}, I'm afraid I can't do that.
|
||||
|
|
8
.github/workflows/lint.yml
vendored
8
.github/workflows/lint.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
|
@ -37,7 +37,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
|
@ -58,7 +58,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
|
@ -82,7 +82,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
|
|
4
.github/workflows/repo-stale.yaml
vendored
4
.github/workflows/repo-stale.yaml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: ${{ contains(github.repository, 'jellyfin/') }}
|
||||
steps:
|
||||
- uses: actions/stale@6f05e4244c9a0b2ed3401882b05d701dd0a7289b # v7.0.0
|
||||
- uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
operations-per-run: 75
|
||||
|
@ -37,7 +37,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: ${{ contains(github.repository, 'jellyfin/') }}
|
||||
steps:
|
||||
- uses: actions/stale@6f05e4244c9a0b2ed3401882b05d701dd0a7289b # v7.0.0
|
||||
- uses: actions/stale@1160a2240286f5da8ec72b1c0816ce2481aabf84 # v8.0.0
|
||||
with:
|
||||
repo-token: ${{ secrets.JF_BOT_TOKEN }}
|
||||
operations-per-run: 75
|
||||
|
|
2
.github/workflows/tsc.yml
vendored
2
.github/workflows/tsc.yml
vendored
|
@ -13,7 +13,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
uses: actions/checkout@24cb9080177205b6e8c946b17badbe402adc938f # v3.4.0
|
||||
uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||
|
||||
- name: Setup node environment
|
||||
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c # v3.6.0
|
||||
|
|
|
@ -61,6 +61,8 @@
|
|||
- [Rob Farraher](https://github.com/farraherbg)
|
||||
- [TelepathicWalrus](https://github.com/TelepathicWalrus)
|
||||
- [Pier-Luc Ducharme](https://github.com/pl-ducharme)
|
||||
- [Anantharaju S](https://github.com/Anantharajus)
|
||||
- [Merlin Sievers](https://github.com/dann-merlin)
|
||||
|
||||
# Emby Contributors
|
||||
|
||||
|
|
|
@ -12,14 +12,7 @@ module.exports = {
|
|||
corejs: 3
|
||||
}
|
||||
],
|
||||
'@babel/preset-react',
|
||||
[
|
||||
'@babel/preset-typescript',
|
||||
{
|
||||
isTSX: true,
|
||||
allExtensions: true
|
||||
}
|
||||
]
|
||||
'@babel/preset-react'
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-class-properties',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
FROM centos:8
|
||||
FROM quay.io/centos/centos:stream8
|
||||
|
||||
# Docker build arguments
|
||||
ARG SOURCE_DIR=/jellyfin
|
||||
|
@ -12,7 +12,7 @@ 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 autoconf automake glibc-devel gcc-c++ make \
|
||||
&& yum install -y rpmdevtools git autoconf automake glibc-devel gcc-c++ make \
|
||||
&& curl -fsSL https://rpm.nodesource.com/setup_16.x | bash - \
|
||||
&& yum install -y nodejs
|
||||
|
||||
|
|
5745
package-lock.json
generated
5745
package-lock.json
generated
File diff suppressed because it is too large
Load diff
72
package.json
72
package.json
|
@ -5,24 +5,23 @@
|
|||
"repository": "https://github.com/jellyfin/jellyfin-web",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.21.0",
|
||||
"@babel/eslint-parser": "7.19.1",
|
||||
"@babel/core": "7.21.4",
|
||||
"@babel/eslint-parser": "7.21.3",
|
||||
"@babel/eslint-plugin": "7.19.1",
|
||||
"@babel/plugin-proposal-class-properties": "7.18.6",
|
||||
"@babel/plugin-proposal-private-methods": "7.18.6",
|
||||
"@babel/plugin-transform-modules-umd": "7.18.6",
|
||||
"@babel/preset-env": "7.20.2",
|
||||
"@babel/preset-env": "7.21.4",
|
||||
"@babel/preset-react": "7.18.6",
|
||||
"@babel/preset-typescript": "7.21.0",
|
||||
"@types/escape-html": "1.0.2",
|
||||
"@types/loadable__component": "5.13.4",
|
||||
"@types/lodash-es": "4.17.6",
|
||||
"@types/react": "17.0.53",
|
||||
"@types/lodash-es": "4.17.7",
|
||||
"@types/react": "17.0.58",
|
||||
"@types/react-dom": "17.0.19",
|
||||
"@typescript-eslint/eslint-plugin": "5.54.1",
|
||||
"@typescript-eslint/parser": "5.54.1",
|
||||
"@typescript-eslint/eslint-plugin": "5.58.0",
|
||||
"@typescript-eslint/parser": "5.58.0",
|
||||
"@uupaa/dynamic-import-polyfill": "1.0.2",
|
||||
"autoprefixer": "10.4.13",
|
||||
"autoprefixer": "10.4.14",
|
||||
"babel-loader": "9.1.2",
|
||||
"babel-plugin-dynamic-import-polyfill": "1.0.0",
|
||||
"clean-webpack-plugin": "4.0.0",
|
||||
|
@ -30,39 +29,39 @@
|
|||
"copy-webpack-plugin": "11.0.0",
|
||||
"cross-env": "7.0.3",
|
||||
"css-loader": "6.7.3",
|
||||
"cssnano": "5.1.15",
|
||||
"es-check": "7.1.0",
|
||||
"eslint": "8.35.0",
|
||||
"eslint-plugin-compat": "4.1.2",
|
||||
"cssnano": "6.0.0",
|
||||
"es-check": "7.1.1",
|
||||
"eslint": "8.38.0",
|
||||
"eslint-plugin-compat": "4.1.4",
|
||||
"eslint-plugin-eslint-comments": "3.2.0",
|
||||
"eslint-plugin-import": "2.27.5",
|
||||
"eslint-plugin-jsx-a11y": "6.7.1",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-react": "7.32.2",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-sonarjs": "0.18.0",
|
||||
"expose-loader": "4.0.0",
|
||||
"eslint-plugin-sonarjs": "0.19.0",
|
||||
"expose-loader": "4.1.0",
|
||||
"html-loader": "4.2.0",
|
||||
"html-webpack-plugin": "5.5.0",
|
||||
"mini-css-extract-plugin": "2.7.3",
|
||||
"mini-css-extract-plugin": "2.7.5",
|
||||
"postcss": "8.4.21",
|
||||
"postcss-loader": "7.0.2",
|
||||
"postcss-preset-env": "8.0.1",
|
||||
"postcss-loader": "7.2.4",
|
||||
"postcss-preset-env": "8.3.1",
|
||||
"postcss-scss": "4.0.6",
|
||||
"sass": "1.58.3",
|
||||
"sass-loader": "13.2.0",
|
||||
"sass": "1.62.0",
|
||||
"sass-loader": "13.2.2",
|
||||
"source-map-loader": "4.0.1",
|
||||
"style-loader": "3.3.1",
|
||||
"stylelint": "15.2.0",
|
||||
"style-loader": "3.3.2",
|
||||
"stylelint": "15.4.0",
|
||||
"stylelint-config-rational-order": "0.1.2",
|
||||
"stylelint-no-browser-hacks": "1.2.1",
|
||||
"stylelint-order": "6.0.3",
|
||||
"stylelint-scss": "4.4.0",
|
||||
"stylelint-scss": "4.6.0",
|
||||
"ts-loader": "9.4.2",
|
||||
"typescript": "4.9.5",
|
||||
"webpack": "5.76.0",
|
||||
"typescript": "5.0.4",
|
||||
"webpack": "5.79.0",
|
||||
"webpack-cli": "5.0.1",
|
||||
"webpack-dev-server": "4.11.1",
|
||||
"webpack-dev-server": "4.13.2",
|
||||
"webpack-merge": "5.8.0",
|
||||
"workbox-webpack-plugin": "6.5.4",
|
||||
"worker-loader": "3.0.8"
|
||||
|
@ -74,35 +73,36 @@
|
|||
"@fontsource/noto-sans-kr": "4.5.12",
|
||||
"@fontsource/noto-sans-sc": "4.5.12",
|
||||
"@fontsource/noto-sans-tc": "4.5.12",
|
||||
"@jellyfin/libass-wasm": "4.1.1",
|
||||
"@jellyfin/sdk": "unstable",
|
||||
"@loadable/component": "5.15.3",
|
||||
"blurhash": "2.0.5",
|
||||
"classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz",
|
||||
"classnames": "2.3.2",
|
||||
"core-js": "3.29.0",
|
||||
"core-js": "3.30.1",
|
||||
"date-fns": "2.29.3",
|
||||
"dompurify": "3.0.1",
|
||||
"epubjs": "0.4.2",
|
||||
"epubjs": "0.3.93",
|
||||
"escape-html": "1.0.3",
|
||||
"event-target-polyfill": "github:ThaUnknown/event-target-polyfill",
|
||||
"fast-text-encoding": "1.0.6",
|
||||
"flv.js": "1.6.2",
|
||||
"headroom.js": "0.12.0",
|
||||
"history": "5.3.0",
|
||||
"hls.js": "1.2.4",
|
||||
"hls.js": "1.4.0",
|
||||
"intersection-observer": "0.12.2",
|
||||
"jassub": "1.5.12",
|
||||
"jellyfin-apiclient": "1.10.0",
|
||||
"jquery": "3.6.3",
|
||||
"jquery": "3.6.4",
|
||||
"jstree": "3.3.15",
|
||||
"libarchive.js": "1.3.0",
|
||||
"lodash-es": "4.17.21",
|
||||
"marked": "4.2.12",
|
||||
"marked": "4.3.0",
|
||||
"material-design-icons-iconfont": "6.7.0",
|
||||
"native-promise-only": "0.8.1",
|
||||
"pdfjs-dist": "2.16.105",
|
||||
"pdfjs-dist": "3.5.141",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"react-router-dom": "6.8.2",
|
||||
"react-router-dom": "6.10.0",
|
||||
"resize-observer-polyfill": "1.5.1",
|
||||
"screenfull": "6.0.2",
|
||||
"sortablejs": "1.15.0",
|
||||
|
@ -131,8 +131,8 @@
|
|||
"scripts": {
|
||||
"start": "npm run serve",
|
||||
"serve": "webpack serve --config webpack.dev.js",
|
||||
"build:development": "webpack --config webpack.dev.js",
|
||||
"build:production": "cross-env NODE_ENV=\"production\" webpack --config webpack.prod.js",
|
||||
"build:development": "cross-env NODE_OPTIONS=\"--max_old_space_size=6144\" webpack --config webpack.dev.js",
|
||||
"build:production": "cross-env NODE_ENV=\"production\" NODE_OPTIONS=\"--max_old_space_size=6144\" webpack --config webpack.prod.js",
|
||||
"build:check": "tsc --noEmit",
|
||||
"escheck": "es-check",
|
||||
"lint": "eslint \"./\"",
|
||||
|
|
29
src/App.tsx
29
src/App.tsx
|
@ -1,15 +1,38 @@
|
|||
import { History } from '@remix-run/router';
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { HistoryRouter } from './components/HistoryRouter';
|
||||
import { ApiProvider } from './hooks/useApi';
|
||||
import AppRoutes from './routes/index';
|
||||
import { AppRoutes, ExperimentalAppRoutes } from './routes';
|
||||
|
||||
const App = ({ history }: { history: History }) => {
|
||||
const layoutMode = localStorage.getItem('layout');
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
// Initialize the UI components after first render
|
||||
import('./scripts/libraryMenu'),
|
||||
import('./scripts/autoBackdrops')
|
||||
]);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<ApiProvider>
|
||||
<HistoryRouter history={history}>
|
||||
<AppRoutes />
|
||||
<div className='backdropContainer' />
|
||||
<div className='backgroundContainer' />
|
||||
|
||||
<div className='mainDrawer hide'>
|
||||
<div className='mainDrawer-scrollContainer scrollContainer focuscontainer-y' />
|
||||
</div>
|
||||
<div className='skinHeader focuscontainer-x' />
|
||||
|
||||
<div className='mainAnimatedPages skinBody' />
|
||||
<div className='skinBody'>
|
||||
{layoutMode === 'experimental' ? <ExperimentalAppRoutes /> : <AppRoutes /> }
|
||||
</div>
|
||||
|
||||
<div className='mainDrawerHandle' />
|
||||
</HistoryRouter>
|
||||
</ApiProvider>
|
||||
);
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for controlling user parental control from.
|
||||
* @module components/accessSchedule/accessSchedule
|
||||
|
@ -91,8 +88,6 @@ import template from './accessSchedule.template.html';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
|
|
@ -11,8 +11,6 @@ import alert from './alert';
|
|||
import { getLocale } from '../utils/dateFnsLocale.ts';
|
||||
import { toBoolean } from '../utils/string.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getEntryHtml(entry, apiClient) {
|
||||
let html = '';
|
||||
html += '<div class="listItem listItem-border">';
|
||||
|
@ -169,5 +167,3 @@ class ActivityLog {
|
|||
}
|
||||
|
||||
export default ActivityLog;
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -3,8 +3,6 @@ import browser from '../scripts/browser';
|
|||
import dialog from './dialog/dialog';
|
||||
import globalize from '../scripts/globalize';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function useNativeAlert() {
|
||||
// webOS seems to block modals
|
||||
// Tizen 2.x seems to block modals
|
||||
|
@ -43,5 +41,3 @@ import globalize from '../scripts/globalize';
|
|||
return dialog.show(options);
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module alphaPicker.
|
||||
* @module components/alphaPicker/alphaPicker
|
||||
|
@ -320,5 +318,4 @@ import 'material-design-icons-iconfont';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default AlphaPicker;
|
||||
|
|
|
@ -366,20 +366,20 @@ export const appHost = {
|
|||
};
|
||||
},
|
||||
deviceName: function () {
|
||||
return window.NativeShell?.AppHost?.deviceName
|
||||
? window.NativeShell.AppHost.deviceName() : getDeviceName();
|
||||
return window.NativeShell?.AppHost?.deviceName ?
|
||||
window.NativeShell.AppHost.deviceName() : getDeviceName();
|
||||
},
|
||||
deviceId: function () {
|
||||
return window.NativeShell?.AppHost?.deviceId
|
||||
? window.NativeShell.AppHost.deviceId() : getDeviceId();
|
||||
return window.NativeShell?.AppHost?.deviceId ?
|
||||
window.NativeShell.AppHost.deviceId() : getDeviceId();
|
||||
},
|
||||
appName: function () {
|
||||
return window.NativeShell?.AppHost?.appName
|
||||
? window.NativeShell.AppHost.appName() : appName;
|
||||
return window.NativeShell?.AppHost?.appName ?
|
||||
window.NativeShell.AppHost.appName() : appName;
|
||||
},
|
||||
appVersion: function () {
|
||||
return window.NativeShell?.AppHost?.appVersion
|
||||
? window.NativeShell.AppHost.appVersion() : Package.version;
|
||||
return window.NativeShell?.AppHost?.appVersion ?
|
||||
window.NativeShell.AppHost.appVersion() : Package.version;
|
||||
},
|
||||
getPushTokenInfo: function () {
|
||||
return {};
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for performing auto-focus.
|
||||
* @module components/autoFocuser
|
||||
|
@ -94,8 +92,6 @@ import layoutManager from './layoutManager';
|
|||
return focusedElement;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
isEnabled: isEnabled,
|
||||
enable: enable,
|
||||
|
|
|
@ -7,8 +7,6 @@ import ServerConnections from '../ServerConnections';
|
|||
|
||||
import './backdrop.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableAnimation() {
|
||||
return !browser.slow;
|
||||
}
|
||||
|
@ -282,8 +280,6 @@ import './backdrop.scss';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
/**
|
||||
* @enum TransparencyLevel
|
||||
*/
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for building cards from item data.
|
||||
|
@ -1753,8 +1752,6 @@ import { appRouter } from '../appRouter';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
getCardsHtml: getCardsHtml,
|
||||
getDefaultBackgroundClass: getDefaultBackgroundClass,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for building cards from item data.
|
||||
|
@ -128,8 +127,6 @@ import ServerConnections from '../ServerConnections';
|
|||
imageLoader.lazyChildren(options.itemsContainer);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
buildChapterCards: buildChapterCards
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for building cards from item data.
|
||||
|
@ -20,8 +19,6 @@ import cardBuilder from './cardBuilder';
|
|||
cardBuilder.buildCards(items, options);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
buildPeopleCards: buildPeopleCards
|
||||
};
|
||||
|
|
|
@ -16,8 +16,6 @@ import '../../styles/flexstyles.scss';
|
|||
import ServerConnections from '../ServerConnections';
|
||||
import toast from '../toast/toast';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let currentServerId;
|
||||
|
||||
function onSubmit(e) {
|
||||
|
@ -265,5 +263,4 @@ import toast from '../toast/toast';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default CollectionEditor;
|
||||
|
|
|
@ -13,8 +13,6 @@ import '../formdialog.scss';
|
|||
import '../../styles/flexstyles.scss';
|
||||
import template from './dialog.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function showDialog(options = { dialogOptions: {}, buttons: [] }) {
|
||||
const dialogOptions = {
|
||||
removeOnClose: true,
|
||||
|
@ -135,7 +133,6 @@ import template from './dialog.template.html';
|
|||
return showDialog(options);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
|
|
@ -9,8 +9,6 @@ import dom from '../../scripts/dom';
|
|||
import './dialoghelper.scss';
|
||||
import '../../styles/scrollstyles.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let globalOnOpenCallback;
|
||||
|
||||
function enableAnimation() {
|
||||
|
@ -250,7 +248,6 @@ import '../../styles/scrollstyles.scss';
|
|||
}
|
||||
|
||||
function isOpened(dlg) {
|
||||
//return dlg.opened;
|
||||
return !dlg.classList.contains('hide');
|
||||
}
|
||||
|
||||
|
@ -508,8 +505,6 @@ import '../../styles/scrollstyles.scss';
|
|||
globalOnOpenCallback = val;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
open: open,
|
||||
close: close,
|
||||
|
|
|
@ -18,8 +18,6 @@ import ServerConnections from '../ServerConnections';
|
|||
import toast from '../toast/toast';
|
||||
import template from './displaySettings.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillThemes(select, selectedTheme) {
|
||||
skinManager.getThemes().then(themes => {
|
||||
select.innerHTML = themes.map(t => {
|
||||
|
@ -251,5 +249,4 @@ import template from './displaySettings.template.html';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default DisplaySettings;
|
||||
|
|
|
@ -9,8 +9,6 @@ import { getParameterByName } from '../utils/url.ts';
|
|||
import '../styles/scrollstyles.scss';
|
||||
import '../elements/emby-itemscontainer/emby-itemscontainer';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function enableScrollX() {
|
||||
return !layoutManager.desktop;
|
||||
}
|
||||
|
@ -240,5 +238,3 @@ import '../elements/emby-itemscontainer/emby-itemscontainer';
|
|||
export default {
|
||||
render: loadSections
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
export function getFetchPromise(request) {
|
||||
const headers = request.headers || {};
|
||||
|
||||
|
@ -107,4 +106,3 @@
|
|||
throw err;
|
||||
});
|
||||
}
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -8,7 +8,6 @@ import './style.scss';
|
|||
import ServerConnections from '../ServerConnections';
|
||||
import template from './filterdialog.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function renderOptions(context, selector, cssClass, items, isCheckedFn) {
|
||||
const elem = context.querySelector(selector);
|
||||
if (items.length) {
|
||||
|
@ -419,6 +418,4 @@ import template from './filterdialog.template.html';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default FilterDialog;
|
||||
|
|
|
@ -297,10 +297,8 @@ class FilterMenu {
|
|||
}
|
||||
|
||||
if (submitted) {
|
||||
//if (!options.onChange) {
|
||||
saveValues(dlg, options.settings, options.settingsKey, options.setfilters);
|
||||
return resolve();
|
||||
//}
|
||||
}
|
||||
return resolve();
|
||||
});
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
import dom from '../scripts/dom';
|
||||
import scrollManager from './scrollManager';
|
||||
|
||||
|
@ -464,8 +462,6 @@ import scrollManager from './scrollManager';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
autoFocus: autoFocus,
|
||||
focus: focus,
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
import dom from '../scripts/dom';
|
||||
import { appRouter } from './appRouter';
|
||||
import Dashboard from '../utils/dashboard';
|
||||
|
@ -43,5 +41,3 @@ import ServerConnections from './ServerConnections';
|
|||
onGroupedCardClick(e, groupedCard);
|
||||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -14,8 +14,6 @@ import ServerConnections from '../ServerConnections';
|
|||
import toast from '../toast/toast';
|
||||
import template from './homeScreenSettings.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const numConfigurableSections = 7;
|
||||
|
||||
function renderViews(page, user, result) {
|
||||
|
@ -506,6 +504,4 @@ import template from './homeScreenSettings.template.html';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default HomeScreenSettings;
|
||||
|
|
|
@ -13,8 +13,6 @@ import './homesections.scss';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function getDefaultSection(index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
|
@ -750,4 +748,3 @@ export default {
|
|||
resume: resume
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
|
||||
/* eslint-disable indent */
|
||||
|
||||
import appSettings from '../scripts/settings/appSettings' ;
|
||||
import browser from '../scripts/browser';
|
||||
import Events from '../utils/events.ts';
|
||||
|
@ -26,8 +23,8 @@ import Events from '../utils/events.ts';
|
|||
function canPlayNativeHls() {
|
||||
const media = document.createElement('video');
|
||||
|
||||
return !!(media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
|
||||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, ''));
|
||||
return !!(media.canPlayType('application/x-mpegURL').replace(/no/, '')
|
||||
|| media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, ''));
|
||||
}
|
||||
|
||||
export function enableHlsJsPlayer(runTimeTicks, mediaType) {
|
||||
|
@ -51,18 +48,10 @@ import Events from '../utils/events.ts';
|
|||
return true;
|
||||
}
|
||||
|
||||
if (browser.edge && mediaType === 'Video') {
|
||||
//return true;
|
||||
}
|
||||
|
||||
// simple playback should use the native support
|
||||
if (runTimeTicks) {
|
||||
//if (!browser.edge) {
|
||||
return false;
|
||||
//}
|
||||
}
|
||||
|
||||
//return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -201,8 +190,8 @@ import Events from '../utils/events.ts';
|
|||
.catch((e) => {
|
||||
const errorName = (e.name || '').toLowerCase();
|
||||
// safari uses aborterror
|
||||
if (errorName === 'notallowederror' ||
|
||||
errorName === 'aborterror') {
|
||||
if (errorName === 'notallowederror'
|
||||
|| errorName === 'aborterror') {
|
||||
// swallow this error because the user can still click the play button on the video element
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
@ -391,5 +380,3 @@ import Events from '../utils/events.ts';
|
|||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -15,8 +15,6 @@ import '../cardbuilder/card.scss';
|
|||
import ServerConnections from '../ServerConnections';
|
||||
import template from './imageDownloader.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItemId;
|
||||
|
@ -397,4 +395,3 @@ export default {
|
|||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for image Options Editor.
|
||||
|
@ -109,5 +108,4 @@ export class editor {
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default editor;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for imageUploader.
|
||||
|
@ -181,7 +180,6 @@ import template from './imageUploader.template.html';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
|
|
@ -18,8 +18,6 @@ import alert from '../alert';
|
|||
import confirm from '../confirm/confirm';
|
||||
import template from './imageeditor.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const enableFocusTransform = !browser.slow && !browser.edge;
|
||||
|
||||
let currentItem;
|
||||
|
@ -465,4 +463,3 @@ export default {
|
|||
show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -17,7 +17,6 @@ worker.addEventListener(
|
|||
}
|
||||
}
|
||||
);
|
||||
/* eslint-disable indent */
|
||||
|
||||
export function lazyImage(elem, source = elem.getAttribute('data-src')) {
|
||||
if (!source) {
|
||||
|
@ -247,7 +246,6 @@ worker.addEventListener(
|
|||
lazyImage(element);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
setLazyImage: setLazyImage,
|
||||
fillImages: fillImages,
|
||||
|
|
|
@ -9,7 +9,6 @@ import { playbackManager } from './playback/playbackmanager';
|
|||
import ServerConnections from './ServerConnections';
|
||||
import toast from './toast/toast';
|
||||
|
||||
/* eslint-disable indent */
|
||||
export function getCommands(options) {
|
||||
const item = options.item;
|
||||
const user = options.user;
|
||||
|
@ -638,8 +637,6 @@ import toast from './toast/toast';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
getCommands: getCommands,
|
||||
show: show
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for display media info.
|
||||
|
@ -252,7 +251,6 @@ const attributeDelimiterHtml = layoutManager.tv ? '' : '<span class="hide">: </s
|
|||
return loadMediaInfo(itemId, serverId);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for itemidentifier media item.
|
||||
|
@ -489,7 +488,6 @@ import datetime from '../../scripts/datetime';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
show: show,
|
||||
showFindNew: showFindNew
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
export class LazyLoader {
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
|
@ -63,7 +63,6 @@
|
|||
unveilElements(elem.getElementsByClassName('lazy'), elem, callback);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
LazyLoader: LazyLoader,
|
||||
lazyChildren: lazyChildren
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for library options editor.
|
||||
|
@ -613,7 +612,6 @@ import template from './libraryoptionseditor.template.html';
|
|||
let currentLibraryOptions;
|
||||
let currentAvailableOptions;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
embed: embed,
|
||||
setContentType: setContentType,
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for display list view.
|
||||
|
@ -495,7 +494,6 @@ import ServerConnections from '../ServerConnections';
|
|||
return outerHtml;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default {
|
||||
getListViewHtml: getListViewHtml
|
||||
};
|
||||
|
|
|
@ -4,8 +4,6 @@ import Events from '../utils/events.ts';
|
|||
import '../elements/emby-tabs/emby-tabs';
|
||||
import '../elements/emby-button/emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let tabOwnerView;
|
||||
const queryScope = document.querySelector('.skinHeader');
|
||||
let headerTabsContainer;
|
||||
|
@ -199,5 +197,3 @@ import '../elements/emby-button/emby-button';
|
|||
export function getTabsElement() {
|
||||
return document.querySelector('.tabs-viewmenubar');
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for media library creator.
|
||||
|
@ -25,7 +24,7 @@ import toast from '../toast/toast';
|
|||
import alert from '../alert';
|
||||
import template from './mediaLibraryCreator.template.html';
|
||||
|
||||
function onAddLibrary() {
|
||||
function onAddLibrary(e) {
|
||||
if (isCreating) {
|
||||
return false;
|
||||
}
|
||||
|
@ -62,7 +61,7 @@ import template from './mediaLibraryCreator.template.html';
|
|||
isCreating = false;
|
||||
loading.hide();
|
||||
});
|
||||
return false;
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function getCollectionTypeOptionsHtml(collectionTypeOptions) {
|
||||
|
@ -87,7 +86,9 @@ import template from './mediaLibraryCreator.template.html';
|
|||
const index = this.selectedIndex;
|
||||
|
||||
if (index != -1) {
|
||||
const name = this.options[index].innerHTML.replace('*', '').replace('&', '&');
|
||||
const name = this.options[index].innerHTML
|
||||
.replaceAll('*', '')
|
||||
.replaceAll('&', '&');
|
||||
$('#txtValue', dlg).val(name);
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +97,7 @@ import template from './mediaLibraryCreator.template.html';
|
|||
$('.collectionTypeFieldDescription', dlg).html(folderOption?.message || '');
|
||||
});
|
||||
page.querySelector('.btnAddFolder').addEventListener('click', onAddButtonClick);
|
||||
page.querySelector('.btnSubmit').addEventListener('click', onAddLibrary);
|
||||
page.querySelector('.addLibraryForm').addEventListener('submit', onAddLibrary);
|
||||
page.querySelector('.folderList').addEventListener('click', onRemoveClick);
|
||||
}
|
||||
|
||||
|
@ -223,5 +224,4 @@ export class showEditor {
|
|||
let hasChanges = false;
|
||||
let isCreating = false;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
<form class="addLibraryForm" style="max-width:100%;">
|
||||
<div class="formDialogHeader">
|
||||
<button type="button" is="paper-icon-button-light" class="btnCancel autoSize" tabindex="-1" title="${ButtonBack}"><span class="material-icons arrow_back" aria-hidden="true"></span></button>
|
||||
<h3 class="formDialogHeaderTitle">${ButtonAddMediaLibrary}</h3>
|
||||
|
@ -31,7 +32,8 @@
|
|||
</div>
|
||||
|
||||
<div class="formDialogFooter">
|
||||
<button is="emby-button" type="button" class="raised btnSubmit button-submit block formDialogFooterItem">
|
||||
<button is="emby-button" type="submit" class="raised btnSubmit button-submit block formDialogFooterItem">
|
||||
<span>${ButtonOk}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for media library editor.
|
||||
|
@ -232,5 +231,4 @@ export class showEditor {
|
|||
let hasChanges = false;
|
||||
let isCreating = false;
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
|
|
@ -10,7 +10,6 @@ import '../guide/programs.scss';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import * as userSettings from '../../scripts/settings/userSettings';
|
||||
|
||||
/* eslint-disable indent */
|
||||
function getTimerIndicator(item) {
|
||||
let status;
|
||||
|
||||
|
@ -577,8 +576,6 @@ import * as userSettings from '../../scripts/settings/userSettings';
|
|||
return list;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
getMediaInfoHtml: getPrimaryMediaInfoHtml,
|
||||
getEndsAt: getEndsAt,
|
||||
|
|
|
@ -23,8 +23,6 @@ import toast from '../toast/toast';
|
|||
import { appRouter } from '../appRouter';
|
||||
import template from './metadataEditor.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let currentContext;
|
||||
let metadataEditorInfo;
|
||||
let currentItem;
|
||||
|
@ -588,12 +586,12 @@ import template from './metadataEditor.template.html';
|
|||
hideElement('#collapsibleSpecialEpisodeInfo', context);
|
||||
}
|
||||
|
||||
if (item.Type === 'Person' ||
|
||||
item.Type === 'Genre' ||
|
||||
item.Type === 'Studio' ||
|
||||
item.Type === 'MusicGenre' ||
|
||||
item.Type === 'TvChannel' ||
|
||||
item.Type === 'Book') {
|
||||
if (item.Type === 'Person'
|
||||
|| item.Type === 'Genre'
|
||||
|| item.Type === 'Studio'
|
||||
|| item.Type === 'MusicGenre'
|
||||
|| item.Type === 'TvChannel'
|
||||
|| item.Type === 'Book') {
|
||||
hideElement('#peopleCollapsible', context);
|
||||
} else {
|
||||
showElement('#peopleCollapsible', context);
|
||||
|
@ -1113,4 +1111,3 @@ import template from './metadataEditor.template.html';
|
|||
}
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -8,8 +8,6 @@ import '../../elements/emby-select/emby-select';
|
|||
import '../formdialog.scss';
|
||||
import template from './personEditor.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function centerFocus(elem, horiz, on) {
|
||||
import('../../scripts/scrollHelper').then((scrollHelper) => {
|
||||
const fn = on ? 'on' : 'off';
|
||||
|
@ -98,4 +96,3 @@ export default {
|
|||
show: show
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -11,8 +11,6 @@ import confirm from '../confirm/confirm';
|
|||
import itemHelper from '../itemHelper';
|
||||
import datetime from '../../scripts/datetime';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let selectedItems = [];
|
||||
let selectedElements = [];
|
||||
let currentSelectionCommandsPanel;
|
||||
|
@ -205,13 +203,6 @@ import datetime from '../../scripts/datetime';
|
|||
|
||||
if (user.Policy.EnableContentDownloading && appHost.supports('filedownload')) {
|
||||
// Disabled because there is no callback for this item
|
||||
/*
|
||||
menuItems.push({
|
||||
name: globalize.translate('Download'),
|
||||
id: 'download',
|
||||
icon: 'file_download'
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
|
@ -573,4 +564,3 @@ import datetime from '../../scripts/datetime';
|
|||
};
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -2,6 +2,7 @@ import serverNotifications from '../../scripts/serverNotifications';
|
|||
import { playbackManager } from '../playback/playbackmanager';
|
||||
import Events from '../../utils/events.ts';
|
||||
import globalize from '../../scripts/globalize';
|
||||
import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts';
|
||||
|
||||
import NotificationIcon from './notificationicon.png';
|
||||
|
||||
|
@ -130,7 +131,7 @@ function onLibraryChanged(data, apiClient) {
|
|||
newItems.length = 12;
|
||||
}
|
||||
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), {
|
||||
getItems(apiClient, apiClient.getCurrentUserId(), {
|
||||
|
||||
Recursive: true,
|
||||
Limit: 3,
|
||||
|
|
|
@ -17,8 +17,6 @@ import './nowPlayingBar.scss';
|
|||
import '../../elements/emby-slider/emby-slider';
|
||||
import { appRouter } from '../appRouter';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let currentPlayer;
|
||||
let currentPlayerSupportedCommands = [];
|
||||
|
||||
|
@ -169,19 +167,23 @@ import { appRouter } from '../appRouter';
|
|||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('click', function (e) {
|
||||
if (currentPlayer) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
|
||||
// Cancel this event if doubleclick is fired
|
||||
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio') {
|
||||
// Cancel this event if doubleclick is fired. The actual previousTrack will be processed by the 'dblclick' event
|
||||
if (e.detail > 1 ) {
|
||||
return;
|
||||
}
|
||||
// Return to start of track, unless we are already (almost) at the beginning. In the latter case, continue and move
|
||||
// to the previous track, unless we are at the first track so no previous track exists.
|
||||
if (currentPlayer._currentTime >= 5 || playbackManager.getCurrentPlaylistIndex(currentPlayer) <= 1) {
|
||||
playbackManager.seekPercent(0, currentPlayer);
|
||||
// This is done automatically by playbackManager, however, setting this here gives instant visual feedback.
|
||||
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
|
||||
positionSlider.value = 0;
|
||||
} else {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
elem.querySelector('.previousTrackButton').addEventListener('dblclick', function () {
|
||||
|
@ -780,4 +782,3 @@ import { appRouter } from '../appRouter';
|
|||
}
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import appSettings from '../scripts/settings/appSettings';
|
||||
import { pluginManager } from './pluginManager';
|
||||
/* eslint-disable indent */
|
||||
|
||||
class PackageManager {
|
||||
#packagesList = [];
|
||||
|
@ -135,6 +134,4 @@ import { pluginManager } from './pluginManager';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default new PackageManager();
|
||||
|
|
|
@ -4,8 +4,6 @@ import Events from '../../utils/events.ts';
|
|||
import ServerConnections from '../ServerConnections';
|
||||
import shell from '../../scripts/shell';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Reports media playback to the device for lock screen control
|
||||
|
||||
let currentPlayer;
|
||||
|
@ -259,4 +257,3 @@ import shell from '../../scripts/shell';
|
|||
|
||||
bindToPlayer(playbackManager.getCurrentPlayer());
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -13,6 +13,7 @@ import ServerConnections from '../ServerConnections';
|
|||
import alert from '../alert';
|
||||
import { PluginType } from '../../types/plugin.ts';
|
||||
import { includesAny } from '../../utils/container.ts';
|
||||
import { getItems } from '../../utils/jellyfin-apiclient/getItems.ts';
|
||||
|
||||
const UNLIMITED_ITEMS = -1;
|
||||
|
||||
|
@ -127,7 +128,7 @@ function getItemsForPlayback(serverId, query) {
|
|||
query.EnableTotalRecordCount = false;
|
||||
query.CollapseBoxSetItems = false;
|
||||
|
||||
return apiClient.getItems(apiClient.getCurrentUserId(), query);
|
||||
return getItems(apiClient, apiClient.getCurrentUserId(), query);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1038,7 +1039,6 @@ class PlaybackManager {
|
|||
}
|
||||
}
|
||||
|
||||
//var mediaType = item.MediaType;
|
||||
return getPlayer(item, getDefaultPlayOptions()) != null;
|
||||
};
|
||||
|
||||
|
|
|
@ -12,8 +12,6 @@ import ServerConnections from '../ServerConnections';
|
|||
import toast from '../toast/toast';
|
||||
import template from './playbackSettings.template.html';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillSkipLengths(select) {
|
||||
const options = [5, 10, 15, 20, 25, 30];
|
||||
|
||||
|
@ -360,5 +358,4 @@ import template from './playbackSettings.template.html';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default PlaybackSettings;
|
||||
|
|
|
@ -4,12 +4,11 @@ import Events from '../../utils/events.ts';
|
|||
import layoutManager from '../layoutManager';
|
||||
import { playbackManager } from '../playback/playbackmanager';
|
||||
import playMethodHelper from '../playback/playmethodhelper';
|
||||
import SyncPlay from '../../plugins/syncPlay/core';
|
||||
import { pluginManager } from '../pluginManager';
|
||||
import { PluginType } from '../../types/plugin.ts';
|
||||
import './playerstats.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function init(instance) {
|
||||
const parent = document.createElement('div');
|
||||
|
||||
|
@ -325,6 +324,12 @@ import ServerConnections from '../ServerConnections';
|
|||
}
|
||||
|
||||
function getSyncPlayStats() {
|
||||
const SyncPlay = pluginManager.firstOfType(PluginType.SyncPlay)?.instance;
|
||||
|
||||
if (!SyncPlay?.Manager.isSyncPlayEnabled()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const syncStats = [];
|
||||
const stats = SyncPlay.Manager.getStats();
|
||||
|
||||
|
@ -422,10 +427,10 @@ import ServerConnections from '../ServerConnections';
|
|||
name: globalize.translate('LabelOriginalMediaInfo')
|
||||
});
|
||||
|
||||
const apiClient = ServerConnections.getApiClient(playbackManager.currentItem(player).ServerId);
|
||||
if (SyncPlay.Manager.isSyncPlayEnabled() && apiClient.isMinServerVersion('10.6.0')) {
|
||||
const syncPlayStats = getSyncPlayStats();
|
||||
if (syncPlayStats.length > 0) {
|
||||
categories.push({
|
||||
stats: getSyncPlayStats(),
|
||||
stats: syncPlayStats,
|
||||
name: globalize.translate('LabelSyncPlayInfo')
|
||||
});
|
||||
}
|
||||
|
@ -520,6 +525,4 @@ class PlayerStats {
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default PlayerStats;
|
||||
|
|
|
@ -4,10 +4,12 @@ import dialogHelper from '../dialogHelper/dialogHelper';
|
|||
import loading from '../loading/loading';
|
||||
import layoutManager from '../layoutManager';
|
||||
import { playbackManager } from '../playback/playbackmanager';
|
||||
import SyncPlay from '../../plugins/syncPlay/core';
|
||||
import { pluginManager } from '../pluginManager';
|
||||
import * as userSettings from '../../scripts/settings/userSettings';
|
||||
import { appRouter } from '../appRouter';
|
||||
import globalize from '../../scripts/globalize';
|
||||
import { PluginType } from '../../types/plugin.ts';
|
||||
|
||||
import '../../elements/emby-button/emby-button';
|
||||
import '../../elements/emby-input/emby-input';
|
||||
import '../../elements/emby-button/paper-icon-button-light';
|
||||
|
@ -16,8 +18,6 @@ import 'material-design-icons-iconfont';
|
|||
import '../formdialog.scss';
|
||||
import ServerConnections from '../ServerConnections';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
let currentServerId;
|
||||
|
||||
function onSubmit(e) {
|
||||
|
@ -117,10 +117,12 @@ import ServerConnections from '../ServerConnections';
|
|||
};
|
||||
|
||||
const apiClient = ServerConnections.getApiClient(currentServerId);
|
||||
const SyncPlay = pluginManager.firstOfType(PluginType.SyncPlay)?.instance;
|
||||
|
||||
apiClient.getItems(apiClient.getCurrentUserId(), options).then(result => {
|
||||
let html = '';
|
||||
|
||||
if ((editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) || SyncPlay.Manager.isSyncPlayEnabled()) {
|
||||
if ((editorOptions.enableAddToPlayQueue !== false && playbackManager.isPlaying()) || SyncPlay?.Manager.isSyncPlayEnabled()) {
|
||||
html += `<option value="queue">${globalize.translate('AddToPlayQueue')}</option>`;
|
||||
}
|
||||
|
||||
|
@ -278,5 +280,4 @@ import ServerConnections from '../ServerConnections';
|
|||
}
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
export default showEditor;
|
||||
|
|
|
@ -119,9 +119,14 @@ class PluginManager {
|
|||
}
|
||||
|
||||
ofType(type) {
|
||||
return this.pluginsList.filter((o) => {
|
||||
return o.type === type;
|
||||
});
|
||||
return this.pluginsList.filter(plugin => plugin.type === type);
|
||||
}
|
||||
|
||||
firstOfType(type) {
|
||||
// Get all plugins of the specified type
|
||||
return this.ofType(type)
|
||||
// Return the plugin with the "highest" (lowest numeric value) priority
|
||||
.sort((p1, p2) => (p1.priority || 0) - (p2.priority || 0))[0];
|
||||
}
|
||||
|
||||
#mapRoute(plugin, route) {
|
||||
|
|
|
@ -325,10 +325,11 @@ export default function () {
|
|||
if (layoutManager.mobile) {
|
||||
const playingVideo = playbackManager.isPlayingVideo() && item !== null;
|
||||
const playingAudio = !playbackManager.isPlayingVideo() && item !== null;
|
||||
buttonVisible(context.querySelector('.btnRepeat'), playingAudio);
|
||||
buttonVisible(context.querySelector('.btnShuffleQueue'), playingAudio);
|
||||
buttonVisible(context.querySelector('.btnRewind'), playingVideo);
|
||||
buttonVisible(context.querySelector('.btnFastForward'), playingVideo);
|
||||
const playingAudioBook = playingAudio && item.Type == 'AudioBook';
|
||||
buttonVisible(context.querySelector('.btnRepeat'), playingAudio && !playingAudioBook);
|
||||
buttonVisible(context.querySelector('.btnShuffleQueue'), playingAudio && !playingAudioBook);
|
||||
buttonVisible(context.querySelector('.btnRewind'), playingVideo || playingAudioBook);
|
||||
buttonVisible(context.querySelector('.btnFastForward'), playingVideo || playingAudioBook);
|
||||
buttonVisible(context.querySelector('.nowPlayingSecondaryButtons .btnShuffleQueue'), playingVideo);
|
||||
buttonVisible(context.querySelector('.nowPlayingSecondaryButtons .btnRepeat'), playingVideo);
|
||||
} else {
|
||||
|
@ -763,19 +764,23 @@ export default function () {
|
|||
|
||||
context.querySelector('.btnPreviousTrack').addEventListener('click', function (e) {
|
||||
if (currentPlayer) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio' && (currentPlayer._currentTime >= 5 || !playbackManager.previousTrack(currentPlayer))) {
|
||||
// Cancel this event if doubleclick is fired
|
||||
if (e.detail > 1 && playbackManager.previousTrack(currentPlayer)) {
|
||||
if (lastPlayerState.NowPlayingItem.MediaType === 'Audio') {
|
||||
// Cancel this event if doubleclick is fired. The actual previousTrack will be processed by the 'dblclick' event
|
||||
if (e.detail > 1 ) {
|
||||
return;
|
||||
}
|
||||
// Return to start of track, unless we are already (almost) at the beginning. In the latter case, continue and move
|
||||
// to the previous track, unless we are at the first track so no previous track exists.
|
||||
if (currentPlayer._currentTime >= 5 || playbackManager.getCurrentPlaylistIndex(currentPlayer) <= 1) {
|
||||
playbackManager.seekPercent(0, currentPlayer);
|
||||
// This is done automatically by playbackManager. However, setting this here gives instant visual feedback.
|
||||
// This is done automatically by playbackManager, however, setting this here gives instant visual feedback.
|
||||
// TODO: Check why seekPercentage doesn't reflect the changes inmmediately, so we can remove this workaround.
|
||||
positionSlider.value = 0;
|
||||
} else {
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
playbackManager.previousTrack(currentPlayer);
|
||||
}
|
||||
});
|
||||
|
||||
context.querySelector('.btnPreviousTrack').addEventListener('dblclick', function () {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module for controlling scroll behavior.
|
||||
* @module components/scrollManager
|
||||
|
@ -600,8 +598,6 @@ import layoutManager from './layoutManager';
|
|||
}, { capture: true });
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
isEnabled: isEnabled,
|
||||
scrollTo: scrollTo,
|
||||
|
|
|
@ -85,8 +85,8 @@ const SearchFields: FunctionComponent<SearchFieldsProps> = ({ onSearch = () => {
|
|||
dangerouslySetInnerHTML={createInputElement()}
|
||||
/>
|
||||
</div>
|
||||
{layoutManager.tv && !browser.tv &&
|
||||
<AlphaPicker onAlphaPicked={onAlphaPicked} />
|
||||
{layoutManager.tv && !browser.tv
|
||||
&& <AlphaPicker onAlphaPicked={onAlphaPicked} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* eslint-disable indent */
|
||||
|
||||
/**
|
||||
* Module shortcuts.
|
||||
* @module components/shortcuts
|
||||
|
@ -392,8 +390,6 @@ import toast from './toast/toast';
|
|||
return html;
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
||||
export default {
|
||||
on: on,
|
||||
off: off,
|
||||
|
|
|
@ -94,9 +94,9 @@ function init(instance) {
|
|||
|
||||
subtitleSyncSlider.getBubbleHtml = function (value) {
|
||||
const newOffset = getOffsetFromPercentage(value);
|
||||
return '<h1 class="sliderBubbleText">' +
|
||||
(newOffset > 0 ? '+' : '') + parseFloat(newOffset) + 's' +
|
||||
'</h1>';
|
||||
return '<h1 class="sliderBubbleText">'
|
||||
+ (newOffset > 0 ? '+' : '') + parseFloat(newOffset) + 's'
|
||||
+ '</h1>';
|
||||
};
|
||||
|
||||
subtitleSyncCloseButton.addEventListener('click', function () {
|
||||
|
|
114
src/components/tabbedview/tabbedview.js
Normal file
114
src/components/tabbedview/tabbedview.js
Normal file
|
@ -0,0 +1,114 @@
|
|||
import { clearBackdrop } from '../backdrop/backdrop';
|
||||
import * as mainTabsManager from '../maintabsmanager';
|
||||
import layoutManager from '../layoutManager';
|
||||
import '../../elements/emby-tabs/emby-tabs';
|
||||
import LibraryMenu from '../../scripts/libraryMenu';
|
||||
|
||||
function onViewDestroy() {
|
||||
const tabControllers = this.tabControllers;
|
||||
|
||||
if (tabControllers) {
|
||||
tabControllers.forEach(function (t) {
|
||||
if (t.destroy) {
|
||||
t.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
this.tabControllers = null;
|
||||
}
|
||||
|
||||
this.view = null;
|
||||
this.params = null;
|
||||
this.currentTabController = null;
|
||||
this.initialTabIndex = null;
|
||||
}
|
||||
|
||||
class TabbedView {
|
||||
constructor(view, params) {
|
||||
this.tabControllers = [];
|
||||
this.view = view;
|
||||
this.params = params;
|
||||
|
||||
const self = this;
|
||||
|
||||
let currentTabIndex = parseInt(params.tab || this.getDefaultTabIndex(params.parentId), 10);
|
||||
this.initialTabIndex = currentTabIndex;
|
||||
|
||||
function validateTabLoad(index) {
|
||||
return self.validateTabLoad ? self.validateTabLoad(index) : Promise.resolve();
|
||||
}
|
||||
|
||||
function loadTab(index, previousIndex) {
|
||||
validateTabLoad(index).then(function () {
|
||||
self.getTabController(index).then(function (controller) {
|
||||
const refresh = !controller.refreshed;
|
||||
|
||||
controller.onResume({
|
||||
autoFocus: previousIndex == null && layoutManager.tv,
|
||||
refresh: refresh
|
||||
});
|
||||
|
||||
controller.refreshed = true;
|
||||
|
||||
currentTabIndex = index;
|
||||
self.currentTabController = controller;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getTabContainers() {
|
||||
return view.querySelectorAll('.tabContent');
|
||||
}
|
||||
|
||||
function onTabChange(e) {
|
||||
const newIndex = parseInt(e.detail.selectedTabIndex, 10);
|
||||
const previousIndex = e.detail.previousIndex;
|
||||
|
||||
const previousTabController = previousIndex == null ? null : self.tabControllers[previousIndex];
|
||||
if (previousTabController && previousTabController.onPause) {
|
||||
previousTabController.onPause();
|
||||
}
|
||||
|
||||
loadTab(newIndex, previousIndex);
|
||||
}
|
||||
|
||||
view.addEventListener('viewbeforehide', this.onPause.bind(this));
|
||||
|
||||
view.addEventListener('viewbeforeshow', function () {
|
||||
mainTabsManager.setTabs(view, currentTabIndex, self.getTabs, getTabContainers, null, onTabChange, false);
|
||||
});
|
||||
|
||||
view.addEventListener('viewshow', function (e) {
|
||||
self.onResume(e.detail);
|
||||
});
|
||||
|
||||
view.addEventListener('viewdestroy', onViewDestroy.bind(this));
|
||||
}
|
||||
|
||||
onResume() {
|
||||
this.setTitle();
|
||||
clearBackdrop();
|
||||
|
||||
const currentTabController = this.currentTabController;
|
||||
|
||||
if (!currentTabController) {
|
||||
mainTabsManager.selectedTabIndex(this.initialTabIndex);
|
||||
} else if (currentTabController && currentTabController.onResume) {
|
||||
currentTabController.onResume({});
|
||||
}
|
||||
}
|
||||
|
||||
onPause() {
|
||||
const currentTabController = this.currentTabController;
|
||||
|
||||
if (currentTabController && currentTabController.onPause) {
|
||||
currentTabController.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
setTitle() {
|
||||
LibraryMenu.setTitle('');
|
||||
}
|
||||
}
|
||||
|
||||
export default TabbedView;
|
|
@ -10,8 +10,6 @@ import './upnextdialog.scss';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import '../../styles/flexstyles.scss';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
const transitionEndEventName = dom.whichTransitionEvent();
|
||||
|
||||
function getHtml() {
|
||||
|
@ -69,9 +67,9 @@ import '../../styles/flexstyles.scss';
|
|||
const elem = instance.options.parent;
|
||||
|
||||
elem.querySelector('.upNextDialog-mediainfo').innerHTML = mediaInfo.getPrimaryMediaInfoHtml(item, {
|
||||
criticRating: false,
|
||||
criticRating: true,
|
||||
originalAirDate: false,
|
||||
starRating: false,
|
||||
starRating: true,
|
||||
subtitles: false
|
||||
});
|
||||
|
||||
|
@ -243,4 +241,3 @@ class UpNextDialog {
|
|||
|
||||
export default UpNextDialog;
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -2,7 +2,13 @@ import { importModule } from '@uupaa/dynamic-import-polyfill';
|
|||
import './viewManager/viewContainer.scss';
|
||||
import Dashboard from '../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
const getMainAnimatedPages = () => {
|
||||
if (!mainAnimatedPages) {
|
||||
mainAnimatedPages = document.querySelector('.mainAnimatedPages');
|
||||
}
|
||||
|
||||
return mainAnimatedPages;
|
||||
};
|
||||
|
||||
function setControllerClass(view, options) {
|
||||
if (options.controllerFactory) {
|
||||
|
@ -55,6 +61,11 @@ import Dashboard from '../utils/dashboard';
|
|||
|
||||
view.classList.add('mainAnimatedPage');
|
||||
|
||||
if (!getMainAnimatedPages()) {
|
||||
console.warn('[viewContainer] main animated pages element is not present');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentPage) {
|
||||
if (newViewInfo.hasScript && window.$) {
|
||||
mainAnimatedPages.removeChild(currentPage);
|
||||
|
@ -225,20 +236,18 @@ import Dashboard from '../utils/dashboard';
|
|||
export function reset() {
|
||||
allPages = [];
|
||||
currentUrls = [];
|
||||
mainAnimatedPages.innerHTML = '';
|
||||
if (mainAnimatedPages) mainAnimatedPages.innerHTML = '';
|
||||
selectedPageIndex = -1;
|
||||
}
|
||||
|
||||
let onBeforeChange;
|
||||
const mainAnimatedPages = document.querySelector('.mainAnimatedPages');
|
||||
let mainAnimatedPages;
|
||||
let allPages = [];
|
||||
let currentUrls = [];
|
||||
const pageContainerCount = 3;
|
||||
let selectedPageIndex = -1;
|
||||
reset();
|
||||
mainAnimatedPages.classList.remove('hide');
|
||||
|
||||
/* eslint-enable indent */
|
||||
getMainAnimatedPages()?.classList.remove('hide');
|
||||
|
||||
export default {
|
||||
loadView: loadView,
|
||||
|
|
|
@ -6,8 +6,6 @@ import '../../elements/emby-button/emby-button';
|
|||
import confirm from '../../components/confirm/confirm';
|
||||
import { pageIdOn } from '../../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function revoke(page, key) {
|
||||
confirm(globalize.translate('MessageConfirmRevokeApiKey'), globalize.translate('HeaderConfirmRevokeApiKey')).then(function () {
|
||||
loading.show();
|
||||
|
@ -87,4 +85,3 @@ import { pageIdOn } from '../../utils/dashboard';
|
|||
loadData(this);
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -24,8 +24,6 @@ import ServerConnections from '../../components/ServerConnections';
|
|||
import alert from '../../components/alert';
|
||||
import confirm from '../../components/confirm/confirm';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function showPlaybackInfo(btn, session) {
|
||||
let title;
|
||||
const text = [];
|
||||
|
@ -846,4 +844,3 @@ import confirm from '../../components/confirm/confirm';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -5,8 +5,6 @@ import '../../../elements/emby-button/emby-button';
|
|||
import Dashboard from '../../../utils/dashboard';
|
||||
import { getParameterByName } from '../../../utils/url.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function load(page, device, deviceOptions) {
|
||||
page.querySelector('#txtCustomName', page).value = deviceOptions.CustomName || '';
|
||||
page.querySelector('.reportedName', page).innerText = device.Name || '';
|
||||
|
@ -54,4 +52,3 @@ import { getParameterByName } from '../../../utils/url.ts';
|
|||
view.addEventListener('viewshow', loadData);
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -12,8 +12,6 @@ import '../../../components/cardbuilder/card.scss';
|
|||
import Dashboard from '../../../utils/dashboard';
|
||||
import confirm from '../../../components/confirm/confirm';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
// Local cache of loaded
|
||||
let deviceIds = [];
|
||||
|
||||
|
@ -167,4 +165,4 @@ import confirm from '../../../components/confirm/confirm';
|
|||
deleteAllDevices(view);
|
||||
});
|
||||
}
|
||||
/* eslint-enable indent */
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@ import Dashboard from '../../../utils/dashboard';
|
|||
import toast from '../../../components/toast/toast';
|
||||
import { getParameterByName } from '../../../utils/url.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadProfile(page) {
|
||||
loading.show();
|
||||
const promise1 = getProfile();
|
||||
|
@ -836,4 +834,3 @@ import { getParameterByName } from '../../../utils/url.ts';
|
|||
}
|
||||
};
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -7,8 +7,6 @@ import '../../../components/listview/listview.scss';
|
|||
import '../../../elements/emby-button/emby-button';
|
||||
import confirm from '../../../components/confirm/confirm';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadProfiles(page) {
|
||||
loading.show();
|
||||
ApiClient.getJSON(ApiClient.getUrl('Dlna/ProfileInfos')).then(function (result) {
|
||||
|
@ -93,4 +91,3 @@ import confirm from '../../../components/confirm/confirm';
|
|||
loadProfiles(this);
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -5,8 +5,6 @@ import libraryMenu from '../../../scripts/libraryMenu';
|
|||
import globalize from '../../../scripts/globalize';
|
||||
import Dashboard from '../../../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config, users) {
|
||||
page.querySelector('#chkEnablePlayTo').checked = config.EnablePlayTo;
|
||||
page.querySelector('#chkEnableDlnaDebugLogging').checked = config.EnableDebugLog;
|
||||
|
@ -60,4 +58,3 @@ import Dashboard from '../../../utils/dashboard';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
<span>${EnableIntelLowPowerHevcHwEncoder}</span>
|
||||
</label>
|
||||
<div class="fieldDescription">
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://01.org/linuxgraphics/downloads/firmware" target="_blank">${IntelLowPowerEncHelp}</a>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="button-link" href="https://jellyfin.org/docs/general/administration/hardware-acceleration/intel#configure-and-verify-lp-mode-on-linux" target="_blank">${IntelLowPowerEncHelp}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -253,6 +253,13 @@
|
|||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${EnableFallbackFontHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="chkEnableAudioVbr" />
|
||||
<span>${LabelEnableAudioVbr}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${LabelEnableAudioVbrHelp}</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtDownMixAudioBoost" pattern="[0-9]*" required="required" min=".5" max="3" step=".1" label="${LabelDownMixAudioScale}" />
|
||||
<div class="fieldDescription">${LabelDownMixAudioScaleHelp}</div>
|
||||
|
|
|
@ -6,8 +6,6 @@ import libraryMenu from '../../scripts/libraryMenu';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import alert from '../../components/alert';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config, systemInfo) {
|
||||
Array.prototype.forEach.call(page.querySelectorAll('.chkDecodeCodec'), function (c) {
|
||||
c.checked = (config.HardwareDecodingCodecs || []).indexOf(c.getAttribute('data-codec')) !== -1;
|
||||
|
@ -22,6 +20,7 @@ import alert from '../../components/alert';
|
|||
page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding;
|
||||
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
|
||||
$('#selectThreadCount', page).val(config.EncodingThreadCount);
|
||||
page.querySelector('#chkEnableAudioVbr').checked = config.EnableAudioVbr;
|
||||
$('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost);
|
||||
$('#selectStereoDownmixAlgorithm').val(config.DownMixStereoAlgorithm || 'None');
|
||||
page.querySelector('#txtMaxMuxingQueueSize').value = config.MaxMuxingQueueSize || '';
|
||||
|
@ -78,6 +77,7 @@ import alert from '../../components/alert';
|
|||
const onDecoderConfirmed = function () {
|
||||
loading.show();
|
||||
ApiClient.getNamedConfiguration('encoding').then(function (config) {
|
||||
config.EnableAudioVbr = form.querySelector('#chkEnableAudioVbr').checked;
|
||||
config.DownMixAudioBoost = $('#txtDownMixAudioBoost', form).val();
|
||||
config.DownMixStereoAlgorithm = $('#selectStereoDownmixAlgorithm', form).val() || 'None';
|
||||
config.MaxMuxingQueueSize = form.querySelector('#txtMaxMuxingQueueSize').value;
|
||||
|
@ -297,4 +297,3 @@ import alert from '../../components/alert';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -10,8 +10,6 @@ import '../../elements/emby-button/emby-button';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import alert from '../../components/alert';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config, languageOptions, systemInfo) {
|
||||
page.querySelector('#txtServerName').value = systemInfo.ServerName;
|
||||
page.querySelector('#txtCachePath').value = systemInfo.CachePath || '';
|
||||
|
@ -116,4 +114,3 @@ import alert from '../../components/alert';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -12,8 +12,6 @@ import Dashboard, { pageClassOn, pageIdOn } from '../../utils/dashboard';
|
|||
import confirm from '../../components/confirm/confirm';
|
||||
import cardBuilder from '../../components/cardbuilder/cardBuilder';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function addVirtualFolder(page) {
|
||||
import('../../components/mediaLibraryCreator/mediaLibraryCreator').then(({ default: medialibrarycreator }) => {
|
||||
new medialibrarycreator({
|
||||
|
@ -407,4 +405,3 @@ import cardBuilder from '../../components/cardbuilder/cardBuilder';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -5,8 +5,6 @@ import '../../elements/emby-checkbox/emby-checkbox';
|
|||
import '../../elements/emby-button/emby-button';
|
||||
import Dashboard from '../../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function getTabs() {
|
||||
return [{
|
||||
href: '#/library.html',
|
||||
|
@ -71,4 +69,3 @@ import Dashboard from '../../utils/dashboard';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -7,8 +7,6 @@ import '../../styles/flexstyles.scss';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import alert from '../../components/alert';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function onSubmit(event) {
|
||||
event.preventDefault();
|
||||
loading.show();
|
||||
|
@ -63,5 +61,3 @@ import alert from '../../components/alert';
|
|||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -30,8 +30,6 @@ function populateImageResolutionOptions(select) {
|
|||
select.innerHTML = html;
|
||||
}
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function populateLanguages(select) {
|
||||
return ApiClient.getCultures().then(function(languages) {
|
||||
let html = '';
|
||||
|
@ -114,4 +112,3 @@ function populateImageResolutionOptions(select) {
|
|||
loadPage(this);
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -6,8 +6,6 @@ import globalize from '../../scripts/globalize';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import alert from '../../components/alert';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config, users) {
|
||||
let html = '<option value="" selected="selected">' + globalize.translate('None') + '</option>';
|
||||
html += users.map(function (user) {
|
||||
|
@ -76,4 +74,3 @@ import alert from '../../components/alert';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -5,8 +5,6 @@ import '../../elements/emby-select/emby-select';
|
|||
import Dashboard from '../../utils/dashboard';
|
||||
import alert from '../../components/alert';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function onSubmit(e) {
|
||||
const form = this;
|
||||
const localAddress = form.querySelector('#txtLocalAddress').value;
|
||||
|
@ -206,4 +204,3 @@ import alert from '../../components/alert';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,8 +4,6 @@ import libraryMenu from '../../scripts/libraryMenu';
|
|||
import globalize from '../../scripts/globalize';
|
||||
import Dashboard from '../../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config) {
|
||||
$('#txtMinResumePct', page).val(config.MinResumePct);
|
||||
$('#txtMaxResumePct', page).val(config.MaxResumePct);
|
||||
|
@ -55,4 +53,3 @@ import Dashboard from '../../utils/dashboard';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -9,8 +9,6 @@ import '../../../elements/emby-select/emby-select';
|
|||
import confirm from '../../../components/confirm/confirm';
|
||||
import { getParameterByName } from '../../../utils/url.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function fillTimeOfDay(select) {
|
||||
const options = [];
|
||||
|
||||
|
@ -243,4 +241,3 @@ import { getParameterByName } from '../../../utils/url.ts';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -9,8 +9,6 @@ import Events from '../../../utils/events.ts';
|
|||
import '../../../components/listview/listview.scss';
|
||||
import '../../../elements/emby-button/emby-button';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function reloadList(page) {
|
||||
ApiClient.getScheduledTasks({
|
||||
isHidden: false
|
||||
|
@ -199,4 +197,3 @@ import '../../../elements/emby-button/emby-button';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -2,8 +2,6 @@ import ActivityLog from '../../components/activitylog';
|
|||
import globalize from '../../scripts/globalize';
|
||||
import { toBoolean } from '../../utils/string.ts';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
export default function (view, params) {
|
||||
let activityLog;
|
||||
|
||||
|
@ -32,4 +30,3 @@ import { toBoolean } from '../../utils/string.ts';
|
|||
});
|
||||
}
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
|
@ -4,8 +4,6 @@ import loading from '../../components/loading/loading';
|
|||
import globalize from '../../scripts/globalize';
|
||||
import Dashboard from '../../utils/dashboard';
|
||||
|
||||
/* eslint-disable indent */
|
||||
|
||||
function loadPage(page, config) {
|
||||
$('#txtRemoteClientBitrateLimit', page).val(config.RemoteClientBitrateLimit / 1e6 || '');
|
||||
loading.hide();
|
||||
|
@ -46,4 +44,3 @@ import Dashboard from '../../utils/dashboard';
|
|||
});
|
||||
});
|
||||
|
||||
/* eslint-enable indent */
|
||||
|
|
198
src/controllers/dashboard/users/useredit.html
Normal file
198
src/controllers/dashboard/users/useredit.html
Normal file
|
@ -0,0 +1,198 @@
|
|||
<div id="editUserPage" data-role="page" class="page type-interior">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle username"></h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/users/">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" id="userProfileNavigation" data-mini="true">
|
||||
<a href="#" is="emby-linkbutton" data-role="button" class="ui-btn-active">${Profile}</a>
|
||||
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);">${TabAccess}</a>
|
||||
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);">${TabParentalControl}</a>
|
||||
<a href="#" is="emby-linkbutton" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${HeaderPassword}</a>
|
||||
</div>
|
||||
<p class="lnkEditUserPreferencesContainer">
|
||||
<a class="lnkEditUserPreferences button-link" href="#" is="emby-linkbutton">${ButtonEditOtherUserPreferences}</a>
|
||||
</p>
|
||||
<form class="editUserProfileForm">
|
||||
|
||||
<div class="disabledUserBanner" style="display: none;">
|
||||
<div class="btn btnDarkAccent btnStatic">
|
||||
<div>
|
||||
${HeaderThisUserIsCurrentlyDisabled}
|
||||
</div>
|
||||
<div style="margin-top: 5px;">
|
||||
${MessageReenableUser}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div id="fldUserName" class="inputContainer">
|
||||
<input is="emby-input" id="txtUserName" required type="text" label="${LabelName}" />
|
||||
</div>
|
||||
|
||||
<div class="selectContainer fldSelectLoginProvider hide">
|
||||
<select class="selectLoginProvider" is="emby-select" label="${LabelAuthProvider}"></select>
|
||||
<div class="fieldDescription">${AuthProviderHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer fldSelectPasswordResetProvider hide">
|
||||
<select class="selectPasswordResetProvider" is="emby-select" label="${LabelPasswordResetProvider}"></select>
|
||||
<div class="fieldDescription">${PasswordResetProviderHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription fldRemoteAccess hide">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkRemoteAccess" />
|
||||
<span>${AllowRemoteAccess}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${AllowRemoteAccessHelp}</div>
|
||||
</div>
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkIsAdmin" />
|
||||
<span>${OptionAllowUserToManageServer}</span>
|
||||
</label>
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableCollectionManagement" />
|
||||
<span>${AllowCollectionManagement}</span>
|
||||
</label>
|
||||
<div id="featureAccessFields" class="verticalSection">
|
||||
<h2 class="paperListLabel">${HeaderFeatureAccess}</h2>
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableLiveTvAccess" />
|
||||
<span>${OptionAllowBrowsingLiveTv}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkManageLiveTv" />
|
||||
<span>${OptionAllowManageLiveTv}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<h2 class="paperListLabel">${HeaderPlayback}</h2>
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableMediaPlayback" />
|
||||
<span>${OptionAllowMediaPlayback}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAudioPlaybackTranscoding" />
|
||||
<span>${OptionAllowAudioPlaybackTranscoding}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableVideoPlaybackTranscoding" />
|
||||
<span>${OptionAllowVideoPlaybackTranscoding}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableVideoPlaybackRemuxing" />
|
||||
<span>${OptionAllowVideoPlaybackRemuxing}</span>
|
||||
</label>
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkForceRemoteSourceTranscoding" />
|
||||
<span>${OptionForceRemoteSourceTranscoding}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="fieldDescription">${OptionAllowMediaPlaybackTranscodingHelp}</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="verticalSection">
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" type="number" id="txtRemoteClientBitrateLimit" inputmode="decimal" pattern="[0-9]*(\.[0-9]+)?" min="0" step=".25" label="${LabelRemoteClientBitrateLimit}" />
|
||||
<div class="fieldDescription">${LabelRemoteClientBitrateLimitHelp}</div>
|
||||
<div class="fieldDescription">${LabelUserRemoteClientBitrateLimitHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<div class="selectContainer fldSelectSyncPlayAccess">
|
||||
<select class="selectSyncPlayAccess" is="emby-select" id="selectSyncPlayAccess" label="${LabelSyncPlayAccess}">
|
||||
<option value="CreateAndJoinGroups">${LabelSyncPlayAccessCreateAndJoinGroups}</option>
|
||||
<option value="JoinGroups">${LabelSyncPlayAccessJoinGroups}</option>
|
||||
<option value="None">${LabelSyncPlayAccessNone}</option>
|
||||
</select>
|
||||
<div class="fieldDescription">${SyncPlayAccessHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<h2 class="checkboxListLabel" style="margin-bottom:1em;">${HeaderAllowMediaDeletionFrom}</h2>
|
||||
<div class="checkboxList paperList checkboxList-paperList">
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableDeleteAllFolders" />
|
||||
<span>${AllLibraries}</span>
|
||||
</label>
|
||||
<div class="deleteAccess">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="verticalSection">
|
||||
<h2 class="checkboxListLabel">${HeaderRemoteControl}</h2>
|
||||
<div class="checkboxList paperList" style="padding:.5em 1em;">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableRemoteControlOtherUsers" />
|
||||
<span>${OptionAllowRemoteControlOthers}</span>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkRemoteControlSharedDevices" />
|
||||
<span>${OptionAllowRemoteSharedDevices}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="fieldDescription">${OptionAllowRemoteSharedDevicesHelp}</div>
|
||||
</div>
|
||||
<h2 class="checkboxListLabel">${Other}</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableDownloading" />
|
||||
<span>${OptionAllowContentDownload}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionAllowContentDownloadHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription" id="fldIsEnabled">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkDisabled" />
|
||||
<span>${OptionDisableUser}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionDisableUserHelp}</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription" id="fldIsHidden">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkIsHidden" />
|
||||
<span>${OptionHideUser}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${OptionHideUserFromLoginHelp}</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div class=verticalSection>
|
||||
<div class="inputContainer" id="fldLoginAttemptsBeforeLockout">
|
||||
<input is="emby-input" type="number" id="txtLoginAttemptsBeforeLockout" min="-1" step="1" label="${LabelUserLoginAttemptsBeforeLockout}"/>
|
||||
<div class="fieldDescription">${OptionLoginAttemptsBeforeLockout}</div>
|
||||
<div class="fieldDescription">${OptionLoginAttemptsBeforeLockoutHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class=verticalSection>
|
||||
<div class="inputContainer" id="fldMaxActiveSessions">
|
||||
<input is="emby-input" type="number" id="txtMaxActiveSessions" min="0" step="1" label="${LabelUserMaxActiveSessions}"/>
|
||||
<div class="fieldDescription">${OptionMaxActiveSessions}</div>
|
||||
<div class="fieldDescription">${OptionMaxActiveSessionsHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised button-cancel block btnCancel" onclick="history.back();">
|
||||
<span>${ButtonCancel}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
196
src/controllers/dashboard/users/useredit.js
Normal file
196
src/controllers/dashboard/users/useredit.js
Normal file
|
@ -0,0 +1,196 @@
|
|||
import 'jquery';
|
||||
import loading from '../../../components/loading/loading';
|
||||
import libraryMenu from '../../../scripts/libraryMenu';
|
||||
import globalize from '../../../scripts/globalize';
|
||||
import Dashboard from '../../../utils/dashboard';
|
||||
import toast from '../../../components/toast/toast';
|
||||
import { getParameterByName } from '../../../utils/url.ts';
|
||||
|
||||
function loadDeleteFolders(page, user, mediaFolders) {
|
||||
ApiClient.getJSON(ApiClient.getUrl('Channels', {
|
||||
SupportsMediaDeletion: true
|
||||
})).then(function (channelsResult) {
|
||||
let isChecked;
|
||||
let checkedAttribute;
|
||||
let html = '';
|
||||
|
||||
for (const folder of mediaFolders) {
|
||||
isChecked = user.Policy.EnableContentDeletion || user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id) != -1;
|
||||
checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkFolder" data-id="' + folder.Id + '" ' + checkedAttribute + '><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
for (const folder of channelsResult.Items) {
|
||||
isChecked = user.Policy.EnableContentDeletion || user.Policy.EnableContentDeletionFromFolders.indexOf(folder.Id) != -1;
|
||||
checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkFolder" data-id="' + folder.Id + '" ' + checkedAttribute + '><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
$('.deleteAccess', page).html(html).trigger('create');
|
||||
$('#chkEnableDeleteAllFolders', page).prop('checked', user.Policy.EnableContentDeletion);
|
||||
});
|
||||
}
|
||||
|
||||
function loadAuthProviders(page, user, providers) {
|
||||
if (providers.length > 1) {
|
||||
page.querySelector('.fldSelectLoginProvider').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('.fldSelectLoginProvider').classList.add('hide');
|
||||
}
|
||||
|
||||
const currentProviderId = user.Policy.AuthenticationProviderId;
|
||||
page.querySelector('.selectLoginProvider').innerHTML = providers.map(function (provider) {
|
||||
const selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : '';
|
||||
return '<option value="' + provider.Id + '"' + selected + '>' + provider.Name + '</option>';
|
||||
});
|
||||
}
|
||||
|
||||
function loadPasswordResetProviders(page, user, providers) {
|
||||
if (providers.length > 1) {
|
||||
page.querySelector('.fldSelectPasswordResetProvider').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('.fldSelectPasswordResetProvider').classList.add('hide');
|
||||
}
|
||||
|
||||
const currentProviderId = user.Policy.PasswordResetProviderId;
|
||||
page.querySelector('.selectPasswordResetProvider').innerHTML = providers.map(function (provider) {
|
||||
const selected = provider.Id === currentProviderId || providers.length < 2 ? ' selected' : '';
|
||||
return '<option value="' + provider.Id + '"' + selected + '>' + provider.Name + '</option>';
|
||||
});
|
||||
}
|
||||
|
||||
function loadUser(page, user) {
|
||||
ApiClient.getJSON(ApiClient.getUrl('Auth/Providers')).then(function (providers) {
|
||||
loadAuthProviders(page, user, providers);
|
||||
});
|
||||
ApiClient.getJSON(ApiClient.getUrl('Auth/PasswordResetProviders')).then(function (providers) {
|
||||
loadPasswordResetProviders(page, user, providers);
|
||||
});
|
||||
ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', {
|
||||
IsHidden: false
|
||||
})).then(function (folders) {
|
||||
loadDeleteFolders(page, user, folders.Items);
|
||||
});
|
||||
|
||||
if (user.Policy.IsDisabled) {
|
||||
$('.disabledUserBanner', page).show();
|
||||
} else {
|
||||
$('.disabledUserBanner', page).hide();
|
||||
}
|
||||
|
||||
$('#txtUserName', page).prop('disabled', '').removeAttr('disabled');
|
||||
$('#fldConnectInfo', page).show();
|
||||
$('.lnkEditUserPreferences', page).attr('href', 'mypreferencesmenu.html?userId=' + user.Id);
|
||||
libraryMenu.setTitle(user.Name);
|
||||
page.querySelector('.username').innerHTML = user.Name;
|
||||
$('#txtUserName', page).val(user.Name);
|
||||
$('#chkIsAdmin', page).prop('checked', user.Policy.IsAdministrator);
|
||||
$('#chkDisabled', page).prop('checked', user.Policy.IsDisabled);
|
||||
$('#chkIsHidden', page).prop('checked', user.Policy.IsHidden);
|
||||
$('#chkEnableCollectionManagement', page).prop('checked', user.Policy.chkEnableCollectionManagement);
|
||||
$('#chkRemoteControlSharedDevices', page).prop('checked', user.Policy.EnableSharedDeviceControl);
|
||||
$('#chkEnableRemoteControlOtherUsers', page).prop('checked', user.Policy.EnableRemoteControlOfOtherUsers);
|
||||
$('#chkEnableDownloading', page).prop('checked', user.Policy.EnableContentDownloading);
|
||||
$('#chkManageLiveTv', page).prop('checked', user.Policy.EnableLiveTvManagement);
|
||||
$('#chkEnableLiveTvAccess', page).prop('checked', user.Policy.EnableLiveTvAccess);
|
||||
$('#chkEnableMediaPlayback', page).prop('checked', user.Policy.EnableMediaPlayback);
|
||||
$('#chkEnableAudioPlaybackTranscoding', page).prop('checked', user.Policy.EnableAudioPlaybackTranscoding);
|
||||
$('#chkEnableVideoPlaybackTranscoding', page).prop('checked', user.Policy.EnableVideoPlaybackTranscoding);
|
||||
$('#chkEnableVideoPlaybackRemuxing', page).prop('checked', user.Policy.EnablePlaybackRemuxing);
|
||||
$('#chkForceRemoteSourceTranscoding', page).prop('checked', user.Policy.ForceRemoteSourceTranscoding);
|
||||
$('#chkRemoteAccess', page).prop('checked', user.Policy.EnableRemoteAccess == null || user.Policy.EnableRemoteAccess);
|
||||
$('#txtRemoteClientBitrateLimit', page).val(user.Policy.RemoteClientBitrateLimit / 1e6 || '');
|
||||
$('#txtLoginAttemptsBeforeLockout', page).val(user.Policy.LoginAttemptsBeforeLockout || '0');
|
||||
$('#txtMaxActiveSessions', page).val(user.Policy.MaxActiveSessions || '0');
|
||||
if (ApiClient.isMinServerVersion('10.6.0')) {
|
||||
$('#selectSyncPlayAccess').val(user.Policy.SyncPlayAccess);
|
||||
}
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function onSaveComplete() {
|
||||
Dashboard.navigate('userprofiles.html');
|
||||
loading.hide();
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
function saveUser(user, page) {
|
||||
user.Name = $('#txtUserName', page).val();
|
||||
user.Policy.IsAdministrator = $('#chkIsAdmin', page).is(':checked');
|
||||
user.Policy.IsHidden = $('#chkIsHidden', page).is(':checked');
|
||||
user.Policy.IsDisabled = $('#chkDisabled', page).is(':checked');
|
||||
user.Policy.EnableRemoteControlOfOtherUsers = $('#chkEnableRemoteControlOtherUsers', page).is(':checked');
|
||||
user.Policy.EnableLiveTvManagement = $('#chkManageLiveTv', page).is(':checked');
|
||||
user.Policy.EnableLiveTvAccess = $('#chkEnableLiveTvAccess', page).is(':checked');
|
||||
user.Policy.EnableSharedDeviceControl = $('#chkRemoteControlSharedDevices', page).is(':checked');
|
||||
user.Policy.EnableMediaPlayback = $('#chkEnableMediaPlayback', page).is(':checked');
|
||||
user.Policy.EnableAudioPlaybackTranscoding = $('#chkEnableAudioPlaybackTranscoding', page).is(':checked');
|
||||
user.Policy.EnableVideoPlaybackTranscoding = $('#chkEnableVideoPlaybackTranscoding', page).is(':checked');
|
||||
user.Policy.EnablePlaybackRemuxing = $('#chkEnableVideoPlaybackRemuxing', page).is(':checked');
|
||||
user.Policy.EnableCollectionManagement = $('#chkEnableCollectionManagement', page).is(':checked');
|
||||
user.Policy.ForceRemoteSourceTranscoding = $('#chkForceRemoteSourceTranscoding', page).is(':checked');
|
||||
user.Policy.EnableContentDownloading = $('#chkEnableDownloading', page).is(':checked');
|
||||
user.Policy.EnableRemoteAccess = $('#chkRemoteAccess', page).is(':checked');
|
||||
user.Policy.RemoteClientBitrateLimit = parseInt(1e6 * parseFloat($('#txtRemoteClientBitrateLimit', page).val() || '0'), 10);
|
||||
user.Policy.LoginAttemptsBeforeLockout = parseInt($('#txtLoginAttemptsBeforeLockout', page).val() || '0', 10);
|
||||
user.Policy.MaxActiveSessions = parseInt($('#txtMaxActiveSessions', page).val() || '0', 10);
|
||||
user.Policy.AuthenticationProviderId = page.querySelector('.selectLoginProvider').value;
|
||||
user.Policy.PasswordResetProviderId = page.querySelector('.selectPasswordResetProvider').value;
|
||||
user.Policy.EnableContentDeletion = $('#chkEnableDeleteAllFolders', page).is(':checked');
|
||||
user.Policy.EnableContentDeletionFromFolders = user.Policy.EnableContentDeletion ? [] : $('.chkFolder', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
if (ApiClient.isMinServerVersion('10.6.0')) {
|
||||
user.Policy.SyncPlayAccess = page.querySelector('#selectSyncPlayAccess').value;
|
||||
}
|
||||
ApiClient.updateUser(user).then(function () {
|
||||
ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () {
|
||||
onSaveComplete();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
const page = $(this).parents('.page')[0];
|
||||
loading.show();
|
||||
getUser().then(function (result) {
|
||||
saveUser(result, page);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function getUser() {
|
||||
const userId = getParameterByName('userId');
|
||||
return ApiClient.getUser(userId);
|
||||
}
|
||||
|
||||
function loadData(page) {
|
||||
loading.show();
|
||||
getUser().then(function (user) {
|
||||
loadUser(page, user);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('pageinit', '#editUserPage', function () {
|
||||
$('.editUserProfileForm').off('submit', onSubmit).on('submit', onSubmit);
|
||||
const page = this;
|
||||
$('#chkEnableDeleteAllFolders', this).on('change', function () {
|
||||
if (this.checked) {
|
||||
$('.deleteAccess', page).hide();
|
||||
} else {
|
||||
$('.deleteAccess', page).show();
|
||||
}
|
||||
});
|
||||
ApiClient.getServerConfiguration().then(function (config) {
|
||||
if (config.EnableRemoteAccess) {
|
||||
page.querySelector('.fldRemoteAccess').classList.remove('hide');
|
||||
} else {
|
||||
page.querySelector('.fldRemoteAccess').classList.add('hide');
|
||||
}
|
||||
});
|
||||
}).on('pagebeforeshow', '#editUserPage', function () {
|
||||
loadData(this);
|
||||
});
|
||||
|
68
src/controllers/dashboard/users/userlibraryaccess.html
Normal file
68
src/controllers/dashboard/users/userlibraryaccess.html
Normal file
|
@ -0,0 +1,68 @@
|
|||
<div id="userLibraryAccessPage" data-role="page" class="page type-interior">
|
||||
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle username"></h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/users/">${Help}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div data-role="controlgroup" data-type="horizontal" class="localnav" data-mini="true">
|
||||
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('useredit.html', true);">${Profile}</a>
|
||||
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userlibraryaccess.html', true);" class="ui-btn-active">${TabAccess}</a>
|
||||
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userparentalcontrol.html', true);">${TabParentalControl}</a>
|
||||
<a is="emby-linkbutton" href="#" data-role="button" onclick="Dashboard.navigate('userpassword.html', true);">${HeaderPassword}</a>
|
||||
</div>
|
||||
<form class="userLibraryAccessForm">
|
||||
|
||||
<div class="folderAccessContainer">
|
||||
<h2>${HeaderLibraryAccess}</h2>
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAllFolders" />
|
||||
<span>${OptionEnableAccessToAllLibraries}</span>
|
||||
</label>
|
||||
<div class="folderAccessListContainer">
|
||||
<div class="folderAccess">
|
||||
</div>
|
||||
<div class="fieldDescription">${LibraryAccessHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="channelAccessContainer" style="display:none;">
|
||||
<h2>${HeaderChannelAccess}</h2>
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAllChannels" />
|
||||
<span>${OptionEnableAccessToAllChannels}</span>
|
||||
</label>
|
||||
<div class="channelAccessListContainer">
|
||||
<div class="channelAccess">
|
||||
</div>
|
||||
<div class="fieldDescription">${ChannelAccessHelp}</div>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="deviceAccessContainer hide">
|
||||
<h2>${HeaderDeviceAccess}</h2>
|
||||
<label class="checkboxContainer">
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAllDevices" />
|
||||
<span>${OptionEnableAccessFromAllDevices}</span>
|
||||
</label>
|
||||
<div class="deviceAccessListContainer">
|
||||
<div class="deviceAccess">
|
||||
</div>
|
||||
<div class="fieldDescription">${DeviceAccessHelp}</div>
|
||||
</div>
|
||||
<br />
|
||||
</div>
|
||||
<br />
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
184
src/controllers/dashboard/users/userlibraryaccess.js
Normal file
184
src/controllers/dashboard/users/userlibraryaccess.js
Normal file
|
@ -0,0 +1,184 @@
|
|||
import 'jquery';
|
||||
import loading from '../../../components/loading/loading';
|
||||
import libraryMenu from '../../../scripts/libraryMenu';
|
||||
import globalize from '../../../scripts/globalize';
|
||||
import Dashboard from '../../../utils/dashboard';
|
||||
import toast from '../../../components/toast/toast';
|
||||
import { getParameterByName } from '../../../utils/url.ts';
|
||||
|
||||
function triggerChange(select) {
|
||||
const evt = document.createEvent('HTMLEvents');
|
||||
evt.initEvent('change', false, true);
|
||||
select.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
function loadMediaFolders(page, user, mediaFolders) {
|
||||
let html = '';
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('HeaderLibraries') + '</h3>';
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
|
||||
for (let i = 0, length = mediaFolders.length; i < length; i++) {
|
||||
const folder = mediaFolders[i];
|
||||
const isChecked = user.Policy.EnableAllFolders || user.Policy.EnabledFolders.indexOf(folder.Id) != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkFolder" data-id="' + folder.Id + '" ' + checkedAttribute + '><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
page.querySelector('.folderAccess').innerHTML = html;
|
||||
const chkEnableAllFolders = page.querySelector('#chkEnableAllFolders');
|
||||
chkEnableAllFolders.checked = user.Policy.EnableAllFolders;
|
||||
triggerChange(chkEnableAllFolders);
|
||||
}
|
||||
|
||||
function loadChannels(page, user, channels) {
|
||||
let html = '';
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('Channels') + '</h3>';
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
|
||||
for (let i = 0, length = channels.length; i < length; i++) {
|
||||
const folder = channels[i];
|
||||
const isChecked = user.Policy.EnableAllChannels || user.Policy.EnabledChannels.indexOf(folder.Id) != -1;
|
||||
const checkedAttribute = isChecked ? ' checked="checked"' : '';
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkChannel" data-id="' + folder.Id + '" ' + checkedAttribute + '><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
$('.channelAccess', page).show().html(html);
|
||||
|
||||
if (channels.length) {
|
||||
$('.channelAccessContainer', page).show();
|
||||
} else {
|
||||
$('.channelAccessContainer', page).hide();
|
||||
}
|
||||
|
||||
const chkEnableAllChannels = page.querySelector('#chkEnableAllChannels');
|
||||
chkEnableAllChannels.checked = user.Policy.EnableAllChannels;
|
||||
triggerChange(chkEnableAllChannels);
|
||||
}
|
||||
|
||||
function loadDevices(page, user, devices) {
|
||||
let html = '';
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('HeaderDevices') + '</h3>';
|
||||
html += '<div class="checkboxList paperList checkboxList-paperList">';
|
||||
|
||||
for (let i = 0, length = devices.length; i < length; i++) {
|
||||
const device = devices[i];
|
||||
const checkedAttribute = user.Policy.EnableAllDevices || user.Policy.EnabledDevices.indexOf(device.Id) != -1 ? ' checked="checked"' : '';
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkDevice" data-id="' + device.Id + '" ' + checkedAttribute + '><span>' + device.Name + ' - ' + device.AppName + '</span></label>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
$('.deviceAccess', page).show().html(html);
|
||||
const chkEnableAllDevices = page.querySelector('#chkEnableAllDevices');
|
||||
chkEnableAllDevices.checked = user.Policy.EnableAllDevices;
|
||||
triggerChange(chkEnableAllDevices);
|
||||
|
||||
if (user.Policy.IsAdministrator) {
|
||||
page.querySelector('.deviceAccessContainer').classList.add('hide');
|
||||
} else {
|
||||
page.querySelector('.deviceAccessContainer').classList.remove('hide');
|
||||
}
|
||||
}
|
||||
|
||||
function loadUser(page, user, loggedInUser, mediaFolders, channels, devices) {
|
||||
page.querySelector('.username').innerHTML = user.Name;
|
||||
libraryMenu.setTitle(user.Name);
|
||||
loadChannels(page, user, channels);
|
||||
loadMediaFolders(page, user, mediaFolders);
|
||||
loadDevices(page, user, devices);
|
||||
loading.hide();
|
||||
}
|
||||
|
||||
function onSaveComplete() {
|
||||
loading.hide();
|
||||
toast(globalize.translate('SettingsSaved'));
|
||||
}
|
||||
|
||||
function saveUser(user, page) {
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
|
||||
user.Policy.EnabledFolders = user.Policy.EnableAllFolders ? [] : $('.chkFolder', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
|
||||
user.Policy.EnabledChannels = user.Policy.EnableAllChannels ? [] : $('.chkChannel', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.EnableAllDevices = $('#chkEnableAllDevices', page).is(':checked');
|
||||
user.Policy.EnabledDevices = user.Policy.EnableAllDevices ? [] : $('.chkDevice', page).get().filter(function (c) {
|
||||
return c.checked;
|
||||
}).map(function (c) {
|
||||
return c.getAttribute('data-id');
|
||||
});
|
||||
user.Policy.BlockedChannels = null;
|
||||
user.Policy.BlockedMediaFolders = null;
|
||||
ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () {
|
||||
onSaveComplete();
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
const page = $(this).parents('.page');
|
||||
loading.show();
|
||||
const userId = getParameterByName('userId');
|
||||
ApiClient.getUser(userId).then(function (result) {
|
||||
saveUser(result, page);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
$(document).on('pageinit', '#userLibraryAccessPage', function () {
|
||||
const page = this;
|
||||
$('#chkEnableAllDevices', page).on('change', function () {
|
||||
if (this.checked) {
|
||||
$('.deviceAccessListContainer', page).hide();
|
||||
} else {
|
||||
$('.deviceAccessListContainer', page).show();
|
||||
}
|
||||
});
|
||||
$('#chkEnableAllChannels', page).on('change', function () {
|
||||
if (this.checked) {
|
||||
$('.channelAccessListContainer', page).hide();
|
||||
} else {
|
||||
$('.channelAccessListContainer', page).show();
|
||||
}
|
||||
});
|
||||
page.querySelector('#chkEnableAllFolders').addEventListener('change', function () {
|
||||
if (this.checked) {
|
||||
page.querySelector('.folderAccessListContainer').classList.add('hide');
|
||||
} else {
|
||||
page.querySelector('.folderAccessListContainer').classList.remove('hide');
|
||||
}
|
||||
});
|
||||
$('.userLibraryAccessForm').off('submit', onSubmit).on('submit', onSubmit);
|
||||
}).on('pageshow', '#userLibraryAccessPage', function () {
|
||||
const page = this;
|
||||
loading.show();
|
||||
let promise1;
|
||||
const userId = getParameterByName('userId');
|
||||
|
||||
if (userId) {
|
||||
promise1 = ApiClient.getUser(userId);
|
||||
} else {
|
||||
const deferred = $.Deferred();
|
||||
deferred.resolveWith(null, [{
|
||||
Configuration: {}
|
||||
}]);
|
||||
promise1 = deferred.promise();
|
||||
}
|
||||
|
||||
const promise2 = Dashboard.getCurrentUser();
|
||||
const promise4 = ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', {
|
||||
IsHidden: false
|
||||
}));
|
||||
const promise5 = ApiClient.getJSON(ApiClient.getUrl('Channels'));
|
||||
const promise6 = ApiClient.getJSON(ApiClient.getUrl('Devices'));
|
||||
Promise.all([promise1, promise2, promise4, promise5, promise6]).then(function (responses) {
|
||||
loadUser(page, responses[0], responses[1], responses[2].Items, responses[3].Items, responses[4].Items);
|
||||
});
|
||||
});
|
||||
|
62
src/controllers/dashboard/users/usernew.html
Normal file
62
src/controllers/dashboard/users/usernew.html
Normal file
|
@ -0,0 +1,62 @@
|
|||
<div id="newUserPage" data-role="page" class="page type-interior">
|
||||
<div>
|
||||
<div class="content-primary">
|
||||
<form class="newUserProfileForm">
|
||||
<div class="verticalSection">
|
||||
<div class="sectionTitleContainer flex align-items-center">
|
||||
<h2 class="sectionTitle">${ButtonAddUser}</h2>
|
||||
<a is="emby-linkbutton" rel="noopener noreferrer" class="raised button-alt headerHelpButton" target="_blank" href="https://jellyfin.org/docs/general/server/users/">${Help}</a>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtUsername" required type="text" label="${LabelName}" />
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<input is="emby-input" id="txtPassword" type="password" label="${LabelPassword}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="folderAccessContainer verticalSection">
|
||||
<h2 class="sectionTitle">${HeaderLibraryAccess}</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAllFolders" />
|
||||
<span>${OptionEnableAccessToAllLibraries}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${LibraryAccessHelp}</div>
|
||||
</div>
|
||||
<div class="folderAccessListContainer">
|
||||
<div class="folderAccess">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="channelAccessContainer verticalSection verticalSection-extrabottompadding" style="display:none;">
|
||||
<h2 class="sectionTitle">${HeaderChannelAccess}</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkEnableAllChannels" />
|
||||
<span>${OptionEnableAccessToAllChannels}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${ChannelAccessHelp}</div>
|
||||
</div>
|
||||
<div class="channelAccessListContainer">
|
||||
<div class="channelAccess">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
|
||||
<button is="emby-button" type="button" class="raised button-cancel block btnCancel" onclick="history.back();">
|
||||
<span>${ButtonCancel}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
128
src/controllers/dashboard/users/usernew.js
Normal file
128
src/controllers/dashboard/users/usernew.js
Normal file
|
@ -0,0 +1,128 @@
|
|||
import 'jquery';
|
||||
import loading from '../../../components/loading/loading';
|
||||
import globalize from '../../../scripts/globalize';
|
||||
import '../../../elements/emby-checkbox/emby-checkbox';
|
||||
import Dashboard from '../../../utils/dashboard';
|
||||
import toast from '../../../components/toast/toast';
|
||||
|
||||
function loadMediaFolders(page, mediaFolders) {
|
||||
let html = '';
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('HeaderLibraries') + '</h3>';
|
||||
html += '<div class="checkboxList paperList" style="padding:.5em 1em;">';
|
||||
|
||||
for (let i = 0; i < mediaFolders.length; i++) {
|
||||
const folder = mediaFolders[i];
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkFolder" data-id="' + folder.Id + '"/><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
$('.folderAccess', page).html(html).trigger('create');
|
||||
$('#chkEnableAllFolders', page).prop('checked', false);
|
||||
}
|
||||
|
||||
function loadChannels(page, channels) {
|
||||
let html = '';
|
||||
html += '<h3 class="checkboxListLabel">' + globalize.translate('Channels') + '</h3>';
|
||||
html += '<div class="checkboxList paperList" style="padding:.5em 1em;">';
|
||||
|
||||
for (let i = 0; i < channels.length; i++) {
|
||||
const folder = channels[i];
|
||||
html += '<label><input type="checkbox" is="emby-checkbox" class="chkChannel" data-id="' + folder.Id + '"/><span>' + folder.Name + '</span></label>';
|
||||
}
|
||||
|
||||
html += '</div>';
|
||||
$('.channelAccess', page).show().html(html).trigger('create');
|
||||
|
||||
if (channels.length) {
|
||||
$('.channelAccessContainer', page).show();
|
||||
} else {
|
||||
$('.channelAccessContainer', page).hide();
|
||||
}
|
||||
|
||||
$('#chkEnableAllChannels', page).prop('checked', false);
|
||||
}
|
||||
|
||||
function loadUser(page) {
|
||||
$('#txtUsername', page).val('');
|
||||
$('#txtPassword', page).val('');
|
||||
loading.show();
|
||||
const promiseFolders = ApiClient.getJSON(ApiClient.getUrl('Library/MediaFolders', {
|
||||
IsHidden: false
|
||||
}));
|
||||
const promiseChannels = ApiClient.getJSON(ApiClient.getUrl('Channels'));
|
||||
Promise.all([promiseFolders, promiseChannels]).then(function (responses) {
|
||||
loadMediaFolders(page, responses[0].Items);
|
||||
loadChannels(page, responses[1].Items);
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function saveUser(page) {
|
||||
const _user = {
|
||||
Name: $('#txtUsername', page).val(),
|
||||
Password: $('#txtPassword', page).val()
|
||||
};
|
||||
ApiClient.createUser(_user).then(function (user) {
|
||||
user.Policy.EnableAllFolders = $('#chkEnableAllFolders', page).is(':checked');
|
||||
user.Policy.EnabledFolders = [];
|
||||
|
||||
if (!user.Policy.EnableAllFolders) {
|
||||
user.Policy.EnabledFolders = $('.chkFolder', page).get().filter(function (i) {
|
||||
return i.checked;
|
||||
}).map(function (i) {
|
||||
return i.getAttribute('data-id');
|
||||
});
|
||||
}
|
||||
|
||||
user.Policy.EnableAllChannels = $('#chkEnableAllChannels', page).is(':checked');
|
||||
user.Policy.EnabledChannels = [];
|
||||
|
||||
if (!user.Policy.EnableAllChannels) {
|
||||
user.Policy.EnabledChannels = $('.chkChannel', page).get().filter(function (i) {
|
||||
return i.checked;
|
||||
}).map(function (i) {
|
||||
return i.getAttribute('data-id');
|
||||
});
|
||||
}
|
||||
|
||||
ApiClient.updateUserPolicy(user.Id, user.Policy).then(function () {
|
||||
Dashboard.navigate('useredit.html?userId=' + user.Id);
|
||||
});
|
||||
}, function () {
|
||||
toast(globalize.translate('ErrorDefault'));
|
||||
loading.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function onSubmit() {
|
||||
const page = $(this).parents('.page')[0];
|
||||
loading.show();
|
||||
saveUser(page);
|
||||
return false;
|
||||
}
|
||||
|
||||
function loadData(page) {
|
||||
loadUser(page);
|
||||
}
|
||||
|
||||
$(document).on('pageinit', '#newUserPage', function () {
|
||||
const page = this;
|
||||
$('#chkEnableAllChannels', page).on('change', function () {
|
||||
if (this.checked) {
|
||||
$('.channelAccessListContainer', page).hide();
|
||||
} else {
|
||||
$('.channelAccessListContainer', page).show();
|
||||
}
|
||||
});
|
||||
$('#chkEnableAllFolders', page).on('change', function () {
|
||||
if (this.checked) {
|
||||
$('.folderAccessListContainer', page).hide();
|
||||
} else {
|
||||
$('.folderAccessListContainer', page).show();
|
||||
}
|
||||
});
|
||||
$('.newUserProfileForm').off('submit', onSubmit).on('submit', onSubmit);
|
||||
}).on('pageshow', '#newUserPage', function () {
|
||||
loadData(this);
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue