Merge pull request #94 from ffplayout/ffpapi

ffpapi
This commit is contained in:
jb-alvarado 2022-07-06 16:23:23 +02:00 committed by GitHub
commit b22938d0fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 650 additions and 844 deletions

View File

@ -8,7 +8,7 @@ module.exports = {
parser: '@babel/eslint-parser', parser: '@babel/eslint-parser',
requireConfigFile: false, requireConfigFile: false,
babelOptions: { babelOptions: {
presets: ["@babel/preset-react"] presets: ['@babel/preset-react']
} }
}, },
extends: [ extends: [
@ -19,9 +19,9 @@ module.exports = {
rules: { rules: {
'vue/html-indent': ['error', 4], 'vue/html-indent': ['error', 4],
'vue/html-closing-bracket-newline': 'off', 'vue/html-closing-bracket-newline': 'off',
'indent': [2, 4], indent: [2, 4],
'no-tabs': 'off', 'no-tabs': 'off',
"no-console": 0, 'no-console': 0,
"camelcase": ["error", {properties: "never"}] camelcase: ['error', { properties: 'never' }]
} }
} }

4
.gitignore vendored
View File

@ -94,3 +94,7 @@ sw.*
master.m3u8 master.m3u8
tv-media tv-media
tv-media/ tv-media/
Videos
Videos/
live
live/

View File

@ -15,25 +15,22 @@ After installations you have to setup ssl for your **https** connections.
## Some Impressions: ## Some Impressions:
#### Login #### Login
![login](/docs/assets/login.png) ![login](/docs/images/login.png)
#### Landing Page
![landing-page](/docs/assets/landing-page.png)
#### Control Page #### Control Page
![control](/docs/assets/control.png) ![control](/docs/images/control.png)
#### Media Page #### Media Page
![media](/docs/assets/media.png) ![media](/docs/images/media.png)
#### Media Page / Upload #### Media Page / Upload
![media-upload](/docs/assets/media-upload.png) ![media-upload](/docs/images/media-upload.png)
#### Message Page #### Message Page
![message](/docs/assets/message.png) ![message](/docs/images/message.png)
#### Logging Page #### Logging Page
![logging](/docs/assets/logging.png) ![logging](/docs/images/logging.png)
#### Configuration Page / GUI #### Configuration Page / GUI
![config-gui](/docs/assets/config-gui.png) ![config-gui](/docs/images/config-gui.png)

View File

@ -13,7 +13,7 @@
.date-row { .date-row {
height: 40px; height: 40px;
width: 100%; width: 100%;
padding-top: 5px; padding-top: 7px;
margin: 0; margin: 0;
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 378 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

BIN
docs/images/config-gui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
docs/images/control.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

BIN
docs/images/logging.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
docs/images/login.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
docs/images/media.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 KiB

BIN
docs/images/message.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@ -1,5 +1,3 @@
require('dotenv').config()
export default { export default {
ssr: false, ssr: false,
/* /*
@ -7,7 +5,8 @@ export default {
*/ */
head: { head: {
title: process.env.npm_package_name || '', title: process.env.npm_package_name || '',
meta: [{ meta: [
{
charset: 'utf-8' charset: 'utf-8'
}, },
{ {
@ -20,11 +19,13 @@ export default {
content: process.env.npm_package_description || '' content: process.env.npm_package_description || ''
} }
], ],
link: [{ link: [
{
rel: 'icon', rel: 'icon',
type: 'image/x-icon', type: 'image/x-icon',
href: '/favicon.ico' href: '/favicon.ico'
}] }
]
}, },
/* /*
** Customize the progress-bar color ** Customize the progress-bar color
@ -35,9 +36,7 @@ export default {
/* /*
** Global CSS ** Global CSS
*/ */
css: [ css: ['@/assets/css/bootstrap.min.css'],
'@/assets/css/bootstrap.min.css'
],
/* /*
** Plugins to load before mounting the App ** Plugins to load before mounting the App
*/ */
@ -78,24 +77,18 @@ export default {
** See https://axios.nuxtjs.org/options ** See https://axios.nuxtjs.org/options
*/ */
axios: { axios: {
baseURL: process.env.API_URL baseURL: '/'
}, },
dayjs: { dayjs: {
locales: ['en', 'de'], locales: ['en', 'de'],
defaultLocale: 'en', defaultLocale: 'en',
defaultTimeZone: 'Europe/Berlin', defaultTimeZone: 'Europe/Berlin',
plugins: [ plugins: ['utc', 'timezone']
'utc',
'timezone'
]
}, },
styleResources: { styleResources: {
scss: [ scss: ['@/assets/css/_variables.scss', '@/assets/scss/globals.scss']
'@/assets/css/_variables.scss',
'@/assets/scss/globals.scss'
]
}, },
bootstrapVue: { bootstrapVue: {
@ -114,10 +107,10 @@ export default {
babel: { compact: true }, babel: { compact: true },
loaders: { loaders: {
sass: { sass: {
implementation: require('sass'), implementation: require('sass')
}, },
scss: { scss: {
implementation: require('sass'), implementation: require('sass')
} }
} }
} }

428
package-lock.json generated
View File

@ -1,38 +1,38 @@
{ {
"name": "ffplayout", "name": "ffplayout",
"version": "4.0.0", "version": "5.0.0",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ffplayout", "name": "ffplayout",
"version": "4.0.0", "version": "5.0.0",
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.13.6", "@nuxtjs/axios": "^5.13.6",
"@nuxtjs/dayjs": "^1.4.1", "@nuxtjs/dayjs": "^1.4.1",
"@nuxtjs/dotenv": "^1.4.1", "@nuxtjs/dotenv": "^1.4.1",
"bootstrap": "^4.6.1", "bootstrap": "^4.6.1",
"bootstrap-vue": "^2.22.0", "bootstrap-vue": "^2.22.0",
"cookie-universal-nuxt": "^2.1.5", "cookie-universal-nuxt": "^2.2.1",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mpegts.js": "^1.6.10", "mpegts.js": "^1.6.10",
"nuxt": "^2.15.8", "nuxt": "^2.15.8",
"splitpanes": "^2.3.8", "splitpanes": "^2.3.8",
"video.js": "^7.18.1", "video.js": "^7.19.2",
"vue-loading-overlay": "^3.4.2", "vue-loading-overlay": "^3.4.2",
"vue2-perfect-scrollbar": "^1.5.5", "vue2-perfect-scrollbar": "^1.5.5",
"vuedraggable": "^2.24.3" "vuedraggable": "^2.24.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.17.0", "@babel/eslint-parser": "^7.18.2",
"@babel/preset-react": "^7.16.7", "@babel/preset-react": "^7.18.6",
"@nuxtjs/eslint-config": "^5.0.0", "@nuxtjs/eslint-config": "^5.0.0",
"@nuxtjs/eslint-module": "^3.1.0", "@nuxtjs/eslint-module": "^3.1.0",
"@nuxtjs/style-resources": "^1.2.1", "@nuxtjs/style-resources": "^1.2.1",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-nuxt": ">=2.0.0", "eslint-plugin-nuxt": ">=2.0.0",
"sass": "^1.51.0", "sass": "^1.53.0",
"sass-loader": "^10.2.1" "sass-loader": "^10.2.1"
} }
}, },
@ -85,9 +85,9 @@
} }
}, },
"node_modules/@babel/eslint-parser": { "node_modules/@babel/eslint-parser": {
"version": "7.17.0", "version": "7.18.2",
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz",
"integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "integrity": "sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"eslint-scope": "^5.1.1", "eslint-scope": "^5.1.1",
@ -116,11 +116,11 @@
} }
}, },
"node_modules/@babel/helper-annotate-as-pure": { "node_modules/@babel/helper-annotate-as-pure": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
"integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
"dependencies": { "dependencies": {
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -277,11 +277,11 @@
} }
}, },
"node_modules/@babel/helper-module-imports": { "node_modules/@babel/helper-module-imports": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
"dependencies": { "dependencies": {
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -317,9 +317,9 @@
} }
}, },
"node_modules/@babel/helper-plugin-utils": { "node_modules/@babel/helper-plugin-utils": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
"integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -386,17 +386,17 @@
} }
}, },
"node_modules/@babel/helper-validator-identifier": { "node_modules/@babel/helper-validator-identifier": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@babel/helper-validator-option": { "node_modules/@babel/helper-validator-option": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
} }
@ -815,11 +815,11 @@
} }
}, },
"node_modules/@babel/plugin-syntax-jsx": { "node_modules/@babel/plugin-syntax-jsx": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
"integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1269,12 +1269,12 @@
} }
}, },
"node_modules/@babel/plugin-transform-react-display-name": { "node_modules/@babel/plugin-transform-react-display-name": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz",
"integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1284,16 +1284,16 @@
} }
}, },
"node_modules/@babel/plugin-transform-react-jsx": { "node_modules/@babel/plugin-transform-react-jsx": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz",
"integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.18.6",
"@babel/helper-module-imports": "^7.16.7", "@babel/helper-module-imports": "^7.18.6",
"@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-plugin-utils": "^7.18.6",
"@babel/plugin-syntax-jsx": "^7.16.7", "@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1303,12 +1303,12 @@
} }
}, },
"node_modules/@babel/plugin-transform-react-jsx-development": { "node_modules/@babel/plugin-transform-react-jsx-development": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz",
"integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/plugin-transform-react-jsx": "^7.16.7" "@babel/plugin-transform-react-jsx": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1318,13 +1318,13 @@
} }
}, },
"node_modules/@babel/plugin-transform-react-pure-annotations": { "node_modules/@babel/plugin-transform-react-pure-annotations": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz",
"integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.18.6",
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1583,17 +1583,17 @@
} }
}, },
"node_modules/@babel/preset-react": { "node_modules/@babel/preset-react": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz",
"integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-plugin-utils": "^7.18.6",
"@babel/helper-validator-option": "^7.16.7", "@babel/helper-validator-option": "^7.18.6",
"@babel/plugin-transform-react-display-name": "^7.16.7", "@babel/plugin-transform-react-display-name": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.16.7", "@babel/plugin-transform-react-jsx": "^7.18.6",
"@babel/plugin-transform-react-jsx-development": "^7.16.7", "@babel/plugin-transform-react-jsx-development": "^7.18.6",
"@babel/plugin-transform-react-pure-annotations": "^7.16.7" "@babel/plugin-transform-react-pure-annotations": "^7.18.6"
}, },
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
@ -1647,11 +1647,11 @@
} }
}, },
"node_modules/@babel/types": { "node_modules/@babel/types": {
"version": "7.16.8", "version": "7.18.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
"integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
"dependencies": { "dependencies": {
"@babel/helper-validator-identifier": "^7.16.7", "@babel/helper-validator-identifier": "^7.18.6",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
}, },
"engines": { "engines": {
@ -3153,16 +3153,16 @@
} }
}, },
"node_modules/@videojs/http-streaming": { "node_modules/@videojs/http-streaming": {
"version": "2.13.1", "version": "2.14.2",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.13.1.tgz", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz",
"integrity": "sha512-1x3fkGSPyL0+iaS3/lTvfnPTtfqzfgG+ELQtPPtTvDwqGol9Mx3TNyZwtSTdIufBrqYRn7XybB/3QNMsyjq13A==", "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "3.0.4", "@videojs/vhs-utils": "3.0.5",
"aes-decrypter": "3.1.2", "aes-decrypter": "3.1.3",
"global": "^4.4.0", "global": "^4.4.0",
"m3u8-parser": "4.7.0", "m3u8-parser": "4.7.1",
"mpd-parser": "0.21.0", "mpd-parser": "0.21.1",
"mux.js": "6.0.1", "mux.js": "6.0.1",
"video.js": "^6 || ^7" "video.js": "^6 || ^7"
}, },
@ -3174,20 +3174,6 @@
"video.js": "^6 || ^7" "video.js": "^6 || ^7"
} }
}, },
"node_modules/@videojs/http-streaming/node_modules/@videojs/vhs-utils": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.4.tgz",
"integrity": "sha512-hui4zOj2I1kLzDgf8QDVxD3IzrwjS/43KiS8IHQO0OeeSsb4pB/lgNt1NG7Dv0wMQfCccUpMVLGcK618s890Yg==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"global": "^4.4.0",
"url-toolkit": "^2.2.1"
},
"engines": {
"node": ">=8",
"npm": ">=5"
}
},
"node_modules/@videojs/vhs-utils": { "node_modules/@videojs/vhs-utils": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.5.tgz",
@ -3586,12 +3572,12 @@
} }
}, },
"node_modules/aes-decrypter": { "node_modules/aes-decrypter": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz",
"integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==", "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.5",
"global": "^4.4.0", "global": "^4.4.0",
"pkcs7": "^1.0.4" "pkcs7": "^1.0.4"
} }
@ -5105,29 +5091,29 @@
} }
}, },
"node_modules/cookie": { "node_modules/cookie": {
"version": "0.4.1", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cookie-universal": { "node_modules/cookie-universal": {
"version": "2.1.5", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/cookie-universal/-/cookie-universal-2.1.5.tgz", "resolved": "https://registry.npmjs.org/cookie-universal/-/cookie-universal-2.2.1.tgz",
"integrity": "sha512-nqOOmEkovCQxNYGIyzhcwsmh4c7xnxe7RWdiYFOoml9MP4L32IlU3LdPC7r7nQEnnM+9Uxlk/UhtvBl5is6M/w==", "integrity": "sha512-HMm8mNbMJ81IER5BZ3QF0wz5OA/od4jDB6agNwJjJ7oDnBnQBQwUJNeCXrYCBiCKh+ZzHDQ74D96HjUTHQHjsg==",
"dependencies": { "dependencies": {
"@types/cookie": "^0.3.3", "@types/cookie": "^0.3.3",
"cookie": "^0.4.0" "cookie": "^0.4.0"
} }
}, },
"node_modules/cookie-universal-nuxt": { "node_modules/cookie-universal-nuxt": {
"version": "2.1.5", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/cookie-universal-nuxt/-/cookie-universal-nuxt-2.1.5.tgz", "resolved": "https://registry.npmjs.org/cookie-universal-nuxt/-/cookie-universal-nuxt-2.2.1.tgz",
"integrity": "sha512-P0WCTKIyemWNtHi9lxrS5cxZmieOIEjt28B7Alu6cdSB9RqtUtpkqYyV9PRK6oJrT5eIPDYjHsJQlh6SUrFJOg==", "integrity": "sha512-pzk+CsmnNgcpFPNr8GO+B3dR0d0ovjnyFMC5Trx3zNUEEplw94CoEbv+SLSjxsXCMOF21Cmq202Od0zYbkOa+g==",
"dependencies": { "dependencies": {
"@types/cookie": "^0.3.3", "@types/cookie": "^0.3.3",
"cookie-universal": "^2.1.5" "cookie-universal": "^2.2.1"
} }
}, },
"node_modules/copy-concurrently": { "node_modules/copy-concurrently": {
@ -9390,12 +9376,12 @@
} }
}, },
"node_modules/m3u8-parser": { "node_modules/m3u8-parser": {
"version": "4.7.0", "version": "4.7.1",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz", "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.1.tgz",
"integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==", "integrity": "sha512-pbrQwiMiq+MmI9bl7UjtPT3AK603PV9bogNlr83uC+X9IoxqL5E4k7kU7fMQ0dpRgxgeSMygqUa0IMLQNXLBNA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.5",
"global": "^4.4.0" "global": "^4.4.0"
} }
}, },
@ -9779,12 +9765,12 @@
} }
}, },
"node_modules/mpd-parser": { "node_modules/mpd-parser": {
"version": "0.21.0", "version": "0.21.1",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.0.tgz", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz",
"integrity": "sha512-NbpMJ57qQzFmfCiP1pbL7cGMbVTD0X1hqNgL0VYP1wLlZXLf/HtmvQpNkOA1AHkPVeGQng+7/jEtSvNUzV7Gdg==", "integrity": "sha512-BxlSXWbKE1n7eyEPBnTEkrzhS3PdmkkKdM1pgKbPnPOH0WFZIc0sPOWi7m0Uo3Wd2a4Or8Qf4ZbS7+ASqQ49fw==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.2", "@videojs/vhs-utils": "^3.0.5",
"@xmldom/xmldom": "^0.7.2", "@xmldom/xmldom": "^0.7.2",
"global": "^4.4.0" "global": "^4.4.0"
}, },
@ -12830,9 +12816,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/sass": { "node_modules/sass": {
"version": "1.51.0", "version": "1.53.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.51.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz",
"integrity": "sha512-haGdpTgywJTvHC2b91GSq+clTKGbtkkZmVAb82jZQN/wTy6qs8DdFm2lhEQbEwrY0QDRgSQ3xDurqM977C3noA==", "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
@ -14931,19 +14917,19 @@
} }
}, },
"node_modules/video.js": { "node_modules/video.js": {
"version": "7.18.1", "version": "7.19.2",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.18.1.tgz", "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.19.2.tgz",
"integrity": "sha512-mnXdmkVcD5qQdKMZafDjqdhrnKGettZaGSVkExjACiylSB4r2Yt5W1bchsKmjFpfuNfszsMjTUnnoIWSSqoe/Q==", "integrity": "sha512-+rV/lJ1bDoMW3SbYlRp0eC9//RgvfBpEQ0USOyx44tHVxVyMjq+G9jZoiulsDXaIp4BX9q5+/y87TbZUysXBHA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/http-streaming": "2.13.1", "@videojs/http-streaming": "2.14.2",
"@videojs/vhs-utils": "^3.0.4", "@videojs/vhs-utils": "^3.0.4",
"@videojs/xhr": "2.6.0", "@videojs/xhr": "2.6.0",
"aes-decrypter": "3.1.2", "aes-decrypter": "3.1.3",
"global": "^4.4.0", "global": "^4.4.0",
"keycode": "^2.2.0", "keycode": "^2.2.0",
"m3u8-parser": "4.7.0", "m3u8-parser": "4.7.1",
"mpd-parser": "0.21.0", "mpd-parser": "0.21.1",
"mux.js": "6.0.1", "mux.js": "6.0.1",
"safe-json-parse": "4.0.0", "safe-json-parse": "4.0.0",
"videojs-font": "3.2.0", "videojs-font": "3.2.0",
@ -16749,9 +16735,9 @@
} }
}, },
"@babel/eslint-parser": { "@babel/eslint-parser": {
"version": "7.17.0", "version": "7.18.2",
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.17.0.tgz", "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.18.2.tgz",
"integrity": "sha512-PUEJ7ZBXbRkbq3qqM/jZ2nIuakUBqCYc7Qf52Lj7dlZ6zERnqisdHioL0l4wwQZnmskMeasqUNzLBFKs3nylXA==", "integrity": "sha512-oFQYkE8SuH14+uR51JVAmdqwKYXGRjEXx7s+WiagVjqQ+HPE+nnwyF2qlVG8evUsUHmPcA+6YXMEDbIhEyQc5A==",
"dev": true, "dev": true,
"requires": { "requires": {
"eslint-scope": "^5.1.1", "eslint-scope": "^5.1.1",
@ -16770,11 +16756,11 @@
} }
}, },
"@babel/helper-annotate-as-pure": { "@babel/helper-annotate-as-pure": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
"integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
"requires": { "requires": {
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
} }
}, },
"@babel/helper-builder-binary-assignment-operator-visitor": { "@babel/helper-builder-binary-assignment-operator-visitor": {
@ -16886,11 +16872,11 @@
} }
}, },
"@babel/helper-module-imports": { "@babel/helper-module-imports": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
"integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
"requires": { "requires": {
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
} }
}, },
"@babel/helper-module-transforms": { "@babel/helper-module-transforms": {
@ -16917,9 +16903,9 @@
} }
}, },
"@babel/helper-plugin-utils": { "@babel/helper-plugin-utils": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz",
"integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==" "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg=="
}, },
"@babel/helper-remap-async-to-generator": { "@babel/helper-remap-async-to-generator": {
"version": "7.16.8", "version": "7.16.8",
@ -16968,14 +16954,14 @@
} }
}, },
"@babel/helper-validator-identifier": { "@babel/helper-validator-identifier": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==" "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g=="
}, },
"@babel/helper-validator-option": { "@babel/helper-validator-option": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
"integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==" "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw=="
}, },
"@babel/helper-wrap-function": { "@babel/helper-wrap-function": {
"version": "7.16.8", "version": "7.16.8",
@ -17241,11 +17227,11 @@
} }
}, },
"@babel/plugin-syntax-jsx": { "@babel/plugin-syntax-jsx": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz",
"integrity": "sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==", "integrity": "sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==",
"requires": { "requires": {
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
} }
}, },
"@babel/plugin-syntax-logical-assignment-operators": { "@babel/plugin-syntax-logical-assignment-operators": {
@ -17521,44 +17507,44 @@
} }
}, },
"@babel/plugin-transform-react-display-name": { "@babel/plugin-transform-react-display-name": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz",
"integrity": "sha512-qgIg8BcZgd0G/Cz916D5+9kqX0c7nPZyXaP8R2tLNN5tkyIZdG5fEwBrxwplzSnjC1jvQmyMNVwUCZPcbGY7Pg==", "integrity": "sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
} }
}, },
"@babel/plugin-transform-react-jsx": { "@babel/plugin-transform-react-jsx": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz",
"integrity": "sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==", "integrity": "sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.18.6",
"@babel/helper-module-imports": "^7.16.7", "@babel/helper-module-imports": "^7.18.6",
"@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-plugin-utils": "^7.18.6",
"@babel/plugin-syntax-jsx": "^7.16.7", "@babel/plugin-syntax-jsx": "^7.18.6",
"@babel/types": "^7.16.7" "@babel/types": "^7.18.6"
} }
}, },
"@babel/plugin-transform-react-jsx-development": { "@babel/plugin-transform-react-jsx-development": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz",
"integrity": "sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==", "integrity": "sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/plugin-transform-react-jsx": "^7.16.7" "@babel/plugin-transform-react-jsx": "^7.18.6"
} }
}, },
"@babel/plugin-transform-react-pure-annotations": { "@babel/plugin-transform-react-pure-annotations": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz",
"integrity": "sha512-hs71ToC97k3QWxswh2ElzMFABXHvGiJ01IB1TbYQDGeWRKWz/MPUTh5jGExdHvosYKpnJW5Pm3S4+TA3FyX+GA==", "integrity": "sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-annotate-as-pure": "^7.18.6",
"@babel/helper-plugin-utils": "^7.16.7" "@babel/helper-plugin-utils": "^7.18.6"
} }
}, },
"@babel/plugin-transform-regenerator": { "@babel/plugin-transform-regenerator": {
@ -17742,17 +17728,17 @@
} }
}, },
"@babel/preset-react": { "@babel/preset-react": {
"version": "7.16.7", "version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.16.7.tgz", "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.18.6.tgz",
"integrity": "sha512-fWpyI8UM/HE6DfPBzD8LnhQ/OcH8AgTaqcqP2nGOXEUV+VKBR5JRN9hCk9ai+zQQ57vtm9oWeXguBCPNUjytgA==", "integrity": "sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-plugin-utils": "^7.18.6",
"@babel/helper-validator-option": "^7.16.7", "@babel/helper-validator-option": "^7.18.6",
"@babel/plugin-transform-react-display-name": "^7.16.7", "@babel/plugin-transform-react-display-name": "^7.18.6",
"@babel/plugin-transform-react-jsx": "^7.16.7", "@babel/plugin-transform-react-jsx": "^7.18.6",
"@babel/plugin-transform-react-jsx-development": "^7.16.7", "@babel/plugin-transform-react-jsx-development": "^7.18.6",
"@babel/plugin-transform-react-pure-annotations": "^7.16.7" "@babel/plugin-transform-react-pure-annotations": "^7.18.6"
} }
}, },
"@babel/runtime": { "@babel/runtime": {
@ -17791,11 +17777,11 @@
} }
}, },
"@babel/types": { "@babel/types": {
"version": "7.16.8", "version": "7.18.7",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz",
"integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==",
"requires": { "requires": {
"@babel/helper-validator-identifier": "^7.16.7", "@babel/helper-validator-identifier": "^7.18.6",
"to-fast-properties": "^2.0.0" "to-fast-properties": "^2.0.0"
} }
}, },
@ -19006,30 +18992,18 @@
} }
}, },
"@videojs/http-streaming": { "@videojs/http-streaming": {
"version": "2.13.1", "version": "2.14.2",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.13.1.tgz", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.14.2.tgz",
"integrity": "sha512-1x3fkGSPyL0+iaS3/lTvfnPTtfqzfgG+ELQtPPtTvDwqGol9Mx3TNyZwtSTdIufBrqYRn7XybB/3QNMsyjq13A==", "integrity": "sha512-K1raSfO/pq5r8iUas3OSYni0kXOj91n8ealIpV02khghzGv9LQ6O3YUqYd/eAhJ1HIrmZWOnrYpK/P+mhUExXQ==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "3.0.4", "@videojs/vhs-utils": "3.0.5",
"aes-decrypter": "3.1.2", "aes-decrypter": "3.1.3",
"global": "^4.4.0", "global": "^4.4.0",
"m3u8-parser": "4.7.0", "m3u8-parser": "4.7.1",
"mpd-parser": "0.21.0", "mpd-parser": "0.21.1",
"mux.js": "6.0.1", "mux.js": "6.0.1",
"video.js": "^6 || ^7" "video.js": "^6 || ^7"
},
"dependencies": {
"@videojs/vhs-utils": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-3.0.4.tgz",
"integrity": "sha512-hui4zOj2I1kLzDgf8QDVxD3IzrwjS/43KiS8IHQO0OeeSsb4pB/lgNt1NG7Dv0wMQfCccUpMVLGcK618s890Yg==",
"requires": {
"@babel/runtime": "^7.12.5",
"global": "^4.4.0",
"url-toolkit": "^2.2.1"
}
}
} }
}, },
"@videojs/vhs-utils": { "@videojs/vhs-utils": {
@ -19382,12 +19356,12 @@
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
}, },
"aes-decrypter": { "aes-decrypter": {
"version": "3.1.2", "version": "3.1.3",
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.2.tgz", "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.3.tgz",
"integrity": "sha512-42nRwfQuPRj9R1zqZBdoxnaAmnIFyDi0MNyTVhjdFOd8fifXKKRfwIHIZ6AMn1or4x5WONzjwRTbTWcsIQ0O4A==", "integrity": "sha512-VkG9g4BbhMBy+N5/XodDeV6F02chEk9IpgRTq/0bS80y4dzy79VH2Gtms02VXomf3HmyRe3yyJYkJ990ns+d6A==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.5",
"global": "^4.4.0", "global": "^4.4.0",
"pkcs7": "^1.0.4" "pkcs7": "^1.0.4"
} }
@ -20559,26 +20533,26 @@
} }
}, },
"cookie": { "cookie": {
"version": "0.4.1", "version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA=="
}, },
"cookie-universal": { "cookie-universal": {
"version": "2.1.5", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/cookie-universal/-/cookie-universal-2.1.5.tgz", "resolved": "https://registry.npmjs.org/cookie-universal/-/cookie-universal-2.2.1.tgz",
"integrity": "sha512-nqOOmEkovCQxNYGIyzhcwsmh4c7xnxe7RWdiYFOoml9MP4L32IlU3LdPC7r7nQEnnM+9Uxlk/UhtvBl5is6M/w==", "integrity": "sha512-HMm8mNbMJ81IER5BZ3QF0wz5OA/od4jDB6agNwJjJ7oDnBnQBQwUJNeCXrYCBiCKh+ZzHDQ74D96HjUTHQHjsg==",
"requires": { "requires": {
"@types/cookie": "^0.3.3", "@types/cookie": "^0.3.3",
"cookie": "^0.4.0" "cookie": "^0.4.0"
} }
}, },
"cookie-universal-nuxt": { "cookie-universal-nuxt": {
"version": "2.1.5", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/cookie-universal-nuxt/-/cookie-universal-nuxt-2.1.5.tgz", "resolved": "https://registry.npmjs.org/cookie-universal-nuxt/-/cookie-universal-nuxt-2.2.1.tgz",
"integrity": "sha512-P0WCTKIyemWNtHi9lxrS5cxZmieOIEjt28B7Alu6cdSB9RqtUtpkqYyV9PRK6oJrT5eIPDYjHsJQlh6SUrFJOg==", "integrity": "sha512-pzk+CsmnNgcpFPNr8GO+B3dR0d0ovjnyFMC5Trx3zNUEEplw94CoEbv+SLSjxsXCMOF21Cmq202Od0zYbkOa+g==",
"requires": { "requires": {
"@types/cookie": "^0.3.3", "@types/cookie": "^0.3.3",
"cookie-universal": "^2.1.5" "cookie-universal": "^2.2.1"
} }
}, },
"copy-concurrently": { "copy-concurrently": {
@ -23801,12 +23775,12 @@
} }
}, },
"m3u8-parser": { "m3u8-parser": {
"version": "4.7.0", "version": "4.7.1",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.0.tgz", "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.7.1.tgz",
"integrity": "sha512-48l/OwRyjBm+QhNNigEEcRcgbRvnUjL7rxs597HmW9QSNbyNvt+RcZ9T/d9vxi9A9z7EZrB1POtZYhdRlwYQkQ==", "integrity": "sha512-pbrQwiMiq+MmI9bl7UjtPT3AK603PV9bogNlr83uC+X9IoxqL5E4k7kU7fMQ0dpRgxgeSMygqUa0IMLQNXLBNA==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.0", "@videojs/vhs-utils": "^3.0.5",
"global": "^4.4.0" "global": "^4.4.0"
} }
}, },
@ -24114,12 +24088,12 @@
} }
}, },
"mpd-parser": { "mpd-parser": {
"version": "0.21.0", "version": "0.21.1",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.0.tgz", "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.21.1.tgz",
"integrity": "sha512-NbpMJ57qQzFmfCiP1pbL7cGMbVTD0X1hqNgL0VYP1wLlZXLf/HtmvQpNkOA1AHkPVeGQng+7/jEtSvNUzV7Gdg==", "integrity": "sha512-BxlSXWbKE1n7eyEPBnTEkrzhS3PdmkkKdM1pgKbPnPOH0WFZIc0sPOWi7m0Uo3Wd2a4Or8Qf4ZbS7+ASqQ49fw==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/vhs-utils": "^3.0.2", "@videojs/vhs-utils": "^3.0.5",
"@xmldom/xmldom": "^0.7.2", "@xmldom/xmldom": "^0.7.2",
"global": "^4.4.0" "global": "^4.4.0"
} }
@ -26538,9 +26512,9 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"sass": { "sass": {
"version": "1.51.0", "version": "1.53.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.51.0.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.53.0.tgz",
"integrity": "sha512-haGdpTgywJTvHC2b91GSq+clTKGbtkkZmVAb82jZQN/wTy6qs8DdFm2lhEQbEwrY0QDRgSQ3xDurqM977C3noA==", "integrity": "sha512-zb/oMirbKhUgRQ0/GFz8TSAwRq2IlR29vOUJZOx0l8sV+CkHUfHa4u5nqrG+1VceZp7Jfj59SVW9ogdhTvJDcQ==",
"dev": true, "dev": true,
"requires": { "requires": {
"chokidar": ">=3.0.0 <4.0.0", "chokidar": ">=3.0.0 <4.0.0",
@ -28171,19 +28145,19 @@
"integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==" "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w=="
}, },
"video.js": { "video.js": {
"version": "7.18.1", "version": "7.19.2",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.18.1.tgz", "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.19.2.tgz",
"integrity": "sha512-mnXdmkVcD5qQdKMZafDjqdhrnKGettZaGSVkExjACiylSB4r2Yt5W1bchsKmjFpfuNfszsMjTUnnoIWSSqoe/Q==", "integrity": "sha512-+rV/lJ1bDoMW3SbYlRp0eC9//RgvfBpEQ0USOyx44tHVxVyMjq+G9jZoiulsDXaIp4BX9q5+/y87TbZUysXBHA==",
"requires": { "requires": {
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@videojs/http-streaming": "2.13.1", "@videojs/http-streaming": "2.14.2",
"@videojs/vhs-utils": "^3.0.4", "@videojs/vhs-utils": "^3.0.4",
"@videojs/xhr": "2.6.0", "@videojs/xhr": "2.6.0",
"aes-decrypter": "3.1.2", "aes-decrypter": "3.1.3",
"global": "^4.4.0", "global": "^4.4.0",
"keycode": "^2.2.0", "keycode": "^2.2.0",
"m3u8-parser": "4.7.0", "m3u8-parser": "4.7.1",
"mpd-parser": "0.21.0", "mpd-parser": "0.21.1",
"mux.js": "6.0.1", "mux.js": "6.0.1",
"safe-json-parse": "4.0.0", "safe-json-parse": "4.0.0",
"videojs-font": "3.2.0", "videojs-font": "3.2.0",

View File

@ -1,7 +1,7 @@
{ {
"name": "ffplayout", "name": "ffplayout-frontend",
"version": "5.0.0", "version": "5.0.0",
"description": "web GUI for ffplayout engine", "description": "Web GUI for ffplayout",
"author": "Jonathan Baecker", "author": "Jonathan Baecker",
"private": true, "private": true,
"scripts": { "scripts": {
@ -17,26 +17,26 @@
"@nuxtjs/dotenv": "^1.4.1", "@nuxtjs/dotenv": "^1.4.1",
"bootstrap": "^4.6.1", "bootstrap": "^4.6.1",
"bootstrap-vue": "^2.22.0", "bootstrap-vue": "^2.22.0",
"cookie-universal-nuxt": "^2.1.5", "cookie-universal-nuxt": "^2.2.1",
"jwt-decode": "^3.1.2", "jwt-decode": "^3.1.2",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"mpegts.js": "^1.6.10", "mpegts.js": "^1.6.10",
"nuxt": "^2.15.8", "nuxt": "^2.15.8",
"splitpanes": "^2.3.8", "splitpanes": "^2.3.8",
"video.js": "^7.18.1", "video.js": "^7.19.2",
"vue-loading-overlay": "^3.4.2", "vue-loading-overlay": "^3.4.2",
"vue2-perfect-scrollbar": "^1.5.5", "vue2-perfect-scrollbar": "^1.5.5",
"vuedraggable": "^2.24.3" "vuedraggable": "^2.24.3"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.17.0", "@babel/eslint-parser": "^7.18.2",
"@babel/preset-react": "^7.16.7", "@babel/preset-react": "^7.18.6",
"@nuxtjs/eslint-config": "^5.0.0", "@nuxtjs/eslint-config": "^5.0.0",
"@nuxtjs/eslint-module": "^3.1.0", "@nuxtjs/eslint-module": "^3.1.0",
"@nuxtjs/style-resources": "^1.2.1", "@nuxtjs/style-resources": "^1.2.1",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-nuxt": ">=2.0.0", "eslint-plugin-nuxt": ">=2.0.0",
"sass": "^1.51.0", "sass": "^1.53.0",
"sass-loader": "^10.2.1" "sass-loader": "^10.2.1"
} }
} }

View File

@ -184,19 +184,11 @@
</b-form-group> </b-form-group>
<b-form-group <b-form-group
label-cols-sm="2" label-cols-sm="2"
:label="'email'" :label="'mail'"
label-align-sm="right" label-align-sm="right"
:label-for="'email'" :label-for="'mail'"
> >
<b-form-input id="email" v-model="configUser['email']" :value="configUser['email']" /> <b-form-input id="mail" v-model="configUser['mail']" :value="configUser['mail']" />
</b-form-group>
<b-form-group
label-cols-sm="2"
label="old password"
label-align-sm="right"
label-for="oldPass"
>
<b-form-input id="oldPass" v-model="oldPass" type="password" />
</b-form-group> </b-form-group>
<b-form-group <b-form-group
label-cols-sm="2" label-cols-sm="2"
@ -251,7 +243,6 @@ export default {
data () { data () {
return { return {
oldPass: null,
newPass: null, newPass: null,
confirmPass: null, confirmPass: null,
showAlert: false, showAlert: false,
@ -368,9 +359,8 @@ export default {
}, },
async onSubmitUser (evt) { async onSubmitUser (evt) {
evt.preventDefault() evt.preventDefault()
if (this.oldPass && this.newPass && this.newPass === this.confirmPass) { if (this.newPass && this.newPass === this.confirmPass) {
this.configUser.old_password = this.oldPass this.configUser.password = this.newPass
this.configUser.new_password = this.newPass
} }
await this.$store.dispatch('auth/inspectToken') await this.$store.dispatch('auth/inspectToken')
const update = await this.$store.dispatch('config/setUserConfig', this.configUser) const update = await this.$store.dispatch('config/setUserConfig', this.configUser)
@ -385,7 +375,6 @@ export default {
this.showAlert = true this.showAlert = true
this.oldPass = null
this.newPass = null this.newPass = null
this.confirmPass = null this.confirmPass = null
}, },

View File

@ -33,105 +33,13 @@
<div v-else> <div v-else>
<b-container class="login-container"> <b-container class="login-container">
<div> <div>
<b-row cols="3"> <div class="logo-div">
<b-col cols="4" class="chart-col chart1"> <b-img-lazy
<br> src="/images/ffplayout.png"
<div class="stat-div"> alt="Logo"
<div class="stat-center" style="text-align: left;"> fluid
<h1>ffplayout</h1> />
<h3 v-if="stat.system">
{{ stat.system }}<br>
{{ stat.node }}<br>
{{ stat.machine }}
</h3>
</div> </div>
</div>
</b-col>
<b-col cols="4" class="chart-col chart2">
<div v-if="stat.cpu_usage || stat.cpu_usage >= 0">
<div>
<strong>CPU</strong>
</div>
<div class="stat-div">
<div class="stat-center">
<div style="text-align: left;">
<strong>Usage: </strong>{{ stat.cpu_usage }}%<br>
<strong>Load: </strong> {{ stat.cpu_load[0] }} {{ stat.cpu_load[1] }} {{ stat.cpu_load[2] }}
</div>
</div>
</div>
</div>
</b-col>
<b-col cols="4" class="chart-col chart3">
<div v-if="stat.ram_total">
<div>
<strong>RAM</strong>
</div>
<div class="stat-div">
<div class="stat-center">
<div style="text-align: left;">
<strong>Total: </strong> {{ stat.ram_total[1] }}<br>
<strong>Used: </strong> {{ stat.ram_used[1] }}<br>
<strong>Free: </strong> {{ stat.ram_free[1] }}<br>
<strong>Cached: </strong> {{ stat.ram_cached[1] }}
</div>
</div>
</div>
</div>
</b-col>
<b-col cols="4" class="chart-col chart4">
<div v-if="stat.swap_total">
<div>
<strong>SWAP</strong>
</div>
<div class="stat-div">
<div class="stat-center">
<div style="text-align: left;">
<strong>Total: </strong> {{ stat.swap_total[1] }}<br>
<strong>Used: </strong> {{ stat.swap_used[1] }}<br>
<strong>Free: </strong> {{ stat.swap_free[1] }}
</div>
</div>
</div>
</div>
</b-col>
<b-col cols="4" class="chart-col chart5">
<div v-if="stat.disk_total">
<div>
<strong>DISK</strong>
</div>
<div class="stat-div">
<div class="stat-center">
<div style="text-align: left;">
<strong>Total: </strong> {{ stat.disk_total[1] }}<br>
<strong>Used: </strong> {{ stat.disk_used[1] }}<br>
<strong>Free: </strong> {{ stat.disk_free[1] }}
</div>
</div>
</div>
</div>
</b-col>
<b-col cols="4" class="chart-col chart6">
<div v-if="stat.net_send">
<div>
<strong>NET</strong>
</div>
<div class="stat-div">
<div class="stat-center">
<div style="text-align: left;">
<strong>Download: </strong> {{ stat.net_speed_recv[1] }}/s<br>
<strong>Upload: </strong> {{ stat.net_speed_send[1] }}/s<br>
<strong>Downloaded: </strong> {{ stat.net_recv[1] }}<br>
<strong>Uploaded: </strong> {{ stat.net_send[1] }}<br>
<strong>Recived Errors: </strong> {{ stat.net_errin }}<br>
<strong>Sended Errors: </strong> {{ stat.net_errout }}
</div>
</div>
</div>
</div>
</b-col>
</b-row>
<div class="actions"> <div class="actions">
<b-button-group class="actions-grp"> <b-button-group class="actions-grp">
<b-button to="/player" variant="primary"> <b-button to="/player" variant="primary">
@ -183,7 +91,6 @@ export default {
methods: { methods: {
async init () { async init () {
await this.$store.dispatch('auth/inspectToken') await this.$store.dispatch('auth/inspectToken')
this.checkLogin()
}, },
async login () { async login () {
try { try {
@ -195,12 +102,11 @@ export default {
this.formPassword = '' this.formPassword = ''
this.formError = null this.formError = null
if (status === 401) { if (status === 401 || status === 400) {
this.formError = 'Wrong user or password!' this.formError = 'Wrong user or password!'
this.showError = true this.showError = true
} }
this.checkLogin()
await this.$store.dispatch('config/nuxtClientInit') await this.$store.dispatch('config/nuxtClientInit')
} catch (e) { } catch (e) {
this.formError = e.message this.formError = e.message
@ -215,31 +121,6 @@ export default {
} catch (e) { } catch (e) {
this.formError = e.message this.formError = e.message
} }
},
checkLogin () {
if (this.$store.state.auth.isLogin) {
this.sysStats()
}
},
async sysStats () {
const response = await this.$axios.get('api/player/stats/?stats=all')
if (!response.data) {
this.$router.push('/configure')
}
this.stat = response.data
if (process.browser && !this.interval) {
this.interval = setInterval(async () => {
if (this.$store.state.auth.isLogin && this.$route.path === '/') {
const response = await this.$axios.get('api/player/stats/?stats=all')
this.stat = response.data
} else {
clearInterval(this.interval)
}
}, 2000)
}
} }
} }
} }
@ -258,6 +139,12 @@ export default {
margin-bottom: 3em; margin-bottom: 3em;
} }
.logo-div {
width: 100%;
text-align: center;
margin-bottom: 5em;
}
.login-form { .login-form {
min-width: 300px; min-width: 300px;
} }

View File

@ -81,11 +81,17 @@ export default {
methods: { methods: {
async getLog () { async getLog () {
const response = await this.$axios.get( let date = this.listDate
`api/player/log/?date=${this.listDate}&channel=${this.$store.state.config.configGui[this.$store.state.config.configID].id}`)
if (response.data.log) { if (date === this.$dayjs().tz(this.timezone).format('YYYY-MM-DD')) {
this.currentLog = response.data.log date = ''
}
const response = await this.$axios.get(
`api/log/${this.$store.state.config.configGui[this.$store.state.config.configID].id}?date=${date}`)
if (response.data) {
this.currentLog = response.data
} else { } else {
this.currentLog = '' this.currentLog = ''
} }

View File

@ -14,14 +14,14 @@
</span> </span>
</div> </div>
<div v-if="folderTree.tree" class="browser"> <div v-if="folderTree" class="browser">
<div class="bread-div"> <div class="bread-div">
<b-breadcrumb> <b-breadcrumb>
<b-breadcrumb-item <b-breadcrumb-item
v-for="(crumb, index) in crumbs" v-for="(crumb, index) in crumbs"
:key="crumb.key" :key="crumb.key"
:active="index === crumbs.length - 1" :active="index === crumbs.length - 1"
@click="getPath(extensions, crumb.path)" @click="getPath(crumb.path)"
> >
{{ crumb.text }} {{ crumb.text }}
</b-breadcrumb-item> </b-breadcrumb-item>
@ -34,8 +34,8 @@
<perfect-scrollbar :options="scrollOP" class="media-browser-scroll"> <perfect-scrollbar :options="scrollOP" class="media-browser-scroll">
<b-list-group class="folder-list"> <b-list-group class="folder-list">
<b-list-group-item <b-list-group-item
v-for="folder in folderTree.tree[1]" v-for="folder in folderTree.folders"
:key="folder.key" :key="folder"
class="browser-item folder" class="browser-item folder"
> >
<b-row> <b-row>
@ -43,12 +43,12 @@
<b-icon-folder-fill class="browser-icons" /> <b-icon-folder-fill class="browser-icons" />
</b-col> </b-col>
<b-col class="browser-item-text"> <b-col class="browser-item-text">
<b-link @click="getPath(extensions, `/${folderTree.tree[0]}/${folder}`)"> <b-link @click="getPath(`/${folderTree.source}/${folder}`)">
{{ folder }} {{ folder }}
</b-link> </b-link>
</b-col> </b-col>
<b-col v-if="folder !== '..'" cols="1" class="folder-delete"> <b-col v-if="folder !== '..'" cols="1" class="folder-delete">
<b-link @click="showDeleteModal('Folder', `/${folderTree.tree[0]}/${folder}`)"> <b-link @click="showDeleteModal('Folder', `/${folderTree.source}/${folder}`)">
<b-icon-x-circle-fill /> <b-icon-x-circle-fill />
</b-link> </b-link>
</b-col> </b-col>
@ -70,8 +70,8 @@
<perfect-scrollbar :options="scrollOP" class="media-browser-scroll"> <perfect-scrollbar :options="scrollOP" class="media-browser-scroll">
<b-list-group class="files-list"> <b-list-group class="files-list">
<b-list-group-item <b-list-group-item
v-for="file in folderTree.tree[2]" v-for="file in folderTree.files"
:key="file.key" :key="file.name"
class="browser-item" class="browser-item"
> >
<b-row> <b-row>
@ -79,10 +79,10 @@
<b-icon-film class="browser-icons" /> <b-icon-film class="browser-icons" />
</b-col> </b-col>
<b-col class="browser-item-text"> <b-col class="browser-item-text">
{{ file.file }} {{ file.name }}
</b-col> </b-col>
<b-col cols="1" class="browser-play-col"> <b-col cols="1" class="browser-play-col">
<b-link title="Preview" @click="showPreviewModal(`/${folderTree.tree[0]}/${file.file}`)"> <b-link title="Preview" @click="showPreviewModal(`/${folderTree.parent}/${folderTree.source}/${file.name}`)">
<b-icon-play-fill /> <b-icon-play-fill />
</b-link> </b-link>
</b-col> </b-col>
@ -90,12 +90,12 @@
<span class="duration">{{ file.duration | toMin }}</span> <span class="duration">{{ file.duration | toMin }}</span>
</b-col> </b-col>
<b-col cols="1" class="small-col"> <b-col cols="1" class="small-col">
<b-link title="Rename File" @click="showRenameModal(`/${folderTree.tree[0]}/`, file.file)"> <b-link title="Rename File" @click="showRenameModal(file.name)">
<b-icon-pencil-square /> <b-icon-pencil-square />
</b-link> </b-link>
</b-col> </b-col>
<b-col cols="1" class="small-col"> <b-col cols="1" class="small-col">
<b-link title="Delete File" @click="showDeleteModal('File', `/${folderTree.tree[0]}/${file.file}`)"> <b-link title="Delete File" @click="showDeleteModal('File', `/${folderTree.parent}/${folderTree.source}/${file.name}`)">
<b-icon-x-circle-fill /> <b-icon-x-circle-fill />
</b-link> </b-link>
</b-col> </b-col>
@ -304,20 +304,24 @@ export default {
watch: { watch: {
configID () { configID () {
this.getPath(this.extensions, '') this.getPath('')
} }
}, },
mounted () { mounted () {
this.extensions = [...this.configPlayout.storage.extensions, ...this.configGui[this.configID].extra_extensions].join(',') const exts = [...this.configPlayout.storage.extensions, ...this.configGui[this.configID].extra_extensions].map((ext) => {
this.getPath(this.extensions, '') return `.${ext}`
})
this.extensions = exts.join(',')
this.getPath('')
}, },
methods: { methods: {
async getPath (extensions, path) { async getPath (path) {
this.lastPath = path this.lastPath = path
this.isLoading = true this.isLoading = true
await this.$store.dispatch('media/getTree', { extensions, path }) await this.$store.dispatch('media/getTree', { path })
this.isLoading = false this.isLoading = false
}, },
@ -358,18 +362,14 @@ export default {
async onSubmitCreateFolder (evt) { async onSubmitCreateFolder (evt) {
evt.preventDefault() evt.preventDefault()
const path = (this.crumbs[this.crumbs.length - 1].path + '/' + this.folderName).replace(/\/[/]+/, '/')
await this.$axios.post( await this.$axios.post(
'api/player/media/op/', `api/file/${this.configGui[this.configID].id}/create-folder/`, { source: path }
{
folder: this.folderName,
path: this.crumbs.map(e => e.text).join('/'),
channel: this.configGui[this.configID].id
}
) )
this.$root.$emit('bv::hide::modal', 'folder-modal') this.$root.$emit('bv::hide::modal', 'folder-modal')
this.getPath(this.extensions, this.lastPath) this.getPath(this.lastPath)
}, },
onCancelCreateFolder (evt) { onCancelCreateFolder (evt) {
@ -400,12 +400,13 @@ export default {
this.currentProgress = progress this.currentProgress = progress
} }
const channel = this.configGui[this.configID].id
for (const [i, file] of this.inputFiles.entries()) { for (const [i, file] of this.inputFiles.entries()) {
this.uploadTask = file.name this.uploadTask = file.name
this.currentNumber = i + 1 this.currentNumber = i + 1
const formData = new FormData()
formData.append(file.name, file)
const config = { const config = {
onUploadProgress: uploadProgress(file.name), onUploadProgress: uploadProgress(file.name),
cancelToken: this.cancelTokenSource.token, cancelToken: this.cancelTokenSource.token,
@ -413,8 +414,8 @@ export default {
} }
await this.$axios.put( await this.$axios.put(
`api/player/media/upload/${encodeURIComponent(file.name)}?path=${encodeURIComponent(this.crumbs.map(e => e.text).join('/'))}&channel=${channel}`, `api/file/${this.configGui[this.configID].id}/upload/?path=${encodeURIComponent(this.crumbs[this.crumbs.length - 1].path)}`,
file, formData,
config config
) )
.then((res) => { .then((res) => {
@ -428,7 +429,7 @@ export default {
this.currentNumber = 0 this.currentNumber = 0
this.inputPlaceholder = 'Choose files or drop them here...' this.inputPlaceholder = 'Choose files or drop them here...'
this.inputFiles = [] this.inputFiles = []
this.getPath(this.extensions, this.lastPath) this.getPath(this.lastPath)
this.$root.$emit('bv::hide::modal', 'upload-modal') this.$root.$emit('bv::hide::modal', 'upload-modal')
}, },
@ -441,7 +442,7 @@ export default {
this.inputPlaceholder = 'Choose files or drop them here...' this.inputPlaceholder = 'Choose files or drop them here...'
this.cancelTokenSource.cancel('Upload cancelled') this.cancelTokenSource.cancel('Upload cancelled')
this.getPath(this.extensions, this.lastPath) this.getPath(this.lastPath)
this.$root.$emit('bv::hide::modal', 'upload-modal') this.$root.$emit('bv::hide::modal', 'upload-modal')
}, },
@ -451,7 +452,7 @@ export default {
this.previewName = src.split('/').slice(-1)[0] this.previewName = src.split('/').slice(-1)[0]
const ext = this.previewName.split('.').slice(-1)[0] const ext = this.previewName.split('.').slice(-1)[0]
if (this.configPlayout.storage.extensions.includes(`.${ext}`)) { if (this.configPlayout.storage.extensions.includes(`${ext}`)) {
this.isImage = false this.isImage = false
this.previewOptions = { this.previewOptions = {
liveui: false, liveui: false,
@ -462,7 +463,7 @@ export default {
sources: [ sources: [
{ {
type: `video/${ext}`, type: `video/${ext}`,
src: '/' + encodeURIComponent(src.replace(/^\//, '')) src: '/' + encodeURIComponent(src.replace(/^[/]+/, ''))
} }
] ]
} }
@ -472,8 +473,7 @@ export default {
this.$root.$emit('bv::show::modal', 'preview-modal') this.$root.$emit('bv::show::modal', 'preview-modal')
}, },
showRenameModal (path, file) { showRenameModal (file) {
this.renamePath = path
this.renameOldName = file this.renameOldName = file
this.renameNewName = file this.renameNewName = file
this.$root.$emit('bv::show::modal', 'rename-modal') this.$root.$emit('bv::show::modal', 'rename-modal')
@ -482,16 +482,14 @@ export default {
async renameFile (evt) { async renameFile (evt) {
evt.preventDefault() evt.preventDefault()
await this.$axios.patch( await this.$axios.post(
'api/player/media/op/', { `api/file/${this.configGui[this.configID].id}/rename/`, {
path: this.renamePath.replace(/^\/\//g, '/'), source: `/${this.folderTree.parent}/${this.folderTree.source}/${this.renameOldName}`.replace('//', '/'),
oldname: this.renameOldName, target: `/${this.folderTree.parent}/${this.folderTree.source}/${this.renameNewName}`.replace('//', '/')
newname: this.renameNewName,
channel: this.configGui[this.configID].id
} }
) )
this.getPath(this.extensions, this.lastPath) this.getPath(this.lastPath)
this.renamePath = '' this.renamePath = ''
this.renameOldName = '' this.renameOldName = ''
@ -510,9 +508,9 @@ export default {
this.deleteSource = src this.deleteSource = src
if (type === 'File') { if (type === 'File') {
this.previewName = src.split('/').slice(-1)[0] this.previewName = src.split('/').slice(-1)[0].replace('//', '/')
} else { } else {
this.previewName = src this.previewName = src.replace('//', '/')
} }
this.deleteType = type this.deleteType = type
@ -527,17 +525,19 @@ export default {
file = this.deleteSource.split('/').slice(-1)[0] file = this.deleteSource.split('/').slice(-1)[0]
pathName = this.deleteSource.substring(0, this.deleteSource.lastIndexOf('/') + 1) pathName = this.deleteSource.substring(0, this.deleteSource.lastIndexOf('/') + 1)
} else { } else {
file = null file = ''
pathName = this.deleteSource pathName = this.deleteSource
} }
await this.$axios.delete( const source = `${pathName}/${file}`.replace('//', '/')
`api/player/media/op/?file=${encodeURIComponent(file)}&path=${encodeURIComponent(pathName)}&channel=${this.configGui[this.configID].id}`)
await this.$axios.post(
`api/file/${this.configGui[this.configID].id}/remove/`, { source })
.catch(err => console.log(err)) .catch(err => console.log(err))
this.$root.$emit('bv::hide::modal', 'delete-modal') this.$root.$emit('bv::hide::modal', 'delete-modal')
this.getPath(this.extensions, this.lastPath) this.getPath(this.lastPath)
}, },
cancelDelete () { cancelDelete () {

View File

@ -266,44 +266,52 @@ export default {
}, },
watch: { watch: {
selected (name) { selected (index) {
this.getPreset(name) this.getPreset(index)
} }
}, },
created () { created () {
this.getPreset('') this.getPreset(null)
}, },
methods: { methods: {
async getPreset (preset) { decToHex (num) {
let req = '' return '0x' + Math.round(num * 255).toString(16)
},
if (preset) { hexToDec (num) {
req = `?name=${preset}` return (parseFloat(parseInt(num, 16)) / 255).toFixed(2)
} },
const response = await this.$axios.get(`api/player/messenger/${req}`)
if (response.data && !preset) { async getPreset (index) {
for (const item of response.data) { const response = await this.$axios.get(`api/presets/${this.configGui[this.configID].id}`)
this.presets.push({ value: item.name, text: item.name })
if (response.data && index === null) {
this.presets = []
for (let index = 0; index < response.data.length; index++) {
const elem = response.data[index]
this.presets.push({ value: index, text: elem.name })
} }
} else if (response.data) { } else if (response.data) {
const fColor = response.data[index].fontcolor.split('@')
const bColor = response.data[index].boxcolor.split('@')
this.form = { this.form = {
id: response.data[0].id, id: response.data[index].id,
name: response.data[0].name, name: response.data[index].name,
text: response.data[0].message, text: response.data[index].text,
x: response.data[0].x, x: response.data[index].x,
y: response.data[0].y, y: response.data[index].y,
fontSize: response.data[0].font_size, fontSize: response.data[index].fontsize,
fontSpacing: response.data[0].font_spacing, fontSpacing: response.data[index].line_spacing,
fontColor: response.data[0].font_color, fontColor: fColor[0],
fontAlpha: response.data[0].font_alpha, fontAlpha: (fColor[1]) ? this.hexToDec(fColor[1]) : 1.0,
showBox: response.data[0].show_box, showBox: response.data[index].box,
boxColor: response.data[0].box_color, boxColor: bColor[0],
boxAlpha: response.data[0].box_alpha, boxAlpha: (bColor[1]) ? this.hexToDec(bColor[1]) : 1.0,
border: response.data[0].border_width, border: response.data[index].boxborderw,
overallAlpha: response.data[0].overall_alpha overallAlpha: response.data[index].alpha
} }
} }
}, },
@ -319,24 +327,24 @@ export default {
async createPreset () { async createPreset () {
const preset = { const preset = {
name: this.newPresetName, name: this.newPresetName,
message: this.form.text, text: this.form.text,
x: this.form.x, x: this.form.x.toString(),
y: this.form.y, y: this.form.y.toString(),
font_size: this.form.fontSize, fontsize: this.form.fontSize.toString(),
font_spacing: this.form.fontSpacing, line_spacing: this.form.fontSpacing.toString(),
font_color: this.form.fontColor, fontcolor: (this.form.fontAlpha === 1) ? this.form.fontColor : this.form.fontColor + '@' + this.decToHex(this.form.fontAlpha),
font_alpha: this.form.fontAlpha, box: (this.form.showBox) ? '1' : '0',
show_box: this.form.showBox, boxcolor: (this.form.boxAlpha === 1) ? this.form.boxColor : this.form.boxColor + '@' + this.decToHex(this.form.boxAlpha),
box_color: this.form.boxColor, boxborderw: this.form.border.toString(),
box_alpha: this.form.boxAlpha, alpha: this.form.overallAlpha.toString(),
border_width: this.form.border, channel_id: this.configGui[this.configID].id
overall_alpha: this.form.overallAlpha
} }
const response = await this.$axios.post('api/player/messenger/', preset) const response = await this.$axios.post('api/presets/', preset)
if (response.status === 201) { if (response.status === 200) {
this.success = true this.success = true
this.getPreset(null)
} else { } else {
this.failed = true this.failed = true
} }
@ -350,21 +358,20 @@ export default {
const preset = { const preset = {
id: this.form.id, id: this.form.id,
name: this.form.name, name: this.form.name,
message: this.form.text, text: this.form.text,
x: this.form.x, x: this.form.x,
y: this.form.y, y: this.form.y,
font_size: this.form.fontSize, fontsize: this.form.fontSize,
font_spacing: this.form.fontSpacing, line_spacing: this.form.fontSpacing,
font_color: this.form.fontColor, fontcolor: (this.form.fontAlpha === 1) ? this.form.fontColor : this.form.fontColor + '@' + this.decToHex(this.form.fontAlpha),
font_alpha: this.form.fontAlpha, box: (this.form.showBox) ? '1' : '0',
show_box: this.form.showBox, boxcolor: (this.form.boxAlpha === 1) ? this.form.boxColor : this.form.boxColor + '@' + this.decToHex(this.form.boxAlpha),
box_color: this.form.boxColor, boxborderw: this.form.border,
box_alpha: this.form.boxAlpha, alpha: this.form.overallAlpha,
border_width: this.form.border, channel_id: this.configGui[this.configID].id
overall_alpha: this.form.overallAlpha
} }
const response = await this.$axios.put(`api/player/messenger/${this.form.id}/`, preset) const response = await this.$axios.put(`api/presets/${this.form.id}`, preset)
if (response.status === 200) { if (response.status === 200) {
this.success = true this.success = true
@ -383,37 +390,30 @@ export default {
}, },
async deletePreset () { async deletePreset () {
if (this.selected) { if (this.selected) {
await this.$axios.delete(`api/player/messenger/${this.form.id}/`) await this.$axios.delete(`api/presets/${this.form.id}`)
} }
this.$bvModal.hide('delete-modal') this.$bvModal.hide('delete-modal')
this.getPreset('') this.getPreset(null)
}, },
async submitMessage () { async submitMessage () {
function aToHex (num) {
return '0x' + Math.round(num * 255).toString(16)
}
const obj = { const obj = {
text: this.form.text, text: this.form.text,
x: this.form.x, x: this.form.x.toString(),
y: this.form.y, y: this.form.y.toString(),
fontsize: this.form.fontSize, fontsize: this.form.fontSize.toString(),
line_spacing: this.form.fontSpacing, line_spacing: this.form.fontSpacing.toString(),
fontcolor: this.form.fontColor + '@' + aToHex(this.form.fontAlpha), fontcolor: this.form.fontColor + '@' + this.decToHex(this.form.fontAlpha),
alpha: this.form.overallAlpha, alpha: this.form.overallAlpha.toString(),
box: (this.form.showBox) ? 1 : 0, box: (this.form.showBox) ? '1' : '0',
boxcolor: this.form.boxColor + '@' + aToHex(this.form.boxAlpha), boxcolor: this.form.boxColor + '@' + this.decToHex(this.form.boxAlpha),
boxborderw: this.form.border boxborderw: this.form.border.toString()
} }
const response = await this.$axios.post('api/player/send/message/', { const response = await this.$axios.post(`api/control/${this.configGui[this.configID].id}/text/`, obj)
data: obj,
channel: this.configGui[this.configID].id
})
if (response.data && response.data.status.Success && response.data.status.Success.split(' ')[0] === '0') { if (response.data && response.status === 200) {
this.success = true this.success = true
} else { } else {
this.failed = true this.failed = true

View File

@ -2,11 +2,11 @@
<div style="height:100%;"> <div style="height:100%;">
<Menu /> <Menu />
<b-container class="control-container"> <b-container class="control-container">
<b-row class="control-row"> <b-row class="control-row" align-v="stretch">
<b-col cols="3" class="player-col"> <b-col cols="3" class="player-col">
<b-aspect aspect="16:9"> <b-aspect aspect="16:9">
<video <video
v-if="configGui[configID].player_url.split('.').pop() === 'flv'" v-if="configGui[configID].preview_url.split('.').pop() === 'flv'"
id="httpStream" id="httpStream"
ref="httpStream" ref="httpStream"
width="100%" width="100%"
@ -15,7 +15,7 @@
<video-player v-else-if="videoOptions.sources" :key="configID" reference="videoPlayer" :options="videoOptions" /> <video-player v-else-if="videoOptions.sources" :key="configID" reference="videoPlayer" :options="videoOptions" />
</b-aspect> </b-aspect>
</b-col> </b-col>
<b-col class="control-col"> <b-col>
<b-row class="control-col"> <b-row class="control-col">
<b-col cols="8" class="status-col"> <b-col cols="8" class="status-col">
<b-row class="status-row"> <b-row class="status-row">
@ -52,7 +52,7 @@
class="control-button control-button-play" class="control-button control-button-play"
:class="isPlaying" :class="isPlaying"
variant="primary" variant="primary"
@click="playoutControl('start')" @click="controlProcess('start')"
> >
<b-icon-play /> <b-icon-play />
</b-button> </b-button>
@ -64,25 +64,61 @@
title="Stop Playout Service" title="Stop Playout Service"
class="control-button control-button-stop" class="control-button control-button-stop"
variant="primary" variant="primary"
@click="playoutControl('stop')" @click="controlProcess('stop')"
> >
<b-icon-stop /> <b-icon-stop />
</b-button> </b-button>
</div> </div>
</b-col> </b-col>
<!-- <div class="w-100" />-->
<b-col> <b-col>
<div> <div>
<b-button <b-button
title="Restart Playout Service" title="Restart Playout Service"
class="control-button control-button-restart" class="control-button control-button-restart"
variant="primary" variant="primary"
@click="playoutControl('restart')" @click="controlProcess('restart')"
> >
<b-icon-arrow-clockwise /> <b-icon-arrow-clockwise />
</b-button> </b-button>
</div> </div>
</b-col> </b-col>
<div class="w-100" />
<b-col>
<div>
<b-button
title="Jump to last Clip"
class="control-button control-button-control"
variant="primary"
@click="controlPlayout('back')"
>
<b-icon-skip-start />
</b-button>
</div>
</b-col>
<b-col>
<div>
<b-button
title="Reset Playout State"
class="control-button control-button-control"
variant="primary"
@click="controlPlayout('reset')"
>
<b-icon-arrow-repeat />
</b-button>
</div>
</b-col>
<b-col>
<div>
<b-button
title="Jump to next Clip"
class="control-button control-button-control"
variant="primary"
@click="controlPlayout('next')"
>
<b-icon-skip-end />
</b-button>
</div>
</b-col>
</b-row> </b-row>
</b-col> </b-col>
</b-row> </b-row>
@ -102,21 +138,21 @@
<splitpanes class="list-row default-theme pane-row"> <splitpanes class="list-row default-theme pane-row">
<pane min-size="20" size="24"> <pane min-size="20" size="24">
<loading <loading
:active.sync="isLoading" :active.sync="browserIsLoading"
:can-cancel="false" :can-cancel="false"
:is-full-page="false" :is-full-page="false"
background-color="#485159" background-color="#485159"
color="#ff9c36" color="#ff9c36"
/> />
<div v-if="folderTree.tree" class="browser-div"> <div v-if="folderTree.parent" class="browser-div">
<div> <div>
<b-breadcrumb> <b-breadcrumb>
<b-breadcrumb-item <b-breadcrumb-item
v-for="(crumb, index) in crumbs" v-for="(crumb, index) in crumbs"
:key="crumb.key" :key="crumb.key"
:active="index === crumbs.length - 1" :active="index === crumbs.length - 1"
@click="getPath(extensions, crumb.path)" @click="getPath(crumb.path)"
> >
{{ crumb.text }} {{ crumb.text }}
</b-breadcrumb-item> </b-breadcrumb-item>
@ -126,23 +162,23 @@
<perfect-scrollbar :options="scrollOP" class="player-browser-scroll"> <perfect-scrollbar :options="scrollOP" class="player-browser-scroll">
<b-list-group> <b-list-group>
<b-list-group-item <b-list-group-item
v-for="folder in folderTree.tree[1]" v-for="folder in folderTree.folders"
:key="folder.key" :key="folder.key"
class="browser-item" class="browser-item"
> >
<b-link @click="getPath(extensions, `/${folderTree.tree[0]}/${folder}`)"> <b-link @click="getPath(`/${folderTree.source}/${folder}`)">
<b-icon-folder-fill class="browser-icons" /> {{ folder }} <b-icon-folder-fill class="browser-icons" /> {{ folder }}
</b-link> </b-link>
</b-list-group-item> </b-list-group-item>
<draggable <draggable
:list="folderTree.tree[2]" :list="folderTree.files"
:clone="cloneClip" :clone="cloneClip"
:group="{ name: 'playlist', pull: 'clone', put: false }" :group="{ name: 'playlist', pull: 'clone', put: false }"
:sort="false" :sort="false"
> >
<b-list-group-item <b-list-group-item
v-for="file in folderTree.tree[2]" v-for="file in folderTree.files"
:key="file.key" :key="file.name"
class="browser-item" class="browser-item"
> >
<b-row> <b-row>
@ -150,10 +186,10 @@
<b-icon-film class="browser-icons" /> <b-icon-film class="browser-icons" />
</b-col> </b-col>
<b-col class="browser-item-text grabbing"> <b-col class="browser-item-text grabbing">
{{ file.file }} {{ file.name }}
</b-col> </b-col>
<b-col cols="1" class="browser-play-col"> <b-col cols="1" class="browser-play-col">
<b-link @click="showPreviewModal(`/${folderTree.tree[0]}/${file.file}`)"> <b-link @click="showPreviewModal(`/${folderTree.parent}/${folderTree.source}/${file.name}`)">
<b-icon-play-fill /> <b-icon-play-fill />
</b-link> </b-link>
</b-col> </b-col>
@ -200,6 +236,13 @@
</b-list-group-item> </b-list-group-item>
</b-list-group> </b-list-group>
<perfect-scrollbar id="scroll-container" :options="scrollOP"> <perfect-scrollbar id="scroll-container" :options="scrollOP">
<loading
:active.sync="playlistIsLoading"
:can-cancel="false"
:is-full-page="false"
background-color="#485159"
color="#ff9c36"
/>
<b-list-group class="playlist-list-group" :style="`height: ${(playlist) ? playlist.length * 52 + 52 : 300}px`"> <b-list-group class="playlist-list-group" :style="`height: ${(playlist) ? playlist.length * 52 + 52 : 300}px`">
<draggable <draggable
id="playlist-group" id="playlist-group"
@ -267,6 +310,12 @@
<b-button v-if="!configPlayout.playlist.loop" v-b-tooltip.hover title="Loop Clips in Playlist" variant="primary" @click="loopClips()"> <b-button v-if="!configPlayout.playlist.loop" v-b-tooltip.hover title="Loop Clips in Playlist" variant="primary" @click="loopClips()">
<b-icon-view-stacked /> <b-icon-view-stacked />
</b-button> </b-button>
<b-button v-b-tooltip.hover title="Add (remote) Source to Playlist" variant="primary" @click="showAddSource()">
<b-icon-file-earmark-plus />
</b-button>
<b-button v-b-tooltip.hover title="Generate a randomized Playlist" variant="primary" @click="generatePlaylist(listDate)">
<b-icon-sort-down-alt />
</b-button>
<b-button v-b-tooltip.hover title="Save Playlist" variant="primary" @click="savePlaylist(listDate)"> <b-button v-b-tooltip.hover title="Save Playlist" variant="primary" @click="savePlaylist(listDate)">
<b-icon-download /> <b-icon-download />
</b-button> </b-button>
@ -305,6 +354,35 @@
> >
Delete program from {{ listDate }} Delete program from {{ listDate }}
</b-modal> </b-modal>
<b-modal
id="add-source-modal"
ref="add-source-modal"
title="Add (remote) Source"
@ok="handleSource"
>
<form ref="form" @submit.stop.prevent="addSource">
<b-form-group label="In" label-for="in-input">
<b-form-input id="in-input" v-model.number="newSource.in" type="number" inline />
</b-form-group>
<b-form-group label="Out" label-for="out-input" invalid-feedback="Out is required">
<b-form-input id="out-input" v-model.number="newSource.out" type="number" inline required />
</b-form-group>
<b-form-group label="Duration" label-for="duration-input" invalid-feedback="Out is required">
<b-form-input id="duration-input" v-model.number="newSource.duration" type="number" inline required />
</b-form-group>
<b-form-group label="Source" label-for="source-input" invalid-feedback="Source is required">
<b-form-input id="source-input" v-model="newSource.source" required />
</b-form-group>
<b-form-checkbox
id="ad-input"
v-model="newSource.category"
value="advertisement"
:unchecked-value="newSource.category"
>
Advertisement
</b-form-checkbox>
</form>
</b-modal>
</div> </div>
</template> </template>
@ -346,12 +424,12 @@ export default {
data () { data () {
return { return {
isLoading: false, browserIsLoading: false,
playlistIsLoading: false,
isPlaying: '', isPlaying: '',
listDate: this.$dayjs().tz(this.timezone).format('YYYY-MM-DD'), listDate: this.$dayjs().tz(this.timezone).format('YYYY-MM-DD'),
targetDate: this.$dayjs().tz(this.timezone).format('YYYY-MM-DD'), targetDate: this.$dayjs().tz(this.timezone).format('YYYY-MM-DD'),
interval: null, interval: null,
extensions: '',
videoOptions: { videoOptions: {
liveui: true, liveui: true,
controls: true, controls: true,
@ -377,6 +455,14 @@ export default {
scrollOP: { scrollOP: {
suppressScrollX: true, suppressScrollX: true,
minScrollbarLength: 30 minScrollbarLength: 30
},
newSource: {
begin: 0,
in: 0,
out: 0,
duration: 0,
category: '',
source: ''
} }
} }
}, },
@ -399,7 +485,9 @@ export default {
watch: { watch: {
listDate () { listDate () {
this.playlistIsLoading = true
this.getPlaylist() this.getPlaylist()
this.playlistIsLoading = false
setTimeout(() => { scrollTo(this) }, 5000) setTimeout(() => { scrollTo(this) }, 5000)
}, },
@ -407,11 +495,11 @@ export default {
this.videoOptions.sources = [ this.videoOptions.sources = [
{ {
type: 'application/x-mpegURL', type: 'application/x-mpegURL',
src: this.configGui[id].player_url src: this.configGui[id].preview_url
} }
] ]
this.getPath(this.extensions, '') this.getPath('')
this.getPlaylist() this.getPlaylist()
setTimeout(() => { scrollTo(this) }, 3000) setTimeout(() => { scrollTo(this) }, 3000)
} }
@ -421,13 +509,12 @@ export default {
this.videoOptions.sources = [ this.videoOptions.sources = [
{ {
type: 'application/x-mpegURL', type: 'application/x-mpegURL',
src: this.configGui[this.configID].player_url src: this.configGui[this.configID].preview_url
} }
] ]
this.getStatus() this.getStatus()
this.extensions = this.configPlayout.storage.extensions.join(',') await this.getPath('')
await this.getPath(this.extensions, '')
const timeInSec = this.$timeToSeconds(this.$dayjs().tz(this.timezone).format('HH:mm:ss')) const timeInSec = this.$timeToSeconds(this.$dayjs().tz(this.timezone).format('HH:mm:ss'))
const listStartSec = this.$timeToSeconds(this.configPlayout.playlist.day_start) const listStartSec = this.$timeToSeconds(this.configPlayout.playlist.day_start)
@ -442,18 +529,19 @@ export default {
mounted () { mounted () {
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
this.interval = setInterval(() => { this.interval = setInterval(() => {
this.$store.dispatch('playlist/animClock') this.$store.dispatch('playlist/playoutStat')
this.getStatus() this.getStatus()
}, 5000) }, 5000)
this.$store.dispatch('playlist/playoutStat')
} else { } else {
this.$store.dispatch('playlist/animClock') this.$store.dispatch('playlist/playoutStat')
} }
const streamExtension = this.configGui[this.configID].player_url.split('.').pop() const streamExtension = this.configGui[this.configID].preview_url.split('.').pop()
let player let player
if (streamExtension === 'flv') { if (streamExtension === 'flv') {
this.httpFlvSource.url = this.configGui[this.configID].player_url this.httpFlvSource.url = this.configGui[this.configID].preview_url
const element = this.$refs.httpStream const element = this.$refs.httpStream
if (typeof player !== 'undefined') { if (typeof player !== 'undefined') {
@ -478,26 +566,33 @@ export default {
}, },
methods: { methods: {
async getPath (extensions, path) { async getPath (path) {
this.isLoading = true this.browserIsLoading = true
await this.$store.dispatch('media/getTree', { extensions, path }) await this.$store.dispatch('media/getTree', { path })
this.isLoading = false this.browserIsLoading = false
}, },
async getStatus () { async getStatus () {
const channel = this.configGui[this.configID].id const channel = this.configGui[this.configID].id
const status = await this.$axios.post('api/player/system/', { run: 'status', channel }) const status = await this.$axios.post(`api/control/${channel}/process/`, { command: 'status' })
if (status.data.data && (status.data.data === 'RUNNING' || status.data.data === 'active')) { if (status.data && status.data === 'active') {
this.isPlaying = 'is-playing' this.isPlaying = 'is-playing'
} else { } else {
this.isPlaying = '' this.isPlaying = ''
} }
}, },
async playoutControl (state) { async controlProcess (state) {
const channel = this.configGui[this.configID].id const channel = this.configGui[this.configID].id
await this.$axios.post('api/player/system/', { run: state, channel }) await this.$axios.post(`api/control/${channel}/process/`, { command: state })
setTimeout(() => { this.getStatus() }, 1000)
},
async controlPlayout (state) {
const channel = this.configGui[this.configID].id
await this.$axios.post(`api/control/${channel}/playout/`, { command: state })
setTimeout(() => { this.getStatus() }, 1000) setTimeout(() => { this.getStatus() }, 1000)
}, },
@ -529,14 +624,12 @@ export default {
this.$root.$emit('bv::show::modal', 'preview-modal') this.$root.$emit('bv::show::modal', 'preview-modal')
}, },
cloneClip ({ file, duration }) { cloneClip ({ name, duration }) {
const storagePath = this.configPlayout.storage.path const storagePath = this.configPlayout.storage.path
const storagePathArr = storagePath.split('/') const sourcePath = `${storagePath}/${this.folderTree.source}/${name}`.replace('//', '/')
const storageRoot = storagePathArr.pop()
const sourcePath = `${storagePathArr.join('/')}/${this.folderTree.tree[0].substring(this.folderTree.tree[0].indexOf(storageRoot))}`
return { return {
source: `${sourcePath}/${file}`, source: sourcePath,
in: 0, in: 0,
out: duration, out: duration,
duration duration
@ -592,39 +685,50 @@ export default {
this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, tempList)) this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, tempList))
}, },
async generatePlaylist (listDate) {
this.playlistIsLoading = true
const generate = await this.$axios.get(
`api/playlist/${this.configGui[this.configID].id}/generate/${listDate}`
)
this.playlistIsLoading = false
if (generate.status === 200 || generate.status === 201) {
this.$store.commit('UPDATE_VARIANT', 'success')
this.$store.commit('UPDATE_SHOW_ERROR_ALERT', true)
this.$store.commit('UPDATE_ERROR_ALERT_MESSAGE', 'Generate Playlist done...')
this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, generate.data.program))
setTimeout(() => { this.$store.commit('UPDATE_SHOW_ERROR_ALERT', false) }, 2000)
}
},
async savePlaylist (saveDate) { async savePlaylist (saveDate) {
this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, this.playlist)) this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, this.playlist))
const saveList = this.playlist.map(({ begin, ...item }) => item) const saveList = this.playlist.map(({ begin, ...item }) => item)
const postSave = await this.$axios.post( const postSave = await this.$axios.post(
'api/player/playlist/', `api/playlist/${this.configGui[this.configID].id}/`,
{ { channel: this.$store.state.config.configGui.channel, date: saveDate, program: saveList }
data: { channel: this.$store.state.config.configGui.channel, date: saveDate, program: saveList },
channel: this.configGui[this.configID].id
}
) )
if (postSave.status === 200 || postSave.status === 201) { if (postSave.status === 200 || postSave.status === 201) {
this.$store.commit('UPDATE_VARIANT', 'success') this.$store.commit('UPDATE_VARIANT', 'success')
this.$store.commit('UPDATE_SHOW_ERROR_ALERT', true) this.$store.commit('UPDATE_SHOW_ERROR_ALERT', true)
this.$store.commit('UPDATE_ERROR_AERT_MESSAGE', 'Playlist saved...') this.$store.commit('UPDATE_ERROR_ALERT_MESSAGE', 'Playlist saved...')
setTimeout(() => { this.$store.commit('UPDATE_SHOW_ERROR_ALERT', false) }, 2000) setTimeout(() => { this.$store.commit('UPDATE_SHOW_ERROR_ALERT', false) }, 2000)
} }
}, },
async deletePlaylist (playlistDate) { async deletePlaylist (playlistDate) {
this.$store.commit('playlist/UPDATE_PLAYLIST', []) const postDelete = await this.$axios.delete(`api/playlist/${this.configGui[this.configID].id}/${playlistDate}`)
const date = playlistDate.split('-')
const playlistPath = `${this.configPlayout.playlist.path}/${date[0]}/${date[1]}/${playlistDate}.json`
const postDelete = await this.$axios.post('api/player/playlist/', { data: { delete: playlistPath } })
if (postDelete.status === 200 || postDelete.status === 201) { if (postDelete.status === 200 || postDelete.status === 201) {
this.$store.commit('playlist/UPDATE_PLAYLIST', [])
this.$store.commit('UPDATE_VARIANT', 'success') this.$store.commit('UPDATE_VARIANT', 'success')
this.$store.commit('UPDATE_SHOW_ERROR_ALERT', true) this.$store.commit('UPDATE_SHOW_ERROR_ALERT', true)
this.$store.commit('UPDATE_ERROR_AERT_MESSAGE', 'Playlist deleted...') this.$store.commit('UPDATE_ERROR_ALERT_MESSAGE', 'Playlist deleted...')
setTimeout(() => { this.$store.commit('UPDATE_SHOW_ERROR_ALERT', false) }, 2000) setTimeout(() => { this.$store.commit('UPDATE_SHOW_ERROR_ALERT', false) }, 2000)
} }
@ -636,6 +740,36 @@ export default {
showDeleteModal () { showDeleteModal () {
this.$root.$emit('bv::show::modal', 'delete-modal') this.$root.$emit('bv::show::modal', 'delete-modal')
},
showAddSource () {
this.$bvModal.show('add-source-modal')
},
handleSource (bvModalEvt) {
// Prevent modal from closing
bvModalEvt.preventDefault()
// Trigger submit handler
this.addSource()
},
addSource () {
const list = this.playlist
list.push(this.newSource)
this.$store.commit('playlist/UPDATE_PLAYLIST', this.$processPlaylist(this.startInSec, list))
this.newSource = {
begin: 0,
in: 0,
out: 0,
duration: 0,
category: '',
source: ''
}
this.$nextTick(() => {
this.$bvModal.hide('add-source-modal')
})
} }
} }
} }
@ -655,7 +789,6 @@ export default {
.player-col { .player-col {
max-width: 542px; max-width: 542px;
min-width: 380px; min-width: 380px;
margin-bottom: 6px;
} }
.control-col { .control-col {
@ -696,6 +829,10 @@ export default {
height: 100%; height: 100%;
} }
.control-button-control {
color: #06aad3;
}
.status-row { .status-row {
height: 100%; height: 100%;
min-width: 370px; min-width: 370px;

View File

@ -5,8 +5,8 @@ export default function ({ $axios, store, redirect, route }) {
config.headers.common.Authorization = `Bearer ${token}` config.headers.common.Authorization = `Bearer ${token}`
} }
// disable progress on auth and stats // disable progress on auth
if (config.url.includes('stats') || config.url.includes('auth') || config.url.includes('system')) { if (config.url.includes('auth') || config.url.includes('process') || config.url.includes('current')) {
config.progress = false config.progress = false
} }
}) })
@ -17,7 +17,7 @@ export default function ({ $axios, store, redirect, route }) {
const originalRequest = error.config const originalRequest = error.config
// prevent infinite loop // prevent infinite loop
if (error.response.status === 401 && originalRequest.url.includes('auth/refresh') && route.path !== '/') { if (error.response.status === 401 && route.path !== '/') {
store.commit('auth/REMOVE_TOKEN') store.commit('auth/REMOVE_TOKEN')
redirect('/') redirect('/')
return Promise.reject(error) return Promise.reject(error)
@ -25,24 +25,10 @@ export default function ({ $axios, store, redirect, route }) {
if (error.response.status === 401 && !originalRequest._retry && !originalRequest.url.includes('auth/token')) { if (error.response.status === 401 && !originalRequest._retry && !originalRequest.url.includes('auth/token')) {
originalRequest._retry = true originalRequest._retry = true
return $axios.post('auth/token/refresh/', {
refresh: store.state.auth.jwtRefresh
})
.then((res) => {
if (res.status === 201 || res.status === 200) {
store.commit('auth/UPADTE_TOKEN', { token: res.data.access })
originalRequest.headers.Authorization = `Bearer ${res.data.access}`
return $axios(originalRequest)
}
})
.catch((error) => {
if (error.response.status === 401) {
store.commit('auth/REMOVE_TOKEN') store.commit('auth/REMOVE_TOKEN')
store.commit('auth/UPDATE_IS_LOGIN', false) store.commit('auth/UPDATE_IS_LOGIN', false)
redirect('/') redirect('/')
return Promise.reject(error)
}
})
} }
return Promise.reject(error) return Promise.reject(error)
}) })
@ -55,7 +41,7 @@ export default function ({ $axios, store, redirect, route }) {
} else if (code !== 401) { } else if (code !== 401) {
store.commit('UPDATE_VARIANT', 'danger') store.commit('UPDATE_VARIANT', 'danger')
store.commit('UPDATE_SHOW_ERROR_ALERT', true) store.commit('UPDATE_SHOW_ERROR_ALERT', true)
store.commit('UPDATE_ERROR_AERT_MESSAGE', error) store.commit('UPDATE_ERROR_ALERT_MESSAGE', error)
} }
}) })
} }

BIN
static/images/ffplayout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -3,37 +3,25 @@ import jwt_decode from 'jwt-decode'
export const state = () => ({ export const state = () => ({
jwtToken: '', jwtToken: '',
jwtRefresh: '',
isLogin: false isLogin: false
}) })
// mutate values in state // mutate values in state
export const mutations = { export const mutations = {
UPADTE_TOKEN (state, obj) { UPDATE_TOKEN (state, obj) {
state.jwtToken = obj.token state.jwtToken = obj.token
this.$cookies.set('token', obj.token, { this.$cookies.set('token', obj.token, {
path: '/', path: '/',
maxAge: 60 * 60 * 24 * 365, maxAge: 60 * 60 * 24 * 365,
sameSite: 'lax' sameSite: 'lax'
}) })
if (obj.refresh) {
state.jwtRefresh = obj.refresh
this.$cookies.set('refresh', obj.refresh, {
path: '/',
maxAge: 60 * 60 * 24 * 365,
sameSite: 'lax'
})
}
}, },
UPDATE_IS_LOGIN (state, bool) { UPDATE_IS_LOGIN (state, bool) {
state.isLogin = bool state.isLogin = bool
}, },
REMOVE_TOKEN (state) { REMOVE_TOKEN (state) {
this.$cookies.remove('token') this.$cookies.remove('token')
this.$cookies.remove('refresh')
state.jwtToken = null state.jwtToken = null
state.jwtRefresh = null
} }
} }
@ -44,9 +32,9 @@ export const actions = {
password password
} }
let code = null let code = null
await this.$axios.post('auth/token/', payload) await this.$axios.post('auth/login/', payload)
.then((response) => { .then((response) => {
commit('UPADTE_TOKEN', { token: response.data.access, refresh: response.data.refresh }) commit('UPDATE_TOKEN', { token: response.data.user.token })
commit('UPDATE_IS_LOGIN', true) commit('UPDATE_IS_LOGIN', true)
code = response.status code = response.status
}) })
@ -56,43 +44,18 @@ export const actions = {
return code return code
}, },
async refreshToken ({ commit, state }) {
const payload = {
refresh: state.jwtRefresh,
progress: false
}
await this.$axios.post('auth/token/refresh/', payload) inspectToken ({ commit, dispatch, state }) {
.then((response) => {
commit('UPADTE_TOKEN', { token: response.data.access })
commit('UPDATE_IS_LOGIN', true)
})
.catch((error) => {
if (error.response.status === 401) {
commit('REMOVE_TOKEN')
commit('UPDATE_IS_LOGIN', false)
}
})
},
async inspectToken ({ commit, dispatch, state }) {
const token = this.$cookies.get('token') const token = this.$cookies.get('token')
const refresh = this.$cookies.get('refresh')
if (token && refresh) { if (token) {
commit('UPADTE_TOKEN', { token, refresh }) commit('UPDATE_TOKEN', { token })
const decoded_token = jwt_decode(token) const decoded_token = jwt_decode(token)
const decoded_refresh = jwt_decode(refresh)
const timestamp = Date.now() / 1000 const timestamp = Date.now() / 1000
const expire_token = decoded_token.exp const expire_token = decoded_token.exp
const expire_refresh = decoded_refresh.exp
if (state.jwtToken && expire_token - timestamp > 15) { if (state.jwtToken && expire_token - timestamp > 15) {
// DO NOTHING, DO NOT REFRESH
commit('UPDATE_IS_LOGIN', true) commit('UPDATE_IS_LOGIN', true)
} else if (!state.jwtToken || expire_refresh - timestamp > 0) {
commit('UPADTE_TOKEN', { token, refresh })
await dispatch('refreshToken')
} else { } else {
// PROMPT USER TO RE-LOGIN, THIS ELSE CLAUSE COVERS THE CONDITION WHERE A TOKEN IS EXPIRED AS WELL // PROMPT USER TO RE-LOGIN, THIS ELSE CLAUSE COVERS THE CONDITION WHERE A TOKEN IS EXPIRED AS WELL
commit('UPDATE_IS_LOGIN', false) commit('UPDATE_IS_LOGIN', false)

View File

@ -5,7 +5,6 @@ export const state = () => ({
configCount: 0, configCount: 0,
configGui: null, configGui: null,
configGuiRaw: null, configGuiRaw: null,
netChoices: [],
startInSec: 0, startInSec: 0,
playlistLength: 86400.0, playlistLength: 86400.0,
configPlayout: {}, configPlayout: {},
@ -28,9 +27,6 @@ export const mutations = {
UPDATE_GUI_CONFIG_RAW (state, config) { UPDATE_GUI_CONFIG_RAW (state, config) {
state.configGuiRaw = config state.configGuiRaw = config
}, },
UPDATE_NET_CHOICES (state, list) {
state.netChoices = list
},
UPDATE_START_TIME (state, sec) { UPDATE_START_TIME (state, sec) {
state.startInSec = sec state.startInSec = sec
}, },
@ -48,9 +44,6 @@ export const mutations = {
}, },
UPDATE_TIMEZONE (state, zone) { UPDATE_TIMEZONE (state, zone) {
state.timezone = zone state.timezone = zone
},
UPDATE_MULTI_CHANNEL (state, bool) {
state.multiChannel = bool
} }
} }
@ -58,38 +51,16 @@ export const actions = {
async nuxtClientInit ({ commit, dispatch, rootState }) { async nuxtClientInit ({ commit, dispatch, rootState }) {
await dispatch('auth/inspectToken', null, { root: true }) await dispatch('auth/inspectToken', null, { root: true })
if (rootState.auth.isLogin) { if (rootState.auth.isLogin) {
await dispatch('getTimezone')
await dispatch('getGuiConfig') await dispatch('getGuiConfig')
await dispatch('getPlayoutConfig') await dispatch('getPlayoutConfig')
await dispatch('getUserConfig') await dispatch('getUserConfig')
} }
}, },
async getTimezone ({ commit, state }) { async getGuiConfig ({ commit, state }) {
const response = await this.$axios.get('api/player/stats/?stats=settings') const response = await this.$axios.get('api/settings')
if (response.data) { if (response.data) {
commit('UPDATE_TIMEZONE', response.data.timezone)
commit('UPDATE_MULTI_CHANNEL', response.data.multi_channel)
} else {
commit('UPDATE_TIMEZONE', this.$dayjs.tz.guess())
}
},
async getGuiConfig ({ commit, state }) {
const options = await this.$axios.options('api/player/guisettings/')
const response = await this.$axios.get('api/player/guisettings/')
if (options.data) {
const choices = options.data.actions.POST.net_interface.choices.map(function (obj) {
obj.text = obj.display_name
delete obj.display_name
return obj
})
commit('UPDATE_NET_CHOICES', choices)
}
if (response.data && response.data[0]) {
for (const data of response.data) { for (const data of response.data) {
if (data.extra_extensions) { if (data.extra_extensions) {
data.extra_extensions = data.extra_extensions.split(',') data.extra_extensions = data.extra_extensions.split(',')
@ -98,6 +69,7 @@ export const actions = {
} }
} }
commit('UPDATE_TIMEZONE', response.data.timezone)
commit('UPDATE_GUI_CONFIG', response.data) commit('UPDATE_GUI_CONFIG', response.data)
commit('UPDATE_GUI_CONFIG_RAW', _.cloneDeep(response.data)) commit('UPDATE_GUI_CONFIG_RAW', _.cloneDeep(response.data))
commit('UPDATE_CONFIG_COUNT', response.data.length) commit('UPDATE_CONFIG_COUNT', response.data.length)
@ -105,10 +77,8 @@ export const actions = {
commit('UPDATE_GUI_CONFIG', [{ commit('UPDATE_GUI_CONFIG', [{
id: 1, id: 1,
channel: '', channel: '',
player_url: '', preview_url: '',
playout_config: '', playout_config: '',
net_interface: '',
media_disk: '',
extra_extensions: [] extra_extensions: []
}]) }])
} }
@ -120,9 +90,9 @@ export const actions = {
let response let response
if (state.configGuiRaw.some(e => e.id === stringObj.id)) { if (state.configGuiRaw.some(e => e.id === stringObj.id)) {
response = await this.$axios.put(`api/player/guisettings/${obj.id}/`, stringObj) response = await this.$axios.patch(`api/settings/${obj.id}`, stringObj)
} else { } else {
response = await this.$axios.post('api/player/guisettings/', stringObj) response = await this.$axios.post('api/settings/', stringObj)
const guiConfigs = [] const guiConfigs = []
for (const obj of state.configGui) { for (const obj of state.configGui) {
@ -146,7 +116,7 @@ export const actions = {
async getPlayoutConfig ({ commit, state, rootState }) { async getPlayoutConfig ({ commit, state, rootState }) {
const channel = state.configGui[state.configID].id const channel = state.configGui[state.configID].id
const response = await this.$axios.get(`api/player/config/?configPlayout&channel=${channel}`) const response = await this.$axios.get(`api/playout/config/${channel}`)
if (response.data) { if (response.data) {
if (response.data.playlist.day_start) { if (response.data.playlist.day_start) {
@ -165,27 +135,24 @@ export const actions = {
}, },
async setPlayoutConfig ({ commit, state }, obj) { async setPlayoutConfig ({ commit, state }, obj) {
const update = await this.$axios.post('api/player/config/?configPlayout', { const channel = state.configGui[state.configID].id
data: obj, const update = await this.$axios.put(`api/playout/config/${channel}`, obj)
channel: state.configGui[state.configID].id
})
return update return update
}, },
async getUserConfig ({ commit, state }) { async getUserConfig ({ commit, state }) {
const user = await this.$axios.get('api/player/user/current/') const user = await this.$axios.get('api/user')
const response = await this.$axios.get(`api/player/user/users/?username=${user.data.username}`)
if (user.data) { if (user.data) {
commit('SET_CURRENT_USER', user.data.username) commit('SET_CURRENT_USER', user.data.username)
} }
if (response.data) { if (user.data) {
commit('UPDATE_USER_CONFIG', response.data[0]) commit('UPDATE_USER_CONFIG', user.data)
} }
}, },
async setUserConfig ({ commit, state }, obj) { async setUserConfig ({ commit, state }, obj) {
const update = await this.$axios.put(`api/player/user/users/${obj.id}/`, obj) const update = await this.$axios.put(`api/user/${obj.id}`, obj)
return update return update
} }
} }

View File

@ -13,7 +13,7 @@ export const mutations = {
UPDATE_VARIANT (state, variant) { UPDATE_VARIANT (state, variant) {
state.variant = variant state.variant = variant
}, },
UPDATE_ERROR_AERT_MESSAGE (state, message) { UPDATE_ERROR_ALERT_MESSAGE (state, message) {
state.ErrorAlertMessage = message state.ErrorAlertMessage = message
} }
} }

View File

@ -17,29 +17,28 @@ export const mutations = {
} }
export const actions = { export const actions = {
async getTree ({ commit, dispatch, state, rootState }, { extensions, path }) { async getTree ({ commit, dispatch, state, rootState }, { path }) {
const crumbs = [] const crumbs = []
let root = '/' let root = '/'
const channel = rootState.config.configGui[rootState.config.configID].id const channel = rootState.config.configGui[rootState.config.configID].id
const response = await this.$axios.get( const response = await this.$axios.post(
`api/player/media/?extensions=${extensions}&channel=${channel}&path=${path}`) `api/file/${channel}/browse/`, { source: path })
if (response.data.tree) { if (response.data) {
const pathArr = response.data.tree[0].split('/') const pathStr = 'Home/' + response.data.source
const pathArr = pathStr.split('/')
if (response.data.tree[1].length === 0) {
response.data.tree[1].push(pathArr[pathArr.length - 1])
}
if (path) { if (path) {
for (const crumb of pathArr) { for (const crumb of pathArr) {
if (crumb) { if (crumb === 'Home') {
crumbs.push({ text: crumb, path: root })
} else if (crumb) {
root += crumb + '/' root += crumb + '/'
crumbs.push({ text: crumb, path: root }) crumbs.push({ text: crumb, path: root })
} }
} }
} else { } else {
crumbs.push({ text: pathArr[pathArr.length - 1], path: '' }) crumbs.push({ text: 'Home', path: '' })
} }
commit('UPDATE_CURRENT_PATH', path) commit('UPDATE_CURRENT_PATH', path)

View File

@ -60,14 +60,13 @@ export const actions = {
dateToday = this.$dayjs(dateToday).tz(rootState.config.timezone).subtract(1, 'day').format('YYYY-MM-DD') dateToday = this.$dayjs(dateToday).tz(rootState.config.timezone).subtract(1, 'day').format('YYYY-MM-DD')
} }
const response = await this.$axios.get(`api/player/playlist/?date=${date}&channel=${channel}`) const response = await this.$axios.get(`api/playlist/${channel}?date=${date}`)
if (response.data && response.data.program) { if (response.data && response.data.program) {
commit('UPDATE_PLAYLIST', this.$processPlaylist(rootState.config.startInSec, response.data.program)) commit('UPDATE_PLAYLIST', this.$processPlaylist(rootState.config.startInSec, response.data.program))
if (date === dateToday) { if (date === dateToday) {
commit('UPDATE_TODAYS_PLAYLIST', _.cloneDeep(response.data.program)) commit('UPDATE_TODAYS_PLAYLIST', _.cloneDeep(response.data.program))
dispatch('setCurrentClip')
} else { } else {
commit('SET_CURRENT_CLIP_INDEX', null) commit('SET_CURRENT_CLIP_INDEX', null)
} }
@ -76,43 +75,8 @@ export const actions = {
} }
}, },
setCurrentClip ({ commit, dispatch, state, rootState }) { async playoutStat ({ commit, dispatch, state, rootState }) {
let begin const channel = rootState.config.configGui[rootState.config.configID].id
let lastTime = this.$timeToSeconds(this.$dayjs().tz(rootState.config.timezone).format('HH:mm:ss'))
if (Number.isFinite(rootState.config.startInSec)) {
begin = rootState.config.startInSec
} else {
commit('SET_CURRENT_CLIP', 'day_start is not set, cannot calculate current clip')
return
}
if (lastTime < begin) {
lastTime += rootState.config.playlistLength
}
for (let i = 0; i < state.playlistToday.length; i++) {
const duration = state.playlistToday[i].out - state.playlistToday[i].in
// animate the progress bar
if (lastTime < begin + duration) {
const progValue = (lastTime - begin) * 100 / duration
commit('SET_PROGRESS_VALUE', progValue)
commit('SET_CURRENT_CLIP', state.playlistToday[i].source)
commit('SET_CURRENT_CLIP_INDEX', i)
commit('SET_CURRENT_CLIP_START', begin)
commit('SET_CURRENT_CLIP_DURATION', duration)
commit('SET_CURRENT_CLIP_IN', state.playlistToday[i].in)
commit('SET_CURRENT_CLIP_OUT', state.playlistToday[i].out)
break
}
begin += duration
}
},
animClock ({ commit, dispatch, state, rootState }) {
const time = this.$dayjs().tz(rootState.config.timezone).format('HH:mm:ss') const time = this.$dayjs().tz(rootState.config.timezone).format('HH:mm:ss')
let timeSec = this.$timeToSeconds(time) let timeSec = this.$timeToSeconds(time)
@ -126,16 +90,19 @@ export const actions = {
return return
} }
const playTime = timeSec - state.currentClipStart const response = await this.$axios.get(`api/control/${channel}/media/current`)
const progValue = playTime * 100 / state.currentClipDuration
// set progress bar value if (response.data) {
if (playTime <= state.currentClipDuration && progValue >= 0) { const obj = response.data.result
const progValue = obj.played_sec * 100 / obj.current_media.out
commit('SET_PROGRESS_VALUE', progValue) commit('SET_PROGRESS_VALUE', progValue)
commit('SET_TIME_LEFT', this.$secToHMS(state.currentClipDuration - playTime)) commit('SET_CURRENT_CLIP', obj.current_media.source)
} else { commit('SET_CURRENT_CLIP_INDEX', obj.index)
commit('SET_PROGRESS_VALUE', 0) commit('SET_CURRENT_CLIP_START', obj.start_sec)
dispatch('setCurrentClip') commit('SET_CURRENT_CLIP_DURATION', obj.current_media.duration)
commit('SET_CURRENT_CLIP_IN', obj.current_media.seek)
commit('SET_CURRENT_CLIP_OUT', obj.current_media.out)
commit('SET_TIME_LEFT', this.$secToHMS(obj.remaining_sec))
} }
} }
} }

View File

@ -1,63 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>videojs</title>
<link href="https://unpkg.com/video.js@7.7.5/dist/video-js.min.css" rel="stylesheet" />
</head>
<body>
<video-js id="my-video" class="video-js" autoplay muted preload="auto" data-setup="">
</video-js>
<script src="https://unpkg.com/video.js@7.7.5/dist/video.min.js"></script>
<script src="https://unpkg.com/flv.js@1.5.0/dist/flv.min.js"></script>
<script src="https://unpkg.com/videojs-flvjs@0.2.0/dist/videojs-flvjs.min.js"></script>
<script>
var player = videojs(
"my-video",
{
controls: false,
bigPlayButton: false,
autoplay: 'muted',
preload: 'auto',
width: 800,
height: 640,
flvjs: {
mediaDataSource: {
isLive: true,
withCredentials: false,
hasAudio: false,
hasVideo: true,
type: 'flv'
},
config: {
enableStashBuffer: true,
enableWorker: false,
lazyLoad: false,
seekType: 'range'
}
},
},
function onPlayerReady() {
videojs.log("Your player is ready!");
console.log(this
.tech({ IWillNotUseThisInPlugins: true }))
this
.tech({ IWillNotUseThisInPlugins: true })
.flvPlayer.on(flvjs.Events.STATISTICS_INFO, (metadata) =>
console.log(metadata)
);
}
);
player.src({
fluid: true,
src: 'http://ffplayout.local/preview/stream.flv',
type: 'video/x-flv'
})
</script>
</body>
</html>