diff --git a/.github/workflows/automerge.yml b/.github/workflows/automerge.yml new file mode 100644 index 000000000..c7d71434b --- /dev/null +++ b/.github/workflows/automerge.yml @@ -0,0 +1,23 @@ +name: automerge + +on: + schedule: + - cron: '15 0 * * *' # every night + workflow_dispatch: # on button click + +jobs: + merge-staging-to-dev: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set Git config + run: | + git config --local user.email "${GITHUB_ACTOR}" + git config --local user.name "${GITHUB_ACTOR}@users.noreply.github.com" + - name: Merge staging to develop + run: | + git fetch --unshallow + git checkout develop + git pull + git merge --no-ff origin/staging -m "Auto-merge staging to develop" + git push diff --git a/.github/workflows/deploy-image.yml b/.github/workflows/deploy-image.yml index f1c343978..c96f5bb84 100644 --- a/.github/workflows/deploy-image.yml +++ b/.github/workflows/deploy-image.yml @@ -1,4 +1,7 @@ name: Node CI +env: + node-version: 16.14 + node-packager-manager: yarn on: push: branches: @@ -17,7 +20,10 @@ jobs: with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - + - uses: actions/setup-node@v2 + with: + node-version: "16.14" + registry-url: "https://registry.npmjs.org" - name: yarn install run: yarn install --check-files --frozen-lockfile @@ -74,4 +80,4 @@ jobs: context: . push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml index 9d053660d..3aba30e82 100644 --- a/.github/workflows/node.yml +++ b/.github/workflows/node.yml @@ -1,4 +1,7 @@ name: Node CI +env: + node-version: 16.14 + node-packager-manager: yarn on: push: branches: @@ -17,7 +20,10 @@ jobs: with: path: '**/node_modules' key: ${{ runner.os }}-modules-${{ hashFiles('**/yarn.lock') }} - + - uses: actions/setup-node@v2 + with: + node-version: "16.14" + registry-url: "https://registry.npmjs.org" - name: yarn install run: yarn install --check-files --frozen-lockfile @@ -116,4 +122,4 @@ jobs: context: . push: true tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file + labels: ${{ steps.meta.outputs.labels }} diff --git a/.gitignore b/.gitignore index 7d5c53328..6456f91e3 100755 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ src/**.js wallaby.conf.js .DS_Store + +# Ignore JetBrains config files +.idea \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b08a31705..8777bef3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [1.6.9](https://github.com/olzzon/tv2-sofie-blueprints-inews/compare/v1.6.8...v1.6.9) (2021-11-22) + + +### Bug Fixes + +* apply delayed enable to wall graphics when part has preroll ([b368090](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/b368090f7b18ae01c738eb1fd473186e02118448)) +* apply effekt part properties before evaluating cues ([a235267](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/a2352671f7e1b21362ebf0c1ba87c99cf11a2ffc)) +* apply full and dve part properties before evaluating cues ([cfd5ee5](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/cfd5ee585b2ad7a1ba289245fec9d51c85f654a9)) +* apply full graphic properties only when contains a full ([c1d0fa8](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/c1d0fa8d7fffbc8c753fa115d0ec3df0c78c3f71)) +* Apply jingle part properties before evaluating cues ([e187f60](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/e187f608706ad71a164a92bcc8de7b8d08fae2d7)) +* create parent class for VOs ([784df52](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/784df52cafd21734036593bedfe28fab13904bb0)) +* don't update infinites from previous part ([e2bfa83](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/e2bfa83cebd774bf5bb6496ef8408fcb10065dc9)) +* set enable for pilots targeting wall ([22a2a4c](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/22a2a4c7c2c26cba3bd52ee21a5d411e59d82d53)) +* set higher priority on WALL graphics to make them last during prerollDuration ([de6dbca](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/de6dbca531faf6a2af4eea994dd0625ac04e2819)) +* undefined properties not synced ([cf44d4e](https://github.com/olzzon/tv2-sofie-blueprints-inews/commit/cf44d4eac88f19e8eeda0de086f2d5d6d145e60f)) + ### [1.6.8](https://github.com/olzzon/tv2-sofie-blueprints-inews/compare/v1.6.7...v1.6.8) (2021-08-18) diff --git a/Dockerfile b/Dockerfile index 0b23334c4..64922d85e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:12-alpine +FROM node:16-alpine RUN apk update RUN apk add git @@ -8,4 +8,4 @@ WORKDIR /opt/blueprints/ RUN yarn install --production -CMD ["./docker-entrypoint.sh"] \ No newline at end of file +CMD ["./docker-entrypoint.sh"] diff --git a/README.md b/README.md index b52a2b75f..3e28b4d7d 100644 --- a/README.md +++ b/README.md @@ -52,8 +52,10 @@ yarn test # watch for changes ``` ## Ingest mockdata: -Ingest mock data into Sofie: -In ./rundowns/upload.sh rename "studio0" to _id of studio (look in mongoDb under collection studios) +To ingest mock data into Sofie use the 'upload.sh' script found in ./rundowns. + +The script takes two optional parameters: name of the rundown file and id of the studio. The default values are: 'converted-rundown.json' and 'studio0'. + Run: ``` ./upload.sh on-air.json diff --git a/config/tsconfig.base.json b/config/tsconfig.base.json index 34c2e3b1b..2101867f0 100644 --- a/config/tsconfig.base.json +++ b/config/tsconfig.base.json @@ -5,7 +5,7 @@ "target": "es6", "noImplicitAny": true, "moduleResolution": "node", - "sourceMap": false, + "sourceMap": true, "outDir": "../dist", "baseUrl": "../", "paths": { @@ -19,7 +19,7 @@ "traceResolution": false, "pretty": true, "lib": [ - "es6" + "ES2019" ], "types": [ "node", diff --git a/config/tsconfig.strict.json b/config/tsconfig.strict.json index 7d976bd40..05ff016e9 100755 --- a/config/tsconfig.strict.json +++ b/config/tsconfig.strict.json @@ -7,6 +7,7 @@ "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": true, - "noUnusedParameters": true + "noUnusedParameters": true, + "strictPropertyInitialization": true } } diff --git a/config/webpack.config.js b/config/webpack.config.js index e9c2a013d..356e5a979 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -20,15 +20,15 @@ module.exports = env => { versionStr = () => JSON.stringify(pkg.version + '+dev-' + moment().format('YYYYMMDD-HHmm')) } - let versionIntegration = pkg.dependencies['@sofie-automation/blueprints-integration'] + let versionIntegration = pkg.dependencies['@tv2media/blueprints-integration'] - if (!versionIntegration) throw Error('@sofie-automation/blueprints-integration version missing!') + if (!versionIntegration) throw Error('@tv2media/blueprints-integration version missing!') // versionTSRTypes = versionTSRTypes.replace(/[^\d.]/g, '') || '0.0.0' // versionIntegration = versionIntegration.replace(/[^\d.]/g, '') || '0.0.0' versionTSRTypes = '1.3.0' - versionIntegration = '1.37.0' + versionIntegration = '42.0.0' const entrypoints = env.bundle ? GetEntrypointsForBundle(env.bundle) : BlueprintEntrypoints @@ -68,8 +68,6 @@ module.exports = env => { }, target: 'node', externals: { - underscore: '_', - moment: 'moment' }, plugins: [ new webpack.DefinePlugin({ diff --git a/jest.config.js b/jest.config.js index 85eaaeedd..313d6a6b1 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,7 @@ module.exports = { globals: { 'ts-jest': { - tsConfig: 'tsconfig.json', + tsconfig: 'tsconfig.json', }, }, moduleFileExtensions: [ diff --git a/package.json b/package.json index 142dca5d6..fa692afbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tv2-sofie-blueprints-inews", - "version": "1.6.10", + "version": "1.7.5", "repository": "https://github.com/olzzon/tv2-sofie-blueprints-inews", "license": "MIT", "private": true, @@ -20,8 +20,9 @@ "test": "yarn lint --fix && yarn unit", "release": "standard-version", "prepareChangelog": "standard-version --prerelease", + "validate": "yarn validate:dependencies", "validate:dependencies": "yarn audit --groups dependencies && yarn license-validate", - "license-validate": "node-license-validator -p -d --allow-licenses MIT MIT/X11 BSD BSD-3-Clause 0BSD ISC Apache Unlicense" + "license-validate": "license-checker --onlyAllow \"MIT;Apache-2.0;ISC;BSD;CC0;CC-BY-3.0;CC-BY-4.0;UNLICENSED\" --summary" }, "husky": { "hooks": { @@ -35,31 +36,34 @@ ] }, "devDependencies": { - "@types/jest": "^24.0.0", + "@types/jest": "^27.4.1", "@types/node": "^12.12.2", "@types/underscore": "^1.8.9", "axios": "^0.19.0", "git-revision-webpack-plugin": "^3.0.3", - "jest": "^24.0.0", + "jest": "^27.5.1", "jest-haste-map": "^24.5.0", "jest-resolve": "^24.5.0", - "moment": "^2.22.2", - "node-license-validator": "^1.3.0", + "license-checker": "^25.0.1", + "moment": "^2.29.2", "prettier": "^1.18.2", "standard-version": "9.1.1", - "ts-jest": "^24.0.0", + "ts-jest": "^27.1.3", "ts-loader": "^6.2.1", "ts-node": "^8.0.3", "tsconfig-paths-webpack-plugin": "^3.2.0", "tslint": "^5.12.1", "tslint-config-prettier": "^1.18.0", "tslint-plugin-prettier": "^2.0.1", - "typescript": "^3.3.3", + "typescript": "^4.1", "webpack": "^4.27.1", "webpack-cli": "^3.1.2" }, "dependencies": { - "@sofie-automation/blueprints-integration": "npm:@tv2media/blueprints-integration@1.37.0-rc19", + "@tv2media/blueprints-integration": "1.42.7", "underscore": "^1.12.1" + }, + "resolutions": { + "moment": "^2.29.2" } -} \ No newline at end of file +} diff --git a/rundowns/.gitignore b/rundowns/.gitignore index 7ceb50f3e..ed69df547 100644 --- a/rundowns/.gitignore +++ b/rundowns/.gitignore @@ -1 +1,3 @@ dump.json + +converted-rundown.json diff --git a/rundowns/convert.js b/rundowns/convert.js index 7a5fc161b..e274f9ff5 100644 --- a/rundowns/convert.js +++ b/rundowns/convert.js @@ -1,8 +1,8 @@ // this converts a snapshot into importable rundown data -// use with `node convert.js snapshot.json mock-rundown.json` -if (process.argv.length < 4) { +// use with `node convert.js snapshot.json [output-rundown.json]` +if (process.argv.length < 3) { console.log(process.argv) - console.log(`Usage: node convert.js snapshot.json mock-rundown.json`) + console.log(`Usage: node convert.js snapshot.json [output-rundown.json]`) process.exit(0) } const fs = require('fs') @@ -26,5 +26,10 @@ segments = segments.sort((a, b) => b.rank - a.rank) const rundown = rundownData[0].data rundown.segments = segments // console.log(JSON.stringify(rundown, undefined, 4)) -fs.writeFileSync(process.argv[3], JSON.stringify(rundown, undefined, 4)) +let outputString = 'converted-rundown.json'; +const outputArgument = process.argv[3]; +if (outputArgument !== undefined && outputArgument !== '') { + outputString = outputArgument; +} +fs.writeFileSync(outputString, JSON.stringify(rundown, undefined, 4)) console.log('done') \ No newline at end of file diff --git a/rundowns/upload.sh b/rundowns/upload.sh index bbd612e60..f6f394e5e 100755 --- a/rundowns/upload.sh +++ b/rundowns/upload.sh @@ -1,5 +1,19 @@ #!/bin/bash -curl -ks --data-binary @$1 --header 'Content-Type:application/json' http://localhost:3000/ingest/studio0 +RUNDOWN_FILE=converted-rundown.json +if [[ $1 != "" ]] +then + RUNDOWN_FILE=$1 +fi + +STUDIO_ID=studio0 +if [[ $2 != "" ]] +then + STUDIO_ID=$2 +fi + +echo $STUDIO_ID + +curl -ks --data-binary @$RUNDOWN_FILE --header 'Content-Type:application/json' http://localhost:3000/ingest/${STUDIO_ID} echo "\n" diff --git a/scripts/bundle.ts b/scripts/bundle.ts index d1b36f261..a65782e18 100644 --- a/scripts/bundle.ts +++ b/scripts/bundle.ts @@ -1,7 +1,7 @@ +import { BlueprintManifestSet } from '@tv2media/blueprints-integration' import * as fs from 'fs' -import * as util from 'util' import * as _ from 'underscore' -import { BlueprintManifestSet } from '@sofie-automation/blueprints-integration' +import * as util from 'util' const { BlueprintBundles } = require('./blueprint-map') const readFile = util.promisify(fs.readFile) diff --git a/shelf-layouts/AFVD_Default_showstyle_hotkeys.json b/shelf-layouts/AFVD_Default_showstyle_hotkeys.json index d012fa638..4933aed9a 100644 --- a/shelf-layouts/AFVD_Default_showstyle_hotkeys.json +++ b/shelf-layouts/AFVD_Default_showstyle_hotkeys.json @@ -28,34 +28,6 @@ "platformKey": "q", "buttonColor": "#f0d718" }, - { - "_id": "agPkaQMbK2FKZpPcv", - "key": "E", - "label": "EVS 1 VO", - "sourceLayerType": 15, - "platformKey": "E" - }, - { - "_id": "Kz8QpoLd3iEWtspyb", - "key": "R", - "label": "EVS 1 100%", - "sourceLayerType": 15, - "platformKey": "R" - }, - { - "_id": "7oCTKdx4Qn7hoKxFT", - "key": "U", - "label": "EVS 2 VO", - "sourceLayerType": 15, - "platformKey": "U" - }, - { - "_id": "YSXBpa44zMLAGdrSx", - "key": "I", - "label": "EVS 2 100%", - "sourceLayerType": 15, - "platformKey": "I" - }, { "_id": "qSptFwTukCezFNK8D", "key": "C", @@ -112,20 +84,6 @@ "platformKey": "Period", "buttonColor": "#8e44ad" }, - { - "_id": "gzN4rBopAsrN9Hubh", - "key": "SHIFT+e", - "label": "EVS 1 100% inp 1", - "sourceLayerType": 15, - "platformKey": "SHIFT+e" - }, - { - "_id": "cjzA9Wi7ReFeGQHRk", - "key": "SHIFT+D", - "label": "EVS 1 VO inp 1", - "sourceLayerType": 15, - "platformKey": "SHIFT+D" - }, { "_id": "CRmsnZEboXfLtiRQw", "key": "SHIFT+A", @@ -141,55 +99,6 @@ "platformKey": "", "buttonColor": "#000000" }, - { - "_id": "zXCnABCGodoiBjecn", - "key": "SHIFT+U", - "label": "EVS 2 VO inp 1", - "sourceLayerType": 15, - "platformKey": "SHIFT+U" - }, - { - "_id": "5xmjuHQidyXfgJcHb", - "key": "SHIFT+I", - "label": "EVS 2 100% inp 1", - "sourceLayerType": 15, - "platformKey": "SHIFT+I" - }, - { - "_id": "vDF35PGiHBvWpeTxv", - "key": "SHIFT+F1", - "label": "KAM 1 inp 1", - "sourceLayerType": 1, - "platformKey": "SHIFT+F1" - }, - { - "_id": "8MgfgjiW2NJLye2zr", - "key": "SHIFT+F2", - "label": "KAM 2 inp 1", - "sourceLayerType": 1, - "platformKey": "SHIFT+F2" - }, - { - "_id": "5RGpzWrTCfxhSpdvi", - "key": "SHIFT+F3", - "label": "KAM 3 inp 1", - "sourceLayerType": 1, - "platformKey": "SHIFT+F3" - }, - { - "_id": "JTsP9ecyp5JB9A6fv", - "key": "SHIFT+F4", - "label": "KAM 4 inp 1", - "sourceLayerType": 1, - "platformKey": "SHIFT+F4" - }, - { - "_id": "727iMuZT9GW3f4ntq", - "key": "SHIFT+F5", - "label": "KAM 5 inp 1", - "sourceLayerType": 1, - "platformKey": "SHIFT+F5" - }, { "_id": "QtCCqL72TBM7xdLHz", "key": "1", @@ -260,146 +169,6 @@ "sourceLayerType": 3, "platformKey": "0" }, - { - "_id": "Rk585scZjcNdG4oxM", - "key": "SHIFT+1", - "label": "LIVE 1 inp 1", - "sourceLayerType": 3, - "platformKey": "SHIFT+1" - }, - { - "_id": "kpdoQuBaQSG9WgnJ3", - "key": "SHIFT+2", - "label": "LIVE 2 inp 1", - "sourceLayerType": 3, - "platformKey": "SHIFT+2" - }, - { - "_id": "LyZ5oTez6FoYNJ4Ek", - "key": "shift+3", - "label": "LIVE 3 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+3" - }, - { - "_id": "ixxRGQk8y3fk6LnbH", - "key": "shift+4", - "label": "LIVE 4 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+4" - }, - { - "_id": "qZ4AhPGiqB9xhdqyg", - "key": "shift+5", - "label": "LIVE 5 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+5" - }, - { - "_id": "Q4ePKSSKLYMN4fuyi", - "key": "shift+6", - "label": "LIVE 6 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+6" - }, - { - "_id": "ck263XymZdg6q6vL4", - "key": "shift+7", - "label": "LIVE 7 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+7" - }, - { - "_id": "HfjjdjeASpcy7YFsd", - "key": "shift+8", - "label": "LIVE 8 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+8" - }, - { - "_id": "C6oNik83Q6PfWNdGS", - "key": "shift+9", - "label": "LIVE 9 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+9" - }, - { - "_id": "JnMrbNg86KNSaQQYW", - "key": "shift+0", - "label": "LIVE 10 inp 1", - "sourceLayerType": 3, - "platformKey": "shift+0" - }, - { - "_id": "Cq886fvBRfgAgKgbf", - "key": "ctrl+1", - "label": "LIVE 1 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+1" - }, - { - "_id": "c5TxgSSoA4tHYZ3xt", - "key": "ctrl+2", - "label": "LIVE 2 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+2" - }, - { - "_id": "KgZpj2Q3gjGLS9CYa", - "key": "ctrl+3", - "label": "LIVE 3 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+3" - }, - { - "_id": "ymsGD9SH8HR4TmCGS", - "key": "ctrl+4", - "label": "LIVE 4 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+4" - }, - { - "_id": "rexi6Jm2nz8NqBw4q", - "key": "ctrl+5", - "label": "LIVE 5 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+5" - }, - { - "_id": "ncMKuPussDv8uZ7xP", - "key": "ctrl+6", - "label": "LIVE 6 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+6" - }, - { - "_id": "5npcfZbFRiuyeSgzR", - "key": "ctrl+7", - "label": "LIVE 7 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+7" - }, - { - "_id": "AbsJ8SG3JTptoF8Gi", - "key": "ctrl+8", - "label": "LIVE 8 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+8" - }, - { - "_id": "o4qEp4K8BQMAfixHH", - "key": "ctrl+9", - "label": "LIVE 9 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+9" - }, - { - "_id": "KjPdj5SjYXGsPw8rQ", - "key": "ctrl+0", - "label": "LIVE 10 inp 2", - "sourceLayerType": 3, - "platformKey": "ctrl+0" - }, { "_id": "sRMm2pfzf34smfJnP", "key": "ctrl+F1", @@ -489,34 +258,6 @@ "label": "øve rundown", "platformKey": "ctrl+½" }, - { - "_id": "sCzTBw8MCcSxrXNqD", - "key": "ctrl+e", - "label": "EVS 1 100% inp 2", - "sourceLayerType": 15, - "platformKey": "ctrl+e" - }, - { - "_id": "Ew6cNpWbBEbr99h9K", - "key": "ctrl+d", - "label": "EVS 1 VO inp 2", - "sourceLayerType": 15, - "platformKey": "ctrl+d" - }, - { - "_id": "p4jf6mpGY3CfNJhiJ", - "key": "Ctrl+Alt+Shift+i", - "label": "EVS 2 VO inp 2", - "sourceLayerType": 15, - "platformKey": "ctrl+u" - }, - { - "_id": "6BdRrR258vtZr35jv", - "key": "ctrl+i", - "label": "EVS 2 100% inp 2", - "sourceLayerType": 15, - "platformKey": "ctrl+i" - }, { "_id": "rphiEaRPCrQphceAZ", "key": "ctrl+home", @@ -635,12 +376,6 @@ "sourceLayerType": 3, "platformKey": "shift+ctrl+0" }, - { - "_id": "R2i2648kXwPaJpGb4", - "key": "shift+ctrl+e", - "label": "EVS 1 til SS", - "platformKey": "shift+ctrl+e" - }, { "_id": "6Lyc63BnGt5k8LXus", "key": "shift+ctrl+a", @@ -677,12 +412,6 @@ "label": "deaktivate rundown", "platformKey": "ctrl+shift+½" }, - { - "_id": "zfr6hP3ozv4nomNRC", - "key": "CTRL+ALT+SHIFT+F", - "label": "EVS 1 til OVL inp1", - "platformKey": "ALT+E" - }, { "_id": "BDi5mebWYmX5dp8YQ", "key": "SHIFT+CTRL+F1", @@ -721,29 +450,8 @@ { "_id": "kS3YARWkhv3nLfRsJ", "key": "CTRL+ALT+SHIFT+G", - "label": "serv til inp 2", + "label": "serv inp 2", "sourceLayerType": 2, "platformKey": "ctrl+T" - }, - { - "_id": "n8nZWWRcHSkrG7GqM", - "key": "SHIFT+ctrl+alt+c", - "label": "KAM 5", - "sourceLayerType": 1, - "platformKey": "F5" - }, - { - "_id": "QS6pXQ2CARySFJKkh", - "key": "shift+t", - "label": "serv til inp 1", - "sourceLayerType": 2, - "platformKey": "shift+t" - }, - { - "_id": "6gREn5sKmuyE8dN8h", - "key": "ctrl+r", - "label": "Reload Browser", - "platformKey": "ctrl+r", - "buttonColor": "#95a5a6" } -] \ No newline at end of file +] diff --git a/shelf-layouts/Kommentator.json b/shelf-layouts/Kommentator.json index 44c52ea8b..a38310348 100644 --- a/shelf-layouts/Kommentator.json +++ b/shelf-layouts/Kommentator.json @@ -11,7 +11,7 @@ "rank": 0, "rundownBaseline": false, "default": false, - "url": "http://multiview.sofxxXX-od.tv2.local/", + "url": "http://multiview.sofqbXX-od.tv2.local/", "width": -1, "height": -1, "x": 0, @@ -44,7 +44,8 @@ "kommentator" ], "showThumbnailsInList": true, - "hideDuplicates": false + "hideDuplicates": false, + "toggleOnSingleClick": true }, { "_id": "QZ6xdWdFmm5Mu7ZKJ", @@ -77,7 +78,8 @@ "offtube_adlib_100pc_server", "kommentator" ], - "showThumbnailsInList": true + "showThumbnailsInList": true, + "toggleOnSingleClick": true }, { "_id": "zHX89zpASjzyn7GTz", @@ -104,7 +106,8 @@ "studio0_clip", "studio0_voiceover" ], - "showThumbnailsInList": true + "showThumbnailsInList": true, + "toggleOnSingleClick": true }, { "_id": "YC7RNPTbkXd5wnagp", @@ -122,6 +125,7 @@ "displayTakeButtons": true, "sourceLayerIds": [ "studio0_graphicsIdent", + "studio0_graphicsIdent_persistent", "studio0_graphicsTop", "studio0_graphicsLower" ], @@ -129,7 +133,8 @@ "kommentator" ], "hideDuplicates": true, - "lineBreak": "\n - " + "lineBreak": "\n - ", + "toggleOnSingleClick": true }, { "_id": "icuekg6wiJxejsYsZ", @@ -152,7 +157,24 @@ "tags": [ "kommentator" ], - "showThumbnailsInList": true + "showThumbnailsInList": true, + "toggleOnSingleClick": true + }, + { + "_id": "LiFso7gPYn2SPwHwg", + "type": "external_frame", + "name": "Mic tally", + "currentSegment": false, + "displayStyle": "buttons", + "rank": 0, + "rundownBaseline": false, + "default": false, + "x": 0, + "y": 0, + "width": 22, + "height": 7, + "url": "https://sisyfos.sofsrv04-od.tv2.local?view=mic-tally", + "scale": 0 }, { "_id": "6GDpdq547HjjZL9YK", @@ -169,7 +191,9 @@ "height": -11, "windowNumber": 1, "role": "take", - "scale": 1, + "scale": 0, + "thumbnailPriorityNextPieces": true, + "hideThumbnailsForActivePieces": true, "thumbnailPriorityNextPieces": true, "hideThumbnailsForActivePieces": true, "thumbnailSourceLayerIds": [ @@ -390,8 +414,27 @@ "x": 1.3, "y": 24.9, "width": 22, - "scale": 0.8, + "scale": 0, "showPartTitle": true + }, + { + "_id" : "jLzHen2LoGEMxE68N", + "type" : "mini_rundown", + "name" : "Mini rundown", + "currentSegment" : false, + "displayStyle" : "buttons", + "rank" : 0, + "rundownBaseline" : false, + "showThumbnailsInList" : false, + "hideDuplicates" : false, + "default" : false, + "nextInCurrentPart" : false, + "oneNextPerSourceLayer" : false, + "x" : 7, + "y" : 0, + "width" : 14, + "height" : 7, + "scale" : 0 } ], "type": "dashboard_layout", @@ -399,7 +442,7 @@ { "_id": "PTJBfPjrxPMwY4cqW", "label": "Activate", - "type": "klar_on_air", + "type": "ready_on_air", "x": -1, "y": 0, "width": 14, @@ -428,6 +471,7 @@ } ], "exposeAsStandalone": true, + "exposeAsShelf": true, "iconColor": "#8e44ad", "icon": { "prefix": "fas", @@ -444,4 +488,4 @@ "startingHeight": 80, "disableContextMenu": true, "regionId": "shelf_layouts" -} \ No newline at end of file +} diff --git a/shelf-layouts/List.json b/shelf-layouts/List.json index 2eb6a5fda..cf6fbfdc0 100755 --- a/shelf-layouts/List.json +++ b/shelf-layouts/List.json @@ -3,5 +3,6 @@ "name": "List", "showStyleBaseId": "show0", "filters": [], - "type": "dashboard_layout" + "type": "dashboard_layout", + "regionId": "shelf_layouts" } \ No newline at end of file diff --git a/shelf-layouts/Mini_Shelf_Layout.json b/shelf-layouts/Mini_Shelf_Layout.json index 09a82b1c1..30d492451 100644 --- a/shelf-layouts/Mini_Shelf_Layout.json +++ b/shelf-layouts/Mini_Shelf_Layout.json @@ -27,7 +27,8 @@ ], "tags": [ "flow_producer" - ] + ], + "toggleOnSingleClick": true } ] } \ No newline at end of file diff --git a/shelf-layouts/Q flow.json b/shelf-layouts/Q flow.json index 2cb2b5379..15c73cc44 100644 --- a/shelf-layouts/Q flow.json +++ b/shelf-layouts/Q flow.json @@ -33,6 +33,7 @@ "studio0_offtube_graphicsFull", "studio0_offtube_aux_studio_screen", "studio0_graphicsIdent", + "studio0_graphicsIdent_persistent", "studio0_graphicsTop", "studio0_graphicsLower", "studio0_graphicsHeadline", @@ -48,7 +49,8 @@ "assignHotKeys": true, "tags": [ "flow_producer" - ] + ], + "toggleOnSingleClick": true }, { "_id": "ibMYwgJfn8TB52vhb", @@ -60,7 +62,8 @@ "rundownBaseline": "only", "default": false, "hide": true, - "assignHotKeys": true + "assignHotKeys": true, + "toggleOnSingleClick": true }, { "_id": "tGynaBdafH5dZnttN", diff --git a/shelf-layouts/Q_Flow_Rundown_View_Layout.json b/shelf-layouts/Q_Flow_Rundown_View_Layout.json new file mode 100644 index 000000000..1e06d78ba --- /dev/null +++ b/shelf-layouts/Q_Flow_Rundown_View_Layout.json @@ -0,0 +1,34 @@ +{ + "_id": "X4GYdLrEcFTXWKkhm", + "name": "Q flow", + "showStyleBaseId": "show0", + "type": "rundown_view_layout", + "icon": { + "prefix": "fas", + "iconName": "columns", + "icon": [ + 512, + 512, + [], + "f0db", + "M464 32H48C21.49 32 0 53.49 0 80v352c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V80c0-26.51-21.49-48-48-48zM224 416H64V160h160v256zm224 0H288V160h160v256z" + ] + }, + "iconColor": "#14c942", + "regionId": "rundown_view_layouts", + "shelfLayout": "Ri9ZjAJh3QfeJ7KzG", + "miniShelfLayout": "2LcnzqDKS6PaQKhze", + "exposeAsSelectableLayout": true, + "liveLineProps": { + "requiredLayerIds": [ + "studio0_clip", + "studio0_voiceover" + ] + }, + "hideRundownDivider": true, + "showBreaksAsSegments": true, + "fixedSegmentDuration": true, + "countdownToSegmentRequireLayers": [ + "studio0_live" + ] +} \ No newline at end of file diff --git a/shelf-layouts/Rundown_Header_Layout.json b/shelf-layouts/Rundown_Header_Layout.json index 243cf244b..964c687b0 100644 --- a/shelf-layouts/Rundown_Header_Layout.json +++ b/shelf-layouts/Rundown_Header_Layout.json @@ -192,8 +192,8 @@ "iconColor": "#000000", "x": 37, "width": 27, - "height": 1, - "y": -1.1, + "height": 2, + "y": 0, "xUnit": "%", "widthUnit": "%" }, @@ -215,7 +215,7 @@ "" ], "timingType": "count_down", - "y": -1.25, + "y": -1.35, "x": 37.5, "hideLabel": true, "requiredLayerIds": [ diff --git a/shelf-layouts/Shortcuts and adlib scroll.json b/shelf-layouts/Shortcuts and adlib scroll.json index 7fec243f4..c70961fb9 100755 --- a/shelf-layouts/Shortcuts and adlib scroll.json +++ b/shelf-layouts/Shortcuts and adlib scroll.json @@ -14,7 +14,7 @@ "default": false, "x": 1, "y": 7, - "width": 58, + "width": 64.5, "height": 5, "overflowHorizontally": true, "showAsTimeline": true, @@ -31,6 +31,7 @@ "studio0_audio_bed", "studio0_graphicsTop", "studio0_graphicsIdent", + "studio0_graphicsIdent_persistent", "studio0_graphicsTema", "studio0_graphicsHeadline", "studio0_overlay", @@ -39,7 +40,8 @@ ], "tags": [ "flow_producer" - ] + ], + "toggleOnSingleClick": true }, { "_id": "s4KkTnsERPNcrkqeD", @@ -51,10 +53,10 @@ "rundownBaseline": false, "default": false, "url": "http://10.201.76.12:8005/keyboardmap", - "x": 1, - "y": 21, - "width": 76, - "height": -1, + "x": 1.2, + "y": 18, + "width": 54.3, + "height": 18.5, "scale": 0.79 }, { @@ -68,8 +70,8 @@ "default": false, "x": -1, "y": 0, - "width": 21, - "height": -1, + "width": 15.7, + "height": 15.5, "includeClearInRundownBaseline": false, "assignHotKeys": false, "hide": false, @@ -80,7 +82,9 @@ "studio0_adlib_graphic_cmd" ], "buttonWidthScale": 1.7, - "buttonHeightScale": 1.7 + "buttonHeightScale": 1.7, + "toggleOnSingleClick": true, + "scale": 0.6 }, { "_id": "QZ6xdWdFmm5Mu7ZKJ", @@ -97,7 +101,8 @@ "x": -1, "includeClearInRundownBaseline": true, "assignHotKeys": true, - "hide": true + "hide": true, + "toggleOnSingleClick": true }, { "_id": "j54rMBuuTvufKJ8yp", @@ -115,12 +120,13 @@ "sourceLayerIds": [ "studio0_dve" ], - "width": 58, + "width": 64.5, "height": 5, "buttonWidthScale": 1.5, "buttonHeightScale": 1.5, "showAsTimeline": true, - "includeClearInRundownBaseline": true + "includeClearInRundownBaseline": true, + "toggleOnSingleClick": true }, { "_id": "nmNfZ8azaAAHD7jjT", @@ -140,10 +146,11 @@ "buttonWidthScale": 1.5, "buttonHeightScale": 1.5, "y": 0, - "width": 58, + "width": 64.5, "height": 5, "showAsTimeline": true, - "includeClearInRundownBaseline": true + "includeClearInRundownBaseline": true, + "toggleOnSingleClick": true } ], "type": "dashboard_layout", @@ -153,4 +160,4 @@ "startingHeight": 50, "openByDefault": true, "regionId": "shelf_layouts" -} \ No newline at end of file +} diff --git a/shelf-layouts/Streamdeck.json b/shelf-layouts/Streamdeck.json index 882a5680d..e72309736 100755 --- a/shelf-layouts/Streamdeck.json +++ b/shelf-layouts/Streamdeck.json @@ -46,5 +46,6 @@ ] } ], - "type": "dashboard_layout" + "type": "dashboard_layout", + "regionId": "shelf_layouts" } \ No newline at end of file diff --git a/shelf-layouts/dve controls.json b/shelf-layouts/dve controls.json index df8cd324c..6f8a2b6f2 100755 --- a/shelf-layouts/dve controls.json +++ b/shelf-layouts/dve controls.json @@ -49,5 +49,6 @@ "y": 23 } ], - "type": "dashboard_layout" + "type": "dashboard_layout", + "regionId": "shelf_layouts" } \ No newline at end of file diff --git a/shelf-layouts/inspect all adlibs.json b/shelf-layouts/inspect all adlibs.json index 176901acd..681d6847f 100755 --- a/shelf-layouts/inspect all adlibs.json +++ b/shelf-layouts/inspect all adlibs.json @@ -21,5 +21,6 @@ "height": -1 } ], - "type": "dashboard_layout" + "type": "dashboard_layout", + "regionId": "shelf_layouts" } \ No newline at end of file diff --git a/src/__mocks__/context.ts b/src/__mocks__/context.ts index a2350230c..1473f5ca3 100644 --- a/src/__mocks__/context.ts +++ b/src/__mocks__/context.ts @@ -4,7 +4,6 @@ import * as _ from 'underscore' import { BlueprintMappings, ConfigItemValue, - IActionExecutionContext, IBlueprintConfig, IBlueprintMutatablePart, IBlueprintPart, @@ -13,7 +12,9 @@ import { IBlueprintPieceInstance, IBlueprintResolvedPieceInstance, IBlueprintRundownDB, + IBlueprintRundownPlaylist, ICommonContext, + IGetRundownContext, IPackageInfoContext, IRundownContext, IRundownUserContext, @@ -24,10 +25,16 @@ import { IUserNotesContext, OmitId, PackageInfo, - PieceLifespan -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' + PieceLifespan, + PlaylistTimingType, + Time +} from '@tv2media/blueprints-integration' +import { ITV2ActionExecutionContext, PieceMetaData } from 'tv2-common' import { NoteType } from 'tv2-constants' +import { defaultShowStyleConfig, defaultStudioConfig } from '../tv2_afvd_showstyle/__tests__/configs' +import { parseConfig as parseShowStyleConfigAFVD } from '../tv2_afvd_showstyle/helpers/config' +import { parseConfig as parseStudioConfigAFVD, StudioConfig } from '../tv2_afvd_studio/helpers/config' +import mappingsDefaultsAFVD from '../tv2_afvd_studio/migrations/mappings-defaults' export function getHash(str: string): string { const hash = crypto.createHash('sha1') @@ -74,7 +81,6 @@ export class CommonContext implements ICommonContext { id = getHash(this.contextName + '_' + str.toString()) this.hashed[id] = str return id - // return Random.id() } public unhashId(hash: string): string { return this.hashed[hash] || hash @@ -110,11 +116,15 @@ export class UserNotesContext extends CommonContext implements IUserNotesContext public notifyUserWarning(message: string, _params?: { [key: string]: any }): void { this.pushNote(NoteType.NOTIFY_USER_WARNING, message) } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } } // tslint:disable-next-line: max-classes-per-file export class StudioContext extends CommonContext implements IStudioContext { - public studioId: string + public studioId: string = 'studio0' public studioConfig: { [key: string]: ConfigItemValue } = {} public showStyleConfig: { [key: string]: ConfigItemValue } = {} @@ -174,7 +184,7 @@ export class ShowStyleContext extends StudioContext implements IShowStyleContext public getShowStyleConfigRef(_configKey: string): string { return 'test' } - public hackGetMediaObjectDuration(_mediaId: string) { + public async hackGetMediaObjectDuration(_mediaId: string): Promise { return undefined } } @@ -187,11 +197,30 @@ export class ShowStyleUserContext extends ShowStyleContext implements IUserNotes public notifyUserWarning(message: string, _params?: { [key: string]: any }): void { this.pushNote(NoteType.NOTIFY_USER_WARNING, message) } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } +} + +// tslint:disable-next-line: max-classes-per-file +export class GetRundownContext extends ShowStyleUserContext implements IGetRundownContext { + public async getCurrentPlaylist(): Promise | undefined> { + return undefined + } + + public async getPlaylists(): Promise> { + return [] + } + + public getRandomId(): string { + return '' + } } // tslint:disable-next-line: max-classes-per-file export class RundownContext extends ShowStyleContext implements IRundownContext { - public readonly rundownId: string + public readonly rundownId: string = 'rundown0' public readonly rundown: Readonly constructor( @@ -204,6 +233,16 @@ export class RundownContext extends ShowStyleContext implements IRundownContext partId?: string ) { super(contextName, mappingsDefaults, parseStudioConfig, parseShowStyleConfig, rundownId, segmentId, partId) + this.rundownId = rundownId ?? this.rundownId + this.rundown = { + _id: this.rundownId, + externalId: this.rundownId, + name: this.rundownId, + timing: { + type: PlaylistTimingType.None + }, + showStyleVariantId: 'variant0' + } } } @@ -215,6 +254,10 @@ export class RundownUserContext extends RundownContext implements IRundownUserCo public notifyUserWarning(message: string, _params?: { [key: string]: any }): void { this.pushNote(NoteType.NOTIFY_USER_WARNING, message) } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } } // tslint:disable-next-line: max-classes-per-file @@ -245,12 +288,16 @@ export class SegmentUserContext extends RundownContext implements ISegmentUserCo ) { this.pushNote(NoteType.NOTIFY_USER_WARNING, message) } - public hackGetMediaObjectDuration(_mediaId: string) { + public async hackGetMediaObjectDuration(_mediaId: string): Promise { return undefined } public getPackageInfo(_packageId: string): readonly PackageInfo.Any[] { return [] } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } } // tslint:disable-next-line: max-classes-per-file @@ -266,7 +313,7 @@ export class SyncIngestUpdateToPartInstanceContext extends RundownUserContext mappingsDefaults: BlueprintMappings, parseStudioConfig: (context: ICommonContext, rawConfig: IBlueprintConfig) => any, parseShowStyleConfig: (context: ICommonContext, config: IBlueprintConfig) => any, - rundownId?: string, + rundownId: string, segmentId?: string, partId?: string ) { @@ -278,7 +325,7 @@ export class SyncIngestUpdateToPartInstanceContext extends RundownUserContext mutatedPiece?: Omit, 'lifespan'> ): IBlueprintPieceInstance { this.syncedPieceInstances.push(pieceInstanceId) - return literal({ + return { _id: pieceInstanceId, piece: { _id: '', @@ -294,24 +341,24 @@ export class SyncIngestUpdateToPartInstanceContext extends RundownUserContext content: mutatedPiece?.content ?? { timelineObjects: [] } }, partInstanceId: '' - }) + } } public insertPieceInstance(piece: IBlueprintPiece): IBlueprintPieceInstance { - return literal({ + return { _id: '', piece: { _id: '', ...piece }, partInstanceId: '' - }) + } } public updatePieceInstance( pieceInstanceId: string, piece: Partial> ): IBlueprintPieceInstance { this.updatedPieceInstances.push(pieceInstanceId) - return literal({ + return { _id: pieceInstanceId, piece: { _id: '', @@ -327,14 +374,14 @@ export class SyncIngestUpdateToPartInstanceContext extends RundownUserContext content: piece.content ?? { timelineObjects: [] } }, partInstanceId: '' - }) + } } public removePieceInstances(...pieceInstanceIds: string[]): string[] { this.removedPieceInstances.push(...pieceInstanceIds) return pieceInstanceIds } public updatePartInstance(props: Partial>): IBlueprintPartInstance { - this.updatedPartInstance = literal({ + this.updatedPartInstance = { _id: '', segmentId: '', part: { @@ -345,22 +392,24 @@ export class SyncIngestUpdateToPartInstanceContext extends RundownUserContext ...props }, rehearsal: false - }) + } return this.updatedPartInstance } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } } // tslint:disable-next-line: max-classes-per-file -export class ActionExecutionContext extends ShowStyleUserContext implements IActionExecutionContext { +export class ActionExecutionContext extends ShowStyleUserContext implements ITV2ActionExecutionContext { public currentPart: IBlueprintPartInstance - public currentPieceInstances: IBlueprintPieceInstance[] + public currentPieceInstances: Array> public nextPart: IBlueprintPartInstance | undefined - public nextPieceInstances: IBlueprintPieceInstance[] | undefined + public nextPieceInstances: Array> | undefined public takeAfterExecute: boolean = false - - /** Get the mappings for the studio */ - public getStudioMappings: () => Readonly + public isTV2Context: true = true constructor( contextName: string, @@ -371,9 +420,9 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct segmentId: string, partId: string, currentPart: IBlueprintPartInstance, - currentPieceInstances: IBlueprintPieceInstance[], + currentPieceInstances: Array>, nextPart?: IBlueprintPartInstance, - nextPieceInstances?: IBlueprintPieceInstance[] + nextPieceInstances?: Array> ) { super(contextName, mappingsDefaults, parseStudioConfig, parseShowStyleConfig, rundownId, segmentId, partId) @@ -383,15 +432,20 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct this.nextPieceInstances = nextPieceInstances } + /** Get the mappings for the studio */ + public getStudioMappings = () => { + throw new Error(`Function not implemented in mock: 'getStudioMappings'`) + } + /** Get a PartInstance which can be modified */ - public getPartInstance(part: 'current' | 'next'): IBlueprintPartInstance | undefined { + public async getPartInstance(part: 'current' | 'next'): Promise { if (part === 'current') { return this.currentPart } return this.nextPart } /** Get the PieceInstances for a modifiable PartInstance */ - public getPieceInstances(part: 'current' | 'next'): IBlueprintPieceInstance[] { + public async getPieceInstances(part: 'current' | 'next'): Promise>> { if (part === 'current') { return this.currentPieceInstances } @@ -399,31 +453,33 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct return this.nextPieceInstances || [] } /** Get the resolved PieceInstances for a modifiable PartInstance */ - public getResolvedPieceInstances(_part: 'current' | 'next'): IBlueprintResolvedPieceInstance[] { + public async getResolvedPieceInstances( + _part: 'current' | 'next' + ): Promise>> { return [] } /** Get the last active piece on given layer */ - public findLastPieceOnLayer( + public async findLastPieceOnLayer( _sourceLayerId: string, _options?: { excludeCurrentPart?: boolean originalOnly?: boolean pieceMetaDataFilter?: any } - ): IBlueprintPieceInstance | undefined { + ): Promise | undefined> { return undefined } - public findLastScriptedPieceOnLayer( + public async findLastScriptedPieceOnLayer( _sourceLayerId: string, _options?: { excludeCurrentPart?: boolean pieceMetaDataFilter?: any } - ): IBlueprintPiece | undefined { + ): Promise | undefined> { return undefined } - public getPartInstanceForPreviousPiece(_piece: IBlueprintPieceInstance): IBlueprintPartInstance { - return literal({ + public async getPartInstanceForPreviousPiece(_piece: IBlueprintPieceInstance): Promise { + return { _id: '', segmentId: '', part: { @@ -433,15 +489,18 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct title: '' }, rehearsal: false - }) + } } - public getPartForPreviousPiece(_piece: { _id: string }): IBlueprintPart | undefined { - return + public async getPartForPreviousPiece(_piece: { _id: string }): Promise { + return undefined } /** Creative actions */ /** Insert a piece. Returns id of new PieceInstance. Any timelineObjects will have their ids changed, so are not safe to reference from another piece */ - public insertPiece(part: 'current' | 'next', piece: IBlueprintPiece): IBlueprintPieceInstance { - const pieceInstance: IBlueprintPieceInstance = { + public async insertPiece( + part: 'current' | 'next', + piece: IBlueprintPiece + ): Promise> { + const pieceInstance: IBlueprintPieceInstance = { _id: '', piece: { _id: '', @@ -459,22 +518,25 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct return pieceInstance } /** Update a pieceInstance */ - public updatePieceInstance( + public async updatePieceInstance( _pieceInstanceId: string, piece: Partial> - ): IBlueprintPieceInstance { + ): Promise> { return { _id: '', piece: { _id: '', - ...(piece as IBlueprintPiece) + ...(piece as IBlueprintPiece) }, partInstanceId: '' } } /** Insert a queued part to follow the current part */ - public queuePart(part: IBlueprintPart, pieces: IBlueprintPiece[]): IBlueprintPartInstance { - const instance = literal({ + public async queuePart( + part: IBlueprintPart, + pieces: Array> + ): Promise { + const instance: IBlueprintPartInstance = { _id: '', segmentId: this.notesSegmentId || '', part: { @@ -483,10 +545,10 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct segmentId: this.notesSegmentId || '' }, rehearsal: false - }) + } this.nextPart = instance - this.nextPieceInstances = pieces.map(p => ({ + this.nextPieceInstances = pieces.map>(p => ({ _id: (Date.now() * Math.random()).toString(), piece: { _id: '', @@ -498,7 +560,10 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct return instance } /** Update a partInstance */ - public updatePartInstance(part: 'current' | 'next', props: Partial): IBlueprintPartInstance { + public async updatePartInstance( + part: 'current' | 'next', + props: Partial + ): Promise { if (part === 'current') { this.currentPart.part = { ...this.currentPart.part, ...props } return this.currentPart @@ -511,15 +576,15 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct } /** Destructive actions */ /** Stop any piecesInstances on the specified sourceLayers. Returns ids of piecesInstances that were affected */ - public stopPiecesOnLayers(_sourceLayerIds: string[], _timeOffset?: number): string[] { + public async stopPiecesOnLayers(_sourceLayerIds: string[], _timeOffset?: number): Promise { return [] } /** Stop piecesInstances by id. Returns ids of piecesInstances that were removed */ - public stopPieceInstances(_pieceInstanceIds: string[], _timeOffset?: number): string[] { + public async stopPieceInstances(_pieceInstanceIds: string[], _timeOffset?: number): Promise { return [] } /** Remove piecesInstances by id. Returns ids of piecesInstances that were removed */ - public removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): string[] { + public async removePieceInstances(part: 'current' | 'next', pieceInstanceIds: string[]): Promise { if (part === 'current') { this.currentPieceInstances = this.currentPieceInstances.filter(p => !pieceInstanceIds.includes(p._id)) } else if (this.nextPieceInstances) { @@ -528,16 +593,16 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct return pieceInstanceIds } - public moveNextPart(_partDelta: number, _segmentDelta: number): void { + public async moveNextPart(_partDelta: number, _segmentDelta: number): Promise { throw new Error('Method not implemented.') } /** Set flag to perform take after executing the current action. Returns state of the flag after each call. */ - public takeAfterExecuteAction(take: boolean): boolean { + public async takeAfterExecuteAction(take: boolean): Promise { this.takeAfterExecute = take return take } - public hackGetMediaObjectDuration(_mediaId: string) { + public async hackGetMediaObjectDuration(_mediaId: string): Promise { return undefined } public getPackageInfo(_packageId: string): PackageInfo.Any[] { @@ -546,6 +611,14 @@ export class ActionExecutionContext extends ShowStyleUserContext implements IAct public getCurrentTime(): number { throw new Error('Method not implemented.') } + + public async blockTakeUntil(_time: Time | null): Promise { + return undefined + } + + public notifyUserInfo(_message: string, _params?: { [p: string]: any }): void { + // Do nothing + } } export interface PartNote { @@ -559,3 +632,16 @@ export interface PartNote { } message: string } + +export function makeMockAFVDContext(studioConfigOverrides?: Partial) { + const mockContext = new SegmentUserContext( + 'test', + mappingsDefaultsAFVD, + parseStudioConfigAFVD, + parseShowStyleConfigAFVD + ) + mockContext.studioConfig = { ...defaultStudioConfig, ...studioConfigOverrides } as any + mockContext.showStyleConfig = defaultShowStyleConfig as any + + return mockContext +} diff --git a/src/inews-mixins/__tests__/playlist.spec.ts b/src/inews-mixins/__tests__/playlist.spec.ts new file mode 100644 index 000000000..8893fbd80 --- /dev/null +++ b/src/inews-mixins/__tests__/playlist.spec.ts @@ -0,0 +1,90 @@ +import { + BlueprintResultRundown, + ExtendedIngestRundown, + IngestSegment, + IShowStyleUserContext, + PlaylistTimingType +} from '@tv2media/blueprints-integration' +import { getRundownWithBackTime } from 'inews-mixins' +import { ShowStyleUserContext } from '../../__mocks__/context' +import { parseConfig as parseShowStyleConfig } from '../../tv2_afvd_showstyle/helpers/config' +import { parseConfig as parseStudioConfig } from '../../tv2_afvd_studio/helpers/config' +import mappingsDefaults from '../../tv2_afvd_studio/migrations/mappings-defaults' +import { makeSegmentWithTime } from './rundownDuration.spec' + +const RUNDOWN_ID = 'test_rundown' +const RUNDOWN_NAME = 'Rundown 1' +const SEGMENT_ID = 'test_segment' +const PART_ID = 'test_part' + +function getMockContext(): IShowStyleUserContext { + return new ShowStyleUserContext( + RUNDOWN_NAME, + mappingsDefaults, + parseStudioConfig, + parseShowStyleConfig, + RUNDOWN_ID, + SEGMENT_ID, + PART_ID + ) +} + +function getMockResult(): BlueprintResultRundown { + return { + rundown: { + externalId: RUNDOWN_ID, + name: RUNDOWN_NAME, + timing: { + type: PlaylistTimingType.None + } + }, + globalAdLibPieces: [], + baseline: { + timelineObjects: [] + }, + globalActions: [] + } +} + +function getMockRundown(segments: IngestSegment[]): ExtendedIngestRundown { + return { + externalId: RUNDOWN_ID, + name: RUNDOWN_NAME, + type: 'mock', + payload: {}, + segments, + coreData: undefined + } +} +describe('Rundown BackTime', () => { + it('Discards back time if not on the first continuty', () => { + const segments = [ + makeSegmentWithTime('test-segment_1', 1, 0, {}), + makeSegmentWithTime('test-segment_2', 1, 1, { floated: true }), + makeSegmentWithTime('test-segment_3', 1, 1, {}), + makeSegmentWithTime('continuity', 2, 2, { untimed: true }), + makeSegmentWithTime('test-segment_4', 2, 3, { untimed: true }), + makeSegmentWithTime('continuity', 2, 4, { untimed: true, backTimeInHours: 2 }), + makeSegmentWithTime('test-segment_5', 3, 5, { untimed: true }) + ] + + const result = getRundownWithBackTime(getMockContext(), getMockRundown(segments), getMockResult()) + expect(result.rundown.timing.type).toEqual(PlaylistTimingType.None) + }) + + it('Takes back time if on the first continuty', () => { + const segments = [ + makeSegmentWithTime('test-segment_1', 1, 0, { floated: true }), + makeSegmentWithTime('test-segment_2', 1, 1, { floated: true }), + makeSegmentWithTime('test-segment_3', 1, 1, {}), + makeSegmentWithTime('continuity', 2, 2, { untimed: true, backTimeInHours: 2 }), + makeSegmentWithTime('test-segment_4', 2, 3, { untimed: true }), + makeSegmentWithTime('continuity', 2, 4, { untimed: true }), + makeSegmentWithTime('test-segment_5', 3, 5, { untimed: true }) + ] + + const result = getRundownWithBackTime(getMockContext(), getMockRundown(segments), getMockResult()) + expect(result.rundown.timing.type).toEqual(PlaylistTimingType.BackTime) + // @todo test for correct endTime value after merging the midnight fix + }) +}) diff --git a/src/inews-mixins/__tests__/rundownDuration.spec.ts b/src/inews-mixins/__tests__/rundownDuration.spec.ts index 4c3d4bb82..563faa45d 100644 --- a/src/inews-mixins/__tests__/rundownDuration.spec.ts +++ b/src/inews-mixins/__tests__/rundownDuration.spec.ts @@ -1,8 +1,8 @@ -import { IngestSegment } from '@sofie-automation/blueprints-integration' +import { IngestSegment } from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import { getRundownDuration } from '../rundownDuration' -function makeSegmentWithoutTime(externalId: string, rank: number): IngestSegment { +export function makeSegmentWithoutTime(externalId: string, rank: number): IngestSegment { return literal({ externalId, name: externalId, @@ -11,20 +11,22 @@ function makeSegmentWithoutTime(externalId: string, rank: number): IngestSegment }) } -function makeSegmentWithTime( +export function makeSegmentWithTime( externalId: string, time: number, rank: number, options: { floated?: boolean untimed?: boolean + backTimeInHours?: number } ): IngestSegment { const segment = makeSegmentWithoutTime(externalId, rank) segment.payload = { iNewsStory: { fields: { - totalTime: time + totalTime: time, + backTime: options.backTimeInHours ? `@${options.backTimeInHours * 3600}` : undefined }, meta: { float: options.floated ? 'float' : undefined diff --git a/src/inews-mixins/playlist.ts b/src/inews-mixins/playlist.ts index ad4792294..9da91bec0 100644 --- a/src/inews-mixins/playlist.ts +++ b/src/inews-mixins/playlist.ts @@ -3,8 +3,9 @@ import { BlueprintResultRundown, BlueprintResultRundownPlaylist, ExtendedIngestRundown, + IBlueprintResultRundownPlaylist, IBlueprintRundownDB, - IBlueprintRundownPlaylistInfo, + IGetRundownContext, IngestRundown, IShowStyleUserContext, IStudioUserContext, @@ -12,7 +13,7 @@ import { RundownPlaylistTiming, ShowStyleBlueprintManifest, StudioBlueprintManifest -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { assertUnreachable, literal, TimeFromINewsField } from 'tv2-common' import { getRundownDuration } from './rundownDuration' @@ -35,16 +36,14 @@ function getRundownWithINewsPlaylist( return manifest } -function getRundownWithBackTime( +export function getRundownWithBackTime( _context: IShowStyleUserContext, ingestRundown: ExtendedIngestRundown, manifest: BlueprintResultRundown ): BlueprintResultRundown { const sortedSegments = ingestRundown.segments.sort((a, b) => a.rank - b.rank) - const backTimeStory = sortedSegments.find( - segment => segment.name.match(/^\s*continuity\s*$/i) && segment.payload.iNewsStory.fields.backTime - ) - const backTime = backTimeStory ? backTimeStory.payload.iNewsStory.fields.backTime : undefined + const firstContinuityStory = sortedSegments.find(segment => segment.name.match(/^\s*continuity\s*$/i)) + const backTime = firstContinuityStory ? firstContinuityStory.payload.iNewsStory.fields.backTime : undefined let expectedEnd: number | undefined const expectedDuration = getRundownDuration(ingestRundown.segments) @@ -94,13 +93,13 @@ function getRundownPlaylistInfoINewsPlaylist( resultPlaylist: BlueprintResultRundownPlaylist ): BlueprintResultRundownPlaylist { const result: BlueprintResultOrderedRundowns = {} - return literal({ + return { ...resultPlaylist, order: rundowns.reduce((prev, curr) => { prev[curr.externalId] = (curr.metaData as RundownMetaData).rank return prev }, result) - }) + } } type GetRundownMixin = ( @@ -116,8 +115,14 @@ type GetRundownPlaylistInfoMixin = ( ) => BlueprintResultRundownPlaylist export function GetRundownWithMixins(getRundown: ShowStyleBlueprintManifest['getRundown'], mixins: GetRundownMixin[]) { - return (context: IShowStyleUserContext, ingestRundown: ExtendedIngestRundown) => { - let result = getRundown(context, ingestRundown) + return async ( + context: IGetRundownContext, + ingestRundown: ExtendedIngestRundown + ): Promise => { + let result = await getRundown(context, ingestRundown) + if (result === null) { + return result + } for (const mixin of mixins) { result = mixin(context, ingestRundown, result) @@ -147,15 +152,15 @@ export function GetRundownPlaylistInfoWithMixins( expectedStart: lastRundownTiming.expectedStart } } - let result = - (getRundownPlaylistInfo ? getRundownPlaylistInfo(context, rundowns) : undefined) ?? - literal({ - playlist: literal({ - name: (rundowns[0] ?? { name: '' }).name, - timing - }), - order: null - }) + let result: BlueprintResultRundownPlaylist = (getRundownPlaylistInfo + ? getRundownPlaylistInfo(context, rundowns, '') + : undefined) ?? { + playlist: literal({ + name: (rundowns[0] ?? { name: '' }).name, + timing + }), + order: null + } for (const mixin of mixins) { result = mixin(context, rundowns, result) diff --git a/src/inews-mixins/rundownDuration.ts b/src/inews-mixins/rundownDuration.ts index e0726a5df..6340ddb02 100644 --- a/src/inews-mixins/rundownDuration.ts +++ b/src/inews-mixins/rundownDuration.ts @@ -1,4 +1,4 @@ -import { IngestSegment } from '@sofie-automation/blueprints-integration' +import { IngestSegment } from '@tv2media/blueprints-integration' import { INewsPayload, TimeFromINewsField } from 'tv2-common' export function getRundownDuration(segments: IngestSegment[]) { diff --git a/src/tv2-common/__tests__/frame-time.spec.ts b/src/tv2-common/__tests__/frame-time.spec.ts index b7ca40495..4b599af08 100644 --- a/src/tv2-common/__tests__/frame-time.spec.ts +++ b/src/tv2-common/__tests__/frame-time.spec.ts @@ -1,9 +1,18 @@ -import { IBlueprintPiece, PieceLifespan } from '@sofie-automation/blueprints-integration' -import { CueType } from 'tv2-constants' +import { IBlueprintPiece, PieceLifespan } from '@tv2media/blueprints-integration' +import { CueType, SourceType } from 'tv2-constants' import { CreateTiming } from '../cueTiming' +import { RemoteType, SourceDefinitionRemote } from '../inewsConversion' import { CueDefinitionEkstern } from '../inewsConversion/converters/ParseCue' import { literal } from '../util' +const EKSTERN_SOURCE: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' +} + describe('CreateTiming', () => { test('Start only (seconds)', () => { const time: CueDefinitionEkstern = { @@ -12,7 +21,7 @@ describe('CreateTiming', () => { seconds: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -33,7 +42,7 @@ describe('CreateTiming', () => { frames: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -55,7 +64,7 @@ describe('CreateTiming', () => { frames: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -76,7 +85,7 @@ describe('CreateTiming', () => { seconds: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -97,7 +106,7 @@ describe('CreateTiming', () => { frames: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -119,7 +128,7 @@ describe('CreateTiming', () => { frames: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -140,7 +149,7 @@ describe('CreateTiming', () => { infiniteMode: 'B' }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -160,7 +169,7 @@ describe('CreateTiming', () => { infiniteMode: 'S' }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -180,7 +189,7 @@ describe('CreateTiming', () => { infiniteMode: 'O' }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -203,7 +212,7 @@ describe('CreateTiming', () => { seconds: 1 }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( @@ -227,7 +236,7 @@ describe('CreateTiming', () => { infiniteMode: 'B' }, iNewsCommand: '', - source: '' + sourceDefinition: EKSTERN_SOURCE } const result = CreateTiming(time, 4000) expect(result).toEqual( diff --git a/src/tv2-common/__tests__/getshowStyleVariantId.spec.ts b/src/tv2-common/__tests__/getshowStyleVariantId.spec.ts new file mode 100644 index 000000000..4b2e4ed5c --- /dev/null +++ b/src/tv2-common/__tests__/getshowStyleVariantId.spec.ts @@ -0,0 +1,89 @@ +import { IBlueprintShowStyleVariant, IngestRundown, IStudioUserContext } from '@tv2media/blueprints-integration' +import { makeMockAFVDContext } from '../../__mocks__/context' +import { getShowStyleVariantId } from '../getShowStyleVariantId' + +describe('getShowStyleVariantId', () => { + it('returns the id of the ingestedShowStyleVariant', () => { + const variantName = 'randomVariantName' + const ingestRundown: IngestRundown = getIngestRundown(variantName) + + const result = getShowStyleVariantId(getMockContext(), getShowStyleVariants([variantName]), ingestRundown) + + expect(result).toBe(variantName) + }) + + function getIngestRundown(showStyleVariant?: string): IngestRundown { + return { + externalId: '', + name: '', + type: '', + segments: [], + payload: { + showstyleVariant: showStyleVariant ?? '' + } + } + } + + function getMockContext(): IStudioUserContext { + return makeMockAFVDContext() + } + + function getShowStyleVariants(variantNames?: string[]): IBlueprintShowStyleVariant[] { + const variants: IBlueprintShowStyleVariant[] = [ + { + _id: 'default', + name: 'default', + blueprintConfig: {} + } + ] + if (variantNames) { + variants.push( + ...variantNames.map(variantName => { + return { + _id: variantName, + name: variantName, + blueprintConfig: {} + } + }) + ) + } + + return variants + } + + it('does not have variant, returns default', () => { + const variantName = 'randomVariantName' + const ingestRundown: IngestRundown = getIngestRundown('nonExistentVariantName') + + const result = getShowStyleVariantId(getMockContext(), getShowStyleVariants([variantName]), ingestRundown) + + expect(result).toBe('default') + }) + + it('does not have variant, no default configured, returns null', () => { + const ingestRundown: IngestRundown = getIngestRundown('nonExistentVariantName') + + const result = getShowStyleVariantId(getMockContext(), [], ingestRundown) + + expect(result).toBeNull() + }) + + it('does not have variant, default is not first in variant array, selects default', () => { + const variantName = 'randomVariantName' + const ingestRundown: IngestRundown = getIngestRundown('nonExistentVariantName') + + const showStyleVariants: IBlueprintShowStyleVariant[] = [ + { + _id: 'someVariant', + name: 'someVariant', + blueprintConfig: {} + }, + ...getShowStyleVariants([variantName]) + ] + + expect(showStyleVariants[0]._id).not.toBe('default') + const result = getShowStyleVariantId(getMockContext(), showStyleVariants, ingestRundown) + + expect(result).toBe('default') + }) +}) diff --git a/src/tv2-common/__tests__/jinglePartProperties.spec.ts b/src/tv2-common/__tests__/jinglePartProperties.spec.ts new file mode 100644 index 000000000..ac599ca9c --- /dev/null +++ b/src/tv2-common/__tests__/jinglePartProperties.spec.ts @@ -0,0 +1,64 @@ +import { GetJinglePartPropertiesFromTableValue } from 'tv2-common' + +const BREAKER = { + BreakerName: 'intro', + ClipName: 'intro', + LoadFirstFrame: false, + Autonext: true, + Duration: 200, + StartAlpha: 50, + EndAlpha: 100 +} + +describe('GetJinglePartPropertiesFromTableValue', () => { + it('Subtracts StartAlpha from Duration', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Duration: 200, + StartAlpha: 50, + EndAlpha: 100 + }) + expect(properties.expectedDuration).toBe(6000) + }) + it('Clamps Duration when StartAlpha > Duration', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Duration: 50, + StartAlpha: 100, + EndAlpha: 50 + }) + expect(properties.expectedDuration).toBe(0) + }) + it('Calculates autoNextOverlap from EndAlpha', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Duration: 100, + StartAlpha: 20, + EndAlpha: 50 + }) + expect(properties.autoNextOverlap).toBe(2000) + }) + it('Clamps autoNextOverlap when EndAlpha > Duration - StartAlpha', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Duration: 100, + StartAlpha: 75, + EndAlpha: 50 + }) + expect(properties.autoNextOverlap).toBe(1000) + }) + it('Disables autoNext when Autonext is false', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Autonext: false + }) + expect(properties.autoNext).toBe(false) + }) + it('Enables autoNext when Autonext is true', () => { + const properties = GetJinglePartPropertiesFromTableValue({ + ...BREAKER, + Autonext: true + }) + expect(properties.autoNext).toBe(true) + }) +}) diff --git a/src/tv2-common/__tests__/onTimelineGenerate.spec.ts b/src/tv2-common/__tests__/onTimelineGenerate.spec.ts new file mode 100644 index 000000000..015636d75 --- /dev/null +++ b/src/tv2-common/__tests__/onTimelineGenerate.spec.ts @@ -0,0 +1,342 @@ +import { IBlueprintPieceDB, IBlueprintResolvedPieceInstance, TSR } from '@tv2media/blueprints-integration' +import { SisyfosLLAyer } from '../../tv2_afvd_studio/layers' +import { + createSisyfosPersistedLevelsTimelineObject, + PieceMetaData, + SisyfosPersistMetaData +} from '../onTimelineGenerate' + +const LAYER_THAT_WANTS_TO_BE_PERSISTED = 'layerThatWantsToBePersisted' +const LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY: SisyfosPersistMetaData['sisyfosLayers'] = [ + LAYER_THAT_WANTS_TO_BE_PERSISTED +] + +// tslint:disable:no-object-literal-type-assertion +describe('onTimelineGenerate', () => { + describe('createSisyfosPersistedLevelsTimelineObject', () => { + it('has one layer to persist, piece accept persist - timelineObject with layer is added', () => { + const resolvedPieces: Array> = [ + createPieceInstance('currentPiece', 10, undefined, true, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + const indexOfLayerThatWantToBePersisted = result.content.channels.findIndex( + channel => channel.mappedLayer === LAYER_THAT_WANTS_TO_BE_PERSISTED + ) + expect(indexOfLayerThatWantToBePersisted).toBeGreaterThanOrEqual(0) + }) + + it('has layer to persist, timelineObject with correct Sisyfos information is added', () => { + const resolvedPieces: Array> = [ + createPieceInstance('currentPiece', 10, undefined, true, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.layer).toEqual(SisyfosLLAyer.SisyfosPersistedLevels) + expect(result.content.deviceType).toEqual(TSR.DeviceType.SISYFOS) + expect(result.content.type).toEqual(TSR.TimelineContentTypeSisyfos.CHANNELS) + expect(result.enable).toEqual({ start: 0 }) + }) + + it('should persist non-VO layers with isPgm 1', () => { + const resolvedPieces: Array> = [ + createPieceInstance('currentPiece', 10, undefined, true, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + expect(result.content.channels[0].isPgm).toEqual(1) + }) + + it('should persist only current piece layer when piece wants to persist but dont accept', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPiece', 0, 10, true, true), + createPieceInstance('currentPiece', 10, undefined, true, false) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(1) + }) + + it('should not persist anything when current piece dont accept and dont want to persist', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPiece', 0, 10, true, true), + createPieceInstance('currentPiece', 10, undefined, false, false) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('should persist when previous piece does not accept persist, but current does accept', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPiece', 0, 10, true, false), + createPieceInstance('currentPiece', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(1) + }) + + it('should persist when current piece accepts persist and duration is not undefined', () => { + const resolvedPieces: Array> = [ + createPieceInstance('currentPiece', 0, 5, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(1) + }) + + it('should persist all previous layers that wants to be persisted', () => { + const firstLayerThatWantToBePersisted: string = 'firstLayer' + const secondLayerThatWantToBePersisted: string = 'secondLayer' + const thirdLayerThatWantToBePersisted: string = 'thirdLayer' + const layersThatWantToBePersisted: SisyfosPersistMetaData['sisyfosLayers'] = [ + firstLayerThatWantToBePersisted, + secondLayerThatWantToBePersisted, + thirdLayerThatWantToBePersisted + ] + const resolvedPieces: Array> = [ + createPieceInstance('currentPiece', 0, 5, true, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, layersThatWantToBePersisted) + + expect( + result.content.channels.some(channel => channel.mappedLayer === firstLayerThatWantToBePersisted) + ).toBeTruthy() + expect( + result.content.channels.some(channel => channel.mappedLayer === secondLayerThatWantToBePersisted) + ).toBeTruthy() + expect( + result.content.channels.some(channel => channel.mappedLayer === thirdLayerThatWantToBePersisted) + ).toBeTruthy() + }) + + it('cuts to executeAction that dont accept persist, dont persist layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPieceNotExecuteAction', 0, 10, true, true), + createExecuteActionPieceInstance('currentPieceIsExecuteAction', 10, undefined, false, false) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts to executeAction that accept persist from piece that accept, add persist timelineObject containing all layers that want to be persisted plus previous piece layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPieceNotExecuteAction', 0, 10, true, true), + createExecuteActionPieceInstance('currentPieceIsExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect( + result.content.channels.some(channel => channel.mappedLayer === LAYER_THAT_WANTS_TO_BE_PERSISTED) + ).toBeTruthy() + expect(result.content.channels.some(channel => channel.mappedLayer === resolvedPieces[0].piece.name)).toBeTruthy() + }) + + it('cuts to executionAction that accept from piece that dont accept, add persist timelineObject that only contain previous piece layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPieceNotExecuteAction', 0, 10, true, false), + createExecuteActionPieceInstance('currentPieceIsExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(1) + expect(result.content.channels.some(channel => channel.mappedLayer === resolvedPieces[0].piece.name)).toBeTruthy() + }) + + it('cuts to executeAction that accept persist from piece that dont want to persist and dont accept persist, dont persist any layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPieceNotExecuteAction', 0, 10, false, false), + createExecuteActionPieceInstance('currentPieceIsExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts to executeAction that accept persist from piece that dont want to persist and that accept persist, persist previous layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('previousPieceNotExecuteAction', 0, 10, false, true), + createExecuteActionPieceInstance('currentPieceIsExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(1) + expect( + result.content.channels.some(channel => channel.mappedLayer === LAYER_THAT_WANTS_TO_BE_PERSISTED) + ).toBeTruthy() + }) + + it('cuts from executeAction that dont accept to piece that accepts, dont persist', () => { + const resolvedPieces: Array> = [ + createExecuteActionPieceInstance('previousPieceIsExecuteAction', 0, 10, false, false), + createPieceInstance('currentPieceNotExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts from executeAction that dont accept to piece that dont accepts, dont persist layers', () => { + const resolvedPieces: Array> = [ + createExecuteActionPieceInstance('previousPieceIsExecuteAction', 0, 10, false, false), + createPieceInstance('currentPieceNotExecuteAction', 10, undefined, false, false) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts from executeAction that accept to piece that dont accepts, dont persist layers', () => { + const resolvedPieces: Array> = [ + createExecuteActionPieceInstance('previousPieceIsExecuteAction', 0, 10, false, true), + createPieceInstance('currentPieceNotExecuteAction', 10, undefined, false, false) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts from executeAction that accept to piece that accepts, add persist timelineObject with previous layer before executeAction + new layer', () => { + const resolvedPieces: Array> = [ + createPieceInstance('firstPiece', 0, 5, true, true), + createExecuteActionPieceInstance('previousPieceIsExecuteAction', 5, 5, false, true, { + acceptPersistAudio: true, + sisyfosLayers: [] + }), + createPieceInstance('currentPieceNotExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(2) + }) + + it('cuts from piece that wants to persist to executeAction that do not accept to piece that accepts, do not persist', () => { + const resolvedPieces: Array> = [ + createPieceInstance('firstPiece', 0, 5, true, true), + createExecuteActionPieceInstance('previousPieceIsExecuteAction', 5, 5, false, true, { + acceptPersistAudio: false, + sisyfosLayers: [] + }), + createPieceInstance('currentPieceNotExecuteAction', 10, undefined, false, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, LAYERS_THAT_WANTS_TO_BE_PERSISTED_ARRAY) + + expect(result.content.channels).toHaveLength(0) + }) + + it('cuts from piece that wants to persist to executeAction that accepts to another executeAction that accepts, persist layer from first piece', () => { + const resolvedPieces: Array> = [ + createPieceInstance('firstPiece', 0, 5, true, true), + createExecuteActionPieceInstance('executeAction', 5, undefined, false, true, { + acceptPersistAudio: true, + sisyfosLayers: [], + previousPersistMetaDataForCurrentPiece: { + acceptPersistAudio: true, + sisyfosLayers: [] + } + }) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, []) + + expect(result.content.channels).toHaveLength(1) + expect(result.content.channels.some(channel => channel.mappedLayer === 'firstPiece')).toBeTruthy() + }) + + it('cuts from piece that wants to persist to executeAction that do not accept to another executeAction that accepts, dont persist any layers', () => { + const resolvedPieces: Array> = [ + createPieceInstance('firstPiece', 0, 5, true, true), + createExecuteActionPieceInstance('executeAction', 5, undefined, false, true, { + acceptPersistAudio: true, + sisyfosLayers: [], + previousPersistMetaDataForCurrentPiece: { + acceptPersistAudio: false, + sisyfosLayers: [] + } + }) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, []) + + expect(result.content.channels).toHaveLength(0) + }) + + it('should not contain any duplicate layers to persist', () => { + const resolvedPieces: Array> = [ + createPieceInstance('piece', 0, 5, true, true), + createPieceInstance('piece', 5, undefined, true, true) + ] + + const result = createSisyfosPersistedLevelsTimelineObject(resolvedPieces, []) + + expect(result.content.channels).toHaveLength(1) + }) + }) +}) + +function createPieceInstance( + name: string, + start: number, + duration: number | undefined, + wantToPersistAudio: boolean, + acceptPersistAudio: boolean +): IBlueprintResolvedPieceInstance { + return { + resolvedStart: start, + resolvedDuration: duration, + piece: { + name, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [name], + wantsToPersistAudio: wantToPersistAudio, + acceptPersistAudio + } + } + } as IBlueprintPieceDB + } as IBlueprintResolvedPieceInstance +} + +function createExecuteActionPieceInstance( + name: string, + start: number, + duration: number | undefined, + wantToPersistAudio: boolean, + acceptPersistAudio: boolean, + previousMetaData?: SisyfosPersistMetaData +): IBlueprintResolvedPieceInstance { + return { + resolvedStart: start, + resolvedDuration: duration, + piece: { + name, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [name], + wantsToPersistAudio: wantToPersistAudio, + acceptPersistAudio, + previousPersistMetaDataForCurrentPiece: previousMetaData + } + } + } as IBlueprintPieceDB + } as IBlueprintResolvedPieceInstance +} diff --git a/src/tv2-common/__tests__/transition-from-string.spec.ts b/src/tv2-common/__tests__/transition-from-string.spec.ts index d5fb90b1f..a3002113a 100644 --- a/src/tv2-common/__tests__/transition-from-string.spec.ts +++ b/src/tv2-common/__tests__/transition-from-string.spec.ts @@ -1,18 +1,18 @@ -import { TSR } from '@sofie-automation/blueprints-integration' -import { TransitionFromString } from '../transitionFromString' +import { TSR } from '@tv2media/blueprints-integration' +import { AtemTransitionStyleFromString } from '../atemTransitionStyleFromString' describe('Transition From String', () => { it('Converts strings', () => { - expect(TransitionFromString('mix')).toEqual(TSR.AtemTransitionStyle.MIX) - expect(TransitionFromString('MIX')).toEqual(TSR.AtemTransitionStyle.MIX) - expect(TransitionFromString('dip')).toEqual(TSR.AtemTransitionStyle.DIP) - expect(TransitionFromString('DIP')).toEqual(TSR.AtemTransitionStyle.DIP) - expect(TransitionFromString('wipe')).toEqual(TSR.AtemTransitionStyle.WIPE) - expect(TransitionFromString('WIPE')).toEqual(TSR.AtemTransitionStyle.WIPE) - expect(TransitionFromString('sting')).toEqual(TSR.AtemTransitionStyle.STING) - expect(TransitionFromString('STING')).toEqual(TSR.AtemTransitionStyle.STING) - expect(TransitionFromString('cut')).toEqual(TSR.AtemTransitionStyle.CUT) - expect(TransitionFromString('CUT')).toEqual(TSR.AtemTransitionStyle.CUT) - expect(TransitionFromString('unknown')).toEqual(TSR.AtemTransitionStyle.CUT) + expect(AtemTransitionStyleFromString('mix')).toEqual(TSR.AtemTransitionStyle.MIX) + expect(AtemTransitionStyleFromString('MIX')).toEqual(TSR.AtemTransitionStyle.MIX) + expect(AtemTransitionStyleFromString('dip')).toEqual(TSR.AtemTransitionStyle.DIP) + expect(AtemTransitionStyleFromString('DIP')).toEqual(TSR.AtemTransitionStyle.DIP) + expect(AtemTransitionStyleFromString('wipe')).toEqual(TSR.AtemTransitionStyle.WIPE) + expect(AtemTransitionStyleFromString('WIPE')).toEqual(TSR.AtemTransitionStyle.WIPE) + expect(AtemTransitionStyleFromString('sting')).toEqual(TSR.AtemTransitionStyle.STING) + expect(AtemTransitionStyleFromString('STING')).toEqual(TSR.AtemTransitionStyle.STING) + expect(AtemTransitionStyleFromString('cut')).toEqual(TSR.AtemTransitionStyle.CUT) + expect(AtemTransitionStyleFromString('CUT')).toEqual(TSR.AtemTransitionStyle.CUT) + expect(AtemTransitionStyleFromString('unknown')).toEqual(TSR.AtemTransitionStyle.CUT) }) }) diff --git a/src/tv2-common/__tests__/transitionSettings.spec.ts b/src/tv2-common/__tests__/transitionSettings.spec.ts new file mode 100644 index 000000000..cf13871ba --- /dev/null +++ b/src/tv2-common/__tests__/transitionSettings.spec.ts @@ -0,0 +1,168 @@ +import { TSR } from '@tv2media/blueprints-integration' +import { PartType } from '../../tv2-constants' +import { AtemSourceIndex } from '../../types/atem' +import { TV2BlueprintConfig, TV2BlueprintConfigBase, TV2StudioConfigBase } from '../blueprintConfig' +import { PartDefinition, PartTransition } from '../inewsConversion' +import { TransitionSettings } from '../transitionSettings' + +const DURATION: number = 50 + +describe('transitionsSettingsSuite', () => { + let mockConfig: TV2BlueprintConfig + + beforeEach(() => { + mockConfig = ({} as unknown) as TV2BlueprintConfig + }) + + describe('TransitionSettings', () => { + it('return empty when no transition', () => { + const partDefinition: PartDefinition = createPartDefinition() + + const result = TransitionSettings(mockConfig, partDefinition) + + expect(result).toEqual({}) + }) + + it('should return empty when no duration on transition', () => { + const transition: PartTransition = { + duration: undefined, + style: TSR.AtemTransitionStyle.DUMMY + } + const partDefinition: PartDefinition = createPartDefinition(transition) + const result = TransitionSettings(mockConfig, partDefinition) + + expect(result).toEqual({}) + }) + + it('should return Wipe when transition is style Wip', () => { + const transition: PartTransition = { + style: TSR.AtemTransitionStyle.WIPE, + duration: DURATION + } + const partDefinition: PartDefinition = createPartDefinition(transition) + + const result = TransitionSettings(mockConfig, partDefinition) + const expectedResult: TSR.AtemTransitionSettings = { + wipe: { + rate: DURATION + } + } + expect(result).toEqual(expectedResult) + }) + + it('should return Mix when transition is style Mix', () => { + const transition: PartTransition = { + style: TSR.AtemTransitionStyle.MIX, + duration: DURATION + } + const partDefinition: PartDefinition = createPartDefinition(transition) + + const result = TransitionSettings(mockConfig, partDefinition) + const expectedResult: TSR.AtemTransitionSettings = { + mix: { + rate: DURATION + } + } + expect(result).toEqual(expectedResult) + }) + + it('should return Dip when style is Dip', () => { + const transition: PartTransition = { + style: TSR.AtemTransitionStyle.DIP, + duration: DURATION + } + const partDefinition: PartDefinition = createPartDefinition(transition) + + const result = TransitionSettings(mockConfig, partDefinition) + const expectedResult: TSR.AtemTransitionSettings = { + dip: { + rate: DURATION, + input: AtemSourceIndex.Col2 + } + } + expect(result).toEqual(expectedResult) + }) + + it('should return 100 in Dip.input when AtemSource.Dip config value is 100', () => { + const dipConfigInputSource = 100 + assertDipInputValueFromConfig(mockConfig, dipConfigInputSource) + }) + + it('should return 4 in Dip.input when AtemSource.Dip config value is 4', () => { + const dipConfigInputSource = 4 + assertDipInputValueFromConfig(mockConfig, dipConfigInputSource) + }) + + it('should return 150 in Dip.input when AtemSource.Dip config value is 150', () => { + const dipConfigInputSource = 150 + assertDipInputValueFromConfig(mockConfig, dipConfigInputSource) + }) + }) + + describe('DipTransitionSettings', () => { + it('should return AtemSourceIndex.Col2 when no AtemSource.Dip is configured', () => { + const transition: PartTransition = { + style: TSR.AtemTransitionStyle.DIP, + duration: DURATION + } + const partDefinition: PartDefinition = createPartDefinition(transition) + + const result = TransitionSettings(mockConfig, partDefinition) + const expectedResult: TSR.AtemTransitionSettings = { + dip: { + rate: DURATION, + input: AtemSourceIndex.Col2 + } + } + expect(result).toEqual(expectedResult) + }) + }) +}) + +function createPartDefinition(transition?: PartTransition): PartDefinition { + return { + externalId: `externalId_${Math.random() * 1000}`, + cues: [], + type: PartType.REMOTE, + script: '', + fields: {}, + modified: 123, + storyName: 'someName', + segmentExternalId: `segmentExternalId_${Math.random() * 1000}`, + rawType: '', + transition + } +} + +function assertDipInputValueFromConfig( + mockConfig: TV2BlueprintConfigBase, + dipInputSource: number +) { + mockConfig.studio = ({ + AtemSource: createAtemSourceConfig(dipInputSource) + } as any) as TV2StudioConfigBase + const transition: PartTransition = { + style: TSR.AtemTransitionStyle.DIP, + duration: DURATION + } + const partDefinition: PartDefinition = createPartDefinition(transition) + + const result = TransitionSettings(mockConfig, partDefinition) + const expectedResult: TSR.AtemTransitionSettings = { + dip: { + rate: DURATION, + input: dipInputSource + } + } + expect(result).toEqual(expectedResult) +} + +function createAtemSourceConfig(dip: number) { + return { + Dip: dip, + Default: 1, + SplitArtF: 1, + SplitArtK: 1, + DSK: [] + } +} diff --git a/src/tv2-common/__tests__/util.spec.ts b/src/tv2-common/__tests__/util.spec.ts index 33575f3ba..29d5ea4fd 100644 --- a/src/tv2-common/__tests__/util.spec.ts +++ b/src/tv2-common/__tests__/util.spec.ts @@ -1,4 +1,4 @@ -import { PieceLifespan } from '@sofie-automation/blueprints-integration' +import { PieceLifespan } from '@tv2media/blueprints-integration' import { SharedOutputLayers } from 'tv2-constants' import { assertUnreachable, isAdLibPiece, JoinAssetToFolder, JoinAssetToNetworkPath } from '../util' diff --git a/src/tv2-common/actions/actionTypes.ts b/src/tv2-common/actions/actionTypes.ts index 1ba7b0b8e..0d0e3c282 100644 --- a/src/tv2-common/actions/actionTypes.ts +++ b/src/tv2-common/actions/actionTypes.ts @@ -1,9 +1,14 @@ -import { SourceLayerType } from '@sofie-automation/blueprints-integration' import { AdlibActionType } from 'tv2-constants' import { DVEConfigInput } from '../helpers' -import { CueDefinitionDVE, PartDefinition } from '../inewsConversion' - -interface ActionBase { +import { + CueDefinitionDVE, + PartDefinition, + SourceDefinition, + SourceDefinitionKam, + SourceDefinitionRemote +} from '../inewsConversion' + +export interface ActionBase { type: AdlibActionType } @@ -45,23 +50,19 @@ export interface ActionSelectJingle extends ActionBase { export interface ActionCutToCamera extends ActionBase { type: AdlibActionType.CUT_TO_CAMERA queue: boolean - name: string + sourceDefinition: SourceDefinitionKam } export interface ActionCutToRemote extends ActionBase { type: AdlibActionType.CUT_TO_REMOTE - name: string - port: number + sourceDefinition: SourceDefinitionRemote } export interface ActionCutSourceToBox extends ActionBase { type: AdlibActionType.CUT_SOURCE_TO_BOX - sourceType: SourceLayerType name: string - port: number box: number - vo?: boolean - server?: boolean + sourceDefinition: SourceDefinition } export interface ActionCommentatorSelectServer extends ActionBase { @@ -87,7 +88,7 @@ export interface ActionClearGraphics extends ActionBase { } export interface ActionTakeWithTransitionVariantBase { - type: 'cut' | 'mix' | 'breaker' + type: 'cut' | 'mix' | 'breaker' | 'dip' } export interface ActionTakeWithTransitionVariantCut extends ActionTakeWithTransitionVariantBase { @@ -104,10 +105,16 @@ export interface ActionTakeWithTransitionVariantBreaker extends ActionTakeWithTr breaker: string } +export interface ActionTakeWithTransitionVariantDip extends ActionTakeWithTransitionVariantBase { + type: 'dip' + frames: number +} + export type ActionTakeWithTransitionVariant = | ActionTakeWithTransitionVariantCut | ActionTakeWithTransitionVariantMix | ActionTakeWithTransitionVariantBreaker + | ActionTakeWithTransitionVariantDip export interface ActionTakeWithTransition extends ActionBase { type: AdlibActionType.TAKE_WITH_TRANSITION @@ -124,6 +131,10 @@ export interface ActionRecallLastDVE extends ActionBase { type: AdlibActionType.RECALL_LAST_DVE } +export interface ActionFadeDownPersistedAudioLevels extends ActionBase { + type: AdlibActionType.FADE_DOWN_PERSISTED_AUDIO_LEVELS +} + export type TV2AdlibAction = | ActionSelectServerClip | ActionSelectDVE @@ -140,3 +151,4 @@ export type TV2AdlibAction = | ActionTakeWithTransition | ActionRecallLastLive | ActionRecallLastDVE + | ActionFadeDownPersistedAudioLevels diff --git a/src/tv2-common/actions/context.ts b/src/tv2-common/actions/context.ts index 5a6b89238..e0a8ad5b7 100644 --- a/src/tv2-common/actions/context.ts +++ b/src/tv2-common/actions/context.ts @@ -8,18 +8,51 @@ import { IBlueprintPieceDB, IBlueprintPieceInstance, IBlueprintResolvedPieceInstance, - PackageInfo -} from '@sofie-automation/blueprints-integration' -import { literal, PartMetaData } from 'tv2-common' + PackageInfo, + Time +} from '@tv2media/blueprints-integration' +import { literal, PartMetaData, PieceMetaData } from 'tv2-common' export interface ITV2ActionExecutionContext extends IActionExecutionContext { - /** To prompt type errors for frong context type */ + /** To prompt type errors for wrong context type */ isTV2Context: true + + getPieceInstances(part: 'current' | 'next'): Promise>> + getResolvedPieceInstances(part: 'current' | 'next'): Promise>> + + findLastPieceOnLayer( + sourceLayerId: string | string[], + options?: { + excludeCurrentPart?: boolean + originalOnly?: boolean + pieceMetaDataFilter?: any + } + ): Promise | undefined> + findLastScriptedPieceOnLayer( + sourceLayerId: string | string[], + options?: { + excludeCurrentPart?: boolean + pieceMetaDataFilter?: any + } + ): Promise | undefined> + getPartInstanceForPreviousPiece(piece: IBlueprintPieceInstance): Promise + getPartForPreviousPiece(piece: IBlueprintPieceDB): Promise + insertPiece( + part: 'current' | 'next', + piece: IBlueprintPiece + ): Promise> + updatePieceInstance( + pieceInstanceId: string, + piece: Partial> + ): Promise> + queuePart(part: IBlueprintPart, pieces: Array>): Promise + updatePartInstance(part: 'current' | 'next', props: Partial): Promise } class TV2ActionExecutionContext implements ITV2ActionExecutionContext { public studioId: string - public isTV2Context: true + public isTV2Context: true = true + private coreContext: IActionExecutionContext private modifiedParts: Set<'current' | 'next'> = new Set() @@ -28,148 +61,210 @@ class TV2ActionExecutionContext implements ITV2ActionExecutionContext { this.coreContext = coreContext this.studioId = coreContext.studioId } - public getPartInstance(part: 'current' | 'next'): IBlueprintPartInstance | undefined { + + public async getPartInstance(part: 'current' | 'next'): Promise | undefined> { return this.coreContext.getPartInstance(part) } - public getPieceInstances(part: 'current' | 'next'): Array> { - return this.coreContext.getPieceInstances(part) + + public async getPieceInstances(part: 'current' | 'next'): Promise>> { + return this.coreContext.getPieceInstances(part) as Promise>> } - public getResolvedPieceInstances(part: 'current' | 'next'): Array> { - return this.coreContext.getResolvedPieceInstances(part) + + public async getResolvedPieceInstances( + part: 'current' | 'next' + ): Promise>> { + return this.coreContext.getResolvedPieceInstances(part) as Promise< + Array> + > } - public findLastPieceOnLayer( + + public async findLastPieceOnLayer( sourceLayerId: string | string[], options?: { - excludeCurrentPart?: boolean | undefined - originalOnly?: boolean | undefined + excludeCurrentPart?: boolean + originalOnly?: boolean pieceMetaDataFilter?: any } - ): IBlueprintPieceInstance | undefined { - return this.coreContext.findLastPieceOnLayer(sourceLayerId, options) + ): Promise | undefined> { + return this.coreContext.findLastPieceOnLayer(sourceLayerId, options) as Promise< + IBlueprintPieceInstance | undefined + > } - public findLastScriptedPieceOnLayer( + + public async findLastScriptedPieceOnLayer( sourceLayerId: string | string[], - options?: { excludeCurrentPart?: boolean | undefined; pieceMetaDataFilter?: any } - ): IBlueprintPiece | undefined { - return this.coreContext.findLastScriptedPieceOnLayer(sourceLayerId, options) + options?: { excludeCurrentPart?: boolean; pieceMetaDataFilter?: any } + ): Promise | undefined> { + return this.coreContext.findLastScriptedPieceOnLayer(sourceLayerId, options) as Promise< + IBlueprintPiece | undefined + > } - public getPartInstanceForPreviousPiece(piece: IBlueprintPieceInstance): IBlueprintPartInstance { + + public async getPartInstanceForPreviousPiece( + piece: IBlueprintPieceInstance + ): Promise> { return this.coreContext.getPartInstanceForPreviousPiece(piece) } - public getPartForPreviousPiece(piece: IBlueprintPieceDB): IBlueprintPart | undefined { + + public async getPartForPreviousPiece( + piece: IBlueprintPieceDB + ): Promise | undefined> { return this.coreContext.getPartForPreviousPiece(piece) } - public stopPiecesOnLayers(sourceLayerIds: string[], timeOffset?: number): string[] { + + public async stopPiecesOnLayers(sourceLayerIds: string[], timeOffset?: number): Promise { return this.coreContext.stopPiecesOnLayers(sourceLayerIds, timeOffset) } - public stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number): string[] { + + public async stopPieceInstances(pieceInstanceIds: string[], timeOffset?: number): Promise { return this.coreContext.stopPieceInstances(pieceInstanceIds, timeOffset) } - public takeAfterExecuteAction(take: boolean): boolean { + + public async takeAfterExecuteAction(take: boolean): Promise { return this.coreContext.takeAfterExecuteAction(take) } + public notifyUserError(message: string, params?: { [key: string]: any }): void { return this.coreContext.notifyUserError(message, params) } + public notifyUserWarning(message: string, params?: { [key: string]: any }): void { return this.coreContext.notifyUserWarning(message, params) } + public getHashId(originString: string, originIsNotUnique?: boolean | undefined) { return this.coreContext.getHashId(originString, originIsNotUnique) } + public unhashId(hash: string) { return this.coreContext.unhashId(hash) } + public logDebug(message: string) { return this.coreContext.logDebug(message) } + public logInfo(message: string) { return this.coreContext.logInfo(message) } + public logWarning(message: string) { return this.coreContext.logWarning(message) } + public logError(message: string) { return this.coreContext.logError(message) } + public getShowStyleConfig(): unknown { return this.coreContext.getShowStyleConfig() } + public getShowStyleConfigRef(configKey: string): string { return this.coreContext.getShowStyleConfigRef(configKey) } + public getStudioConfig(): unknown { return this.coreContext.getStudioConfig() } + public getStudioConfigRef(configKey: string): string { return this.coreContext.getShowStyleConfigRef(configKey) } + public getStudioMappings(): Readonly { return this.coreContext.getStudioMappings() } + public getPackageInfo(packageId: string): readonly PackageInfo.Any[] { return this.coreContext.getPackageInfo(packageId) } - public hackGetMediaObjectDuration(mediaId: string): number | undefined { + + public async hackGetMediaObjectDuration(mediaId: string): Promise { return this.coreContext.hackGetMediaObjectDuration(mediaId) } + public getCurrentTime(): number { return this.coreContext.getCurrentTime() } - public moveNextPart(partDelta: number, segmentDelta: number): void { + public async moveNextPart(partDelta: number, segmentDelta: number): Promise { this.modifiedParts.add('next') return this.coreContext.moveNextPart(partDelta, segmentDelta) } - public queuePart(rawPart: IBlueprintPart, rawPieces: IBlueprintPiece[]): IBlueprintPartInstance { + public async queuePart( + rawPart: IBlueprintPart, + rawPieces: Array> + ): Promise { this.modifiedParts.add('next') return this.coreContext.queuePart(rawPart, rawPieces) } - public removePieceInstances(part: 'next', pieceInstanceIds: string[]): string[] { + public async removePieceInstances(part: 'next', pieceInstanceIds: string[]): Promise { this.modifiedParts.add('next') return this.coreContext.removePieceInstances(part, pieceInstanceIds) } - public insertPiece(part: 'current' | 'next', piece: IBlueprintPiece): IBlueprintPieceInstance { + public async insertPiece( + part: 'current' | 'next', + piece: IBlueprintPiece + ): Promise> { this.modifiedParts.add(part) - return this.coreContext.insertPiece(part, piece) + return this.coreContext.insertPiece(part, piece) as Promise> } - public updatePartInstance(part: 'current' | 'next', props: Partial): IBlueprintPartInstance { + + public async updatePartInstance( + part: 'current' | 'next', + props: Partial + ): Promise { this.modifiedParts.add(part) return this.coreContext.updatePartInstance(part, props) } - public updatePieceInstance(pieceInstanceId: string, piece: Partial): IBlueprintPieceInstance { - const currentPieceInstances = this.coreContext.getPieceInstances('current') + + public async updatePieceInstance( + pieceInstanceId: string, + piece: Partial> + ): Promise> { + const currentPieceInstances = await this.coreContext.getPieceInstances('current') if (currentPieceInstances.map(p => p._id).includes(pieceInstanceId)) { this.modifiedParts.add('current') } else { - const nextPieceInstances = this.coreContext.getPieceInstances('next') + const nextPieceInstances = await this.coreContext.getPieceInstances('next') if (nextPieceInstances.map(p => p._id).includes(pieceInstanceId)) { this.modifiedParts.add('next') } } // Regardless of above, let core handle errors - return this.coreContext.updatePieceInstance(pieceInstanceId, piece) + return this.coreContext.updatePieceInstance(pieceInstanceId, piece) as Promise< + IBlueprintPieceInstance + > } /** * Call this when the context is finished with. * After this, no further calls can be made. */ - public afterActions() { + public async afterActions() { for (const part of this.modifiedParts) { - this.markPartAsModifiedByAction(part) + await this.markPartAsModifiedByAction(part) } } - private markPartAsModifiedByAction(part: 'current' | 'next') { - const partInstance = this.coreContext.getPartInstance(part) + public blockTakeUntil(time: Time | null): Promise { + return this.coreContext.blockTakeUntil(time) + } + + public notifyUserInfo(message: string, params?: { [p: string]: any }): void { + this.coreContext.notifyUserInfo(message, params) + } + + private async markPartAsModifiedByAction(part: 'current' | 'next') { + const partInstance = await this.coreContext.getPartInstance(part) if (!partInstance) { return } @@ -178,17 +273,17 @@ class TV2ActionExecutionContext implements ITV2ActionExecutionContext { partInstance.part.metaData = {} } - this.coreContext.updatePartInstance(part, { + await this.coreContext.updatePartInstance(part, { metaData: literal({ ...(partInstance.part.metaData as PartMetaData), dirty: true }) }) } } -export function executeWithContext( +export async function executeWithContext( coreContext: IActionExecutionContext, - func: (context: ITV2ActionExecutionContext) => void + func: (context: ITV2ActionExecutionContext) => Promise ) { const context = new TV2ActionExecutionContext(coreContext) - func(context) - context.afterActions() + await func(context) + await context.afterActions() } diff --git a/src/tv2-common/actions/executeAction.ts b/src/tv2-common/actions/executeAction.ts index 623cb05b6..95c2331bd 100644 --- a/src/tv2-common/actions/executeAction.ts +++ b/src/tv2-common/actions/executeAction.ts @@ -12,12 +12,11 @@ import { IBlueprintPieceInstance, IShowStyleUserContext, PieceLifespan, - SourceLayerType, SplitsContent, TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionClearGraphics, ActionCommentatorSelectDVE, @@ -31,31 +30,29 @@ import { ActionSelectFullGrafik, ActionSelectServerClip, CalculateTime, - CreateFullPiece, + CreateDipTransitionBlueprintPieceForPart, + CreateInTransitionForAtemTransitionStyle, CreatePartServerBase, CueDefinition, CueDefinitionDVE, CueDefinitionGraphic, + DipTransitionSettings, DVEOptions, DVEPieceMetaData, DVESources, EvaluateCuesOptions, executeWithContext, - FindSourceInfoStrict, - GetCameraMetaData, GetDVETemplate, - GetEksternMetaData, GetFullGrafikTemplateName, - GetLayersForCamera, - GetLayersForEkstern, - GetSisyfosTimelineObjForCamera, - GetSisyfosTimelineObjForEkstern, GraphicPilot, ITV2ActionExecutionContext, literal, MakeContentDVE2, + MixTransitionSettings, PartDefinition, PieceMetaData, + SisyfosPersistMetaData, + TimeFromFrames, TimelineBlueprintExt, TV2AdlibAction, TV2BlueprintConfigBase, @@ -64,16 +61,25 @@ import { import { AdlibActionType, CueType, - GraphicLLayer, + SharedGraphicLLayer, SharedOutputLayers, SharedSourceLayers, + SourceType, TallyTags } from 'tv2-constants' import _ = require('underscore') import { EnableServer } from '../content' -import { CreateFullDataStore, GetEnableForWall, PilotGeneratorSettings } from '../helpers' +import { + GetEnableForWall, + getServerPosition, + GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForRemote, + PilotGeneratorSettings, + PilotGraphicGenerator, + ServerSelectMode +} from '../helpers' import { GetJinglePartPropertiesFromTableValue } from '../jinglePartProperties' -import { CreateEffektForPartBase, CreateEffektForPartInner, CreateMixForPartInner } from '../parts' +import { CreateEffektForPartBase, CreateEffektForPartInner, CreateMixTransitionBlueprintPieceForPart } from '../parts' import { GetTagForDVE, GetTagForDVENext, @@ -83,6 +89,7 @@ import { GetTagForLive, GetTagForTransition } from '../pieces' +import { findSourceInfo } from '../sources' import { assertUnreachable } from '../util' import { ActionCommentatorSelectJingle, @@ -94,7 +101,6 @@ import { const STOPPABLE_GRAPHICS_LAYERS = [ SharedSourceLayers.PgmGraphicsIdent, - SharedSourceLayers.PgmGraphicsIdentPersistent, SharedSourceLayers.PgmGraphicsTop, SharedSourceLayers.PgmGraphicsLower, SharedSourceLayers.PgmGraphicsHeadline, @@ -104,6 +110,8 @@ const STOPPABLE_GRAPHICS_LAYERS = [ SharedSourceLayers.PgmGraphicsTLF ] +const FADE_SISYFOS_LEVELS_PIECE_NAME = 'fadeDown' + export interface ActionExecutionSettings< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase @@ -151,7 +159,6 @@ export interface ActionExecutionSettings< ClipPending: string Effekt: string StudioMics: string - PersistedLevels: string } Atem: { MEProgram: string @@ -174,7 +181,6 @@ export interface ActionExecutionSettings< } SELECTED_ADLIB_LAYERS: string[] } - ServerAudioLayers: string[] createJingleContent: ( config: ShowStyleConfig, file: string, @@ -186,68 +192,88 @@ export interface ActionExecutionSettings< pilotGraphicSettings: PilotGeneratorSettings } -export function executeAction< +export async function executeAction< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( coreContext: IActionExecutionContext, settings: ActionExecutionSettings, actionIdStr: string, - userData: ActionUserData -): void { - executeWithContext(coreContext, context => { - const existingTransition = getExistingTransition(context, settings, 'next') + userData: ActionUserData, + triggerMode?: string +): Promise { + await executeWithContext(coreContext, async context => { + const existingTransition = await getExistingTransition(context, settings, 'next') const actionId = actionIdStr as AdlibActionType switch (actionId) { case AdlibActionType.SELECT_SERVER_CLIP: - executeActionSelectServerClip(context, settings, actionId, userData as ActionSelectServerClip) + await executeActionSelectServerClip( + context, + settings, + actionId, + userData as ActionSelectServerClip, + triggerMode as ServerSelectMode | undefined + ) break case AdlibActionType.SELECT_DVE: - executeActionSelectDVE(context, settings, actionId, userData as ActionSelectDVE) + await executeActionSelectDVE(context, settings, actionId, userData as ActionSelectDVE) break case AdlibActionType.SELECT_DVE_LAYOUT: - executeActionSelectDVELayout(context, settings, actionId, userData as ActionSelectDVELayout) + await executeActionSelectDVELayout(context, settings, actionId, userData as ActionSelectDVELayout) break case AdlibActionType.SELECT_FULL_GRAFIK: - executeActionSelectFull(context, settings, actionId, userData as ActionSelectFullGrafik) + await executeActionSelectFull(context, settings, actionId, userData as ActionSelectFullGrafik) break case AdlibActionType.SELECT_JINGLE: - executeActionSelectJingle(context, settings, actionId, userData as ActionSelectJingle) + await executeActionSelectJingle(context, settings, actionId, userData as ActionSelectJingle) break case AdlibActionType.CLEAR_GRAPHICS: - executeActionClearGraphics(context, settings, actionId, userData as ActionClearGraphics) + await executeActionClearGraphics(context, settings, actionId, userData as ActionClearGraphics) break case AdlibActionType.CUT_TO_CAMERA: - executeActionCutToCamera(context, settings, actionId, userData as ActionCutToCamera) + await executeActionCutToCamera(context, settings, actionId, userData as ActionCutToCamera) break case AdlibActionType.CUT_TO_REMOTE: - executeActionCutToRemote(context, settings, actionId, userData as ActionCutToRemote) + await executeActionCutToRemote(context, settings, actionId, userData as ActionCutToRemote) break case AdlibActionType.CUT_SOURCE_TO_BOX: - executeActionCutSourceToBox(context, settings, actionId, userData as ActionCutSourceToBox) + await executeActionCutSourceToBox(context, settings, actionId, userData as ActionCutSourceToBox) break case AdlibActionType.COMMENTATOR_SELECT_DVE: - executeActionCommentatorSelectDVE(context, settings, actionId, userData as ActionCommentatorSelectDVE) + await executeActionCommentatorSelectDVE(context, settings, actionId, userData as ActionCommentatorSelectDVE) break case AdlibActionType.COMMENTATOR_SELECT_SERVER: - executeActionCommentatorSelectServer(context, settings, actionId, userData as ActionCommentatorSelectServer) + await executeActionCommentatorSelectServer( + context, + settings, + actionId, + userData as ActionCommentatorSelectServer + ) break case AdlibActionType.COMMENTATOR_SELECT_FULL: - executeActionCommentatorSelectFull(context, settings, actionId, userData as ActionCommentatorSelectFull) + await executeActionCommentatorSelectFull(context, settings, actionId, userData as ActionCommentatorSelectFull) break case AdlibActionType.COMMENTATOR_SELECT_JINGLE: - executeActionCommentatorSelectJingle(context, settings, actionId, userData as ActionCommentatorSelectJingle) + await executeActionCommentatorSelectJingle( + context, + settings, + actionId, + userData as ActionCommentatorSelectJingle + ) break case AdlibActionType.TAKE_WITH_TRANSITION: - executeActionTakeWithTransition(context, settings, actionId, userData as ActionTakeWithTransition) + await executeActionTakeWithTransition(context, settings, actionId, userData as ActionTakeWithTransition) break case AdlibActionType.RECALL_LAST_LIVE: - executeActionRecallLastLive(context, settings, actionId, userData as ActionRecallLastLive) + await executeActionRecallLastLive(context, settings, actionId, userData as ActionRecallLastLive) break case AdlibActionType.RECALL_LAST_DVE: - executeActionRecallLastDVE(context, settings, actionId, userData as ActionRecallLastDVE) + await executeActionRecallLastDVE(context, settings, actionId, userData as ActionRecallLastDVE) + break + case AdlibActionType.FADE_DOWN_PERSISTED_AUDIO_LEVELS: + await executeActionFadeDownPersistedAudioLevels(context, settings) break default: assertUnreachable(actionId) @@ -256,7 +282,12 @@ export function executeAction< if (actionId !== AdlibActionType.TAKE_WITH_TRANSITION) { if (existingTransition) { - executeActionTakeWithTransition(context, settings, AdlibActionType.TAKE_WITH_TRANSITION, existingTransition) + await executeActionTakeWithTransition( + context, + settings, + AdlibActionType.TAKE_WITH_TRANSITION, + existingTransition + ) } } }) @@ -270,17 +301,17 @@ function sanitizePieceStart(piece: IBlueprintPiece): IBlueprintPiece { return piece } -function getExistingTransition< +async function getExistingTransition< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, settings: ActionExecutionSettings, part: 'current' | 'next' -): ActionTakeWithTransition | undefined { - const existingTransition = context +): Promise { + const existingTransition = await context .getPieceInstances(part) - .find(p => p.piece.sourceLayerId === settings.SourceLayers.Effekt) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === settings.SourceLayers.Effekt)) if (!existingTransition) { return @@ -289,7 +320,7 @@ function getExistingTransition< const transition = existingTransition.piece.name // Case sensitive! Blueprints will set these names correctly. - const transitionProps = transition.match(/CUT|MIX (\d+)|EFFEKT (\d+)/) + const transitionProps = transition.match(/CUT|MIX (\d+)|DIP (\d+)|EFFEKT (\d+)/) if (!transitionProps || !transitionProps[0]) { return } @@ -302,7 +333,9 @@ function getExistingTransition< }, takeNow: false }) - } else if (transitionProps[0].match(/MIX/) && transitionProps[1] !== undefined) { + } + + if (transitionProps[0].match(/MIX/) && transitionProps[1] !== undefined) { return literal({ type: AdlibActionType.TAKE_WITH_TRANSITION, variant: { @@ -311,7 +344,20 @@ function getExistingTransition< }, takeNow: false }) - } else if (transitionProps[0].match(/EFFEKT/) && transitionProps[1] !== undefined) { + } + + if (transitionProps[0].match(/DIP/) && transitionProps[1] !== undefined) { + return literal({ + type: AdlibActionType.TAKE_WITH_TRANSITION, + variant: { + type: 'dip', + frames: Number(transitionProps[1]) + }, + takeNow: false + }) + } + + if (transitionProps[0].match(/EFFEKT/) && transitionProps[1] !== undefined) { return literal({ type: AdlibActionType.TAKE_WITH_TRANSITION, variant: { @@ -320,22 +366,21 @@ function getExistingTransition< }, takeNow: false }) - } else { - return } + return } -function sanitizePieceId(piece: IBlueprintPieceDB): IBlueprintPiece { +function sanitizePieceId(piece: IBlueprintPieceDB): IBlueprintPiece { return _.omit(piece, ['_id', 'partId', 'infiniteId', 'playoutDuration']) } -export function getPiecesToPreserve( +export async function getPiecesToPreserve( context: ITV2ActionExecutionContext, adlibLayers: string[], - ingoreLayers: string[] -): IBlueprintPiece[] { - const currentPartSegmentId = context.getPartInstance('current')?.segmentId - const nextPartSegmentId = context.getPartInstance('next')?.segmentId + ignoreLayers: string[] +): Promise>> { + const currentPartSegmentId = await context.getPartInstance('current').then(partInstance => partInstance?.segmentId) + const nextPartSegmentId = await context.getPartInstance('next').then(partInstance => partInstance?.segmentId) if (!currentPartSegmentId || !nextPartSegmentId) { return [] @@ -345,20 +390,21 @@ export function getPiecesToPreserve( return [] } - return context - .getPieceInstances('next') - .filter(p => adlibLayers.includes(p.piece.sourceLayerId) && !ingoreLayers.includes(p.piece.sourceLayerId)) - .filter(p => !p.infinite?.fromPreviousPart && !p.infinite?.fromPreviousPlayhead) - .map(p => p.piece) - .map(p => sanitizePieceStart(p)) - .map(p => sanitizePieceId(p as IBlueprintPieceDB)) + return context.getPieceInstances('next').then(pieceInstances => { + return pieceInstances + .filter(p => adlibLayers.includes(p.piece.sourceLayerId) && !ignoreLayers.includes(p.piece.sourceLayerId)) + .filter(p => !p.infinite?.fromPreviousPart && !p.infinite?.fromPreviousPlayhead) + .map>(p => p.piece) + .map(p => sanitizePieceStart(p)) + .map(p => sanitizePieceId(p as IBlueprintPieceDB)) + }) } function generateExternalId(context: ITV2ActionExecutionContext, actionId: string, args: string[]): string { return `adlib_action_${actionId}_${context.getHashId(args.join('_'), true)}` } -function executeActionSelectServerClip< +async function executeActionSelectServerClip< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -366,6 +412,7 @@ function executeActionSelectServerClip< settings: ActionExecutionSettings, actionId: string, userData: ActionSelectServerClip, + triggerMode?: ServerSelectMode, sessionToContinue?: string ) { const file = userData.file @@ -375,14 +422,12 @@ function executeActionSelectServerClip< const externalId = generateExternalId(context, actionId, [file]) const currentPiece = settings.SelectedAdlibs - ? context + ? await context .getPieceInstances('current') - .find( - p => p.piece.sourceLayerId === (userData.voLayer ? settings.SourceLayers.VO : settings.SourceLayers.Server) - ) + .then(pieceInstances => pieceInstances.find(p => isServerOnPgm(p, settings, userData.voLayer))) : undefined - const basePart = CreatePartServerBase( + const basePart = await CreatePartServerBase( context, config, partDefinition, @@ -393,7 +438,9 @@ function executeActionSelectServerClip< totalTime: 0, tapeTime: userData.duration / 1000, session: sessionToContinue ?? externalId, - adLibPix: userData.adLibPix + adLibPix: userData.adLibPix, + lastServerPosition: await getServerPosition(context), + actionTriggerMode: triggerMode }, { SourceLayer: { @@ -410,8 +457,7 @@ function executeActionSelectServerClip< ClipPending: settings.LLayer.Caspar.ClipPending }, Sisyfos: { - ClipPending: settings.LLayer.Sisyfos.ClipPending, - StudioMicsGroup: settings.LLayer.Sisyfos.StudioMics + ClipPending: settings.LLayer.Sisyfos.ClipPending }, ATEM: { ServerLookaheadAux: settings.LLayer.Atem.ServerLookaheadAUX @@ -431,8 +477,8 @@ function executeActionSelectServerClip< let part = basePart.part.part - const grafikPieces: IBlueprintPiece[] = [] - const effektPieces: IBlueprintPiece[] = [] + const grafikPieces: Array> = [] + const effektPieces: Array> = [] part = { ...part, @@ -468,20 +514,21 @@ function executeActionSelectServerClip< settings.postProcessPieceTimelineObjects(context, config, activeServerPiece, false) } - context.queuePart(part, [ - activeServerPiece, - serverDataStore, + await context.queuePart(part, [ + activeServerPiece as IBlueprintPiece, // @todo: get rid of these casts + serverDataStore as IBlueprintPiece, ...grafikPieces, ...(settings.SelectedAdlibs - ? getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, [ + ? await getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, [ settings.SelectedAdlibs.SourceLayer.VO, settings.SelectedAdlibs.SourceLayer.Server ]) : []), ...effektPieces ]) + if (settings.SelectedAdlibs && !currentPiece) { - context.stopPiecesOnLayers([ + await context.stopPiecesOnLayers([ userData.voLayer ? settings.SelectedAdlibs.SourceLayer.VO : settings.SelectedAdlibs.SourceLayer.Server ]) } @@ -489,14 +536,29 @@ function executeActionSelectServerClip< function dveContainsServer(sources: DVESources) { return ( - sources.INP1?.match(/SERVER/i) || - sources.INP2?.match(/SERVER/i) || - sources.INP3?.match(/SERVER/i) || - sources.INP4?.match(/SERVER/i) + sources.INP1?.sourceType === SourceType.SERVER || + sources.INP2?.sourceType === SourceType.SERVER || + sources.INP3?.sourceType === SourceType.SERVER || + sources.INP4?.sourceType === SourceType.SERVER + ) +} + +function isServerOnPgm< + StudioConfig extends TV2StudioConfigBase, + ShowStyleConfig extends TV2BlueprintConfigBase +>( + pieceInstance: IBlueprintPieceInstance, + settings: ActionExecutionSettings, + voLayer: boolean +) { + return ( + pieceInstance.piece.sourceLayerId === (voLayer ? settings.SourceLayers.VO : settings.SourceLayers.Server) || + (pieceInstance.piece.sourceLayerId === settings.SourceLayers.DVEAdLib && + dveContainsServer((pieceInstance.piece.metaData as DVEPieceMetaData).sources)) ) } -function executeActionSelectDVE< +async function executeActionSelectDVE< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -509,7 +571,7 @@ function executeActionSelectDVE< const config = settings.getConfig(context) - const parsedCue = userData.config + const parsedCue: CueDefinitionDVE = userData.config const rawTemplate = GetDVETemplate(config.showStyle.DVEStyles, parsedCue.template) if (!rawTemplate) { @@ -531,7 +593,6 @@ function executeActionSelectDVE< settings.DVEGeneratorOptions, undefined, false, - userData.videoId, externalId ) @@ -539,14 +600,17 @@ function executeActionSelectDVE< start = start ? start : 0 const end = parsedCue.end ? CalculateTime(parsedCue.end) : undefined - const metaData = literal({ + const metaData: DVEPieceMetaData = { mediaPlayerSessions: dveContainsServer(parsedCue.sources) ? [externalId] : [], sources: parsedCue.sources, config: rawTemplate, + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, userData - }) + } - let dvePiece = literal({ + let dvePiece: IBlueprintPiece = { externalId, name: `${parsedCue.template}`, enable: { @@ -560,18 +624,18 @@ function executeActionSelectDVE< content: { ...pieceContent.content }, - adlibPreroll: Number(config.studio.CasparPrerollDuration) || 0, + prerollDuration: Number(config.studio.CasparPrerollDuration) || 0, metaData, tags: [ GetTagForDVE(userData.segmentExternalId, parsedCue.template, parsedCue.sources), GetTagForDVENext(userData.segmentExternalId, parsedCue.template, parsedCue.sources), TallyTags.DVE_IS_LIVE ] - }) + } - dvePiece = cutServerToBox(context, settings, dvePiece) + dvePiece = await cutServerToBox(context, settings, dvePiece) - startNewDVELayout( + await startNewDVELayout( context, config, settings, @@ -587,37 +651,47 @@ function executeActionSelectDVE< ) } -function cutServerToBox< +async function cutServerToBox< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, settings: ActionExecutionSettings, - dvePiece: IBlueprintPiece -): IBlueprintPiece { + newDvePiece: IBlueprintPiece, + containedServerBefore?: boolean, + modifiesCurrent?: boolean +): Promise> { // Check if DVE should continue server + copy server properties - if (!dvePiece.metaData) { - return dvePiece + if (!newDvePiece.metaData) { + return newDvePiece } - const meta = dvePiece.metaData as DVEPieceMetaData + const meta = newDvePiece.metaData + + const containsServer = dveContainsServer(meta.sources) - if (!dveContainsServer(meta.sources)) { - return dvePiece + if (!containsServer) { + if (containedServerBefore) { + stopServerMetaData(context, meta) + } + return newDvePiece } - if (dvePiece.content?.timelineObjects) { - const currentPieces = context.getPieceInstances('current') - const currentServer = currentPieces.find( - p => - p.piece.sourceLayerId === settings.SelectedAdlibs?.SourceLayer.Server || - p.piece.sourceLayerId === settings.SelectedAdlibs?.SourceLayer.VO - ) + if (newDvePiece.content?.timelineObjects) { + const currentServer = await context + .getPieceInstances('current') + .then(currentPieces => + currentPieces.find( + p => + p.piece.sourceLayerId === settings.SelectedAdlibs?.SourceLayer.Server || + p.piece.sourceLayerId === settings.SelectedAdlibs?.SourceLayer.VO + ) + ) if (!currentServer || !currentServer.piece.content?.timelineObjects) { context.notifyUserWarning(`No server is playing, cannot start DVE`) - return dvePiece + return newDvePiece } // Find existing CasparCG object @@ -629,8 +703,8 @@ function cutServerToBox< obj => obj.layer === settings.LLayer.Sisyfos.ClipPending ) as TSR.TimelineObjSisyfosChannel & TimelineBlueprintExt // Find SSRC object in DVE piece - const ssrcObjIndex = dvePiece.content?.timelineObjects - ? (dvePiece.content?.timelineObjects as TSR.TSRTimelineObj[]).findIndex( + const ssrcObjIndex = newDvePiece.content?.timelineObjects + ? (newDvePiece.content?.timelineObjects as TSR.TSRTimelineObj[]).findIndex( obj => obj.layer === settings.LLayer.Atem.SSrcDefault ) : -1 @@ -643,30 +717,47 @@ function cutServerToBox< !existingCasparObj.metaData.mediaPlayerSession ) { context.notifyUserWarning(`Failed to start DVE with server`) - return dvePiece + return newDvePiece } - const ssrcObj = (dvePiece.content.timelineObjects as Array)[ssrcObjIndex] + const ssrcObj = newDvePiece.content.timelineObjects[ssrcObjIndex] as TSR.TSRTimelineObj & TimelineBlueprintExt ssrcObj.metaData = { ...ssrcObj.metaData, mediaPlayerSession: existingCasparObj.metaData.mediaPlayerSession } - dvePiece.content.timelineObjects[ssrcObjIndex] = ssrcObj - dvePiece.content.timelineObjects.push(EnableServer(existingCasparObj.metaData.mediaPlayerSession)) + newDvePiece.content.timelineObjects[ssrcObjIndex] = ssrcObj + newDvePiece.content.timelineObjects.push(EnableServer(existingCasparObj.metaData.mediaPlayerSession)) + newDvePiece.metaData.mediaPlayerSessions = [existingCasparObj.metaData.mediaPlayerSession] - if (!dvePiece.metaData) { - dvePiece.metaData = {} + if (!containedServerBefore) { + startServerMetaData(context, meta, modifiesCurrent) } + } + + return newDvePiece +} - ;(dvePiece.metaData as any).mediaPlayerSessions = [existingCasparObj.metaData.mediaPlayerSession] +function stopServerMetaData(context: ITV2ActionExecutionContext, metaData: DVEPieceMetaData) { + const length = metaData.serverPlaybackTiming?.length + if (metaData.serverPlaybackTiming && length) { + metaData.serverPlaybackTiming[length - 1].end = context.getCurrentTime() } +} - return dvePiece +function startServerMetaData( + context: ITV2ActionExecutionContext, + metaData: DVEPieceMetaData, + modifiesCurrent?: boolean +) { + if (!metaData.serverPlaybackTiming) { + metaData.serverPlaybackTiming = [] + } + metaData.serverPlaybackTiming.push(modifiesCurrent ? { start: context.getCurrentTime() } : {}) } -function executeActionSelectDVELayout< +async function executeActionSelectDVELayout< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -682,46 +773,52 @@ function executeActionSelectDVELayout< } const sources: DVESources = { - INP1: 'DEFAULT', - INP2: 'DEFAULT', - INP3: 'DEFAULT', - INP4: 'DEFAULT' + INP1: { sourceType: SourceType.DEFAULT }, + INP2: { sourceType: SourceType.DEFAULT }, + INP3: { sourceType: SourceType.DEFAULT }, + INP4: { sourceType: SourceType.DEFAULT } } const externalId = generateExternalId(context, actionId, [userData.config.DVEName]) - const nextPart = context.getPartInstance('next') + const nextPart = await context.getPartInstance('next') - const nextInstances = context.getPieceInstances('next') - const nextDVE = nextInstances.find(p => p.piece.sourceLayerId === settings.SourceLayers.DVE) + const nextDVE = (await context + .getPieceInstances('next') + .then(nextPieceInstances => nextPieceInstances.find(p => p.piece.sourceLayerId === settings.SourceLayers.DVE))) as + | IBlueprintPieceInstance + | undefined - const meta = nextDVE?.piece.metaData as DVEPieceMetaData + const meta = nextDVE?.piece.metaData - if (!nextPart || !nextDVE || !meta || nextPart.segmentId !== context.getPartInstance('current')?.segmentId) { + if (!nextPart || !nextDVE || !meta || nextPart.segmentId !== (await context.getPartInstance('current'))?.segmentId) { const content = MakeContentDVE2(context, config, userData.config, {}, sources, settings.DVEGeneratorOptions) if (!content.valid) { return } - const newMetaData = literal({ + const newMetaData: DVEPieceMetaData = { sources, config: userData.config, - userData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + userData: { type: AdlibActionType.SELECT_DVE, - config: literal({ + config: { type: CueType.DVE, template: userData.config.DVEName, sources, labels: [], iNewsCommand: `DVE=${userData.config.DVEName}` - }), + }, videoId: undefined, segmentExternalId: '' - }) - }) + } + } - let newDVEPiece = literal({ + let newDVEPiece: IBlueprintPiece = { externalId, enable: { start: 0 @@ -732,9 +829,9 @@ function executeActionSelectDVELayout< outputLayerId: SharedOutputLayers.PGM, metaData: newMetaData, content: content.content - }) + } - newDVEPiece = cutServerToBox(context, settings, newDVEPiece) + newDVEPiece = await cutServerToBox(context, settings, newDVEPiece) return startNewDVELayout( context, @@ -752,13 +849,16 @@ function executeActionSelectDVELayout< ) } - const newMetaData2 = literal({ + const newMetaData2: DVEPieceMetaData = { ...meta, - config: userData.config - }) + config: userData.config, + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + } const pieceContent = MakeContentDVE2(context, config, userData.config, {}, meta.sources, settings.DVEGeneratorOptions) - let dvePiece: IBlueprintPiece = { + let dvePiece: IBlueprintPiece = { ...nextDVE.piece, content: pieceContent.content, metaData: newMetaData2, @@ -769,9 +869,9 @@ function executeActionSelectDVELayout< ] } - dvePiece = cutServerToBox(context, settings, dvePiece) + dvePiece = await cutServerToBox(context, settings, dvePiece) - startNewDVELayout( + await startNewDVELayout( context, config, settings, @@ -789,16 +889,16 @@ function executeActionSelectDVELayout< ) } -function startNewDVELayout< +async function startNewDVELayout< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, config: ShowStyleConfig, settings: ActionExecutionSettings, - dvePiece: IBlueprintPiece, + dvePiece: IBlueprintPiece, pieceContent: WithTimeline, - meta: PieceMetaData & DVEPieceMetaData, + metaData: DVEPieceMetaData, templateName: string, _sources: CueDefinitionDVE['sources'], externalId: string, @@ -808,8 +908,8 @@ function startNewDVELayout< ) { settings.postProcessPieceTimelineObjects(context, config, dvePiece, false) - const dveDataStore = settings.SelectedAdlibs.SourceLayer.DVE - ? literal({ + const dveDataStore: IBlueprintPiece | undefined = settings.SelectedAdlibs.SourceLayer.DVE + ? { externalId, name: templateName, enable: { @@ -818,7 +918,7 @@ function startNewDVELayout< outputLayerId: settings.SelectedAdlibs.OutputLayer.SelectedAdLib, sourceLayerId: settings.SelectedAdlibs.SourceLayer.DVE, lifespan: PieceLifespan.OutOnSegmentEnd, - metaData: meta, + metaData, tags: [nextTag], content: { ...pieceContent, @@ -833,34 +933,34 @@ function startNewDVELayout< ) .map(obj => ({ ...obj, priority: obj.priority ?? 1 / 2 })) } - }) + } : undefined if (replacePieceInstancesOrQueue === 'queue') { - const newPart = literal({ + const newPart: IBlueprintPart = { externalId, title: templateName, metaData: {}, - expectedDuration: 0, - prerollDuration: config.studio.CasparPrerollDuration - }) + expectedDuration: 0 + } + const currentPieceInstances = await context.getPieceInstances('current') // If a DVE is not on air, but a layout is selected, stop the selected layout and replace with the new one. - const onAirPiece = context - .getPieceInstances('current') - .find(p => p.piece.sourceLayerId === settings.SourceLayers.DVE) + const onAirPiece = currentPieceInstances.find(p => p.piece.sourceLayerId === settings.SourceLayers.DVE) + const dataPiece = settings.SelectedAdlibs && - context.getPieceInstances('current').find(p => p.piece.sourceLayerId === settings.SelectedAdlibs!.SourceLayer.DVE) + currentPieceInstances.find(p => p.piece.sourceLayerId === settings.SelectedAdlibs.SourceLayer.DVE) if (onAirPiece === undefined && dataPiece !== undefined) { - context.stopPieceInstances([dataPiece._id]) + await context.stopPieceInstances([dataPiece._id]) } - context.queuePart(newPart, [ + dvePiece.prerollDuration = config.studio.CasparPrerollDuration + await context.queuePart(newPart, [ dvePiece, ...(dveDataStore ? [dveDataStore] : []), ...(settings.SelectedAdlibs - ? getPiecesToPreserve( + ? await getPiecesToPreserve( context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, settings.SelectedAdlibs.SourceLayer.DVE ? [settings.SelectedAdlibs.SourceLayer.DVE] : [] @@ -868,24 +968,24 @@ function startNewDVELayout< : []) ]) if (settings.SelectedAdlibs.SourceLayer.DVE) { - context.stopPiecesOnLayers([settings.SelectedAdlibs.SourceLayer.DVE]) + await context.stopPiecesOnLayers([settings.SelectedAdlibs.SourceLayer.DVE]) } } else { if (replacePieceInstancesOrQueue.activeDVE) { - context.updatePieceInstance(replacePieceInstancesOrQueue.activeDVE, dvePiece) - context.updatePartInstance(part, { expectedDuration: 0 }) + await context.updatePieceInstance(replacePieceInstancesOrQueue.activeDVE, dvePiece) + await context.updatePartInstance(part, { expectedDuration: 0 }) if (dveDataStore) { if (replacePieceInstancesOrQueue.dataStore) { - context.updatePieceInstance(replacePieceInstancesOrQueue.dataStore, dveDataStore) + await context.updatePieceInstance(replacePieceInstancesOrQueue.dataStore, dveDataStore) } else { - context.insertPiece(part, dveDataStore) + await context.insertPiece(part, dveDataStore) } } } } } -function executeActionSelectJingle< +async function executeActionSelectJingle< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -915,7 +1015,7 @@ function executeActionSelectJingle< file = jingle.ClipName.toString() } - const props = GetJinglePartPropertiesFromTableValue(config, jingle) + const props = GetJinglePartPropertiesFromTableValue(jingle) const pieceContent = settings.createJingleContent( config, @@ -926,7 +1026,7 @@ function executeActionSelectJingle< jingle.EndAlpha ) - const piece = literal({ + const piece: IBlueprintPiece = { externalId: `${externalId}-JINGLE`, name: userData.clip, enable: { @@ -935,54 +1035,29 @@ function executeActionSelectJingle< lifespan: PieceLifespan.WithinPart, outputLayerId: SharedOutputLayers.JINGLE, sourceLayerId: settings.SourceLayers.Effekt, + prerollDuration: config.studio.CasparPrerollDuration + TimeFromFrames(Number(jingle.StartAlpha)), content: pieceContent, - metaData: literal({ - transition: { - isJingle: true - } - }), tags: [ GetTagForJingle(userData.segmentExternalId, userData.clip), GetTagForJingleNext(userData.segmentExternalId, userData.clip), - TallyTags.JINGLE_IS_LIVE + TallyTags.JINGLE_IS_LIVE, + TallyTags.JINGLE ] - }) - - const jingleDataStore = settings.SelectedAdlibs.SourceLayer.Effekt - ? literal({ - externalId, - name: userData.clip, - enable: { - start: 0 - }, - outputLayerId: settings.SelectedAdlibs.OutputLayer.SelectedAdLib, - sourceLayerId: settings.SelectedAdlibs.SourceLayer.Effekt, - lifespan: PieceLifespan.WithinPart, - metaData: { - userData - }, - content: { - ...pieceContent, - timelineObjects: [] - }, - tags: [GetTagForJingleNext(userData.segmentExternalId, userData.clip)] - }) - : undefined + } settings.postProcessPieceTimelineObjects(context, config, piece, false) - const part = literal({ + const part: IBlueprintPart = { externalId, title: `JINGLE ${userData.clip}`, metaData: {}, ...props - }) + } - context.queuePart(part, [ + await context.queuePart(part, [ piece, - ...(jingleDataStore ? [] : []), ...(settings.SelectedAdlibs - ? getPiecesToPreserve( + ? await getPiecesToPreserve( context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, settings.SelectedAdlibs.SourceLayer.Effekt ? [settings.SelectedAdlibs.SourceLayer.Effekt] : [] @@ -991,11 +1066,11 @@ function executeActionSelectJingle< ]) if (settings.SelectedAdlibs.SourceLayer.Effekt) { - context.stopPiecesOnLayers([settings.SelectedAdlibs.SourceLayer.Effekt]) + await context.stopPiecesOnLayers([settings.SelectedAdlibs.SourceLayer.Effekt]) } } -function executeActionCutToCamera< +async function executeActionCutToCamera< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1006,21 +1081,21 @@ function executeActionCutToCamera< ) { const config = settings.getConfig(context) - const externalId = generateExternalId(context, actionId, [userData.name]) + const externalId = generateExternalId(context, actionId, [userData.sourceDefinition.name]) - const part = literal({ + const part: IBlueprintPart = { externalId, - title: `KAM ${userData.name}`, + title: userData.sourceDefinition.name, metaData: {}, expectedDuration: 0 - }) + } - const sourceInfoCam = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, `Kam ${userData.name}`) + const sourceInfoCam = findSourceInfo(config.sources, userData.sourceDefinition) if (sourceInfoCam === undefined) { return } - const currentPieceInstances = context.getPieceInstances('current') + const currentPieceInstances = await context.getPieceInstances('current') const serverInCurrentPart = currentPieceInstances.some( p => p.piece.sourceLayerId === settings.SourceLayers.Server || p.piece.sourceLayerId === settings.SourceLayers.VO @@ -1028,24 +1103,25 @@ function executeActionCutToCamera< const currentKam = currentPieceInstances.find(p => p.piece.sourceLayerId === settings.SourceLayers.Cam) - const camSisyfos = GetSisyfosTimelineObjForCamera( - context, - config, - `KAM ${userData.name}`, - settings.LLayer.Sisyfos.StudioMics - ) + const camSisyfos = GetSisyfosTimelineObjForCamera(config, sourceInfoCam, false) - const kamPiece = literal({ + const kamPiece: IBlueprintPiece = { externalId, name: part.title, enable: { start: 0 }, outputLayerId: SharedOutputLayers.PGM, sourceLayerId: settings.SourceLayers.Cam, lifespan: PieceLifespan.WithinPart, - metaData: GetCameraMetaData(config, GetLayersForCamera(config, sourceInfoCam)), - tags: [GetTagForKam(userData.name)], + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [], + acceptPersistAudio: sourceInfoCam.acceptPersistAudio, + isPieceInjectedInPart: true + } + }, + tags: [GetTagForKam(userData.sourceDefinition)], content: { - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: '', enable: { while: '1' }, @@ -1061,75 +1137,44 @@ function executeActionCutToCamera< }, classes: ['adlib_deparent'] }), - camSisyfos, - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: settings.LLayer.Sisyfos.PersistedLevels, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNELS, - overridePriority: 1, - channels: config.stickyLayers - .filter(layer => camSisyfos.content.channels.map(channel => channel.mappedLayer).indexOf(layer) === -1) - .map(layer => { - return { - mappedLayer: layer, - isPgm: 0 - } - }) - }, - metaData: { - sisyfosPersistLevel: true - } - }), - // Force server to be muted (for adlibbing over DVE) - ...settings.ServerAudioLayers.map(layer => { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 2, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - } - }) - }) + ...camSisyfos ]) } - }) + } settings.postProcessPieceTimelineObjects(context, config, kamPiece, false) if (userData.queue || serverInCurrentPart) { - context.queuePart(part, [ + await context.queuePart(part, [ kamPiece, ...(settings.SelectedAdlibs - ? getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, []) + ? await getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, []) : []) ]) + if (serverInCurrentPart && !userData.queue) { - context.takeAfterExecuteAction(true) + await context.takeAfterExecuteAction(true) } } else if (currentKam) { kamPiece.externalId = currentKam.piece.externalId kamPiece.enable = currentKam.piece.enable - context.updatePieceInstance(currentKam._id, kamPiece) + const currentMetaData = currentKam.piece.metaData! + const metaData = kamPiece.metaData! + metaData.sisyfosPersistMetaData!.previousPersistMetaDataForCurrentPiece = currentMetaData.sisyfosPersistMetaData + + await stopGraphicPiecesThatShouldEndWithPart(context, currentPieceInstances) + + await context.updatePieceInstance(currentKam._id, kamPiece) } else { - const currentExternalId = context.getPartInstance('current')?.part.externalId + const currentExternalId = await context + .getPartInstance('current') + .then(currentPartInstance => currentPartInstance?.part.externalId) if (currentExternalId) { kamPiece.externalId = currentExternalId } - context.stopPiecesOnLayers([ + await context.stopPiecesOnLayers([ settings.SourceLayers.DVE, ...(settings.SourceLayers.DVEAdLib ? [settings.SourceLayers.DVEAdLib] : []), settings.SourceLayers.Effekt, @@ -1139,12 +1184,33 @@ function executeActionCutToCamera< ...(settings.SourceLayers.EVS ? [settings.SourceLayers.EVS] : []), settings.SourceLayers.Continuity ]) + await stopGraphicPiecesThatShouldEndWithPart(context, currentPieceInstances) + kamPiece.enable = { start: 'now' } - context.insertPiece('current', kamPiece) + await context.insertPiece('current', kamPiece) } } -function executeActionCutToRemote< +async function stopGraphicPiecesThatShouldEndWithPart( + context: ITV2ActionExecutionContext, + currentPieceInstances: Array> +) { + await context.stopPieceInstances( + currentPieceInstances + .filter(pieceInstance => isGraphicThatShouldEndWithPart(pieceInstance)) + .map(pieceInstance => pieceInstance._id) + ) +} + +function isGraphicThatShouldEndWithPart(pieceInstance: IBlueprintPieceInstance): boolean { + return ( + pieceInstance.piece.lifespan === PieceLifespan.WithinPart && + !pieceInstance.stoppedPlayback && + (STOPPABLE_GRAPHICS_LAYERS as string[]).includes(pieceInstance.piece.sourceLayerId) + ) +} + +async function executeActionCutToRemote< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1155,24 +1221,35 @@ function executeActionCutToRemote< ) { const config = settings.getConfig(context) - const externalId = generateExternalId(context, actionId, [userData.name]) + const externalId = generateExternalId(context, actionId, [userData.sourceDefinition.name]) - const feed = userData.name.match(/^F(.+).*$/) // TODO: fix when refactoring FindSourceInfo - const title = feed ? `FEED ${feed[1]}` : `LIVE ${userData.name}` + const title = userData.sourceDefinition.name - const part = literal({ + const part: IBlueprintPart = { externalId, title, metaData: {}, expectedDuration: 0 - }) + } - const eksternSisyfos: TSR.TimelineObjSisyfosAny[] = [ - ...GetSisyfosTimelineObjForEkstern(context, config.sources, `Live ${userData.name}`, GetLayersForEkstern), - GetSisyfosTimelineObjForCamera(context, config, 'telefon', settings.LLayer.Sisyfos.StudioMics) - ] + const sourceInfo = findSourceInfo(config.sources, userData.sourceDefinition) + if (sourceInfo === undefined) { + context.notifyUserWarning(`Invalid source: ${userData.sourceDefinition.name}`) + return + } + + const eksternSisyfos: TSR.TimelineObjSisyfosAny[] = GetSisyfosTimelineObjForRemote(config, sourceInfo) - const remotePiece = literal({ + const sisyfosPersistMetaData: SisyfosPersistMetaData = + sourceInfo !== undefined + ? { + sisyfosLayers: sourceInfo.sisyfosLayers ?? [], + wantsToPersistAudio: sourceInfo.wantsToPersistAudio, + acceptPersistAudio: sourceInfo.acceptPersistAudio + } + : { sisyfosLayers: [] } + + const remotePiece: IBlueprintPiece = { externalId, name: title, enable: { @@ -1182,14 +1259,12 @@ function executeActionCutToRemote< outputLayerId: SharedOutputLayers.PGM, lifespan: PieceLifespan.WithinPart, toBeQueued: true, - metaData: GetEksternMetaData( - config.stickyLayers, - config.studio.StudioMics, - GetLayersForEkstern(context, config.sources, `Live ${userData.name}`) - ), - tags: [GetTagForLive(userData.name)], + metaData: { + sisyfosPersistMetaData + }, + tags: [GetTagForLive(userData.sourceDefinition)], content: { - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: '', enable: { while: '1' }, @@ -1199,63 +1274,28 @@ function executeActionCutToRemote< deviceType: TSR.DeviceType.ATEM, type: TSR.TimelineContentTypeAtem.ME, me: { - input: userData.port, + input: sourceInfo.port, transition: TSR.AtemTransitionStyle.CUT } }, classes: ['adlib_deparent'] }), - ...eksternSisyfos, - ...config.stickyLayers - .filter(layer => eksternSisyfos.map(obj => obj.layer).indexOf(layer) === -1) - .filter(layer => config.liveAudio.indexOf(layer) === -1) - .map(layer => { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - }, - metaData: { - sisyfosPersistLevel: true - } - }) - }), - // Force server to be muted (for adlibbing over DVE) - ...settings.ServerAudioLayers.map(layer => { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 2, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - } - }) - }) + ...eksternSisyfos ]) } - }) + } settings.postProcessPieceTimelineObjects(context, config, remotePiece, false) - context.queuePart(part, [ + await context.queuePart(part, [ remotePiece, - ...(settings.SelectedAdlibs ? getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, []) : []) + ...(settings.SelectedAdlibs + ? await getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, []) + : []) ]) } -function executeActionCutSourceToBox< +async function executeActionCutSourceToBox< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1266,8 +1306,8 @@ function executeActionCutSourceToBox< ) { const config = settings.getConfig(context) - const currentPieces = context.getPieceInstances('current') - const nextPieces = context.getPieceInstances('next') + const currentPieces: IBlueprintPieceInstance[] = await context.getPieceInstances('current') + const nextPieces: IBlueprintPieceInstance[] = await context.getPieceInstances('next') const currentDVE = currentPieces.find( p => @@ -1287,21 +1327,20 @@ function executeActionCutSourceToBox< ) let modify: undefined | 'current' | 'next' - let modifiedPiece: IBlueprintPieceInstance | undefined + let modifiedPiece: IBlueprintPieceInstance | undefined let modifiedDataStore: IBlueprintPieceInstance | undefined - if (currentDVE) { + if (currentDVE && !currentDVE.stoppedPlayback) { modify = 'current' - modifiedPiece = currentDVE + modifiedPiece = currentDVE as IBlueprintPieceInstance modifiedDataStore = currentDataStore } else if (nextDVE) { modify = 'next' - modifiedPiece = nextDVE + modifiedPiece = nextDVE as IBlueprintPieceInstance modifiedDataStore = nextDataStore } - const meta: (DVEPieceMetaData & PieceMetaData) | undefined = modifiedPiece?.piece.metaData as PieceMetaData & - DVEPieceMetaData + const meta = modifiedPiece?.piece.metaData if ( !modifiedPiece || @@ -1313,12 +1352,13 @@ function executeActionCutSourceToBox< return } - const containsServerBefore = dveContainsServer(meta.sources) + meta.sisyfosPersistMetaData = { + sisyfosLayers: [] + } - // ADD 'VO' to VO sources - const name = `${userData.name}${userData.vo && !userData.name.match(/VO/i) ? 'VO' : ''}` + const containsServerBefore = dveContainsServer(meta.sources) - meta.sources[`INP${userData.box + 1}` as keyof DVEPieceMetaData['sources']] = name + meta.sources[`INP${userData.box + 1}` as keyof DVEPieceMetaData['sources']] = userData.sourceDefinition const containsServerAfter = dveContainsServer(meta.sources) @@ -1339,25 +1379,20 @@ function executeActionCutSourceToBox< settings.DVEGeneratorOptions, undefined, undefined, - undefined, mediaPlayerSession ) - if (userData.vo) { - const studioMics = GetSisyfosTimelineObjForCamera(context, config, 'evs', settings.LLayer.Sisyfos.StudioMics) - // Replace any existing instances of studio mics with VO values - newPieceContent.content.timelineObjects = newPieceContent.content.timelineObjects.filter( - obj => studioMics.layer !== obj.layer - ) - newPieceContent.content.timelineObjects.push(studioMics) - } - let newDVEPiece: IBlueprintPiece = { ...modifiedPiece.piece, content: newPieceContent.content, metaData: meta } - if (!(containsServerBefore && containsServerAfter)) { - newDVEPiece = cutServerToBox(context, settings, newDVEPiece) + let newDVEPiece: IBlueprintPiece = { + ...modifiedPiece.piece, + content: newPieceContent.content, + metaData: meta + } + if (!containsServerBefore || !containsServerAfter) { + newDVEPiece = await cutServerToBox(context, settings, newDVEPiece, !!containsServerBefore, modify === 'current') } if (newPieceContent.valid) { - startNewDVELayout( + await startNewDVELayout( context, config, settings, @@ -1375,10 +1410,10 @@ function executeActionCutSourceToBox< } interface PiecesBySourceLayer { - [key: string]: IBlueprintPieceInstance[] + [key: string]: Array> } -function groupPiecesBySourceLayer(pieceInstances: IBlueprintPieceInstance[]): PiecesBySourceLayer { +function groupPiecesBySourceLayer(pieceInstances: Array>): PiecesBySourceLayer { const piecesBySourceLayer: PiecesBySourceLayer = {} pieceInstances.forEach(piece => { if (!piecesBySourceLayer[piece.piece.sourceLayerId]) { @@ -1412,20 +1447,19 @@ function findPrimaryPieceUsingPriority< return undefined } -function applyPrerollToWallGraphics< +async function applyPrerollToWallGraphics< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, settings: ActionExecutionSettings, - piecesBySourceLayer: PiecesBySourceLayer, - partProps: Partial + piecesBySourceLayer: PiecesBySourceLayer ) { const wallPieces = piecesBySourceLayer[settings.SourceLayers.Wall] if (!wallPieces) { return } - const enable = GetEnableForWall(partProps) + const enable = GetEnableForWall() for (const pieceInstance of wallPieces) { if (pieceInstance.piece.content?.timelineObjects && !pieceInstance.infinite?.fromPreviousPart) { const newPieceProps = { @@ -1433,19 +1467,19 @@ function applyPrerollToWallGraphics< } const timelineObjectsToUpdate = newPieceProps.content.timelineObjects.filter( timelineObject => - timelineObject.layer === GraphicLLayer.GraphicLLayerWall && + timelineObject.layer === SharedGraphicLLayer.GraphicLLayerWall && (timelineObject.content.deviceType === TSR.DeviceType.VIZMSE || timelineObject.content.deviceType === TSR.DeviceType.CASPARCG) ) timelineObjectsToUpdate.forEach(timelineObject => { timelineObject.enable = enable }) - context.updatePieceInstance(pieceInstance._id, newPieceProps) + await context.updatePieceInstance(pieceInstance._id, newPieceProps) } } } -function executeActionTakeWithTransition< +async function executeActionTakeWithTransition< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1456,12 +1490,12 @@ function executeActionTakeWithTransition< ) { const externalId = generateExternalId(context, actionId, [userData.variant.type]) - const nextPieces = context.getPieceInstances('next') + const nextPieces = await context.getPieceInstances('next') const nextPiecesBySourceLayer = groupPiecesBySourceLayer(nextPieces) const primaryPiece = findPrimaryPieceUsingPriority(settings, nextPiecesBySourceLayer) - context.takeAfterExecuteAction(userData.takeNow) + await context.takeAfterExecuteAction(userData.takeNow) if ( !primaryPiece || @@ -1471,26 +1505,28 @@ function executeActionTakeWithTransition< return } - const tlObjIndex = (primaryPiece.piece.content.timelineObjects as TSR.TSRTimelineObj[]).findIndex( + const timelineObjectIndex = (primaryPiece.piece.content.timelineObjects as TSR.TSRTimelineObj[]).findIndex( obj => obj.layer === (settings.LLayer.Atem.cutOnclean ? settings.LLayer.Atem.MEClean : settings.LLayer.Atem.MEProgram) && obj.content.deviceType === TSR.DeviceType.ATEM && obj.content.type === TSR.TimelineContentTypeAtem.ME ) - const tlObj = - tlObjIndex > -1 - ? ((primaryPiece.piece.content.timelineObjects as TSR.TSRTimelineObj[])[tlObjIndex] as TSR.TimelineObjAtemME) + const timelineObject = + timelineObjectIndex > -1 + ? ((primaryPiece.piece.content.timelineObjects as TSR.TSRTimelineObj[])[ + timelineObjectIndex + ] as TSR.TimelineObjAtemME) : undefined - if (!tlObj) { + if (!timelineObject) { return } const existingEffektPiece = nextPieces.find(p => p.piece.sourceLayerId === settings.SourceLayers.Effekt) if (existingEffektPiece) { - context.removePieceInstances('next', [existingEffektPiece._id]) + await context.removePieceInstances('next', [existingEffektPiece._id]) } let partProps: Partial | false = false @@ -1498,13 +1534,13 @@ function executeActionTakeWithTransition< switch (userData.variant.type) { case 'cut': { - tlObj.content.me.transition = TSR.AtemTransitionStyle.CUT + timelineObject.content.me.transition = TSR.AtemTransitionStyle.CUT - primaryPiece.piece.content.timelineObjects[tlObjIndex] = tlObj + primaryPiece.piece.content.timelineObjects[timelineObjectIndex] = timelineObject - context.updatePieceInstance(primaryPiece._id, primaryPiece.piece) + await context.updatePieceInstance(primaryPiece._id, primaryPiece.piece) - const cutTransitionPiece: IBlueprintPiece = { + const cutTransitionPiece: IBlueprintPiece = { enable: { start: 0, duration: 1000 @@ -1522,24 +1558,22 @@ function executeActionTakeWithTransition< } partProps = { - transitionKeepaliveDuration: undefined, - transitionDuration: undefined, - transitionPrerollDuration: undefined + inTransition: undefined } - context.insertPiece('next', cutTransitionPiece) - context.updatePartInstance('next', partProps) + await context.insertPiece('next', cutTransitionPiece) + await context.updatePartInstance('next', partProps) } break case 'breaker': { - tlObj.content.me.transition = TSR.AtemTransitionStyle.CUT + timelineObject.content.me.transition = TSR.AtemTransitionStyle.CUT - primaryPiece.piece.content.timelineObjects[tlObjIndex] = tlObj + primaryPiece.piece.content.timelineObjects[timelineObjectIndex] = timelineObject - context.updatePieceInstance(primaryPiece._id, primaryPiece.piece) + await context.updatePieceInstance(primaryPiece._id, primaryPiece.piece) const config = settings.getConfig(context) - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] partProps = CreateEffektForPartInner( context, config, @@ -1555,55 +1589,89 @@ function executeActionTakeWithTransition< ) if (partProps) { - context.updatePartInstance('next', partProps) + await context.updatePartInstance('next', partProps) pieces.forEach(p => context.insertPiece('next', { ...p, tags: [GetTagForTransition(userData.variant)] })) } break } case 'mix': { - tlObj.content.me.transition = TSR.AtemTransitionStyle.MIX - tlObj.content.me.transitionSettings = { - ...tlObj.content.me.transitionSettings, - mix: { - rate: userData.variant.frames - } - } - - primaryPiece.piece.content.timelineObjects[tlObjIndex] = tlObj + await updateTimelineObjectMeTransition( + context, + timelineObject, + TSR.AtemTransitionStyle.MIX, + MixTransitionSettings(userData.variant.frames), + primaryPiece, + timelineObjectIndex + ) - context.updatePieceInstance(primaryPiece._id, primaryPiece.piece) + const blueprintPiece = CreateMixTransitionBlueprintPieceForPart( + externalId, + userData.variant.frames, + settings.SourceLayers.Effekt + ) - const pieces: IBlueprintPiece[] = [] - partProps = CreateMixForPartInner(pieces, externalId, userData.variant.frames, { - sourceLayer: settings.SourceLayers.Effekt, - casparLayer: settings.LLayer.Caspar.Effekt, - sisyfosLayer: settings.LLayer.Sisyfos.Effekt - }) + partProps = CreateInTransitionForAtemTransitionStyle(userData.variant.frames) + await context.updatePartInstance('next', partProps) + await context.insertPiece('next', { ...blueprintPiece, tags: [GetTagForTransition(userData.variant)] }) - context.updatePartInstance('next', partProps) - pieces.forEach(p => context.insertPiece('next', { ...p, tags: [GetTagForTransition(userData.variant)] })) + break + } + case 'dip': { + const config = settings.getConfig(context) + await updateTimelineObjectMeTransition( + context, + timelineObject, + TSR.AtemTransitionStyle.DIP, + DipTransitionSettings(config, userData.variant.frames), + primaryPiece, + timelineObjectIndex + ) + const blueprintPiece = CreateDipTransitionBlueprintPieceForPart( + externalId, + userData.variant.frames, + settings.SourceLayers.Effekt + ) + partProps = CreateInTransitionForAtemTransitionStyle(userData.variant.frames) + await context.updatePartInstance('next', partProps) + await context.insertPiece('next', { ...blueprintPiece, tags: [GetTagForTransition(userData.variant)] }) break } } if (partProps) { - applyPrerollToWallGraphics(context, settings, nextPiecesBySourceLayer, partProps) + await applyPrerollToWallGraphics(context, settings, nextPiecesBySourceLayer) } } -function findPieceToRecoverDataFrom( +async function updateTimelineObjectMeTransition( + context: ITV2ActionExecutionContext, + timelineObject: TSR.TimelineObjAtemME, + transitionStyle: TSR.AtemTransitionStyle, + transitionSettings: TSR.AtemTransitionSettings, + pieceInstance: IBlueprintPieceInstance, + indexOfTimelineObject: number +): Promise { + timelineObject.content.me.transition = transitionStyle + timelineObject.content.me.transitionSettings = transitionSettings + + pieceInstance.piece.content.timelineObjects[indexOfTimelineObject] = timelineObject + await context.updatePieceInstance(pieceInstance._id, pieceInstance.piece) +} + +async function findPieceToRecoverDataFrom( context: ITV2ActionExecutionContext, dataStoreLayers: string[] -): { piece: IBlueprintPieceInstance; part: 'current' | 'next' } | undefined { - const currentPieces = context.getPieceInstances('current') - const nextPieces = context.getPieceInstances('next') +): Promise<{ piece: IBlueprintPieceInstance; part: 'current' | 'next' } | undefined> { + const pieces = await Promise.all([context.getPieceInstances('current'), context.getPieceInstances('next')]) + const currentPieces = pieces[0] + const nextPieces = pieces[1] const currentServer = currentPieces.find(p => dataStoreLayers.includes(p.piece.sourceLayerId)) const nextServer = nextPieces.find(p => dataStoreLayers.includes(p.piece.sourceLayerId)) - let pieceToRecoverDataFrom: IBlueprintPieceInstance | undefined + let pieceToRecoverDataFrom: IBlueprintPieceInstance | undefined let part: 'current' | 'next' = 'current' @@ -1611,7 +1679,6 @@ function findPieceToRecoverDataFrom( part = 'next' pieceToRecoverDataFrom = nextServer } else if (currentServer) { - part = 'current' pieceToRecoverDataFrom = currentServer } @@ -1625,26 +1692,24 @@ function findPieceToRecoverDataFrom( } } -function findDataStore( +async function findDataStore( context: ITV2ActionExecutionContext, dataStoreLayers: string[] -): T | undefined { - const dataStorePiece = findPieceToRecoverDataFrom(context, dataStoreLayers) +): Promise { + const dataStorePiece = await findPieceToRecoverDataFrom(context, dataStoreLayers) if (!dataStorePiece) { return } - const data = (dataStorePiece.piece.piece.metaData as any)?.userData as T | undefined - - return data + return (dataStorePiece.piece.piece.metaData as any)?.userData as T | undefined } -function findMediaPlayerSessions( +async function findMediaPlayerSessions( context: ITV2ActionExecutionContext, sessionLayers: string[] -): { session: string | undefined; part: 'current' | 'next' | undefined } { - const mediaPlayerSessionPiece = findPieceToRecoverDataFrom(context, sessionLayers) +): Promise<{ session: string | undefined; part: 'current' | 'next' | undefined }> { + const mediaPlayerSessionPiece = await findPieceToRecoverDataFrom(context, sessionLayers) if (!mediaPlayerSessionPiece) { return { @@ -1653,7 +1718,7 @@ function findMediaPlayerSessions( } } - const sessions = (mediaPlayerSessionPiece.piece.piece.metaData as any)?.mediaPlayerSessions + const sessions = mediaPlayerSessionPiece.piece.piece.metaData?.mediaPlayerSessions return { // Assume there will be only one session @@ -1662,7 +1727,7 @@ function findMediaPlayerSessions( } } -function executeActionCommentatorSelectServer< +async function executeActionCommentatorSelectServer< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1671,12 +1736,7 @@ function executeActionCommentatorSelectServer< _actionId: string, _userData: ActionCommentatorSelectServer ) { - const data = findDataStore(context, [ - settings.SelectedAdlibs.SourceLayer.Server, - settings.SelectedAdlibs.SourceLayer.VO - ]) - - const sessions = findMediaPlayerSessions(context, [ + const data = await findDataStore(context, [ settings.SelectedAdlibs.SourceLayer.Server, settings.SelectedAdlibs.SourceLayer.VO ]) @@ -1685,15 +1745,27 @@ function executeActionCommentatorSelectServer< return } + const sessions = await findMediaPlayerSessions(context, [ + settings.SelectedAdlibs.SourceLayer.Server, + settings.SelectedAdlibs.SourceLayer.VO + ]) + let session: string | undefined if (sessions.session && sessions.part && sessions.part === 'current') { session = sessions.session } - executeActionSelectServerClip(context, settings, AdlibActionType.SELECT_SERVER_CLIP, data, session) + await executeActionSelectServerClip( + context, + settings, + AdlibActionType.SELECT_SERVER_CLIP, + data, + ServerSelectMode.RESET, + session + ) } -function executeActionCommentatorSelectDVE< +async function executeActionCommentatorSelectDVE< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1706,16 +1778,16 @@ function executeActionCommentatorSelectDVE< return } - const data = findDataStore(context, [settings.SelectedAdlibs.SourceLayer.DVE]) + const data = await findDataStore(context, [settings.SelectedAdlibs.SourceLayer.DVE]) if (!data) { return } - executeActionSelectDVE(context, settings, AdlibActionType.SELECT_DVE, data) + await executeActionSelectDVE(context, settings, AdlibActionType.SELECT_DVE, data) } -function executeActionCommentatorSelectFull< +async function executeActionCommentatorSelectFull< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1724,16 +1796,16 @@ function executeActionCommentatorSelectFull< _actionId: string, _userData: ActionCommentatorSelectFull ) { - const data = findDataStore(context, [SharedSourceLayers.SelectedAdlibGraphicsFull]) + const data = await findDataStore(context, [SharedSourceLayers.SelectedAdlibGraphicsFull]) if (!data) { return } - executeActionSelectFull(context, settings, AdlibActionType.SELECT_FULL_GRAFIK, data) + await executeActionSelectFull(context, settings, AdlibActionType.SELECT_FULL_GRAFIK, data) } -function executeActionCommentatorSelectJingle< +async function executeActionCommentatorSelectJingle< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1746,16 +1818,16 @@ function executeActionCommentatorSelectJingle< return } - const data = findDataStore(context, [settings.SelectedAdlibs.SourceLayer.Effekt]) + const data = await findDataStore(context, [settings.SelectedAdlibs.SourceLayer.Effekt]) if (!data) { return } - executeActionSelectJingle(context, settings, AdlibActionType.SELECT_JINGLE, data) + await executeActionSelectJingle(context, settings, AdlibActionType.SELECT_JINGLE, data) } -function executeActionRecallLastLive< +async function executeActionRecallLastLive< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1764,11 +1836,7 @@ function executeActionRecallLastLive< actionId: string, _userData: ActionRecallLastLive ) { - const lastLive = context.findLastPieceOnLayer(settings.SourceLayers.Live, { - originalOnly: true, - excludeCurrentPart: false - }) - const lastIdent = context.findLastPieceOnLayer(settings.SourceLayers.Ident, { + const lastLive = await context.findLastPieceOnLayer(settings.SourceLayers.Live, { originalOnly: true, excludeCurrentPart: false }) @@ -1777,14 +1845,22 @@ function executeActionRecallLastLive< return } + const lastIdent = await context.findLastPieceOnLayer(settings.SourceLayers.Ident, { + originalOnly: true, + excludeCurrentPart: false, + pieceMetaDataFilter: { + belongsToRemotePart: true + } + }) + const externalId = generateExternalId(context, actionId, [lastLive.piece.name]) - const part = literal({ + const part: IBlueprintPart = { externalId, title: lastLive.piece.name - }) + } - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] pieces.push({ ...lastLive.piece, externalId, @@ -1794,20 +1870,18 @@ function executeActionRecallLastLive< lifespan: PieceLifespan.WithinPart }) - // externalId should be replaced with something more concrete like partInstanceId - if (lastIdent && lastIdent.piece.externalId === lastLive.piece.externalId) { + if (lastIdent) { pieces.push({ ...lastIdent.piece, externalId, - enable: { ...lastIdent.piece.enable, start: 0 }, lifespan: PieceLifespan.WithinPart }) } - context.queuePart(part, pieces) + await context.queuePart(part, pieces) } -function executeActionRecallLastDVE< +async function executeActionRecallLastDVE< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1822,55 +1896,97 @@ function executeActionRecallLastDVE< return } - const lastPlayedScheduledDVE: IBlueprintPieceInstance | undefined = context.findLastPieceOnLayer( - settings.SourceLayers.DVE, - { - originalOnly: true - } - ) + const lastPlayedScheduledDVE = (await context.findLastPieceOnLayer(settings.SourceLayers.DVE, { + originalOnly: true + })) as IBlueprintPieceInstance | undefined const isLastPlayedAScheduledDVE: boolean = !lastPlayedScheduledDVE?.dynamicallyInserted if (lastPlayedScheduledDVE && isLastPlayedAScheduledDVE) { - scheduleLastPlayedDVE(context, settings, actionId, lastPlayedScheduledDVE) + await scheduleLastPlayedDVE(context, settings, actionId, lastPlayedScheduledDVE) } else { - scheduleNextScriptedDVE(context, settings, actionId) + await scheduleNextScriptedDVE(context, settings, actionId) } } -function scheduleLastPlayedDVE< +async function executeActionFadeDownPersistedAudioLevels< + StudioConfig extends TV2StudioConfigBase, + ShowStyleConfig extends TV2BlueprintConfigBase +>(context: ITV2ActionExecutionContext, _settings: ActionExecutionSettings) { + const fadeSisyfosMetaData = await createFadeSisyfosLevelsMetaData(context) + const resetSisyfosPersistedLevelsPiece: IBlueprintPiece = { + externalId: 'fadeSisyfosPersistedLevelsDown', + name: FADE_SISYFOS_LEVELS_PIECE_NAME, + outputLayerId: '', + sourceLayerId: '', + enable: { start: 'now' }, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: fadeSisyfosMetaData + }, + content: { + timelineObjects: [] + } + } + context.insertPiece('current', resetSisyfosPersistedLevelsPiece) +} + +async function createFadeSisyfosLevelsMetaData(context: ITV2ActionExecutionContext) { + const resolvedPieceInstances = await context.getResolvedPieceInstances('current') + const emptySisyfosMetaData: SisyfosPersistMetaData = { + sisyfosLayers: [] + } + if (resolvedPieceInstances.length === 0) { + return emptySisyfosMetaData + } + + const latestPiece = resolvedPieceInstances + .filter(piece => piece.piece.name !== FADE_SISYFOS_LEVELS_PIECE_NAME) + .sort((a, b) => b.resolvedStart - a.resolvedStart)[0] + + const latestPieceMetaData = latestPiece.piece.metaData + + if (!latestPieceMetaData || !latestPieceMetaData.sisyfosPersistMetaData) { + return emptySisyfosMetaData + } + + return { + sisyfosLayers: latestPieceMetaData.sisyfosPersistMetaData.sisyfosLayers, + wantsToPersistAudio: latestPieceMetaData.sisyfosPersistMetaData.wantsToPersistAudio, + acceptPersistAudio: false + } +} + +async function scheduleLastPlayedDVE< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, settings: ActionExecutionSettings, actionId: string, - lastPlayedDVE: IBlueprintPieceInstance -): void { - const lastPlayedDVEMeta: DVEPieceMetaData = lastPlayedDVE.piece.metaData as DVEPieceMetaData + lastPlayedDVE: IBlueprintPieceInstance +): Promise { + const lastPlayedDVEMeta: DVEPieceMetaData = lastPlayedDVE.piece.metaData! const externalId: string = generateExternalId(context, actionId, [lastPlayedDVE.piece.name]) - executeActionSelectDVE( - context, - settings, - actionId, - literal({ - type: AdlibActionType.SELECT_DVE, - config: lastPlayedDVEMeta.userData.config, - segmentExternalId: externalId, - videoId: lastPlayedDVEMeta.userData.videoId - }) - ) + await executeActionSelectDVE(context, settings, actionId, { + type: AdlibActionType.SELECT_DVE, + config: lastPlayedDVEMeta.userData.config, + segmentExternalId: externalId, + videoId: lastPlayedDVEMeta.userData.videoId + }) } -function scheduleNextScriptedDVE< +async function scheduleNextScriptedDVE< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: ITV2ActionExecutionContext, settings: ActionExecutionSettings, actionId: string -): void { - const nextScriptedDVE: IBlueprintPiece | undefined = context.findLastScriptedPieceOnLayer(settings.SourceLayers.DVE) +): Promise { + const nextScriptedDVE: IBlueprintPiece | undefined = await context.findLastScriptedPieceOnLayer( + settings.SourceLayers.DVE + ) if (!nextScriptedDVE) { return @@ -1879,20 +1995,15 @@ function scheduleNextScriptedDVE< const externalId: string = generateExternalId(context, actionId, [nextScriptedDVE.name]) const dveMeta: DVEPieceMetaData = nextScriptedDVE.metaData as DVEPieceMetaData - executeActionSelectDVE( - context, - settings, - actionId, - literal({ - type: AdlibActionType.SELECT_DVE, - config: dveMeta.userData.config, - segmentExternalId: externalId, - videoId: dveMeta.userData.videoId - }) - ) + await executeActionSelectDVE(context, settings, actionId, { + type: AdlibActionType.SELECT_DVE, + config: dveMeta.userData.config, + segmentExternalId: externalId, + videoId: dveMeta.userData.videoId + }) } -function executeActionSelectFull< +async function executeActionSelectFull< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1905,26 +2016,28 @@ function executeActionSelectFull< const template = GetFullGrafikTemplateName(config, userData.name) - const externalId = `adlib-action_${context.getHashId(`cut_to_full_${template}`)}` + const hash = context.getHashId(`cut_to_full_${template}`) + const externalId = `adlib-action_${hash}` const graphicType = config.studio.GraphicsType - const prerollDuration = - graphicType === 'HTML' ? config.studio.CasparPrerollDuration : config.studio.VizPilotGraphics.OutTransitionDuration - const transitionKeepaliveDuration = + const previousPartKeepaliveDuration = graphicType === 'HTML' ? config.studio.HTMLGraphics.KeepAliveDuration : config.studio.VizPilotGraphics.KeepAliveDuration - const part = literal({ + const part: IBlueprintPart = { externalId, title: `Full ${template}`, metaData: {}, expectedDuration: 0, - prerollDuration, - transitionKeepaliveDuration - }) + inTransition: { + previousPartKeepaliveDuration, + partContentDelayDuration: 0, + blockTakeDuration: 0 + } + } - const cue = literal>({ + const cue: CueDefinitionGraphic = { type: CueType.Graphic, target: 'FULL', graphic: { @@ -1934,46 +2047,37 @@ function executeActionSelectFull< continueCount: -1 }, iNewsCommand: '' - }) + } - const fullPiece = CreateFullPiece( + const generator = new PilotGraphicGenerator({ config, context, - part, - externalId, - cue, - 'FULL', - settings.pilotGraphicSettings, - true, - userData.segmentExternalId - ) + partId: externalId, + settings: settings.pilotGraphicSettings, + parsedCue: cue, + engine: 'FULL', + segmentExternalId: userData.segmentExternalId, + adlib: { rank: 0 } + }) + + const fullPiece = generator.createPiece() settings.postProcessPieceTimelineObjects(context, config, fullPiece, false) - const fullDataStore = CreateFullDataStore( - config, - context, - part, - settings.pilotGraphicSettings, - cue, - 'FULL', - externalId, - true, - userData.segmentExternalId - ) + const fullDataStore = generator.createFullDataStore() - context.queuePart(part, [ + await context.queuePart(part, [ fullPiece, - ...(fullDataStore ? [fullDataStore] : []), - ...getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, [ + fullDataStore, + ...(await getPiecesToPreserve(context, settings.SelectedAdlibs.SELECTED_ADLIB_LAYERS, [ SharedSourceLayers.SelectedAdlibGraphicsFull - ]) + ])) ]) - context.stopPiecesOnLayers([SharedSourceLayers.SelectedAdlibGraphicsFull]) + await context.stopPiecesOnLayers([SharedSourceLayers.SelectedAdlibGraphicsFull]) } -function executeActionClearGraphics< +async function executeActionClearGraphics< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( @@ -1984,54 +2088,52 @@ function executeActionClearGraphics< ) { const config = settings.getConfig(context) - context.stopPiecesOnLayers(STOPPABLE_GRAPHICS_LAYERS) - context.insertPiece( - 'current', - literal({ - enable: { - start: 'now', - duration: 3000 - }, - externalId: 'clearAllGFX', - name: userData.label, - sourceLayerId: SharedSourceLayers.PgmAdlibGraphicCmd, - outputLayerId: SharedOutputLayers.SEC, - lifespan: PieceLifespan.WithinPart, - content: - config.studio.GraphicsType === 'HTML' - ? { - timelineObjects: [ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: GraphicLLayer.GraphicLLayerAdLibs, - content: { - deviceType: TSR.DeviceType.ABSTRACT - } - }) - ] - } - : { - timelineObjects: [ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 100, - layer: GraphicLLayer.GraphicLLayerAdLibs, - content: { - deviceType: TSR.DeviceType.VIZMSE, - type: TSR.TimelineContentTypeVizMSE.CLEAR_ALL_ELEMENTS, - channelsToSendCommands: userData.sendCommands ? ['OVL1', 'FULL1', 'WALL1'] : undefined - } - }) - ] - }, - tags: userData.sendCommands ? [TallyTags.GFX_CLEAR] : [TallyTags.GFX_ALTUD] - }) - ) + await context.stopPiecesOnLayers(STOPPABLE_GRAPHICS_LAYERS) + await context.insertPiece('current', { + enable: { + start: 'now', + duration: 3000 + }, + externalId: 'clearAllGFX', + name: userData.label, + sourceLayerId: SharedSourceLayers.PgmAdlibGraphicCmd, + outputLayerId: SharedOutputLayers.SEC, + lifespan: PieceLifespan.WithinPart, + content: + config.studio.GraphicsType === 'HTML' + ? { + timelineObjects: [ + literal({ + id: '', + enable: { + start: 0 + }, + priority: 1, + layer: SharedGraphicLLayer.GraphicLLayerAdLibs, + content: { + deviceType: TSR.DeviceType.ABSTRACT + } + }) + ] + } + : { + timelineObjects: [ + literal({ + id: '', + enable: { + start: 0 + }, + priority: 100, + layer: SharedGraphicLLayer.GraphicLLayerAdLibs, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.CLEAR_ALL_ELEMENTS, + channelsToSendCommands: userData.sendCommands ? ['OVL1', 'FULL1', 'WALL1'] : undefined, + showId: config.selectedGraphicsSetup.OvlShowId + } + }) + ] + }, + tags: userData.sendCommands ? [TallyTags.GFX_CLEAR] : [TallyTags.GFX_ALTUD] + }) } diff --git a/src/tv2-common/transitionFromString.ts b/src/tv2-common/atemTransitionStyleFromString.ts similarity index 69% rename from src/tv2-common/transitionFromString.ts rename to src/tv2-common/atemTransitionStyleFromString.ts index f34bb7a04..ecc3552ec 100644 --- a/src/tv2-common/transitionFromString.ts +++ b/src/tv2-common/atemTransitionStyleFromString.ts @@ -1,6 +1,6 @@ -import { TSR } from '@sofie-automation/blueprints-integration' +import { TSR } from '@tv2media/blueprints-integration' -export function TransitionFromString(str: string): TSR.AtemTransitionStyle { +export function AtemTransitionStyleFromString(str: string): TSR.AtemTransitionStyle { if (str.match(/MIX/i)) { return TSR.AtemTransitionStyle.MIX } else if (str.match(/DIP/i)) { diff --git a/src/tv2-common/blueprintConfig.ts b/src/tv2-common/blueprintConfig.ts index 484ade861..37bfb4f45 100644 --- a/src/tv2-common/blueprintConfig.ts +++ b/src/tv2-common/blueprintConfig.ts @@ -1,9 +1,5 @@ -import { TableConfigItemValue } from '@sofie-automation/blueprints-integration' -import { - TableConfigItemDSK, - TableConfigItemSourceMappingWithSisyfos, - TableConfigItemSourceMappingWithSisyfosAndKeepAudio -} from 'tv2-common' +import { TableConfigItemValue } from '@tv2media/blueprints-integration' +import { TableConfigItemDSK, TableConfigItemSourceMappingWithSisyfos } from 'tv2-common' import { DVEConfigInput } from './helpers' import { SourceInfo } from './sources' @@ -34,6 +30,21 @@ export interface TableConfigItemAdLibTransitions { Transition: string } +export interface TableConfigSchema { + schemaName: string + designIdentifier: string + vizTemplateName: string + casparCgDveBgScene: string +} + +export interface TableConfigGraphicsSetup { + Name: string + VcpConcept: string + OvlShowId: string + FullShowId: string + DveLayoutFolder: string +} + export interface TV2StudioConfigBase { MaximumPartDuration: number DefaultPartDuration: number @@ -77,12 +88,12 @@ export interface TV2StudioConfigBase { SplitArtF: number SplitArtK: number DSK: TableConfigItemDSK[] + Dip: number } AtemSettings: {} StudioMics: string[] - SourcesRM: TableConfigItemSourceMappingWithSisyfosAndKeepAudio[] - SourcesFeed: TableConfigItemSourceMappingWithSisyfosAndKeepAudio[] - SourcesSkype: TableConfigItemSourceMappingWithSisyfos[] + SourcesRM: TableConfigItemSourceMappingWithSisyfos[] + SourcesFeed: TableConfigItemSourceMappingWithSisyfos[] SourcesCam: TableConfigItemSourceMappingWithSisyfos[] PreventOverlayWithFull?: boolean ServerPostrollDuration: number @@ -111,12 +122,17 @@ export interface TV2StudioConfigBase { } } +export interface SourceMapping { + cameras: SourceInfo[] + lives: SourceInfo[] + feeds: SourceInfo[] + replays: SourceInfo[] +} + export interface TV2StudioBlueprintConfigBase { studio: StudioConfig - sources: SourceInfo[] + sources: SourceMapping mediaPlayers: MediaPlayerConfig // Atem Input Ids - liveAudio: string[] - stickyLayers: string[] dsk: TableConfigItemDSK[] } @@ -130,11 +146,13 @@ export interface TV2ShowstyleBlueprintConfigBase { ShowstyleTransition: string MakeAdlibsForFulls: boolean LYDConfig: TableConfigItemValue + SchemaConfig: TableConfigSchema[] } export interface TV2BlueprintConfigBase extends TV2StudioBlueprintConfigBase { showStyle: TV2ShowstyleBlueprintConfigBase + selectedGraphicsSetup: TableConfigGraphicsSetup } export type TV2BlueprintConfig = TV2BlueprintConfigBase diff --git a/src/tv2-common/content/dve.ts b/src/tv2-common/content/dve.ts index 7952d698f..23795d3a8 100644 --- a/src/tv2-common/content/dve.ts +++ b/src/tv2-common/content/dve.ts @@ -2,7 +2,6 @@ import { CameraContent, GraphicsContent, IShowStyleUserContext, - IStudioUserContext, RemoteContent, SourceLayerType, SplitsContent, @@ -10,7 +9,7 @@ import { TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { createEmptyObject, CueDefinitionDVE, @@ -18,23 +17,27 @@ import { DVEParentClass, DVESources, FindDSKFullGFX, - FindSourceInfoStrict, - GetSisyfosTimelineObjForCamera, - GetSisyfosTimelineObjForEVS, + findSourceInfo, JoinAssetToFolder, literal, PartDefinition, - SourceInfo, - SourceInfoType, + PieceMetaData, TimelineBlueprintExt, TV2BlueprintConfigBase, TV2StudioConfigBase } from 'tv2-common' -import { ControlClasses, GraphicLLayer, MEDIA_PLAYER_AUTO } from 'tv2-constants' +import { ControlClasses, MEDIA_PLAYER_AUTO, SharedGraphicLLayer, SourceType } from 'tv2-constants' import * as _ from 'underscore' import { AtemSourceIndex } from '../../types/atem' import { ActionSelectDVE } from '../actions' -import { CreateHTMLRendererContent } from '../helpers' +import { + CreateHTMLRendererContent, + GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForFull, + GetSisyfosTimelineObjForRemote, + GetSisyfosTimelineObjForReplay +} from '../helpers' +import { SourceDefinition } from '../inewsConversion' import { EnableServer } from './server' export interface DVEConfigBox { @@ -94,7 +97,6 @@ export interface DVELayers { SisyfosLLayer: { ClipPending: string StudioMics: string - PersistedLevels: string } CasparLLayer: { ClipPending: string @@ -105,40 +107,24 @@ export interface DVEMetaData { mediaPlayerSession?: string } -export interface DVEPieceMetaData { +export interface DVEPieceMetaData extends PieceMetaData { config: DVEConfigInput sources: DVESources userData: ActionSelectDVE mediaPlayerSessions?: string[] // TODO: Should probably move to a ServerPieceMetaData -} - -export interface DVETimelineObjectGenerators { - GetSisyfosTimelineObjForEkstern: ( - context: IStudioUserContext, - sources: SourceInfo[], - sourceType: string, - getLayersForEkstern: (context: IStudioUserContext, sources: SourceInfo[], sourceType: string) => string[], - enable?: TSR.Timeline.TimelineEnable - ) => TSR.TSRTimelineObj[] - GetLayersForEkstern: (context: IStudioUserContext, sources: SourceInfo[], sourceType: string) => string[] + serverPlaybackTiming?: Array<{ start?: number; end?: number }> } export interface DVEOptions { dveLayers: DVELayers - dveTimelineGenerators: DVETimelineObjectGenerators boxMappings: [string, string, string, string] - boxLayers: { - INP1: string - INP2: string - INP3: string - INP4: string - } /** All audio layers */ AUDIO_LAYERS: string[] - /** Layers to exclude from filter */ - EXCLUDED_LAYERS: string[] } +type BoxConfig = DVEConfigBox & { source: number } +type BoxSources = Array<(VTContent | CameraContent | RemoteContent | GraphicsContent) & SplitsContentBoxProperties> + export function MakeContentDVEBase< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase @@ -151,7 +137,7 @@ export function MakeContentDVEBase< dveGeneratorOptions: DVEOptions, addClass?: boolean, adlib?: boolean -): { content: WithTimeline; valid: boolean; stickyLayers: string[] } { +): { content: WithTimeline; valid: boolean } { if (!dveConfig) { context.notifyUserWarning(`DVE ${parsedCue.template} is not configured`) return { @@ -159,15 +145,10 @@ export function MakeContentDVEBase< content: { boxSourceConfiguration: [], timelineObjects: [] - }, - stickyLayers: [] + } } } - // console.log('boxmap1', boxMap) - // boxMap = boxMap.filter(map => map !== '') - // console.log('boxmap2', boxMap) - const graphicsTemplateContent: { [key: string]: string } = {} parsedCue.labels.forEach((label, i) => { graphicsTemplateContent[`${i}`] = label @@ -182,7 +163,6 @@ export function MakeContentDVEBase< dveGeneratorOptions, addClass ? DVEParentClass('studio0', dveConfig.DVEName) : undefined, adlib, - partDefinition.fields.videoId, partDefinition.segmentExternalId ) } @@ -199,9 +179,8 @@ export function MakeContentDVE2< dveGeneratorOptions: DVEOptions, className?: string, adlib?: boolean, - videoId?: string, mediaPlayerSessionId?: string -): { content: WithTimeline; valid: boolean; stickyLayers: string[] } { +): { content: WithTimeline; valid: boolean } { let template: DVEConfig try { template = JSON.parse(dveConfig.DVEJSON) as DVEConfig @@ -212,234 +191,104 @@ export function MakeContentDVE2< content: { boxSourceConfiguration: [], timelineObjects: [] - }, - stickyLayers: [] + } } } const inputs = dveConfig.DVEInputs ? dveConfig.DVEInputs.toString().split(';') : '1:INP1;2:INP2;3:INP3;4:INP4'.split(';') - const boxMap: Array<{ source: string; sourceLayer: string }> = [] const classes: string[] = [] - inputs.forEach(source => { - const sourceProps = source.split(':') - const fromCue = sourceProps[1] - const targetBox = Number(sourceProps[0]) - if (!fromCue || !targetBox || isNaN(targetBox)) { - context.notifyUserWarning(`Invalid DVE mapping: ${sourceProps}`) - return - } - - const sourceLayer = dveGeneratorOptions.boxLayers[fromCue as keyof DVESources] as string - classes.push(`${sourceLayer}_${dveGeneratorOptions.boxMappings[targetBox - 1]}`) - - let usedServer = false - - if (sources) { - const prop = sources[fromCue as keyof DVESources] - if (prop?.match(/[K|C]AM(?:era)? ?.*/i)) { - const match = prop.match(/[K|C]AM(?:era)? ?(.*)/i) as RegExpExecArray - - boxMap[targetBox - 1] = { source: `KAM ${match[1]}`, sourceLayer } - } else if (prop?.match(/LIVE ?.*/i)) { - const match = prop.match(/LIVE ?(.*)/i) as RegExpExecArray - - boxMap[targetBox - 1] = { source: `LIVE ${match[1]}`, sourceLayer } - } else if (prop?.match(/FEED ?.*/i)) { - const match = prop.match(/FEED ?(.*)/i) as RegExpExecArray - - boxMap[targetBox - 1] = { source: `FEED ${match[1]}`, sourceLayer } - } else if (prop?.match(/full/i)) { - boxMap[targetBox - 1] = { source: `ENGINE FULL`, sourceLayer } - } else if (prop?.match(/EVS ?(?:\d+)? ?.*/i)) { - const match = prop.match(/EVS ?(\d+)? ?(.*)/i) as RegExpExecArray - - boxMap[targetBox - 1] = { source: `EVS${match[1]} ${match[2]}`, sourceLayer } - } else if (prop?.match(/DEFAULT/)) { - boxMap[targetBox - 1] = { source: `DEFAULT SOURCE`, sourceLayer } - } else if (prop) { - if (videoId && !usedServer) { - boxMap[targetBox - 1] = { source: `SERVER ${videoId}`, sourceLayer } - usedServer = true - } else { - boxMap[targetBox - 1] = { source: prop, sourceLayer } - } - } else { - if (videoId && !usedServer) { - boxMap[targetBox - 1] = { source: `SERVER ${videoId}`, sourceLayer } - usedServer = true - } else { - context.notifyUserWarning(`Missing mapping for ${targetBox}`) - boxMap[targetBox - 1] = { source: '', sourceLayer } - } - } - } else { - // Need something to keep the layout etc - boxMap[targetBox - 1] = { source: '', sourceLayer } - } - }) + const boxAssigments = makeBoxAssignments(inputs, context, classes, dveGeneratorOptions, sources) - const boxes = _.map(template.boxes, box => ({ ...box, source: config.studio.AtemSource.Default })) + const boxes: BoxConfig[] = Object.entries(template.boxes).map(([_num, box]) => ({ + ...box, + source: config.studio.AtemSource.Default + })) const dveTimeline: TSR.TSRTimelineObj[] = [] - const boxSources: Array<(VTContent | CameraContent | RemoteContent | GraphicsContent) & - SplitsContentBoxProperties> = [] - - const setBoxSource = (num: number, sourceInfo: SourceInfo, label: string) => { - if (boxes[num]) { - boxes[num].source = Number(sourceInfo.port) - - boxSources.push({ - // TODO - draw box geometry - ...boxSource(sourceInfo, label), - ...literal({ - studioLabel: '', - switcherInput: Number(sourceInfo.port) - }) - }) - } - } - - const setBoxToBlack = (num: number) => { - setBoxSource( - num, - literal({ - type: SourceLayerType.UNKNOWN, - id: 'black', - port: AtemSourceIndex.Blk - }), - 'Black' - ) - } + const boxSources: BoxSources = [] let valid = true let server = false - boxMap.forEach((mappingFrom, num) => { - if (mappingFrom === undefined || mappingFrom.source === '') { + boxAssigments.forEach((mappingFrom, num) => { + const box = boxes[num] + if (mappingFrom === undefined) { if (sources) { // If it is intentional there are no sources, then ignore // TODO - should this warn? context.notifyUserWarning(`Missing source type for DVE box: ${num + 1}`) + setBoxToBlack(box, boxSources) valid = false } } else { - const props = mappingFrom.source.split(' ') - const sourceType = props[0] - const sourceInput = props[1] - if ((!sourceType || !sourceInput) && !mappingFrom.source.match(/EVS/i) && !mappingFrom.source.match(/SERVER/)) { - context.notifyUserWarning(`Invalid DVE source: ${mappingFrom.source}`) - setBoxToBlack(num) - return - } const audioEnable: TSR.Timeline.TimelineEnable = { while: `1` } - if (sourceType.match(/DEFAULT/)) { - setBoxSource( - num, - { - type: SourceLayerType.UNKNOWN, - id: 'DEFAULT', + switch (mappingFrom.sourceType) { + case SourceType.DEFAULT: + setBoxSource(box, boxSources, { + sourceLayerType: SourceLayerType.UNKNOWN, port: config.studio.AtemSource.Default - }, - mappingFrom.source - ) - } else if (sourceType.match(/KAM/i)) { - const sourceInfoCam = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, mappingFrom.source) - if (sourceInfoCam === undefined) { - context.notifyUserWarning(`Invalid source: ${mappingFrom.source}`) - setBoxToBlack(num) - valid = false - return - } - - setBoxSource(num, sourceInfoCam, mappingFrom.source) - dveTimeline.push( - GetSisyfosTimelineObjForCamera( - context, - config, - mappingFrom.source, - dveGeneratorOptions.dveLayers.SisyfosLLayer.StudioMics, - audioEnable - ) - ) - } else if (sourceType.match(/LIVE/i) || sourceType.match(/FEED/i) || sourceType.match(/SKYPE/i)) { - const sourceInfoLive = FindSourceInfoStrict(context, config.sources, SourceLayerType.REMOTE, mappingFrom.source) - if (sourceInfoLive === undefined) { - context.notifyUserWarning(`Invalid source: ${mappingFrom.source}`) - setBoxToBlack(num) - valid = false - return - } - - setBoxSource(num, sourceInfoLive, mappingFrom.source) - dveTimeline.push( - ...dveGeneratorOptions.dveTimelineGenerators.GetSisyfosTimelineObjForEkstern( - context, - config.sources, - mappingFrom.source, - dveGeneratorOptions.dveTimelineGenerators.GetLayersForEkstern, - audioEnable - ) - ) - } else if (sourceType.match(/EVS/i)) { - const sourceInfoDelayedPlayback = FindSourceInfoStrict( - context, - config.sources, - SourceLayerType.LOCAL, - mappingFrom.source - ) - if (sourceInfoDelayedPlayback === undefined) { - context.notifyUserWarning(`Invalid source: ${mappingFrom.source}`) - setBoxToBlack(num) - valid = false - return - } - - setBoxSource(num, sourceInfoDelayedPlayback, mappingFrom.source) - dveTimeline.push( - GetSisyfosTimelineObjForEVS(sourceInfoDelayedPlayback, !!mappingFrom.source.match(/VO/i)), - GetSisyfosTimelineObjForCamera(context, config, 'evs', dveGeneratorOptions.dveLayers.SisyfosLLayer.StudioMics) - ) - } else if (sourceType.match(/ENGINE/i)) { - if (sourceInput.match(/full/i)) { - const sourceInfoFull: SourceInfo = { - type: SourceLayerType.GRAPHICS, - id: 'full', - port: FindDSKFullGFX(config).Fill + }) + break + case SourceType.KAM: + const sourceInfoCam = findSourceInfo(config.sources, mappingFrom) + if (sourceInfoCam === undefined) { + context.notifyUserWarning(`Invalid source: ${mappingFrom.raw}`) + setBoxToBlack(box, boxSources) + valid = false + return + } + + setBoxSource(box, boxSources, sourceInfoCam) + dveTimeline.push(...GetSisyfosTimelineObjForCamera(config, sourceInfoCam, mappingFrom.minusMic, audioEnable)) + break + case SourceType.REMOTE: + const sourceInfoLive = findSourceInfo(config.sources, mappingFrom) + if (sourceInfoLive === undefined) { + context.notifyUserWarning(`Invalid source: ${mappingFrom.raw}`) + setBoxToBlack(box, boxSources) + valid = false + return } - setBoxSource(num, sourceInfoFull, mappingFrom.source) - dveTimeline.push( - GetSisyfosTimelineObjForCamera( - context, - config, - 'full', - dveGeneratorOptions.dveLayers.SisyfosLLayer.StudioMics - ) - ) - } else { - context.notifyUserWarning(`Unsupported engine for DVE: ${sourceInput}`) - setBoxToBlack(num) - } - } else if (sourceType.match(/SERVER/i)) { - server = true - setBoxSource( - num, - { - type: SourceLayerType.VT, - id: 'SERVER', + + setBoxSource(box, boxSources, sourceInfoLive) + dveTimeline.push(...GetSisyfosTimelineObjForRemote(config, sourceInfoLive, audioEnable)) + break + case SourceType.REPLAY: + const sourceInfoReplay = findSourceInfo(config.sources, mappingFrom) + if (sourceInfoReplay === undefined) { + context.notifyUserWarning(`Invalid source: ${mappingFrom.raw}`) + setBoxToBlack(box, boxSources) + valid = false + return + } + + setBoxSource(box, boxSources, sourceInfoReplay) + dveTimeline.push(...GetSisyfosTimelineObjForReplay(config, sourceInfoReplay, mappingFrom.vo)) + break + case SourceType.GRAFIK: + if (mappingFrom.name === 'FULL') { + setBoxSource(box, boxSources, { + sourceLayerType: SourceLayerType.GRAPHICS, + port: FindDSKFullGFX(config).Fill + }) + dveTimeline.push(...GetSisyfosTimelineObjForFull(config)) + } else { + context.notifyUserWarning(`Unsupported engine for DVE: ${mappingFrom.name}`) + setBoxToBlack(box, boxSources) + } + break + case SourceType.SERVER: + server = true + setBoxSource(box, boxSources, { + sourceLayerType: SourceLayerType.VT, port: -1 - }, - mappingFrom.source - ) - return - } else { - context.notifyUserWarning(`Unknown source type for DVE: ${mappingFrom.source}`) - setBoxToBlack(num) - valid = false + }) + break } } }) @@ -457,46 +306,18 @@ export function MakeContentDVE2< let frameFile = dveConfig.DVEGraphicsFrame ? dveConfig.DVEGraphicsFrame.toString() : undefined if (keyFile) { - keyFile = keyFile = JoinAssetToFolder(config.studio.DVEFolder, keyFile) + keyFile = JoinAssetToFolder(config.studio.DVEFolder, keyFile) } if (frameFile) { frameFile = JoinAssetToFolder(config.studio.DVEFolder, frameFile) } - if (adlib) { - dveTimeline.push( - literal({ - id: '', - enable: getDVEEnable(), - priority: 1, - layer: dveGeneratorOptions.dveLayers.SisyfosLLayer.PersistedLevels, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNELS, - overridePriority: 1, - channels: config.stickyLayers - .filter(layer => dveTimeline.map(obj => obj.layer).indexOf(layer) === -1) - .filter(layer => config.liveAudio.indexOf(layer) === -1) - .map(layer => { - return { - mappedLayer: layer, - isPgm: 0 - } - }) - }, - metaData: { - sisyfosPersistLevel: true - } - }) - ) - } - return { valid, content: literal>({ boxSourceConfiguration: boxSources, - timelineObjects: _.compact([ + timelineObjects: _.compact([ // Setup classes for adlibs to be able to override boxes createEmptyObject({ enable: getDVEEnable(), @@ -569,7 +390,7 @@ export function MakeContentDVE2< id: '', enable: getDVEEnable(), priority: 1, - layer: GraphicLLayer.GraphicLLayerLocators, + layer: SharedGraphicLLayer.GraphicLLayerLocators, content: CreateHTMLRendererContent(config, 'locators', { ...graphicsTemplateContent, style: graphicsTemplateStyle ?? {} @@ -613,29 +434,83 @@ export function MakeContentDVE2< ...(server && mediaPlayerSessionId ? [EnableServer(mediaPlayerSessionId)] : []), ...dveTimeline ]) - }), - stickyLayers: [ - ...dveTimeline - .filter(obj => obj.content.deviceType === TSR.DeviceType.SISYFOS) - .filter(obj => dveGeneratorOptions.AUDIO_LAYERS.includes(obj.layer.toString())) - .filter(obj => !dveGeneratorOptions.EXCLUDED_LAYERS.includes(obj.layer.toString())) - .map(obj => obj.layer.toString()) - ] + }) } } -function boxSource( - info: SourceInfo, - label: string -): { - studioLabel: string +const setBoxSource = ( + boxConfig: BoxConfig, + boxSources: BoxSources, + sourceInfo: { port: number; sourceLayerType: SourceLayerType } +) => { + if (boxConfig) { + boxConfig.source = sourceInfo.port + + boxSources.push({ + // TODO - draw box geometry + ...boxSource(sourceInfo), + ...literal({ + studioLabel: '', + switcherInput: sourceInfo.port + }) + }) + } +} + +const setBoxToBlack = (boxConfig: BoxConfig, boxSources: BoxSources) => { + setBoxSource(boxConfig, boxSources, { + port: AtemSourceIndex.Blk, + sourceLayerType: SourceLayerType.UNKNOWN + }) +} + +function makeBoxAssignments( + inputs: string[], + context: IShowStyleUserContext, + classes: string[], + dveGeneratorOptions: DVEOptions, + sources: DVESources | undefined +) { + const boxAssignments: Array = [] + inputs.forEach(source => { + const sourceProps = source.split(':') + const fromCue = sourceProps[1] + const targetBox = Number(sourceProps[0]) + if (!fromCue || !targetBox || isNaN(targetBox)) { + context.notifyUserWarning(`Invalid DVE mapping: ${sourceProps}`) + return + } + + classes.push(`${fromCue.replace(/\s/g, '')}_${dveGeneratorOptions.boxMappings[targetBox - 1]}`) + + if (!sources) { + // Need something to keep the layout etc + boxAssignments[targetBox - 1] = undefined + return + } + + const prop = sources[fromCue as keyof DVESources] + if (prop) { + boxAssignments[targetBox - 1] = prop + return + } + + context.notifyUserWarning(`Missing mapping for ${targetBox}`) + boxAssignments[targetBox - 1] = undefined + }) + return boxAssignments +} + +function boxSource(info: { + port: number + sourceLayerType: SourceLayerType +}): { switcherInput: number - type: SourceInfoType + type: SourceLayerType } { return { - studioLabel: label, switcherInput: info.port, - type: info.type + type: info.sourceLayerType } } diff --git a/src/tv2-common/content/jingle.ts b/src/tv2-common/content/jingle.ts index e3d8a49f6..52eeff218 100644 --- a/src/tv2-common/content/jingle.ts +++ b/src/tv2-common/content/jingle.ts @@ -1,4 +1,4 @@ -import { TimelineObjectCoreExt, TSR, VTContent, WithTimeline } from '@sofie-automation/blueprints-integration' +import { TimelineObjectCoreExt, TSR, VTContent, WithTimeline } from '@tv2media/blueprints-integration' import { TimeFromFrames } from 'tv2-common' import { TV2BlueprintConfig, TV2BlueprintConfigBase, TV2StudioConfigBase } from '../blueprintConfig' import { EnableDSK, FindDSKJingle } from '../helpers' @@ -8,7 +8,7 @@ import { JoinAssetToFolder, JoinAssetToNetworkPath, literal } from '../util' export interface JingleLayers { Caspar: { PlayerJingle: string - PlayerJingleLookahead?: string + PlayerJinglePreload?: string } ATEM: { USKCleanEffekt?: string @@ -42,6 +42,7 @@ export function CreateJingleExpectedMedia( ignoreBlackFrames: true, ignoreFreezeFrame: true, sourceDuration: TimeFromFrames(Number(duration) - Number(alphaAtEnd)), + postrollDuration: TimeFromFrames(Number(alphaAtEnd)), timelineObjects: [] }) } @@ -63,35 +64,7 @@ export function CreateJingleContentBase< return literal>({ ...CreateJingleExpectedMedia(config, file, alphaAtStart, duration, alphaAtEnd), timelineObjects: literal([ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: layers.Caspar.PlayerJingle, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: fileName - } - }), - - ...(loadFirstFrame && layers.Caspar.PlayerJingleLookahead - ? [ - literal({ - id: '', - enable: { start: 0 }, - priority: 1, - layer: layers.Caspar.PlayerJingleLookahead, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: fileName - } - }) - ] - : []), + CreateJingleCasparTimelineObject(fileName, loadFirstFrame, layers), ...EnableDSK(config, 'JINGLE', { start: Number(config.studio.CasparPrerollDuration) }), @@ -199,3 +172,24 @@ export function CreateJingleContentBase< ]) }) } + +function CreateJingleCasparTimelineObject( + fileName: string, + loadFirstFrame: boolean, + layers: JingleLayers +): TSR.TimelineObjCCGMedia & TimelineBlueprintExt { + return { + id: '', + enable: { start: 0 }, + priority: 1, + layer: + loadFirstFrame && layers.Caspar.PlayerJinglePreload + ? layers.Caspar.PlayerJinglePreload + : layers.Caspar.PlayerJingle, + content: { + deviceType: TSR.DeviceType.CASPARCG, + type: TSR.TimelineContentTypeCasparCg.MEDIA, + file: fileName + } + } +} diff --git a/src/tv2-common/content/server.ts b/src/tv2-common/content/server.ts index 2907e1b66..1e5961e17 100644 --- a/src/tv2-common/content/server.ts +++ b/src/tv2-common/content/server.ts @@ -4,19 +4,19 @@ import { TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddParentClass, - GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForServer, literal, PartDefinition, ServerParentClass, - TransitionFromString, TransitionSettings } from 'tv2-common' import { AbstractLLayer, ControlClasses, GetEnableClassForServer } from 'tv2-constants' import { TV2BlueprintConfig } from '../blueprintConfig' import { TimelineBlueprintExt } from '../onTimelineGenerate' +import { ServerContentProps, ServerPartProps } from '../parts' import { AdlibServerOfftubeOptions } from '../pieces' import { JoinAssetToNetworkPath } from '../util' @@ -27,79 +27,62 @@ export interface MakeContentServerSourceLayers { } Sisyfos: { ClipPending: string - StudioMicsGroup: string } ATEM: { ServerLookaheadAux?: string } } -export interface VTFields { - file: string - duration: number -} - type VTProps = Pick< VTContent, - 'fileName' | 'path' | 'mediaFlowIds' | 'ignoreMediaObjectStatus' | 'sourceDuration' | 'postrollDuration' + 'fileName' | 'path' | 'mediaFlowIds' | 'ignoreMediaObjectStatus' | 'sourceDuration' | 'postrollDuration' | 'seek' > -export function GetVTContentProperties(config: TV2BlueprintConfig, file: string, sourceDuration?: number): VTProps { +export function GetVTContentProperties( + config: TV2BlueprintConfig, + contentProps: Omit +): VTProps { return literal({ - fileName: file, + fileName: contentProps.file, path: JoinAssetToNetworkPath( config.studio.ClipNetworkBasePath, config.studio.ClipFolder, - file, + contentProps.file, config.studio.ClipFileExtension ), // full path on the source network storage mediaFlowIds: [config.studio.ClipMediaFlowId], - sourceDuration: sourceDuration && sourceDuration > 0 ? sourceDuration : undefined, + sourceDuration: contentProps.sourceDuration, postrollDuration: config.studio.ServerPostrollDuration, - ignoreMediaObjectStatus: config.studio.ClipIgnoreStatus + ignoreMediaObjectStatus: config.studio.ClipIgnoreStatus, + seek: contentProps.seek }) } export function MakeContentServer( - context: IShowStyleUserContext, - file: string, - mediaPlayerSessionId: string, + _context: IShowStyleUserContext, partDefinition: PartDefinition, config: TV2BlueprintConfig, sourceLayers: MakeContentServerSourceLayers, - adLibPix: boolean, - voLevels: boolean, - sourceDuration?: number + partProps: ServerPartProps, + contentProps: ServerContentProps ): WithTimeline { return literal>({ - ...GetVTContentProperties(config, file, sourceDuration), + ...GetVTContentProperties(config, contentProps), ignoreMediaObjectStatus: true, - timelineObjects: GetServerTimeline( - context, - file, - mediaPlayerSessionId, - partDefinition, - config, - sourceLayers, - adLibPix, - voLevels - ) + timelineObjects: GetServerTimeline(partDefinition, config, sourceLayers, partProps, contentProps) }) } function GetServerTimeline( - context: IShowStyleUserContext, - file: string, - mediaPlayerSessionId: string, partDefinition: PartDefinition, config: TV2BlueprintConfig, sourceLayers: MakeContentServerSourceLayers, - adLibPix?: boolean, - voLevels?: boolean -) { - const serverEnableClass = `.${GetEnableClassForServer(mediaPlayerSessionId)}` + partProps: ServerPartProps, + contentProps: ServerContentProps +): TimelineObjectCoreExt[] { + const serverEnableClass = `.${GetEnableClassForServer(contentProps.mediaPlayerSession)}` - const mediaObj = literal({ + const mediaObj: TSR.TimelineObjCCGMedia & TimelineBlueprintExt = { id: '', enable: { while: serverEnableClass @@ -109,68 +92,41 @@ function GetServerTimeline( content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.MEDIA, - file, - loop: adLibPix, - seek: 0, - // length: duration, + file: contentProps.file, + loop: partProps.adLibPix, + seek: contentProps.seek, + length: contentProps.seek ? contentProps.clipDuration : undefined, + inPoint: contentProps.seek ? 0 : undefined, playing: true }, metaData: { - mediaPlayerSession: mediaPlayerSessionId + mediaPlayerSession: contentProps.mediaPlayerSession }, - classes: [...(AddParentClass(config, partDefinition) && !adLibPix ? [ServerParentClass('studio0', file)] : [])] - }) + classes: [ + ...(AddParentClass(config, partDefinition) && !partProps.adLibPix + ? [ServerParentClass('studio0', contentProps.file)] + : []) + ] + } const mediaOffObj = JSON.parse(JSON.stringify(mediaObj)) as TSR.TimelineObjCCGMedia & TimelineBlueprintExt mediaOffObj.enable = { while: `!${serverEnableClass}` } mediaOffObj.content.playing = false + mediaOffObj.content.noStarttime = true - return literal([ + const audioEnable = { + while: serverEnableClass + } + return [ mediaObj, mediaOffObj, - - literal({ - id: '', - enable: { - while: serverEnableClass - }, - priority: 1, - layer: sourceLayers.Sisyfos.ClipPending, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - // isPgm: voiceOver ? 2 : 1 - isPgm: 1 - }, - metaData: { - mediaPlayerSession: mediaPlayerSessionId - }, - classes: [] - }), - - ...(adLibPix - ? config.stickyLayers.map(layer => { - return literal({ - id: '', - enable: { - while: serverEnableClass - }, - priority: 1, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - }, - metaData: { - sisyfosPersistLevel: true - } - }) - }) - : []), - ...(voLevels - ? [GetSisyfosTimelineObjForCamera(context, config, 'server', sourceLayers.Sisyfos.StudioMicsGroup)] - : []), + ...GetSisyfosTimelineObjForServer( + config, + partProps.voLevels, + sourceLayers.Sisyfos.ClipPending, + contentProps.mediaPlayerSession, + audioEnable + ), ...(sourceLayers.ATEM.ServerLookaheadAux ? [ literal({ @@ -188,12 +144,12 @@ function GetServerTimeline( } }, metaData: { - mediaPlayerSession: mediaPlayerSessionId + mediaPlayerSession: contentProps.mediaPlayerSession } }) ] : []) - ]) + ] } export function CutToServer( @@ -218,10 +174,8 @@ export function CutToServer( type: TSR.TimelineContentTypeAtem.ME, me: { input: -1, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) } }, metaData: { @@ -251,3 +205,10 @@ export function EnableServer(mediaPlayerSessionId: string) { classes: [GetEnableClassForServer(mediaPlayerSessionId)] }) } + +export function getSourceDuration( + mediaObjectDuration: number | undefined, + serverPostrollDuration: number +): number | undefined { + return mediaObjectDuration !== undefined ? Math.max(mediaObjectDuration - serverPostrollDuration, 0) : undefined +} diff --git a/src/tv2-common/cueTiming.ts b/src/tv2-common/cueTiming.ts index 0626fbc3d..168ec0a1c 100644 --- a/src/tv2-common/cueTiming.ts +++ b/src/tv2-common/cueTiming.ts @@ -1,6 +1,6 @@ import { CueDefinition, CueDefinitionBase, CueTime } from './inewsConversion/converters/ParseCue' -import { IBlueprintAdLibPiece, IBlueprintPiece, PieceLifespan } from '@sofie-automation/blueprints-integration' +import { IBlueprintAdLibPiece, IBlueprintPiece, PieceLifespan } from '@tv2media/blueprints-integration' import { TV2BlueprintConfigBase, TV2StudioConfigBase } from 'tv2-common' const FRAME_TIME = 1000 / 25 // TODO: This should be pulled from config. @@ -38,22 +38,14 @@ export function CreateTimingEnable( lifespan: PieceLifespan.WithinPart } - if (cue.start) { - ;(result.enable as any).start = CalculateTime(cue.start) - } else { - ;(result.enable as any).start = 0 - } + result.enable.start = (cue.start && CalculateTime(cue.start)) ?? 0 if (cue.end) { if (cue.end.infiniteMode) { result.lifespan = LifeSpan(cue.end.infiniteMode, PieceLifespan.WithinPart) } else { const end = CalculateTime(cue.end) - ;(result.enable as any).duration = end - ? result.enable.start - ? end - Number(result.enable.start) - : end - : undefined + result.enable.duration = end ? end - result.enable.start : undefined } } else if (defaultOut !== undefined) { result.enable.duration = defaultOut diff --git a/src/tv2-common/cues/ekstern.ts b/src/tv2-common/cues/ekstern.ts index e47399c58..a10891f19 100644 --- a/src/tv2-common/cues/ekstern.ts +++ b/src/tv2-common/cues/ekstern.ts @@ -5,31 +5,27 @@ import { IShowStyleUserContext, PieceLifespan, RemoteContent, - SourceLayerType, TimelineObjectCoreExt, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddParentClass, createEmptyObject, CueDefinitionEkstern, EksternParentClass, - FindSourceInfoStrict, - GetEksternMetaData, - GetLayersForEkstern, - GetSisyfosTimelineObjForCamera, - GetSisyfosTimelineObjForEkstern, literal, PartDefinition, PartToParentClass, - TransitionFromString, + PieceMetaData, TransitionSettings, TV2BlueprintConfigBase, TV2StudioConfigBase } from 'tv2-common' -import { ControlClasses, SharedOutputLayers } from 'tv2-constants' +import { ControlClasses, SharedOutputLayers, SourceType } from 'tv2-constants' +import { GetSisyfosTimelineObjForRemote } from '../helpers' import { GetTagForLive } from '../pieces' +import { findSourceInfo } from '../sources' interface EksternLayers { SourceLayer: { @@ -38,9 +34,6 @@ interface EksternLayers { ATEM: { MEProgram: string } - Sisyfos: { - StudioMics: string - } } export function EvaluateEksternBase< @@ -50,8 +43,8 @@ export function EvaluateEksternBase< context: IShowStyleUserContext, config: ShowStyleConfig, part: IBlueprintPart, - pieces: IBlueprintPiece[], - adlibPieces: IBlueprintAdLibPiece[], + pieces: Array>, + adlibPieces: Array>, partId: string, parsedCue: CueDefinitionEkstern, partDefinition: PartDefinition, @@ -59,123 +52,110 @@ export function EvaluateEksternBase< adlib?: boolean, rank?: number ) { - const matchesEksternSource = /^(?:LIVE|SKYPE|FEED) ?([^\s]+)(?: (.+))?$/i - const eksternProps = parsedCue.source.match(matchesEksternSource) - if (!eksternProps) { - context.notifyUserWarning(`No source entered for EKSTERN`) - part.invalid = true - return - } - const source = eksternProps[1] - if (!source) { - context.notifyUserWarning(`Could not find live source for ${parsedCue.source}`) - part.invalid = true - return - } - const sourceInfoEkstern = FindSourceInfoStrict(context, config.sources, SourceLayerType.REMOTE, parsedCue.source) - if (sourceInfoEkstern === undefined) { - context.notifyUserWarning(`${parsedCue.source} does not exist in this studio`) + const sourceInfoEkstern = findSourceInfo(config.sources, parsedCue.sourceDefinition) + if (parsedCue.sourceDefinition.sourceType !== SourceType.REMOTE || sourceInfoEkstern === undefined) { + context.notifyUserWarning(`EKSTERN source is not valid: "${parsedCue.sourceDefinition.raw}"`) part.invalid = true return } const atemInput = sourceInfoEkstern.port - const layers = GetLayersForEkstern(context, config.sources, parsedCue.source) - if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name: eksternProps[0], - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: layersEkstern.SourceLayer.PgmLive, - toBeQueued: true, - lifespan: PieceLifespan.WithinPart, - metaData: GetEksternMetaData(config.stickyLayers, config.studio.StudioMics, layers), - content: literal>({ - studioLabel: '', - switcherInput: atemInput, - timelineObjects: literal([ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: layersEkstern.ATEM.MEProgram, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: atemInput, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } - }, - classes: [ControlClasses.LiveSourceOnAir] - }), + adlibPieces.push({ + _rank: rank || 0, + externalId: partId, + name: parsedCue.sourceDefinition.name, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: layersEkstern.SourceLayer.PgmLive, + toBeQueued: true, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: sourceInfoEkstern.sisyfosLayers ?? [], + wantsToPersistAudio: sourceInfoEkstern.wantsToPersistAudio, + acceptPersistAudio: sourceInfoEkstern.acceptPersistAudio + } + }, + content: literal>({ + studioLabel: '', + switcherInput: atemInput, + timelineObjects: literal([ + literal({ + id: '', + enable: { + start: 0 + }, + priority: 1, + layer: layersEkstern.ATEM.MEProgram, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: atemInput, + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) + } + }, + classes: [ControlClasses.LiveSourceOnAir] + }), - ...GetSisyfosTimelineObjForEkstern(context, config.sources, parsedCue.source, GetLayersForEkstern), - GetSisyfosTimelineObjForCamera(context, config, 'telefon', layersEkstern.Sisyfos.StudioMics) - ]) - }) + ...GetSisyfosTimelineObjForRemote(config, sourceInfoEkstern) + ]) }) - ) + }) } else { - pieces.push( - literal({ - externalId: partId, - name: eksternProps[0], - enable: { - start: 0 - }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: layersEkstern.SourceLayer.PgmLive, - lifespan: PieceLifespan.WithinPart, - toBeQueued: true, - metaData: GetEksternMetaData(config.stickyLayers, config.studio.StudioMics, layers), - tags: [GetTagForLive(sourceInfoEkstern.id)], - content: literal>({ - studioLabel: '', - switcherInput: atemInput, - timelineObjects: literal([ - createEmptyObject({ - // Only want the ident for original versions (or clones) - enable: { start: 0 }, - layer: 'ekstern_enable_ident', - classes: [ControlClasses.ShowIdentGraphic, PartToParentClass('studio0', partDefinition) ?? ''] - }), - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: layersEkstern.ATEM.MEProgram, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: atemInput, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } - }, - ...(AddParentClass(config, partDefinition) - ? { classes: [EksternParentClass('studio0', parsedCue.source)] } - : {}) - }), + pieces.push({ + externalId: partId, + name: parsedCue.sourceDefinition.name, + enable: { + start: 0 + }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: layersEkstern.SourceLayer.PgmLive, + lifespan: PieceLifespan.WithinPart, + toBeQueued: true, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: sourceInfoEkstern.sisyfosLayers ?? [], + wantsToPersistAudio: sourceInfoEkstern.wantsToPersistAudio, + acceptPersistAudio: sourceInfoEkstern.acceptPersistAudio + } + }, + tags: [GetTagForLive(parsedCue.sourceDefinition)], + content: literal>({ + studioLabel: '', + switcherInput: atemInput, + timelineObjects: literal([ + createEmptyObject({ + // Only want the ident for original versions (or clones) + enable: { start: 0 }, + layer: 'ekstern_enable_ident', + classes: [PartToParentClass('studio0', partDefinition) ?? ''] + }), + literal({ + id: '', + enable: { + start: 0 + }, + priority: 1, + layer: layersEkstern.ATEM.MEProgram, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: atemInput, + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) + } + }, + ...(AddParentClass(config, partDefinition) + ? { classes: [EksternParentClass('studio0', parsedCue.sourceDefinition.name)] } + : {}) + }), - ...GetSisyfosTimelineObjForEkstern(context, config.sources, parsedCue.source, GetLayersForEkstern), - GetSisyfosTimelineObjForCamera(context, config, 'telefon', layersEkstern.Sisyfos.StudioMics) - ]) - }) + ...GetSisyfosTimelineObjForRemote(config, sourceInfoEkstern) + ]) }) - ) + }) } } diff --git a/src/tv2-common/cues/lyd.ts b/src/tv2-common/cues/lyd.ts index 22c49d2ef..b19456688 100644 --- a/src/tv2-common/cues/lyd.ts +++ b/src/tv2-common/cues/lyd.ts @@ -8,10 +8,18 @@ import { TimelineObjectCoreExt, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CreateTimingEnable, CueDefinitionLYD, literal, PartDefinition, TimeFromFrames } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { + CreateTimingEnable, + CueDefinitionLYD, + JoinAssetToFolder, + literal, + PartDefinition, + TimeFromFrames +} from 'tv2-common' import { AbstractLLayer, + AdlibTags, ControlClasses, SharedCasparLLayer, SharedOutputLayers, @@ -19,7 +27,6 @@ import { SharedSourceLayers } from 'tv2-constants' import { TV2BlueprintConfig } from '../blueprintConfig' -import { JoinAssetToFolder } from '../util' export function EvaluateLYD( context: IShowStyleUserContext, @@ -44,57 +51,51 @@ export function EvaluateLYD( } const file = fade ? 'empty' : conf ? conf.FileName.toString() : parsedCue.variant - const fadeIn = fade ? Number(fade[1]) : conf ? Number(conf.FadeIn) : undefined - const fadeOut = conf ? Number(conf.FadeOut) : undefined + const fadeTimeInFrames = fade ? Number(fade[1]) : undefined + const fadeIn = fadeTimeInFrames ?? (conf ? Number(conf.FadeIn) : undefined) + const fadeOut = fadeTimeInFrames ?? (conf ? Number(conf.FadeOut) : undefined) const lydType = stop ? 'stop' : fade ? 'fade' : 'bed' const lifespan = stop || fade || parsedCue.end ? PieceLifespan.WithinPart : PieceLifespan.OutOnRundownChange if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: part.externalId, - name: parsedCue.variant, - outputLayerId: SharedOutputLayers.MUSIK, - sourceLayerId: SharedSourceLayers.PgmAudioBed, - lifespan, - expectedDuration: stop - ? 2000 - : fade - ? Math.max(1000, fadeIn ? TimeFromFrames(fadeIn) : 0) - : CreateTimingEnable(parsedCue).enable.duration ?? undefined, - content: LydContent(config, file, lydType, fadeIn, fadeOut) - }) - ) + adlibPieces.push({ + _rank: rank || 0, + externalId: part.externalId, + name: parsedCue.variant, + outputLayerId: SharedOutputLayers.MUSIK, + sourceLayerId: SharedSourceLayers.PgmAudioBed, + lifespan, + expectedDuration: stop + ? 2000 + : fade + ? Math.max(1000, fadeIn ? TimeFromFrames(fadeIn) : 0) + : CreateTimingEnable(parsedCue).enable.duration ?? undefined, + content: LydContent(config, file, lydType, fadeIn, fadeOut), + tags: [AdlibTags.ADLIB_FLOW_PRODUCER] + }) } else { - pieces.push( - literal({ - externalId: part.externalId, - name: parsedCue.variant, - ...(stop - ? { enable: { start: CreateTimingEnable(parsedCue).enable.start, duration: 2000 } } - : fade - ? { - enable: { - start: CreateTimingEnable(parsedCue).enable.start, - duration: Math.max(1000, fadeIn ? TimeFromFrames(fadeIn) : 0) - } - } - : CreateTimingEnable(parsedCue)), - outputLayerId: SharedOutputLayers.MUSIK, - sourceLayerId: GetLYDSourceLayer(file), - lifespan, - content: LydContent(config, file, lydType, fadeIn, fadeOut) - }) - ) + pieces.push({ + externalId: part.externalId, + name: parsedCue.variant, + ...(stop + ? { enable: { start: CreateTimingEnable(parsedCue).enable.start, duration: 2000 } } + : fade + ? { + enable: { + start: CreateTimingEnable(parsedCue).enable.start, + duration: Math.max(1000, fadeIn ? TimeFromFrames(fadeIn) : 0) + } + } + : CreateTimingEnable(parsedCue)), + outputLayerId: SharedOutputLayers.MUSIK, + sourceLayerId: SharedSourceLayers.PgmAudioBed, + lifespan, + content: LydContent(config, file, lydType, fadeIn, fadeOut) + }) } } -export function GetLYDSourceLayer(_name: string): SharedSourceLayers { - return SharedSourceLayers.PgmAudioBed -} - function LydContent( config: TV2BlueprintConfig, file: string, @@ -122,7 +123,7 @@ function LydContent( }) } - const filePath = JoinAssetToFolder(config.studio.AudioBedFolder, file) + const filePath = lydType === 'fade' ? file : JoinAssetToFolder(config.studio.AudioBedFolder, file) return literal>({ timelineObjects: literal([ diff --git a/src/tv2-common/cues/mixMinus.ts b/src/tv2-common/cues/mixMinus.ts index c8a8b574e..abf057a1c 100644 --- a/src/tv2-common/cues/mixMinus.ts +++ b/src/tv2-common/cues/mixMinus.ts @@ -6,8 +6,8 @@ import { TimelineObjectCoreExt, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CueDefinitionMixMinus, FindSourceByName, literal, PartDefinition } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { CueDefinitionMixMinus, findSourceInfo, literal, PartDefinition } from 'tv2-common' import { ControlClasses, SharedATEMLLayer, SharedOutputLayers, SharedSourceLayers } from 'tv2-constants' import { TV2BlueprintConfig } from '../blueprintConfig' @@ -18,30 +18,31 @@ export function EvaluateCueMixMinus( part: PartDefinition, parsedCue: CueDefinitionMixMinus ) { - const sourceInfoMixMinus = FindSourceByName(context, config.sources, parsedCue.source) - if (sourceInfoMixMinus === undefined) { - context.notifyUserWarning(`${parsedCue.source} does not exist in this studio (MINUSKAM)`) + const sourceInfo = findSourceInfo(config.sources, parsedCue.sourceDefinition) + + const name = parsedCue.sourceDefinition.name || parsedCue.sourceDefinition.sourceType + + if (sourceInfo === undefined) { + context.notifyUserWarning(`${name} does not exist in this studio (MINUSKAM)`) return } - const atemInput = sourceInfoMixMinus.port + const atemInput = sourceInfo.port - pieces.push( - literal({ - externalId: part.externalId, - name: `MixMinus: ${parsedCue.source}`, - enable: { - start: 0 - }, - lifespan: PieceLifespan.OutOnShowStyleEnd, - sourceLayerId: SharedSourceLayers.AuxMixMinus, - outputLayerId: SharedOutputLayers.AUX, - content: MixMinusContent(atemInput) - }) - ) + pieces.push({ + externalId: part.externalId, + name: `MixMinus: ${name}`, + enable: { + start: 0 + }, + lifespan: PieceLifespan.OutOnShowStyleEnd, + sourceLayerId: SharedSourceLayers.AuxMixMinus, + outputLayerId: SharedOutputLayers.AUX, + content: MixMinusContent(atemInput) + }) } function MixMinusContent(atemInput: number): WithTimeline { - return literal>({ + return { timelineObjects: literal([ literal({ content: { @@ -59,5 +60,5 @@ function MixMinusContent(atemInput: number): WithTimeline { priority: 1 }) ]) - }) + } } diff --git a/src/tv2-common/evaluateCues.ts b/src/tv2-common/evaluateCues.ts index 9d5b7b138..b5191ef41 100644 --- a/src/tv2-common/evaluateCues.ts +++ b/src/tv2-common/evaluateCues.ts @@ -6,7 +6,7 @@ import { IBlueprintPiece, ISegmentUserContext, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { assertUnreachable, CueDefinition, @@ -32,21 +32,23 @@ import { GraphicIsPilot } from './inewsConversion' +export interface Adlib { + rank: number +} export interface EvaluateCuesShowstyleOptions { EvaluateCueGraphic?: ( config: TV2BlueprintConfig, context: ISegmentUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionGraphic, - adlib: boolean, partDefinition: PartDefinition, - rank?: number + adlib?: Adlib ) => void EvaluateCueBackgroundLoop?: ( + config: TV2BlueprintConfig, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], @@ -109,19 +111,17 @@ export interface EvaluateCuesShowstyleOptions { parsedCue: CueDefinitionAdLib, partDefinition: PartDefinition, rank: number - ) => void + ) => Promise EvaluateCueTelefon?: ( config: TV2BlueprintConfig, context: ISegmentUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, partDefinition: PartDefinition, parsedCue: CueDefinitionTelefon, - adlib?: boolean, - rank?: number + adlib?: Adlib ) => void EvaluateCueJingle?: ( context: ISegmentUserContext, @@ -181,14 +181,14 @@ export interface EvaluateCuesOptions { /** Whether the parent part is a graphic part. */ isGrafikPart?: boolean /** Passing this arguments sets the types of cues to evaluate. */ - selectedCueTypes?: CueType[] | undefined + selectedCueTypes?: CueType[] /** Don't evaluate adlibs. */ excludeAdlibs?: boolean /** Only evaluate adlibs. */ adlibsOnly?: boolean } -export function EvaluateCuesBase( +export async function EvaluateCuesBase( showStyleOptions: EvaluateCuesShowstyleOptions, context: ISegmentUserContext, config: TV2BlueprintConfig, @@ -206,6 +206,7 @@ export function EvaluateCuesBase( for (const cue of cues) { if (cue && !SkipCue(cue, options.selectedCueTypes, options.excludeAdlibs, options.adlibsOnly)) { const shouldAdlib = /* config.showStyle.IsOfftube || */ options.adlib ? true : cue.adlib ? true : false + const adlib = shouldAdlib ? { rank: adLibRank } : undefined switch (cue.type) { case CueType.Graphic: @@ -222,15 +223,13 @@ export function EvaluateCuesBase( showStyleOptions.EvaluateCueGraphic( config, context, - part, pieces, adLibPieces, actions, partDefinition.externalId, cue, - shouldAdlib, partDefinition, - adLibRank + adlib ) } break @@ -282,7 +281,7 @@ export function EvaluateCuesBase( break case CueType.AdLib: if (showStyleOptions.EvaluateCueAdLib) { - showStyleOptions.EvaluateCueAdLib( + await showStyleOptions.EvaluateCueAdLib( context, config, adLibPieces, @@ -300,15 +299,13 @@ export function EvaluateCuesBase( showStyleOptions.EvaluateCueTelefon( config, context, - part, pieces, adLibPieces, actions, partDefinition.externalId, partDefinition, cue, - shouldAdlib, - adLibRank + adlib ) } break @@ -373,6 +370,7 @@ export function EvaluateCuesBase( case CueType.BackgroundLoop: if (showStyleOptions.EvaluateCueBackgroundLoop) { showStyleOptions.EvaluateCueBackgroundLoop( + config, pieces, adLibPieces, actions, @@ -444,9 +442,8 @@ export function EvaluateCuesBase( content: { templateName: (obj as TSR.TimelineObjVIZMSEElementInternal).content.templateName, templateData: (obj as TSR.TimelineObjVIZMSEElementInternal).content.templateData, - channelName: o.content.channelName - // R35: rundownId: context.rundownId, - // R35: playlistId: '' + channel: o.content.channelName, + showId: o.content.showId } }) } @@ -456,10 +453,8 @@ export function EvaluateCuesBase( piece.expectedPlayoutItems.push({ deviceSubType: TSR.DeviceType.VIZMSE, content: { - templateName: (obj as TSR.TimelineObjVIZMSEElementPilot).content.templateVcpId, - channelName: (obj as TSR.TimelineObjVIZMSEElementPilot).content.channelName - // R35: rundownId: context.rundownId, - // R35: playlistId: '' + vcpid: (obj as TSR.TimelineObjVIZMSEElementPilot).content.templateVcpId, + channel: (obj as TSR.TimelineObjVIZMSEElementPilot).content.channelName } }) } @@ -468,10 +463,9 @@ export function EvaluateCuesBase( deviceSubType: TSR.DeviceType.VIZMSE, content: { templateName: 'altud', - channelName: 'OVL1', - templateData: [] - // R35: rundownId: context.rundownId, - // R35: playlistId: '' + channel: 'OVL1', + templateData: [], + showId: config.selectedGraphicsSetup.OvlShowId } }) } diff --git a/src/tv2-common/get-next-part-cue.spec.ts b/src/tv2-common/get-next-part-cue.spec.ts index a6ab0c7de..c924b1321 100644 --- a/src/tv2-common/get-next-part-cue.spec.ts +++ b/src/tv2-common/get-next-part-cue.spec.ts @@ -6,17 +6,29 @@ import { literal, PartDefinitionKam } from 'tv2-common' -import { CueType, PartType } from 'tv2-constants' -import { CueDefinitionGraphic, GraphicInternal } from './inewsConversion' +import { CueType, PartType, SourceType } from 'tv2-constants' +import { CueDefinitionGraphic, GraphicInternal, RemoteType, SourceDefinitionKam } from './inewsConversion' import { GetNextPartCue } from './nextPartCue' +const SOURCE_DEFINITION_KAM_1: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '1', + raw: 'Kam 1', + minusMic: false, + name: 'KAM 1' +} +const SOURCE_DEFINITION_KAM_2: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '2', + raw: 'Kam 2', + minusMic: false, + name: 'KAM 2' +} const partDefinitionTest1: PartDefinitionKam = { type: PartType.Kam, externalId: 'test-part', rawType: 'KAM 1', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, fields: {}, script: '', modified: 0, @@ -35,7 +47,13 @@ const partDefinitionTest1: PartDefinitionKam = { // Ekstern 1 - (index 1) literal({ type: CueType.Ekstern, - source: '1', + sourceDefinition: { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' + }, iNewsCommand: 'EKSTERN' }), literal>({ @@ -63,7 +81,13 @@ const partDefinitionTest1: PartDefinitionKam = { // Ekstern 2 - (index 4) literal({ type: CueType.Ekstern, - source: '2', + sourceDefinition: { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '2', + raw: 'Live 2', + name: 'LIVE 2' + }, iNewsCommand: 'EKSTERN' }), literal>({ @@ -98,8 +122,8 @@ const partDefinitionTest1: PartDefinitionKam = { type: CueType.DVE, template: 'MORBARN', sources: { - INP1: 'Kam 1', - INP2: 'Kam 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_KAM_2 }, labels: [], iNewsCommand: 'DVE' @@ -146,9 +170,7 @@ const partDefinitionTest2: PartDefinitionKam = { type: PartType.Kam, externalId: 'test-part', rawType: 'KAM 1', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, fields: {}, script: '', modified: 0, @@ -158,8 +180,8 @@ const partDefinitionTest2: PartDefinitionKam = { type: CueType.DVE, template: 'MORBARN', sources: { - INP1: 'Kam 1', - INP2: 'Kam 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_KAM_2 }, labels: [], iNewsCommand: 'DVE' @@ -167,7 +189,13 @@ const partDefinitionTest2: PartDefinitionKam = { // Ekstern 1 - (index 1) literal({ type: CueType.Ekstern, - source: '1', + sourceDefinition: { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' + }, iNewsCommand: 'EKSTERN' }), literal>({ @@ -208,8 +236,8 @@ const partDefinitionTest2: PartDefinitionKam = { type: CueType.DVE, template: 'MORBARN', sources: { - INP1: 'Kam 1', - INP2: 'Kam 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_KAM_2 }, labels: [], iNewsCommand: 'DVE' @@ -217,7 +245,13 @@ const partDefinitionTest2: PartDefinitionKam = { // Ekstern 2 - (index 6) literal({ type: CueType.Ekstern, - source: '1', + sourceDefinition: { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' + }, iNewsCommand: 'EKSTERN' }), literal>({ diff --git a/src/tv2-common/getSegment.ts b/src/tv2-common/getSegment.ts index 704bc431a..4593e333b 100644 --- a/src/tv2-common/getSegment.ts +++ b/src/tv2-common/getSegment.ts @@ -4,11 +4,11 @@ import { IBlueprintSegment, IngestSegment, IShowStyleUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { assertUnreachable, GetNextPartCue, - INewsStory, + INewsPayload, IsTargetingFull, literal, ParseBody, @@ -17,8 +17,7 @@ import { PartDefinitionKam, PartMetaData } from 'tv2-common' -import { CueType, PartType, SharedSourceLayers } from 'tv2-constants' -import * as _ from 'underscore' +import { CueType, PartType, SharedSourceLayers, TallyTags } from 'tv2-constants' import { TV2BlueprintConfigBase, TV2StudioConfigBase } from './blueprintConfig' import { CueDefinitionUnpairedTarget, @@ -29,7 +28,6 @@ import { PartDefinitionTelefon, TimeFromINewsField } from './inewsConversion' -import { PieceMetaData } from './onTimelineGenerate' import { CreatePartInvalid, ServerPartProps } from './parts' export interface GetSegmentShowstyleOptions< @@ -44,73 +42,74 @@ export interface GetSegmentShowstyleOptions< partDefinition: PartDefinition, totalWords: number, asAdlibs?: boolean - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartIntro?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinition, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartKam?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionKam, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartServer?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinition, - props: ServerPartProps - ) => BlueprintResultPart + partProps: ServerPartProps + ) => BlueprintResultPart | Promise CreatePartTeknik?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionTeknik, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartGrafik?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionGrafik, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartEkstern?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionEkstern, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartTelefon?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionTelefon, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartDVE?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionDVE, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise CreatePartEVS?: ( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinitionEVS, totalWords: number - ) => BlueprintResultPart + ) => BlueprintResultPart | Promise } -export function getSegmentBase< +export async function getSegmentBase< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: IShowStyleUserContext, ingestSegment: IngestSegment, showStyleOptions: GetSegmentShowstyleOptions -): BlueprintResultSegment { - const iNewsStory: INewsStory | undefined = ingestSegment.payload?.iNewsStory - const segment = literal({ +): Promise { + const segmentPayload = ingestSegment.payload as INewsPayload | undefined + const iNewsStory = segmentPayload?.iNewsStory + const segment: IBlueprintSegment = { name: ingestSegment.name || '', metaData: {}, showShelf: false, @@ -118,10 +117,10 @@ export function getSegmentBase< iNewsStory && iNewsStory.fields.pageNumber && iNewsStory.fields.pageNumber.trim() ? iNewsStory.fields.pageNumber.trim() : undefined - }) + } const config = showStyleOptions.getConfig(context) - if (!iNewsStory || iNewsStory.meta.float === 'float' || !iNewsStory.body) { + if (!segmentPayload || !iNewsStory || iNewsStory.meta.float === 'float' || !iNewsStory.body) { segment.isHidden = true return { segment, @@ -133,7 +132,7 @@ export function getSegmentBase< const totalTimeMs = TimeFromINewsField(iNewsStory.fields.totalTime) * 1000 let blueprintParts: BlueprintResultPart[] = [] - const parsedParts = ParseBody( + const parsedParts: PartDefinition[] = ParseBody( config, ingestSegment.externalId, ingestSegment.name, @@ -169,7 +168,7 @@ export function getSegmentBase< part.type === PartType.Unknown && part.cues.filter(cue => cue.type === CueType.Jingle || cue.type === CueType.AdLib).length === 0 ) { - blueprintParts.push(showStyleOptions.CreatePartUnknown(context, config, part, totalWords, true)) + blueprintParts.push(await showStyleOptions.CreatePartUnknown(context, config, part, totalWords, true)) continue } @@ -187,18 +186,18 @@ export function getSegmentBase< switch (part.type) { case PartType.INTRO: if (showStyleOptions.CreatePartIntro) { - blueprintParts.push(showStyleOptions.CreatePartIntro(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartIntro(context, config, part, totalWords)) } break case PartType.Kam: if (showStyleOptions.CreatePartKam) { - blueprintParts.push(showStyleOptions.CreatePartKam(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartKam(context, config, part, totalWords)) } break case PartType.Server: if (showStyleOptions.CreatePartServer) { blueprintParts.push( - showStyleOptions.CreatePartServer(context, config, part, { + await showStyleOptions.CreatePartServer(context, config, part, { voLayer: false, voLevels: false, totalTime, @@ -211,18 +210,18 @@ export function getSegmentBase< break case PartType.Teknik: if (showStyleOptions.CreatePartTeknik) { - blueprintParts.push(showStyleOptions.CreatePartTeknik(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartTeknik(context, config, part, totalWords)) } break case PartType.Grafik: if (showStyleOptions.CreatePartGrafik) { - blueprintParts.push(showStyleOptions.CreatePartGrafik(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartGrafik(context, config, part, totalWords)) } break case PartType.VO: if (showStyleOptions.CreatePartServer) { blueprintParts.push( - showStyleOptions.CreatePartServer(context, config, part, { + await showStyleOptions.CreatePartServer(context, config, part, { voLayer: true, voLevels: true, totalTime, @@ -235,27 +234,27 @@ export function getSegmentBase< break case PartType.DVE: if (showStyleOptions.CreatePartDVE) { - blueprintParts.push(showStyleOptions.CreatePartDVE(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartDVE(context, config, part, totalWords)) } break - case PartType.Ekstern: + case PartType.REMOTE: if (showStyleOptions.CreatePartEkstern) { - blueprintParts.push(showStyleOptions.CreatePartEkstern(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartEkstern(context, config, part, totalWords)) } break case PartType.Telefon: if (showStyleOptions.CreatePartTelefon) { - blueprintParts.push(showStyleOptions.CreatePartTelefon(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartTelefon(context, config, part, totalWords)) } break case PartType.Unknown: if (part.cues.length) { - blueprintParts.push(showStyleOptions.CreatePartUnknown(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartUnknown(context, config, part, totalWords)) } break case PartType.EVS: if (showStyleOptions.CreatePartEVS) { - blueprintParts.push(showStyleOptions.CreatePartEVS(context, config, part, totalWords)) + blueprintParts.push(await showStyleOptions.CreatePartEVS(context, config, part, totalWords)) } break default: @@ -293,11 +292,11 @@ export function getSegmentBase< if (!part.part.expectedDuration && totalTimeMs > 0) { part.part.expectedDuration = (totalTimeMs - allocatedTime || 0) / partsWithoutExpectedDuration - if (part.part.expectedDuration! < 0) { + if (part.part.expectedDuration < 0) { part.part.expectedDuration = 0 } - if (part.part.expectedDuration! > config.studio.MaximumPartDuration) { + if (part.part.expectedDuration > config.studio.MaximumPartDuration) { part.part.expectedDuration = config.studio.MaximumPartDuration } } @@ -347,10 +346,7 @@ export function getSegmentBase< blueprintParts[0].part.budgetDuration = totalTimeMs } - if ( - blueprintParts.filter(part => part.part.invalid === true).length === blueprintParts.length && - iNewsStory.cues.length === 0 - ) { + if (blueprintParts.every(part => part.part.invalid) && iNewsStory.cues.length === 0) { segment.isHidden = true } @@ -359,9 +355,7 @@ export function getSegmentBase< part.part.expectedDuration! < config.studio.DefaultPartDuration && // Jingle-only part, do not modify duration !part.pieces.some( - p => - p.sourceLayerId === SharedSourceLayers.PgmJingle && - (p.metaData as PieceMetaData)?.transition?.isJingle === true + p => p.sourceLayerId === SharedSourceLayers.PgmJingle && p.tags?.some(tag => TallyTags.JINGLE === tag) ) ) { part.part.expectedDuration = config.studio.DefaultPartDuration @@ -383,7 +377,7 @@ export function getSegmentBase< actualPart.invalid = false } - if (ingestSegment.payload?.untimed) { + if (segmentPayload?.untimed) { actualPart.untimed = true } diff --git a/src/tv2-common/getShowStyleVariantId.ts b/src/tv2-common/getShowStyleVariantId.ts new file mode 100644 index 000000000..88009484e --- /dev/null +++ b/src/tv2-common/getShowStyleVariantId.ts @@ -0,0 +1,16 @@ +import { IBlueprintShowStyleVariant, IngestRundown, IStudioUserContext } from '@tv2media/blueprints-integration' + +const DEFAULT_VARIANT_NAME = 'default' + +export function getShowStyleVariantId( + _context: IStudioUserContext, + showStyleVariants: IBlueprintShowStyleVariant[], + ingestRundown: IngestRundown +): string | null { + const ingestVariantName = ingestRundown.payload?.showstyleVariant?.trim().toLowerCase() + const showStyleVariant = + showStyleVariants.find(variant => variant.name?.trim().toLowerCase() === ingestVariantName) ?? + showStyleVariants.find(variant => variant.name?.trim().toLowerCase() === DEFAULT_VARIANT_NAME) + + return showStyleVariant?._id ?? null +} diff --git a/src/tv2-common/helpers/__tests__/rundownAdLibActions.spec.ts b/src/tv2-common/helpers/__tests__/rundownAdLibActions.spec.ts index 0e5bac50c..445b9767f 100644 --- a/src/tv2-common/helpers/__tests__/rundownAdLibActions.spec.ts +++ b/src/tv2-common/helpers/__tests__/rundownAdLibActions.spec.ts @@ -1,107 +1,76 @@ -import { - ActionTakeWithTransition, - ActionTakeWithTransitionVariantBreaker, - ActionTakeWithTransitionVariantMix, - literal, - ParseTransitionSetting -} from 'tv2-common' -import { AdlibActionType } from 'tv2-constants' +import { ActionTakeWithTransitionVariantDip, ParseTransitionString } from 'tv2-common' -describe('Parse Transition Setting', () => { - it('Parses Mix', () => { - let result = ParseTransitionSetting('MIX 12', true) - - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'mix', - frames: 12 - }), - takeNow: true +describe('rundownAdLibActions', () => { + describe('ParseTransitionString', () => { + it('should parses Mix 12', () => { + const result = ParseTransitionString('MIX 12') + expect(result).toEqual({ + type: 'mix', + frames: 12 }) - ) - - result = ParseTransitionSetting('mix9', false) + }) - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'mix', - frames: 9 - }), - takeNow: false + it('should parse Mix 9', () => { + const result = ParseTransitionString('mix9') + expect(result).toEqual({ + type: 'mix', + frames: 9 }) - ) - }) + }) - it('Parses EFFEKT', () => { - let result = ParseTransitionSetting('EFFEKT 1', true) - - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'breaker', - breaker: '1' - }), - takeNow: true + it('should parse EFFEKT 1', () => { + const result = ParseTransitionString('EFFEKT 1') + expect(result).toEqual({ + type: 'breaker', + breaker: '1' }) - ) - - result = ParseTransitionSetting('effekt2', false) + }) - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'breaker', - breaker: '2' - }), - takeNow: false + it('should parse effekt2', () => { + const result = ParseTransitionString('effekt2') + expect(result).toEqual({ + type: 'breaker', + breaker: '2' }) - ) + }) - result = ParseTransitionSetting('13', false) - - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'breaker', - breaker: '13' - }), - takeNow: false + it('should parse 13 as breaker', () => { + const result = ParseTransitionString('13') + expect(result).toEqual({ + type: 'breaker', + breaker: '13' }) - ) - }) + }) - it('Parses Transition', () => { - let result = ParseTransitionSetting('INTRO_19', true) + it('should parse INTRO_19', () => { + const result = ParseTransitionString('INTRO_19') + expect(result).toEqual({ + type: 'breaker', + breaker: 'INTRO_19' + }) + }) - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'breaker', - breaker: 'INTRO_19' - }), - takeNow: true + it('should parse / Branded Transition', () => { + const result = ParseTransitionString('/ Branded Transition') + expect(result).toEqual({ + type: 'breaker', + breaker: '/ Branded Transition' }) - ) + }) - result = ParseTransitionSetting('/ Branded Transition', false) + it('should return Dip when transitionSetting is Dip', () => { + const result = ParseTransitionString('dip 1') + expect(result.type).toEqual('dip') + }) - expect(result).toEqual( - literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant: literal({ - type: 'breaker', - breaker: '/ Branded Transition' - }), - takeNow: false - }) - ) + it('should return a dip with 4 frames when transitionSetting is dip 4', () => { + const result = ParseTransitionString('dip 4') + expect((result as ActionTakeWithTransitionVariantDip).frames).toEqual(4) + }) + + it('should return a dip with 15 frames when transitionSetting is dip 15', () => { + const result = ParseTransitionString('dip 15') + expect((result as ActionTakeWithTransitionVariantDip).frames).toEqual(15) + }) }) }) diff --git a/src/tv2-common/helpers/__tests__/serverResume.spec.ts b/src/tv2-common/helpers/__tests__/serverResume.spec.ts new file mode 100644 index 000000000..feb317794 --- /dev/null +++ b/src/tv2-common/helpers/__tests__/serverResume.spec.ts @@ -0,0 +1,209 @@ +import { + IBlueprintPartInstance, + IBlueprintResolvedPieceInstance, + PieceLifespan, + SplitsContent, + VTContent, + WithTimeline +} from '@tv2media/blueprints-integration' +import { DVEPieceMetaData, literal, PieceMetaData, RemoteType, SourceDefinitionRemote } from 'tv2-common' +import { SharedSourceLayers, SourceType } from 'tv2-constants' +import { getServerPositionForPartInstance } from '../serverResume' + +const EKSTERN_SOURCE: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' +} + +function getMockPartInstance(partInstance: Partial): IBlueprintPartInstance { + return { + _id: '', + segmentId: '', + part: { + _id: '', + segmentId: '', + externalId: '', + title: '' + }, + rehearsal: false, + ...partInstance + } +} + +describe('Server Resume', () => { + it('Returns server position from server part with resolved duration', () => { + const position = getServerPositionForPartInstance(getMockPartInstance({ _id: 'mock_1' }), [ + literal>({ + _id: '', + partInstanceId: 'mock_1', + resolvedStart: 1000, + resolvedDuration: 10000, + dynamicallyInserted: 1, + piece: { + _id: '', + enable: { start: 'now' }, + externalId: '', + name: '', + lifespan: PieceLifespan.WithinPart, + sourceLayerId: SharedSourceLayers.PgmServer, + outputLayerId: '', + content: literal>({ + fileName: '123456', + path: 'somewhere/123456', + timelineObjects: [] + }) + } + }) + ]) + expect(position).toEqual({ fileName: '123456', lastEnd: 10000, isPlaying: false }) + }) + it('Returns server position from server part when setting "now"', () => { + const position = getServerPositionForPartInstance( + getMockPartInstance({ _id: 'mock_1', timings: { startedPlayback: 1000 } }), + [ + literal>({ + _id: '', + partInstanceId: 'mock_1', + startedPlayback: 1000, + resolvedStart: 2000, + dynamicallyInserted: 1, + piece: { + _id: '', + enable: { start: 'now' }, + externalId: '', + name: '', + lifespan: PieceLifespan.WithinPart, + sourceLayerId: SharedSourceLayers.PgmServer, + outputLayerId: '', + content: literal>({ + fileName: '123456', + path: 'somewhere/123456', + timelineObjects: [] + }) + } + }) + ], + 11000 + ) + expect(position).toEqual({ fileName: '123456', lastEnd: 8000, endedWithPartInstance: 'mock_1', isPlaying: false }) + }) + it('Returns server position from DVE adlib with continuous server', () => { + const position = getServerPositionForPartInstance( + getMockPartInstance({ + _id: 'mock_1', + segmentId: 'segment_0', + previousPartEndState: { + partInstanceId: 'mock_0', + sisyfosPersistMetaData: { sisyfosLayers: [] }, + mediaPlayerSessions: {}, + segmentId: 'segment_0', + serverPosition: { fileName: '123456', lastEnd: 10000, endedWithPartInstance: 'mock_0', isPlaying: false } + }, + timings: { startedPlayback: 11000 } + }), + [ + literal>({ + _id: '', + partInstanceId: 'mock_1', + resolvedStart: 1000, + dynamicallyInserted: 1, + piece: { + _id: '', + enable: { start: 'now' }, + externalId: '', + name: '', + lifespan: PieceLifespan.WithinPart, + sourceLayerId: SharedSourceLayers.PgmDVEAdLib, + outputLayerId: '', + content: literal>({ + boxSourceConfiguration: [], + timelineObjects: [] + }), + metaData: literal>({ + sources: { + INP1: { sourceType: SourceType.SERVER }, + INP2: EKSTERN_SOURCE + }, + serverPlaybackTiming: [{}] + }) + } + }) + ], + 20000 + ) + expect(position).toEqual({ fileName: '123456', lastEnd: 18000, isPlaying: false, endedWithPartInstance: 'mock_1' }) + }) + it('Returns server position from DVE adlib with interrupted server', () => { + const position = getServerPositionForPartInstance( + getMockPartInstance({ + _id: 'mock_1', + segmentId: 'segment_0', + previousPartEndState: { + partInstanceId: 'mock_0', + sisyfosPersistMetaData: { sisyfosLayers: [] }, + mediaPlayerSessions: {}, + segmentId: 'segment_0', + serverPosition: { fileName: '123456', lastEnd: 10000, endedWithPartInstance: 'mock_0', isPlaying: false } + }, + timings: { startedPlayback: 11000 } + }), + [ + literal>({ + _id: '', + partInstanceId: 'mock_1', + resolvedStart: 1000, + dynamicallyInserted: 1, + piece: { + _id: '', + enable: { start: 'now' }, + externalId: '', + name: '', + lifespan: PieceLifespan.WithinPart, + sourceLayerId: SharedSourceLayers.PgmDVEAdLib, + outputLayerId: '', + content: literal>({ + boxSourceConfiguration: [], + timelineObjects: [] + }), + metaData: literal>({ + sources: { + INP1: { sourceType: SourceType.SERVER }, + INP2: EKSTERN_SOURCE + }, + serverPlaybackTiming: [{ end: 13000 }, { start: 14000, end: 15000 }, { start: 16000 }] + }) + } + }) + ], + 20000 + ) + expect(position).toEqual({ fileName: '123456', lastEnd: 16000, isPlaying: false, endedWithPartInstance: 'mock_1' }) + }) + it('Includes transition in server position', () => { + const position = getServerPositionForPartInstance( + getMockPartInstance({ + _id: 'mock_1', + segmentId: 'segment_0', + previousPartEndState: { + partInstanceId: 'mock_0', + sisyfosPersistMetaData: { sisyfosLayers: [] }, + mediaPlayerSessions: {}, + segmentId: 'segment_0', + serverPosition: { fileName: '123456', lastEnd: 10000, endedWithPartInstance: 'mock_0', isPlaying: false } + }, + part: { + _id: '', + segmentId: '', + externalId: '', + title: '', + inTransition: { previousPartKeepaliveDuration: 2000, blockTakeDuration: 4000, partContentDelayDuration: 0 } + } + }), + [] + ) + expect(position).toEqual({ fileName: '123456', lastEnd: 12000, isPlaying: false, endedWithPartInstance: 'mock_0' }) + }) +}) diff --git a/src/tv2-common/helpers/__tests__/sisyfos.spec.ts b/src/tv2-common/helpers/__tests__/sisyfos.spec.ts new file mode 100644 index 000000000..47d4f3f80 --- /dev/null +++ b/src/tv2-common/helpers/__tests__/sisyfos.spec.ts @@ -0,0 +1,135 @@ +import { SourceLayerType, TSR } from '@tv2media/blueprints-integration' +import { + GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForRemote, + GetSisyfosTimelineObjForReplay, + SourceInfoType +} from 'tv2-common' +import { SharedSisyfosLLayer } from 'tv2-constants' +import { makeMockAFVDContext } from '../../../__mocks__/context' +import { getConfig } from '../../../tv2_afvd_showstyle/helpers/config' + +describe('Sisyfos', () => { + const config = getConfig(makeMockAFVDContext()) + it('Enables audio layers for cameras', () => { + const sourceInfo = { + type: SourceInfoType.KAM, + sourceLayerType: SourceLayerType.CAMERA, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: false + } + const timelineObjects = GetSisyfosTimelineObjForCamera(config, sourceInfo, false) + expect(timelineObjects.length).toBe(2) + expect(timelineObjects[0].layer).toBe('some_layer') + expect((timelineObjects[0] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + expect(timelineObjects[1].layer).toBe('some_layer2') + expect((timelineObjects[1] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + }) + it('Enables studio mics for cameras', () => { + const sourceInfo = { + type: SourceInfoType.KAM, + sourceLayerType: SourceLayerType.CAMERA, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: true + } + const timelineObjects = GetSisyfosTimelineObjForCamera(config, sourceInfo, false) + expect(timelineObjects.length).toBe(3) + const studioMicsTimelineObject = timelineObjects.find(t => t.layer === SharedSisyfosLLayer.SisyfosGroupStudioMics) + expect(studioMicsTimelineObject).toBeDefined() + }) + it('Does not enable studio mics for "minus mic" cameras', () => { + const sourceInfo = { + type: SourceInfoType.KAM, + sourceLayerType: SourceLayerType.CAMERA, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: true + } + const timelineObjects = GetSisyfosTimelineObjForCamera(config, sourceInfo, true) + expect(timelineObjects.length).toBe(2) + const studioMicsTimelineObject = timelineObjects.find(t => t.layer === SharedSisyfosLLayer.SisyfosGroupStudioMics) + expect(studioMicsTimelineObject).toBeUndefined() + }) + it('Enables audio layers for remotes', () => { + const sourceInfo = { + type: SourceInfoType.LIVE, + sourceLayerType: SourceLayerType.REMOTE, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: false + } + const timelineObjects = GetSisyfosTimelineObjForRemote(config, sourceInfo) + expect(timelineObjects.length).toBe(2) + expect(timelineObjects[0].layer).toBe('some_layer') + expect((timelineObjects[0] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + expect(timelineObjects[1].layer).toBe('some_layer2') + expect((timelineObjects[1] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + }) + it('Enables studio mics for remotes', () => { + const sourceInfo = { + type: SourceInfoType.LIVE, + sourceLayerType: SourceLayerType.REMOTE, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: true + } + const timelineObjects = GetSisyfosTimelineObjForRemote(config, sourceInfo) + expect(timelineObjects.length).toBe(3) + const studioMicsTimelineObject = timelineObjects.find(t => t.layer === SharedSisyfosLLayer.SisyfosGroupStudioMics) + expect(studioMicsTimelineObject).toBeDefined() + }) + it('Enables audio layers for replay', () => { + const sourceInfo = { + type: SourceInfoType.REPLAY, + sourceLayerType: SourceLayerType.LOCAL, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: false + } + const timelineObjects = GetSisyfosTimelineObjForReplay(config, sourceInfo, false) + expect(timelineObjects.length).toBe(2) + expect(timelineObjects[0].layer).toBe('some_layer') + expect((timelineObjects[0] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + expect(timelineObjects[1].layer).toBe('some_layer2') + expect((timelineObjects[1] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(1) + }) + it('Enables audio layers for replay (vo)', () => { + const sourceInfo = { + type: SourceInfoType.REPLAY, + sourceLayerType: SourceLayerType.LOCAL, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: false + } + const timelineObjects = GetSisyfosTimelineObjForReplay(config, sourceInfo, true) + const layersTimelineObjects = timelineObjects.filter(t => t.layer !== SharedSisyfosLLayer.SisyfosGroupStudioMics) + expect(layersTimelineObjects.length).toBe(2) + expect(layersTimelineObjects[0].layer).toBe('some_layer') + expect((layersTimelineObjects[0] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(2) + expect(layersTimelineObjects[1].layer).toBe('some_layer2') + expect((layersTimelineObjects[1] as TSR.TimelineObjSisyfosChannel).content.isPgm).toBe(2) + }) + it('Enables studio mics for replay (vo)', () => { + const sourceInfo = { + type: SourceInfoType.REPLAY, + sourceLayerType: SourceLayerType.LOCAL, + id: '1', + port: 1, + sisyfosLayers: ['some_layer', 'some_layer2'], + useStudioMics: true + } + const timelineObjects = GetSisyfosTimelineObjForReplay(config, sourceInfo, true) + expect(timelineObjects.length).toBe(3) + const studioMicsTimelineObject = timelineObjects.find(t => t.layer === SharedSisyfosLLayer.SisyfosGroupStudioMics) + expect(studioMicsTimelineObject).toBeDefined() + }) +}) diff --git a/src/tv2-common/helpers/abPlayback.ts b/src/tv2-common/helpers/abPlayback.ts index 8d5457053..db086d373 100644 --- a/src/tv2-common/helpers/abPlayback.ts +++ b/src/tv2-common/helpers/abPlayback.ts @@ -3,7 +3,7 @@ import { ITimelineEventContext, OnGenerateTimelineObj, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AbstractLLayer, MEDIA_PLAYER_AUTO, MediaPlayerClaimType } from 'tv2-constants' import * as _ from 'underscore' import { TV2BlueprintConfigBase, TV2StudioConfigBase } from '../blueprintConfig' @@ -72,20 +72,19 @@ interface SessionTime { } function calculateSessionTimeRanges( _context: ITimelineEventContext, - resolvedPieces: IBlueprintResolvedPieceInstance[] + resolvedPieces: Array> ) { const piecesWantingMediaPlayers = _.filter(resolvedPieces, p => { if (!p.piece.metaData) { return false } - const metadata = p.piece.metaData as PieceMetaData - return (metadata.mediaPlayerSessions || []).length > 0 + return (p.piece.metaData.mediaPlayerSessions || []).length > 0 }) const sessionRequests: { [sessionId: string]: SessionTime | undefined } = {} _.each(piecesWantingMediaPlayers, p => { - const metadata = p.piece.metaData as PieceMetaData - const start = p.resolvedStart as number + const metadata = p.piece.metaData! + const start = p.resolvedStart const duration = p.resolvedDuration const end = duration !== undefined ? start + duration : undefined @@ -205,7 +204,7 @@ export function resolveMediaPlayerAssignments< context: ITimelineEventContext, config: ShowStyleConfig, previousAssignmentRev: SessionToPlayerMap, - resolvedPieces: IBlueprintResolvedPieceInstance[] + resolvedPieces: Array> ) { const debugLog = config.studio.ABPlaybackDebugLogging const sessionRequests = calculateSessionTimeRanges(context, resolvedPieces) @@ -370,7 +369,7 @@ export function assignMediaPlayers< config: ShowStyleConfig, timelineObjs: OnGenerateTimelineObj[], previousAssignment: TimelinePersistentStateExt['activeMediaPlayers'], - resolvedPieces: IBlueprintResolvedPieceInstance[], + resolvedPieces: Array>, sourceLayers: ABSourceLayers ): TimelinePersistentStateExt['activeMediaPlayers'] { const previousAssignmentRev = reversePreviousAssignment(previousAssignment, timelineObjs) @@ -414,7 +413,7 @@ export function applyMediaPlayersAssignments< ) const groupedObjs = _.groupBy(labelledObjs, o => { const sessionId = (o.metaData || {}).mediaPlayerSession - if (sessionId === '' || sessionId === MEDIA_PLAYER_AUTO) { + if (sessionId === undefined || sessionId === '' || sessionId === MEDIA_PLAYER_AUTO) { const piece = resolvedPieces.find(p => p._id === o.pieceInstanceId) return piece?.infinite?.infinitePieceId || o.pieceInstanceId || MEDIA_PLAYER_AUTO } else { diff --git a/src/tv2-common/helpers/adLibNames.ts b/src/tv2-common/helpers/adLibNames.ts new file mode 100644 index 000000000..dd6e89624 --- /dev/null +++ b/src/tv2-common/helpers/adLibNames.ts @@ -0,0 +1,20 @@ +export function replaySourceFullAudioName(source: string) { + if (/EPSIO/i.test(source)) { + return source + } + return `${source} 100%` +} + +export function replaySourceVoAudioName(source: string) { + if (/EPSIO/i.test(source)) { + return source + } + return `${source} VO` +} + +export function replaySourceName(source: string, vo: boolean) { + if (/EPSIO/i.test(source)) { + return source + } + return vo ? replaySourceVoAudioName(source) : replaySourceFullAudioName(source) +} diff --git a/src/tv2-common/helpers/dsk.ts b/src/tv2-common/helpers/dsk.ts index a969ea8cc..bbf628afe 100644 --- a/src/tv2-common/helpers/dsk.ts +++ b/src/tv2-common/helpers/dsk.ts @@ -5,7 +5,7 @@ import { PieceLifespan, TableConfigItemValue, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AtemLLayerDSK, literal, SourceLayerAtemDSK } from 'tv2-common' import { AdlibTags, DSKRoles, SharedOutputLayers } from 'tv2-constants' import { ATEMModel } from '../../types/atem' @@ -94,7 +94,7 @@ export function CreateDSKBaselineAdlibs( sourceLayerId: SourceLayerAtemDSK(dsk.Number), outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.OutOnRundownChange, - tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_NO_NEXT_HIGHLIGHT], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_NO_NEXT_HIGHLIGHT, AdlibTags.ADLIB_DSK_OFF], invertOnAirState: true, content: { timelineObjects: [ @@ -122,7 +122,7 @@ export function CreateDSKBaselineAdlibs( sourceLayerId: SourceLayerAtemDSK(dsk.Number), outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.OutOnRundownChange, - tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_NO_NEXT_HIGHLIGHT], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_NO_NEXT_HIGHLIGHT, AdlibTags.ADLIB_DSK_ON], content: { timelineObjects: [ literal({ @@ -206,7 +206,7 @@ export function DSKConfigManifest(defaultVal: TableConfigItemDSK[]) { id: 'Number', name: 'Number', description: 'DSK number, starting from 1', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1, rank: 0, @@ -216,7 +216,7 @@ export function DSKConfigManifest(defaultVal: TableConfigItemDSK[]) { id: 'Fill', name: 'ATEM Fill', description: 'ATEM vision mixer input for DSK Fill', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 21, rank: 1 @@ -225,7 +225,7 @@ export function DSKConfigManifest(defaultVal: TableConfigItemDSK[]) { id: 'Key', name: 'ATEM Key', description: 'ATEM vision mixer input for DSK Key', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 34, rank: 2 diff --git a/src/tv2-common/helpers/graphics/InternalGraphic.ts b/src/tv2-common/helpers/graphics/InternalGraphic.ts new file mode 100644 index 000000000..28218ea4b --- /dev/null +++ b/src/tv2-common/helpers/graphics/InternalGraphic.ts @@ -0,0 +1,140 @@ +import { IBlueprintAdLibPiece, IBlueprintPiece, PieceLifespan } from '@tv2media/blueprints-integration' +import { Adlib } from 'tv2-common' +import _ = require('underscore') +import { AdlibTags, GraphicEngine, PartType, SharedOutputLayers, SharedSourceLayers } from '../../../tv2-constants' +import { TV2BlueprintConfig } from '../../blueprintConfig' +import { CueDefinitionGraphic, GraphicInternal, PartDefinition } from '../../inewsConversion' +import { GraphicPieceMetaData, PieceMetaData } from '../../onTimelineGenerate' +import { GetInternalGraphicContentCaspar } from './caspar' +import { GetSourceLayerForGraphic } from './layers' +import { GetFullGraphicTemplateNameFromCue, GraphicDisplayName } from './name' +import { IsTargetingTLF, IsTargetingWall } from './target' +import { CreateTimingGraphic, GetPieceLifespanForGraphic } from './timing' +import { GetInternalGraphicContentVIZ } from './viz' + +export class InternalGraphic { + public mappedTemplate: string + private readonly config: TV2BlueprintConfig + private readonly parsedCue: CueDefinitionGraphic + private readonly partDefinition?: PartDefinition + private readonly adlib?: Adlib + private readonly engine: GraphicEngine + private readonly name: string + private readonly sourceLayerId: SharedSourceLayers + private readonly outputLayerId: SharedOutputLayers + private readonly partId?: string + private readonly rank?: number + private readonly content: IBlueprintPiece['content'] + + public constructor( + config: TV2BlueprintConfig, + parsedCue: CueDefinitionGraphic, + adlib?: Adlib, + partId?: string, + partDefinition?: PartDefinition + ) { + const mappedTemplate = GetFullGraphicTemplateNameFromCue(config, parsedCue) + + const sourceLayerId = GetSourceLayerForGraphic(config, mappedTemplate) + + this.config = config + this.parsedCue = parsedCue + this.partDefinition = partDefinition + this.adlib = adlib + this.mappedTemplate = mappedTemplate + this.engine = parsedCue.target + this.name = GraphicDisplayName(config, parsedCue) + this.sourceLayerId = sourceLayerId + this.outputLayerId = IsTargetingWall(this.engine) ? SharedOutputLayers.SEC : SharedOutputLayers.OVERLAY + this.partId = partId + this.content = this.getInternalGraphicContent() + } + + public createCommentatorAdlib(): IBlueprintAdLibPiece { + return { + _rank: this.rank || 0, + externalId: this.partId ?? '', + name: this.name, + uniquenessId: `gfx_${this.name}_${this.sourceLayerId}_${this.outputLayerId}_commentator`, + sourceLayerId: this.sourceLayerId, + outputLayerId: SharedOutputLayers.OVERLAY, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, + expectedDuration: 5000, + tags: [AdlibTags.ADLIB_KOMMENTATOR], + content: _.clone(this.content) + } + } + + public createAdlib(): IBlueprintAdLibPiece { + return { + _rank: this.rank || 0, + externalId: this.partId ?? '', + name: this.name, + uniquenessId: `gfx_${this.name}_${this.sourceLayerId}_${this.outputLayerId}_flow`, + sourceLayerId: this.sourceLayerId, + outputLayerId: this.outputLayerId, + tags: [AdlibTags.ADLIB_FLOW_PRODUCER], + ...(IsTargetingTLF(this.engine) || (this.parsedCue.end && this.parsedCue.end.infiniteMode) + ? {} + : { + expectedDuration: CreateTimingGraphic(this.config, this.parsedCue).duration + }), + lifespan: GetPieceLifespanForGraphic(this.engine, this.config, this.parsedCue), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, + content: _.clone(this.content) + } + } + + public createPiece(): IBlueprintPiece { + return { + externalId: this.partId ?? '', + name: this.name, + ...(IsTargetingTLF(this.engine) || IsTargetingWall(this.engine) + ? { enable: { start: 0 } } + : { + enable: { + ...CreateTimingGraphic(this.config, this.parsedCue) + } + }), + outputLayerId: this.outputLayerId, + sourceLayerId: this.sourceLayerId, + lifespan: GetPieceLifespanForGraphic(this.engine, this.config, this.parsedCue), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: this.partDefinition?.type === PartType.REMOTE + }, + content: _.clone(this.content) + } + } + + private getInternalGraphicContent(): IBlueprintPiece['content'] { + return this.config.studio.GraphicsType === 'HTML' + ? GetInternalGraphicContentCaspar( + this.config, + this.engine, + this.parsedCue, + this.partDefinition, + this.mappedTemplate, + !!this.adlib + ) + : GetInternalGraphicContentVIZ( + this.config, + this.engine, + this.parsedCue, + this.partDefinition, + this.mappedTemplate, + !!this.adlib + ) + } +} diff --git a/src/tv2-common/helpers/graphics/caspar/index.ts b/src/tv2-common/helpers/graphics/caspar/index.ts index f4647bd58..96b34ce8b 100644 --- a/src/tv2-common/helpers/graphics/caspar/index.ts +++ b/src/tv2-common/helpers/graphics/caspar/index.ts @@ -2,12 +2,11 @@ export * from './slotMappings' import { GraphicsContent, - IBlueprintPart, IBlueprintPiece, IShowStyleUserContext, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CueDefinitionGraphic, GraphicInternal, @@ -19,7 +18,7 @@ import { TimelineBlueprintExt, TV2BlueprintConfig } from 'tv2-common' -import { GraphicEngine, GraphicLLayer } from 'tv2-constants' +import { GraphicEngine, SharedGraphicLLayer } from 'tv2-constants' import { GetEnableForGraphic, GetTimelineLayerForGraphic } from '..' import { EnableDSK } from '../../dsk' import { IsTargetingFull, IsTargetingWall } from '../target' @@ -31,25 +30,14 @@ export interface CasparPilotGeneratorSettings { export function GetInternalGraphicContentCaspar( config: TV2BlueprintConfig, - part: Readonly, engine: GraphicEngine, parsedCue: CueDefinitionGraphic, - isIdentGraphic: boolean, - partDefinition: PartDefinition, + partDefinition: PartDefinition | undefined, mappedTemplate: string, adlib: boolean ): IBlueprintPiece['content'] { return { - timelineObjects: CasparOverlayTimeline( - config, - part, - engine, - parsedCue, - isIdentGraphic, - partDefinition, - mappedTemplate, - adlib - ) + timelineObjects: CasparOverlayTimeline(config, engine, parsedCue, partDefinition, mappedTemplate, adlib) } } @@ -59,7 +47,7 @@ export function GetPilotGraphicContentCaspar( parsedCue: CueDefinitionGraphic, settings: CasparPilotGeneratorSettings, engine: GraphicEngine -) { +): WithTimeline { const graphicFolder = config.studio.GraphicFolder ? `${config.studio.GraphicFolder}\\` : '' const fileName = JoinAssetToFolder(config.studio.GraphicFolder, parsedCue.graphic.name) const templateData = { @@ -77,7 +65,7 @@ export function GetPilotGraphicContentCaspar( } } } - return literal>({ + return { fileName, path: JoinAssetToNetworkPath( config.studio.GraphicNetworkBasePath, @@ -96,7 +84,7 @@ export function GetPilotGraphicContentCaspar( while: '1' }, priority: 100, - layer: IsTargetingWall(engine) ? GraphicLLayer.GraphicLLayerWall : GraphicLLayer.GraphicLLayerPilot, + layer: IsTargetingWall(engine) ? SharedGraphicLLayer.GraphicLLayerWall : SharedGraphicLLayer.GraphicLLayerPilot, metaData: { templateData, fileName }, content: { deviceType: TSR.DeviceType.CASPARCG, @@ -112,23 +100,21 @@ export function GetPilotGraphicContentCaspar( }), ...(IsTargetingFull(engine) ? settings.createPilotTimelineForStudio(config, context) : []) ] - }) + } } function CasparOverlayTimeline( config: TV2BlueprintConfig, - part: Readonly, engine: GraphicEngine, parsedCue: CueDefinitionGraphic, - isIdentGrafik: boolean, - partDefinition: PartDefinition, + partDefinition: PartDefinition | undefined, mappedTemplate: string, adlib: boolean ): TSR.TSRTimelineObj[] { return [ literal({ id: '', - enable: GetEnableForGraphic(config, part, engine, parsedCue, isIdentGrafik, partDefinition, adlib), + enable: GetEnableForGraphic(config, engine, parsedCue, partDefinition, adlib), priority: 1, layer: GetTimelineLayerForGraphic(config, mappedTemplate), content: CreateHTMLRendererContent(config, mappedTemplate, { ...parsedCue.graphic.textFields }) diff --git a/src/tv2-common/helpers/graphics/caspar/slotMappings.ts b/src/tv2-common/helpers/graphics/caspar/slotMappings.ts index 71798f046..4eeb8c0c9 100644 --- a/src/tv2-common/helpers/graphics/caspar/slotMappings.ts +++ b/src/tv2-common/helpers/graphics/caspar/slotMappings.ts @@ -3,17 +3,17 @@ * This will go to the graphics package and become a dependency of the blueprints. */ -import { GraphicLLayer } from 'tv2-constants' +import { SharedGraphicLLayer } from 'tv2-constants' export const layerToHTMLGraphicSlot: { [slot: string]: string } = { - [GraphicLLayer.GraphicLLayerOverlay]: '', - [GraphicLLayer.GraphicLLayerOverlayIdent]: '650_ident', - [GraphicLLayer.GraphicLLayerOverlayLower]: '450_lowerThird', - [GraphicLLayer.GraphicLLayerOverlayTema]: '', - [GraphicLLayer.GraphicLLayerOverlayTopt]: '660_topt', - [GraphicLLayer.GraphicLLayerPilot]: '250_full', - [GraphicLLayer.GraphicLLayerPilotOverlay]: '250_full', - [GraphicLLayer.GraphicLLayerLocators]: '850_dve' + [SharedGraphicLLayer.GraphicLLayerOverlay]: '', + [SharedGraphicLLayer.GraphicLLayerOverlayIdent]: '650_ident', + [SharedGraphicLLayer.GraphicLLayerOverlayLower]: '450_lowerThird', + [SharedGraphicLLayer.GraphicLLayerOverlayTema]: '', + [SharedGraphicLLayer.GraphicLLayerOverlayTopt]: '660_topt', + [SharedGraphicLLayer.GraphicLLayerPilot]: '250_full', + [SharedGraphicLLayer.GraphicLLayerPilotOverlay]: '250_full', + [SharedGraphicLLayer.GraphicLLayerLocators]: '850_dve' } export interface Slots { diff --git a/src/tv2-common/helpers/graphics/design/index.ts b/src/tv2-common/helpers/graphics/design/index.ts index 255657936..2ca0b22cc 100644 --- a/src/tv2-common/helpers/graphics/design/index.ts +++ b/src/tv2-common/helpers/graphics/design/index.ts @@ -7,9 +7,9 @@ import { PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CalculateTime, CueDefinitionGraphicDesign, literal, TV2BlueprintConfig } from 'tv2-common' -import { GraphicLLayer, SharedOutputLayers, SharedSourceLayers } from 'tv2-constants' +import { SharedGraphicLLayer, SharedOutputLayers, SharedSourceLayers } from 'tv2-constants' export function EvaluateDesignBase( config: TV2BlueprintConfig, @@ -29,41 +29,37 @@ export function EvaluateDesignBase( } if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name: parsedCue.design, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SharedSourceLayers.PgmDesign, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName: parsedCue.design, - path: parsedCue.design, - ignoreMediaObjectStatus: true, - timelineObjects: designTimeline(config, parsedCue) - }) + adlibPieces.push({ + _rank: rank || 0, + externalId: partId, + name: parsedCue.design, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SharedSourceLayers.PgmDesign, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName: parsedCue.design, + path: parsedCue.design, + ignoreMediaObjectStatus: true, + timelineObjects: designTimeline(config, parsedCue) }) - ) + }) } else { - pieces.push( - literal({ - externalId: partId, - name: parsedCue.design, - enable: { - start - }, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SharedSourceLayers.PgmDesign, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName: parsedCue.design, - path: parsedCue.design, - ignoreMediaObjectStatus: true, - timelineObjects: designTimeline(config, parsedCue) - }) + pieces.push({ + externalId: partId, + name: parsedCue.design, + enable: { + start + }, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SharedSourceLayers.PgmDesign, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName: parsedCue.design, + path: parsedCue.design, + ignoreMediaObjectStatus: true, + timelineObjects: designTimeline(config, parsedCue) }) - ) + }) } } @@ -77,7 +73,7 @@ function designTimeline(config: TV2BlueprintConfig, parsedCue: CueDefinitionGrap start: 0 }, priority: 1, - layer: GraphicLLayer.GraphicLLayerDesign, + layer: SharedGraphicLLayer.GraphicLLayerDesign, content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.TEMPLATE, @@ -98,12 +94,13 @@ function designTimeline(config: TV2BlueprintConfig, parsedCue: CueDefinitionGrap id: '', enable: { start: 0 }, priority: 100, - layer: GraphicLLayer.GraphicLLayerDesign, + layer: SharedGraphicLLayer.GraphicLLayerDesign, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: parsedCue.design, - templateData: [] + templateData: [], + showId: config.selectedGraphicsSetup.OvlShowId } }) ] diff --git a/src/tv2-common/helpers/graphics/index.ts b/src/tv2-common/helpers/graphics/index.ts index 0e5b96cb7..c44b89bf7 100644 --- a/src/tv2-common/helpers/graphics/index.ts +++ b/src/tv2-common/helpers/graphics/index.ts @@ -1,6 +1,6 @@ -import { IBlueprintPart, TSR } from '@sofie-automation/blueprints-integration' +import { IBlueprintPart, TSR } from '@tv2media/blueprints-integration' import { layerToHTMLGraphicSlot, literal, TV2BlueprintConfig } from 'tv2-common' -import { GraphicLLayer } from 'tv2-constants' +import { GraphicEngine, SharedGraphicLLayer } from 'tv2-constants' export * from './name' export * from './timing' @@ -13,14 +13,19 @@ export * from './viz' export * from './design' export function ApplyFullGraphicPropertiesToPart(config: TV2BlueprintConfig, part: IBlueprintPart) { - part.prerollDuration = - config.studio.GraphicsType === 'HTML' - ? config.studio.CasparPrerollDuration - : config.studio.VizPilotGraphics.PrerollDuration - part.transitionKeepaliveDuration = + const keepAliveDuration = config.studio.GraphicsType === 'HTML' ? config.studio.HTMLGraphics.KeepAliveDuration : config.studio.VizPilotGraphics.KeepAliveDuration + if (part.inTransition === undefined) { + part.inTransition = { + partContentDelayDuration: 0, + blockTakeDuration: 0, + previousPartKeepaliveDuration: keepAliveDuration + } + } else { + part.inTransition.previousPartKeepaliveDuration = keepAliveDuration + } } export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimelineObj[] { @@ -29,11 +34,11 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli } else { const slotBaselineObjects: TSR.TSRTimelineObj[] = [] ;[ - GraphicLLayer.GraphicLLayerOverlayIdent, - GraphicLLayer.GraphicLLayerOverlayLower, - GraphicLLayer.GraphicLLayerOverlayTema, - GraphicLLayer.GraphicLLayerOverlayTopt, - GraphicLLayer.GraphicLLayerLocators + SharedGraphicLLayer.GraphicLLayerOverlayIdent, + SharedGraphicLLayer.GraphicLLayerOverlayLower, + SharedGraphicLLayer.GraphicLLayerOverlayTema, + SharedGraphicLLayer.GraphicLLayerOverlayTopt, + SharedGraphicLLayer.GraphicLLayerLocators ].forEach(layer => { if (layerToHTMLGraphicSlot[layer]) { slotBaselineObjects.push( @@ -74,7 +79,7 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli while: '1' }, priority: 0, - layer: GraphicLLayer.GraphicLLayerOverlay, + layer: SharedGraphicLLayer.GraphicLLayerOverlay, content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.TEMPLATE, @@ -83,11 +88,11 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli data: { display: 'program', slots: [ - GraphicLLayer.GraphicLLayerOverlayIdent, - GraphicLLayer.GraphicLLayerOverlayLower, - GraphicLLayer.GraphicLLayerOverlayTema, - GraphicLLayer.GraphicLLayerOverlayTopt, - GraphicLLayer.GraphicLLayerLocators + SharedGraphicLLayer.GraphicLLayerOverlayIdent, + SharedGraphicLLayer.GraphicLLayerOverlayLower, + SharedGraphicLLayer.GraphicLLayerOverlayTema, + SharedGraphicLLayer.GraphicLLayerOverlayTopt, + SharedGraphicLLayer.GraphicLLayerLocators ].reduce((obj: Record, layer) => { if (layerToHTMLGraphicSlot[layer]) { obj[layerToHTMLGraphicSlot[layer]] = { @@ -108,7 +113,7 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli while: '1' }, priority: 0, - layer: GraphicLLayer.GraphicLLayerDesign, + layer: SharedGraphicLLayer.GraphicLLayerDesign, content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.TEMPLATE, @@ -128,7 +133,7 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli while: '1' }, priority: 0, - layer: GraphicLLayer.GraphicLLayerPilot, + layer: SharedGraphicLLayer.GraphicLLayerPilot, content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.TEMPLATE, @@ -137,7 +142,7 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli data: { display: 'program', slots: { - [layerToHTMLGraphicSlot[GraphicLLayer.GraphicLLayerPilot]]: { + [layerToHTMLGraphicSlot[SharedGraphicLLayer.GraphicLLayerPilot]]: { payload: {}, display: 'hidden' } @@ -149,3 +154,15 @@ export function CreateGraphicBaseline(config: TV2BlueprintConfig): TSR.TSRTimeli ] } } + +export function findShowId(config: TV2BlueprintConfig, engine: GraphicEngine): string { + const graphicsSetup = config.selectedGraphicsSetup + switch (engine) { + case 'FULL': + case 'WALL': + return graphicsSetup.FullShowId + case 'TLF': + case 'OVL': + return graphicsSetup.OvlShowId + } +} diff --git a/src/tv2-common/helpers/graphics/internal/index.ts b/src/tv2-common/helpers/graphics/internal/index.ts index 85fa1cd16..a38bd8cf8 100644 --- a/src/tv2-common/helpers/graphics/internal/index.ts +++ b/src/tv2-common/helpers/graphics/internal/index.ts @@ -1,175 +1,37 @@ +import { IBlueprintAdLibPiece, IBlueprintPiece, IShowStyleUserContext } from '@tv2media/blueprints-integration' import { - IBlueprintActionManifest, - IBlueprintAdLibPiece, - IBlueprintPart, - IBlueprintPiece, - IShowStyleUserContext, - PieceLifespan, - TSR -} from '@sofie-automation/blueprints-integration' -import { + Adlib, CueDefinitionGraphic, - GetDefaultOut, GraphicInternal, - IsStickyIdent, - literal, + IsTargetingOVL, PartDefinition, TV2BlueprintConfig } from 'tv2-common' -import { AbstractLLayer, AdlibTags, SharedOutputLayers, SharedSourceLayers } from 'tv2-constants' -import _ = require('underscore') -import { - CreateTimingGraphic, - GetFullGraphicTemplateNameFromCue, - GetInfiniteModeForGraphic, - GetSourceLayerForGraphic, - GraphicDisplayName, - IsTargetingOVL, - IsTargetingTLF, - IsTargetingWall -} from '..' -import { GetInternalGraphicContentCaspar } from '../caspar' -import { GetInternalGraphicContentVIZ } from '../viz' +import { InternalGraphic } from '../InternalGraphic' export function CreateInternalGraphic( config: TV2BlueprintConfig, context: IShowStyleUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], - _actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionGraphic, - adlib: boolean, partDefinition: PartDefinition, - rank?: number + adlib?: Adlib ) { - // Whether this graphic "sticks" to the source it was first assigned to. - // e.g. if this is attached to Live 1, when Live 1 is recalled later in a segment, - // this graphic should be shown again. - const isStickyIdent = IsStickyIdent(parsedCue) + const internalGraphic: InternalGraphic = new InternalGraphic(config, parsedCue, adlib, partId, partDefinition) - const mappedTemplate = GetFullGraphicTemplateNameFromCue(config, parsedCue) - - if (!mappedTemplate || !mappedTemplate.length) { + if (!internalGraphic.mappedTemplate || !internalGraphic.mappedTemplate.length) { context.notifyUserWarning(`No valid template found for ${parsedCue.graphic.template}`) return } - const engine = parsedCue.target - - const sourceLayerId = IsTargetingTLF(engine) - ? SharedSourceLayers.PgmGraphicsTLF - : GetSourceLayerForGraphic(config, mappedTemplate, isStickyIdent) - - const outputLayerId = IsTargetingWall(engine) ? SharedOutputLayers.SEC : SharedOutputLayers.OVERLAY - - const name = GraphicDisplayName(config, parsedCue) - - const content = - config.studio.GraphicsType === 'HTML' - ? GetInternalGraphicContentCaspar( - config, - part, - engine, - parsedCue, - isStickyIdent, - partDefinition, - mappedTemplate, - adlib - ) - : GetInternalGraphicContentVIZ( - config, - part, - engine, - parsedCue, - isStickyIdent, - partDefinition, - mappedTemplate, - adlib - ) - if (adlib) { - if (IsTargetingOVL(engine)) { - const adLibPiece = literal({ - _rank: rank || 0, - externalId: partId, - name, - uniquenessId: `gfx_${name}_${sourceLayerId}_${outputLayerId}_commentator`, - sourceLayerId, - outputLayerId: SharedOutputLayers.OVERLAY, - lifespan: PieceLifespan.WithinPart, - expectedDuration: 5000, - tags: [AdlibTags.ADLIB_KOMMENTATOR], - content: _.clone(content), - noHotKey: true - }) - adlibPieces.push(adLibPiece) + if (IsTargetingOVL(parsedCue.target)) { + adlibPieces.push(internalGraphic.createCommentatorAdlib()) } - - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name, - uniquenessId: `gfx_${name}_${sourceLayerId}_${outputLayerId}_flow`, - sourceLayerId, - outputLayerId, - tags: [AdlibTags.ADLIB_FLOW_PRODUCER], - ...(IsTargetingTLF(engine) || (parsedCue.end && parsedCue.end.infiniteMode) - ? {} - : { expectedDuration: CreateTimingGraphic(config, parsedCue).duration || GetDefaultOut(config) }), - lifespan: GetInfiniteModeForGraphic(engine, config, parsedCue, isStickyIdent), - content: _.clone(content) - }) - ) + adlibPieces.push(internalGraphic.createAdlib()) } else { - const piece = literal({ - externalId: partId, - name, - ...(IsTargetingTLF(engine) || IsTargetingWall(engine) - ? { enable: { start: 0 } } - : { - enable: { - ...CreateTimingGraphic(config, parsedCue, !isStickyIdent) - } - }), - outputLayerId, - sourceLayerId, - lifespan: GetInfiniteModeForGraphic(engine, config, parsedCue, isStickyIdent), - content: _.clone(content) - }) - pieces.push(piece) - - if ( - sourceLayerId === SharedSourceLayers.PgmGraphicsIdentPersistent && - (piece.lifespan === PieceLifespan.OutOnSegmentEnd || piece.lifespan === PieceLifespan.OutOnShowStyleEnd) && - isStickyIdent - ) { - // Special case for the ident. We want it to continue to exist in case the Live gets shown again, but we dont want the continuation showing in the ui. - // So we create the normal object on a hidden layer, and then clone it on another layer without content for the ui - pieces.push( - literal({ - ...piece, - enable: { ...CreateTimingGraphic(config, parsedCue, true) }, // Allow default out for visual representation - sourceLayerId: SharedSourceLayers.PgmGraphicsIdent, - lifespan: PieceLifespan.WithinPart, - content: { - timelineObjects: [ - literal({ - id: '', - enable: { - while: '1' - }, - layer: AbstractLLayer.IdentMarker, - content: { - deviceType: TSR.DeviceType.ABSTRACT - } - }) - ] - } - }) - ) - } + pieces.push(internalGraphic.createPiece()) } } diff --git a/src/tv2-common/helpers/graphics/layers.ts b/src/tv2-common/helpers/graphics/layers.ts index 308cfaf59..54e914b0a 100644 --- a/src/tv2-common/helpers/graphics/layers.ts +++ b/src/tv2-common/helpers/graphics/layers.ts @@ -1,7 +1,7 @@ import { TV2BlueprintConfig } from 'tv2-common' -import { GraphicLLayer, SharedSourceLayers } from 'tv2-constants' +import { SharedGraphicLLayer, SharedSourceLayers } from 'tv2-constants' -export function GetSourceLayerForGraphic(config: TV2BlueprintConfig, name: string, isStickyIdent?: boolean) { +export function GetSourceLayerForGraphic(config: TV2BlueprintConfig, name: string) { const conf = config.showStyle.GFXTemplates ? config.showStyle.GFXTemplates.find(gfk => gfk.VizTemplate.toString() === name) : undefined @@ -19,10 +19,6 @@ export function GetSourceLayerForGraphic(config: TV2BlueprintConfig, name: strin } return SharedSourceLayers.PgmGraphicsHeadline case SharedSourceLayers.PgmGraphicsIdent: - if (isStickyIdent) { - return SharedSourceLayers.PgmGraphicsIdentPersistent - } - return SharedSourceLayers.PgmGraphicsIdent case SharedSourceLayers.PgmGraphicsLower: return SharedSourceLayers.PgmGraphicsLower @@ -47,29 +43,29 @@ export function GetTimelineLayerForGraphic(config: TV2BlueprintConfig, name: str : undefined if (!conf) { - return GraphicLLayer.GraphicLLayerOverlay + return SharedGraphicLLayer.GraphicLLayerOverlay } switch (conf.LayerMapping) { // TODO: When adding more output layers - case GraphicLLayer.GraphicLLayerOverlayIdent: - return GraphicLLayer.GraphicLLayerOverlayIdent - case GraphicLLayer.GraphicLLayerOverlayTopt: - return GraphicLLayer.GraphicLLayerOverlayTopt - case GraphicLLayer.GraphicLLayerOverlayLower: - return GraphicLLayer.GraphicLLayerOverlayLower - case GraphicLLayer.GraphicLLayerOverlayHeadline: + case SharedGraphicLLayer.GraphicLLayerOverlayIdent: + return SharedGraphicLLayer.GraphicLLayerOverlayIdent + case SharedGraphicLLayer.GraphicLLayerOverlayTopt: + return SharedGraphicLLayer.GraphicLLayerOverlayTopt + case SharedGraphicLLayer.GraphicLLayerOverlayLower: + return SharedGraphicLLayer.GraphicLLayerOverlayLower + case SharedGraphicLLayer.GraphicLLayerOverlayHeadline: if (config.studio.GraphicsType === 'HTML') { - return GraphicLLayer.GraphicLLayerOverlayLower + return SharedGraphicLLayer.GraphicLLayerOverlayLower } - return GraphicLLayer.GraphicLLayerOverlayHeadline - case GraphicLLayer.GraphicLLayerOverlayTema: - return GraphicLLayer.GraphicLLayerOverlayTema - case GraphicLLayer.GraphicLLayerWall: - return GraphicLLayer.GraphicLLayerWall - case GraphicLLayer.GraphicLLayerLocators: - return GraphicLLayer.GraphicLLayerLocators + return SharedGraphicLLayer.GraphicLLayerOverlayHeadline + case SharedGraphicLLayer.GraphicLLayerOverlayTema: + return SharedGraphicLLayer.GraphicLLayerOverlayTema + case SharedGraphicLLayer.GraphicLLayerWall: + return SharedGraphicLLayer.GraphicLLayerWall + case SharedGraphicLLayer.GraphicLLayerLocators: + return SharedGraphicLLayer.GraphicLLayerLocators default: - return GraphicLLayer.GraphicLLayerOverlay + return SharedGraphicLLayer.GraphicLLayerOverlay } } diff --git a/src/tv2-common/helpers/graphics/name.ts b/src/tv2-common/helpers/graphics/name.ts index 63329eb42..e4a8bed78 100644 --- a/src/tv2-common/helpers/graphics/name.ts +++ b/src/tv2-common/helpers/graphics/name.ts @@ -34,13 +34,11 @@ export function GetFullGraphicTemplateNameFromCue( } export function GetFullGrafikTemplateName(config: TV2BlueprintConfig, iNewsTempalateName: string): string { - if (config.showStyle.GFXTemplates) { - const template = config.showStyle.GFXTemplates.find(templ => - templ.INewsName ? templ.INewsName.toString().toUpperCase() === iNewsTempalateName.toUpperCase() : false - ) - if (template && template.VizTemplate.toString().length) { - return template.VizTemplate.toString() - } + const template = config.showStyle.GFXTemplates.find(templ => + templ.INewsName ? templ.INewsName.toString().toUpperCase() === iNewsTempalateName.toUpperCase() : false + ) + if (template && template.VizTemplate.toString().length) { + return template.VizTemplate.toString() } // This means unconfigured templates will still be supported, with default out. diff --git a/src/tv2-common/helpers/graphics/pilot/index.ts b/src/tv2-common/helpers/graphics/pilot/index.ts index 273065dbb..5308631c5 100644 --- a/src/tv2-common/helpers/graphics/pilot/index.ts +++ b/src/tv2-common/helpers/graphics/pilot/index.ts @@ -2,19 +2,21 @@ import { GraphicsContent, IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, IShowStyleUserContext, PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectFullGrafik, + Adlib, CreateTimingGraphic, CueDefinitionGraphic, + FullPieceMetaData, + generateExternalId, GetFullGraphicTemplateNameFromCue, - GetInfiniteModeForGraphic, + GetPieceLifespanForGraphic, GetPilotGraphicContentViz, GetTagForFull, GetTagForFullNext, @@ -25,6 +27,8 @@ import { IsTargetingTLF, IsTargetingWall, literal, + PieceMetaData, + SisyfosPersistMetaData, TV2BlueprintConfig } from 'tv2-common' import { @@ -45,20 +49,24 @@ export interface PilotGeneratorSettings { viz: VizPilotGeneratorSettings } +export interface PilotGraphicProps { + config: TV2BlueprintConfig + context: IShowStyleUserContext + engine: GraphicEngine + partId: string + parsedCue: CueDefinitionGraphic + settings: PilotGeneratorSettings + adlib?: Adlib + segmentExternalId: string +} + export function CreatePilotGraphic( - config: TV2BlueprintConfig, - context: IShowStyleUserContext, - part: Readonly, pieces: IBlueprintPiece[], - _adlibPieces: IBlueprintAdLibPiece[], + adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], - partId: string, - parsedCue: CueDefinitionGraphic, - settings: PilotGeneratorSettings, - adlib: boolean, - adlibRank: number, - externalSegmentId: string + pilotGraphicProps: PilotGraphicProps ) { + const { context, engine, adlib, parsedCue } = pilotGraphicProps if ( parsedCue.graphic.vcpid === undefined || parsedCue.graphic.vcpid === null || @@ -69,171 +77,186 @@ export function CreatePilotGraphic( return } - const engine = parsedCue.target - - if (IsTargetingFull(engine)) { - actions.push( - CreatePilotAdLibAction(config, context, parsedCue, engine, settings, adlib, adlibRank, externalSegmentId) - ) - } + const generator = new PilotGraphicGenerator(pilotGraphicProps) - if (!(IsTargetingOVL(engine) && adlib)) { - pieces.push(CreateFullPiece(config, context, part, partId, parsedCue, engine, settings, adlib, externalSegmentId)) + if (IsTargetingOVL(engine) && adlib) { + adlibPieces.push(generator.createAdlibPiece()) + } else { + pieces.push(generator.createPiece()) } if (IsTargetingFull(engine)) { - pieces.push( - CreateFullDataStore(config, context, part, settings, parsedCue, engine, partId, adlib, externalSegmentId) - ) + actions.push(generator.createPilotAdLibAction()) + pieces.push(generator.createFullDataStore()) } } -function CreatePilotAdLibAction( - config: TV2BlueprintConfig, - context: IShowStyleUserContext, - parsedCue: CueDefinitionGraphic, - engine: GraphicEngine, - settings: PilotGeneratorSettings, - adlib: boolean, - adlibRank: number, - segmentExternalId: string -) { - const name = GraphicDisplayName(config, parsedCue) - const sourceLayerId = GetSourceLayer(engine) - const outputLayerId = GetOutputLayer(engine) +export class PilotGraphicGenerator { + private readonly config: TV2BlueprintConfig + private readonly context: IShowStyleUserContext + private readonly engine: GraphicEngine + private readonly partId: string + private readonly parsedCue: CueDefinitionGraphic + private readonly settings: PilotGeneratorSettings + private readonly adlib?: Adlib + private readonly segmentExternalId: string + + constructor(graphicProps: PilotGraphicProps) { + this.config = graphicProps.config + this.context = graphicProps.context + this.engine = graphicProps.engine + this.parsedCue = graphicProps.parsedCue + this.partId = graphicProps.partId + this.settings = graphicProps.settings + this.adlib = graphicProps.adlib + this.segmentExternalId = graphicProps.segmentExternalId + } - return literal({ - actionId: AdlibActionType.SELECT_FULL_GRAFIK, - userData: literal({ + public createPilotAdLibAction(): IBlueprintActionManifest { + const name = GraphicDisplayName(this.config, this.parsedCue) + const sourceLayerId = this.getSourceLayer() + const outputLayerId = this.getOutputLayer() + + const userData: ActionSelectFullGrafik = { type: AdlibActionType.SELECT_FULL_GRAFIK, - name: parsedCue.graphic.name, - vcpid: parsedCue.graphic.vcpid, - segmentExternalId - }), - userDataManifest: {}, - display: { - _rank: adlibRank, - label: t(GetFullGraphicTemplateNameFromCue(config, parsedCue)), - sourceLayerId: SharedSourceLayers.PgmPilot, - outputLayerId: SharedOutputLayers.PGM, - content: { - ...CreateFullContent(config, context, undefined, settings, parsedCue, engine, adlib) + name: this.parsedCue.graphic.name, + vcpid: this.parsedCue.graphic.vcpid, + segmentExternalId: this.segmentExternalId + } + return { + externalId: generateExternalId(this.context, userData), + actionId: AdlibActionType.SELECT_FULL_GRAFIK, + userData, + userDataManifest: {}, + display: { + _rank: (this.adlib && this.adlib.rank) || 0, + label: t(GetFullGraphicTemplateNameFromCue(this.config, this.parsedCue)), + sourceLayerId: SharedSourceLayers.PgmPilot, + outputLayerId: SharedOutputLayers.PGM, + content: this.createContent(), + uniquenessId: `gfx_${name}_${sourceLayerId}_${outputLayerId}`, + tags: [ + AdlibTags.ADLIB_KOMMENTATOR, + ...(this.config.showStyle.MakeAdlibsForFulls && IsTargetingFull(this.engine) + ? [AdlibTags.ADLIB_FLOW_PRODUCER] + : []) + ], + currentPieceTags: [GetTagForFull(this.segmentExternalId, this.parsedCue.graphic.vcpid)], + nextPieceTags: [GetTagForFullNext(this.segmentExternalId, this.parsedCue.graphic.vcpid)] + } + } + } + + public createPiece(): IBlueprintPiece { + return { + externalId: this.partId, + name: GraphicDisplayName(this.config, this.parsedCue), + ...(IsTargetingFull(this.engine) || IsTargetingWall(this.engine) + ? { enable: { start: 0 } } + : { + enable: { + ...CreateTimingGraphic(this.config, this.parsedCue) + } + }), + outputLayerId: this.getOutputLayer(), + sourceLayerId: this.getSourceLayer(), + prerollDuration: this.getPrerollDuration(), + lifespan: GetPieceLifespanForGraphic(this.engine, this.config, this.parsedCue), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } }, - uniquenessId: `gfx_${name}_${sourceLayerId}_${outputLayerId}`, - tags: [ - AdlibTags.ADLIB_KOMMENTATOR, - ...(config.showStyle.MakeAdlibsForFulls && IsTargetingFull(engine) ? [AdlibTags.ADLIB_FLOW_PRODUCER] : []) - ], - currentPieceTags: [GetTagForFull(segmentExternalId, parsedCue.graphic.vcpid)], - nextPieceTags: [GetTagForFullNext(segmentExternalId, parsedCue.graphic.vcpid)], - noHotKey: !(config.showStyle.MakeAdlibsForFulls && IsTargetingFull(engine)) + content: this.createContent(), + tags: IsTargetingFull(this.engine) + ? [GetTagForFull(this.segmentExternalId, this.parsedCue.graphic.vcpid), TallyTags.FULL_IS_LIVE] + : [] } - }) -} + } -export function CreateFullPiece( - config: TV2BlueprintConfig, - context: IShowStyleUserContext, - part: Readonly, - partId: string, - parsedCue: CueDefinitionGraphic, - engine: GraphicEngine, - settings: PilotGeneratorSettings, - adlib: boolean, - segmentExternalId: string -): IBlueprintPiece { - return literal({ - externalId: partId, - name: GraphicDisplayName(config, parsedCue), - ...(IsTargetingFull(engine) || IsTargetingWall(engine) - ? { enable: { start: 0 } } - : { - enable: { - ...CreateTimingGraphic(config, parsedCue) - } - }), - outputLayerId: GetOutputLayer(engine), - sourceLayerId: GetSourceLayer(engine), - adlibPreroll: config.studio.VizPilotGraphics.PrerollDuration, - lifespan: GetInfiniteModeForGraphic(engine, config, parsedCue), - content: CreateFullContent(config, context, part, settings, parsedCue, engine, adlib), - tags: [GetTagForFull(segmentExternalId, parsedCue.graphic.vcpid), TallyTags.FULL_IS_LIVE] - }) -} + public createAdlibPiece(rank?: number): IBlueprintAdLibPiece { + const pilotPiece = this.createPiece() + pilotPiece.tags = [...(pilotPiece.tags ?? []), AdlibTags.ADLIB_FLOW_PRODUCER] + return { + ...pilotPiece, + _rank: rank ?? 0 + } + } -export function CreateFullDataStore( - config: TV2BlueprintConfig, - context: IShowStyleUserContext, - part: Readonly, - settings: PilotGeneratorSettings, - parsedCue: CueDefinitionGraphic, - engine: GraphicEngine, - partId: string, - adlib: boolean, - segmentExternalId: string -): IBlueprintPiece { - const content = CreateFullContent(config, context, part, settings, parsedCue, engine, adlib) - content.timelineObjects = content.timelineObjects.filter( - o => - o.content.deviceType !== TSR.DeviceType.ATEM && - o.content.deviceType !== TSR.DeviceType.SISYFOS && - o.content.deviceType !== TSR.DeviceType.VIZMSE && - o.content.deviceType !== TSR.DeviceType.CASPARCG - ) - return literal({ - externalId: partId, - name: GraphicDisplayName(config, parsedCue), - enable: { - start: 0 - }, - outputLayerId: SharedOutputLayers.SELECTED_ADLIB, - sourceLayerId: SharedSourceLayers.SelectedAdlibGraphicsFull, - lifespan: PieceLifespan.OutOnSegmentEnd, - metaData: { - userData: literal({ - type: AdlibActionType.SELECT_FULL_GRAFIK, - name: parsedCue.graphic.name, - vcpid: parsedCue.graphic.vcpid, - segmentExternalId - }) - }, - content, - tags: [GetTagForFullNext(segmentExternalId, parsedCue.graphic.vcpid)] - }) -} + public createFullDataStore(): IBlueprintPiece { + const content = this.createContent() + content.timelineObjects = content.timelineObjects.filter( + o => + o.content.deviceType !== TSR.DeviceType.ATEM && + o.content.deviceType !== TSR.DeviceType.SISYFOS && + o.content.deviceType !== TSR.DeviceType.VIZMSE && + o.content.deviceType !== TSR.DeviceType.CASPARCG + ) + return { + externalId: this.partId, + name: GraphicDisplayName(this.config, this.parsedCue), + enable: { + start: 0 + }, + outputLayerId: SharedOutputLayers.SELECTED_ADLIB, + sourceLayerId: SharedSourceLayers.SelectedAdlibGraphicsFull, + lifespan: PieceLifespan.OutOnSegmentEnd, + metaData: { + userData: { + type: AdlibActionType.SELECT_FULL_GRAFIK, + name: this.parsedCue.graphic.name, + vcpid: this.parsedCue.graphic.vcpid, + segmentExternalId: this.segmentExternalId + }, + sisyfosPersistMetaData: literal({ + sisyfosLayers: [] + }) + }, + content, + tags: [GetTagForFullNext(this.segmentExternalId, this.parsedCue.graphic.vcpid)] + } + } -function CreateFullContent( - config: TV2BlueprintConfig, - context: IShowStyleUserContext, - part: Readonly | undefined, - settings: PilotGeneratorSettings, - cue: CueDefinitionGraphic, - engine: GraphicEngine, - adlib: boolean -): WithTimeline { - if (config.studio.GraphicsType === 'HTML') { - return GetPilotGraphicContentCaspar(config, context, cue, settings.caspar, engine) - } else { - return GetPilotGraphicContentViz(config, part, context, settings.viz, cue, engine, adlib) + private createContent(): WithTimeline { + if (this.config.studio.GraphicsType === 'HTML') { + return GetPilotGraphicContentCaspar(this.config, this.context, this.parsedCue, this.settings.caspar, this.engine) + } else { + return GetPilotGraphicContentViz( + this.config, + this.context, + this.settings.viz, + this.parsedCue, + this.engine, + this.adlib + ) + } } -} -function GetSourceLayer(engine: GraphicEngine): SharedSourceLayers { - return IsTargetingWall(engine) - ? SharedSourceLayers.WallGraphics - : IsTargetingTLF(engine) - ? SharedSourceLayers.PgmGraphicsTLF - : IsTargetingOVL(engine) - ? SharedSourceLayers.PgmPilotOverlay - : SharedSourceLayers.PgmPilot -} + private getPrerollDuration(): number { + return this.config.studio.GraphicsType === 'HTML' + ? this.config.studio.CasparPrerollDuration + : this.config.studio.VizPilotGraphics.PrerollDuration + } + + private getSourceLayer(): SharedSourceLayers { + const engine = this.engine + return IsTargetingWall(engine) + ? SharedSourceLayers.WallGraphics + : IsTargetingTLF(engine) + ? SharedSourceLayers.PgmGraphicsTLF + : IsTargetingOVL(engine) + ? SharedSourceLayers.PgmPilotOverlay + : SharedSourceLayers.PgmPilot + } -function GetOutputLayer(engine: GraphicEngine) { - return IsTargetingWall(engine) - ? SharedOutputLayers.SEC - : IsTargetingOVL(engine) - ? SharedOutputLayers.OVERLAY - : IsTargetingFull(engine) - ? SharedOutputLayers.PGM - : SharedOutputLayers.OVERLAY + private getOutputLayer() { + const engine = this.engine + return IsTargetingWall(engine) + ? SharedOutputLayers.SEC + : IsTargetingOVL(engine) + ? SharedOutputLayers.OVERLAY + : IsTargetingFull(engine) + ? SharedOutputLayers.PGM + : SharedOutputLayers.OVERLAY + } } diff --git a/src/tv2-common/helpers/graphics/timing.ts b/src/tv2-common/helpers/graphics/timing.ts index a4b8fbfb4..3bfd74a9a 100644 --- a/src/tv2-common/helpers/graphics/timing.ts +++ b/src/tv2-common/helpers/graphics/timing.ts @@ -1,4 +1,4 @@ -import { IBlueprintPart, PieceLifespan, TSR } from '@sofie-automation/blueprints-integration' +import { PieceLifespan, TSR } from '@tv2media/blueprints-integration' import { CalculateTime, CreateTimingEnable, @@ -10,104 +10,82 @@ import { LifeSpan, PartDefinition, PartToParentClass, + TableConfigItemGFXTemplates, TV2BlueprintConfig } from 'tv2-common' -import { ControlClasses, GraphicEngine } from 'tv2-constants' +import { GraphicEngine } from 'tv2-constants' import { GetFullGraphicTemplateNameFromCue, IsTargetingTLF, IsTargetingWall } from '.' -export function GetInfiniteModeForGraphic( +export function GetPieceLifespanForGraphic( engine: GraphicEngine, config: TV2BlueprintConfig, - parsedCue: CueDefinitionGraphic, - isStickyIdent?: boolean + parsedCue: CueDefinitionGraphic ): PieceLifespan { - return IsTargetingWall(engine) - ? PieceLifespan.OutOnShowStyleEnd - : IsTargetingTLF(engine) - ? PieceLifespan.WithinPart - : isStickyIdent - ? PieceLifespan.OutOnSegmentEnd - : parsedCue.end && parsedCue.end.infiniteMode - ? LifeSpan(parsedCue.end.infiniteMode, PieceLifespan.WithinPart) - : FindInfiniteModeFromConfig(config, parsedCue) + if (IsTargetingWall(engine)) { + return PieceLifespan.OutOnShowStyleEnd + } + if (IsTargetingTLF(engine)) { + return PieceLifespan.WithinPart + } + if (parsedCue.end && parsedCue.end.infiniteMode) { + return LifeSpan(parsedCue.end.infiniteMode, PieceLifespan.WithinPart) + } + return FindInfiniteModeFromConfig(config, parsedCue) } export function FindInfiniteModeFromConfig( config: TV2BlueprintConfig, parsedCue: CueDefinitionGraphic ): PieceLifespan { - if (config.showStyle.GFXTemplates) { - const template = GetFullGraphicTemplateNameFromCue(config, parsedCue) - const iNewsName = GraphicIsInternal(parsedCue) ? parsedCue.graphic.template : undefined - const conf = config.showStyle.GFXTemplates.find(cnf => - cnf.VizTemplate - ? cnf.VizTemplate.toString().toUpperCase() === template.toUpperCase() && - (iNewsName ? cnf.INewsName.toUpperCase() === iNewsName.toUpperCase() : true) - : false - ) - - if (!conf) { - return PieceLifespan.WithinPart - } - - if (!conf.OutType || !conf.OutType.toString().length) { - return PieceLifespan.WithinPart - } + const template = GetFullGraphicTemplateNameFromCue(config, parsedCue) + const iNewsName = GraphicIsInternal(parsedCue) ? parsedCue.graphic.template : undefined + const conf = config.showStyle.GFXTemplates.find(cnf => + cnf.VizTemplate + ? cnf.VizTemplate.toString().toUpperCase() === template.toUpperCase() && + (iNewsName ? cnf.INewsName.toUpperCase() === iNewsName.toUpperCase() : true) + : false + ) + + if (!conf) { + return PieceLifespan.WithinPart + } - const type = conf.OutType.toString().toUpperCase() + if (!conf.OutType || !conf.OutType.toString().length) { + return PieceLifespan.WithinPart + } - if (type !== 'B' && type !== 'S' && type !== 'O') { - return PieceLifespan.WithinPart - } + const type = conf.OutType.toString().toUpperCase() - return LifeSpan(type, PieceLifespan.WithinPart) + if (type !== 'B' && type !== 'S' && type !== 'O') { + return PieceLifespan.WithinPart } - return PieceLifespan.WithinPart + return LifeSpan(type, PieceLifespan.WithinPart) } export function GetGraphicDuration( config: TV2BlueprintConfig, - cue: CueDefinitionGraphic, - defaultTime: boolean + cue: CueDefinitionGraphic ): number | undefined { if (config.showStyle.GFXTemplates) { - if (GraphicIsInternal(cue)) { - const template = config.showStyle.GFXTemplates.find(templ => - templ.INewsName ? templ.INewsName.toString().toUpperCase() === cue.graphic.template.toUpperCase() : false - ) - if (template) { - if (template.OutType && !template.OutType.toString().match(/default/i)) { - return undefined - } - } - } else if (GraphicIsPilot(cue)) { - const template = config.showStyle.GFXTemplates.find(templ => - templ.INewsName - ? templ.INewsName.toString().toUpperCase() === cue.graphic.vcpid.toString().toUpperCase() - : false - ) - if (template) { - if (template.OutType && !template.OutType.toString().match(/default/i)) { - return undefined - } - } + const template = findGFXTemplate(config, cue) + if (template && template.OutType && !template.OutType.toString().match(/default/i)) { + return undefined } } - return defaultTime ? GetDefaultOut(config) : undefined + return GetDefaultOut(config) } export function CreateTimingGraphic( config: TV2BlueprintConfig, - cue: CueDefinitionGraphic, - defaultTime: boolean = true + cue: CueDefinitionGraphic ): { start: number; duration?: number } { const ret: { start: number; duration?: number } = { start: 0, duration: 0 } const start = cue.start ? CalculateTime(cue.start) : 0 start !== undefined ? (ret.start = start) : (ret.start = 0) - const duration = GetGraphicDuration(config, cue, defaultTime) + const duration = GetGraphicDuration(config, cue) const end = cue.end ? cue.end.infiniteMode ? undefined @@ -120,47 +98,48 @@ export function CreateTimingGraphic( return ret } -export function GetPartPrerollDuration(part: Readonly> | undefined): number { - return (part && (part.transitionPrerollDuration || part.prerollDuration)) || 0 +export function GetEnableForWall(): TSR.TSRTimelineObj['enable'] { + return { + while: '1' + } } -export function GetEnableForWall(part: Readonly> | undefined): TSR.TSRTimelineObj['enable'] { - const partPrerollDuration = GetPartPrerollDuration(part) - return partPrerollDuration - ? { start: partPrerollDuration } - : { - while: '1' - } +export function findGFXTemplate( + config: TV2BlueprintConfig, + cue: CueDefinitionGraphic +): TableConfigItemGFXTemplates | undefined { + let graphicId: string | undefined + if (GraphicIsInternal(cue)) { + graphicId = cue.graphic.template + } else if (GraphicIsPilot(cue)) { + graphicId = cue.graphic.vcpid.toString() + } + if (graphicId === undefined) { + return undefined + } + return config.showStyle.GFXTemplates.find(templ => + templ.INewsName ? templ.INewsName.toString().toUpperCase() === graphicId?.toUpperCase() : false + ) } - export function GetEnableForGraphic( config: TV2BlueprintConfig, - part: Readonly | undefined, engine: GraphicEngine, cue: CueDefinitionGraphic, - isStickyIdent: boolean, partDefinition?: PartDefinition, adlib?: boolean ): TSR.TSRTimelineObj['enable'] { if (IsTargetingWall(engine)) { - return GetEnableForWall(part) + return GetEnableForWall() } if ( - ((cue.end && cue.end.infiniteMode && cue.end.infiniteMode === 'B') || - GetInfiniteModeForGraphic(engine, config, cue, isStickyIdent) === PieceLifespan.OutOnSegmentEnd) && partDefinition && + (endsOnPartEnd(config, cue) || GetPieceLifespanForGraphic(engine, config, cue) === PieceLifespan.OutOnSegmentEnd) && !adlib ) { return { while: `.${PartToParentClass('studio0', partDefinition)} & !.adlib_deparent & !.full` } } - if (isStickyIdent) { - return { - while: `.${ControlClasses.ShowIdentGraphic} & !.full` - } - } - const timing = CreateTimingEnable(cue, GetDefaultOut(config)) if (!timing.lifespan) { @@ -177,3 +156,8 @@ export function GetEnableForGraphic( } } } +function endsOnPartEnd(config: TV2BlueprintConfig, cue: CueDefinitionGraphic) { + return ( + (cue.end && cue.end.infiniteMode && cue.end.infiniteMode === 'B') || findGFXTemplate(config, cue)?.OutType === 'B' + ) +} diff --git a/src/tv2-common/helpers/graphics/viz/index.ts b/src/tv2-common/helpers/graphics/viz/index.ts index c8c59acc6..973f952ac 100644 --- a/src/tv2-common/helpers/graphics/viz/index.ts +++ b/src/tv2-common/helpers/graphics/viz/index.ts @@ -1,13 +1,8 @@ +import { GraphicsContent, IShowStyleUserContext, TSR, WithTimeline } from '@tv2media/blueprints-integration' import { - GraphicsContent, - IBlueprintPart, - IBlueprintPiece, - IShowStyleUserContext, - TSR, - WithTimeline -} from '@sofie-automation/blueprints-integration' -import { + Adlib, CueDefinitionGraphic, + findShowId, GetEnableForGraphic, GetFullGraphicTemplateNameFromCue, GetTimelineLayerForGraphic, @@ -20,7 +15,7 @@ import { PartDefinition, TV2BlueprintConfig } from 'tv2-common' -import { GraphicEngine, GraphicLLayer } from 'tv2-constants' +import { GraphicEngine, SharedGraphicLLayer } from 'tv2-constants' import { EnableDSK } from '../../dsk' export interface VizPilotGeneratorSettings { @@ -33,22 +28,20 @@ export interface VizPilotGeneratorSettings { export function GetInternalGraphicContentVIZ( config: TV2BlueprintConfig, - part: Readonly, engine: GraphicEngine, parsedCue: CueDefinitionGraphic, - isIdentGraphic: boolean, - partDefinition: PartDefinition, + partDefinition: PartDefinition | undefined, mappedTemplate: string, adlib: boolean -): IBlueprintPiece['content'] { - return literal>({ +): WithTimeline { + return { fileName: parsedCue.graphic.template, path: parsedCue.graphic.template, ignoreMediaObjectStatus: true, timelineObjects: literal([ literal({ id: '', - enable: GetEnableForGraphic(config, part, engine, parsedCue, isIdentGraphic, partDefinition, adlib), + enable: GetEnableForGraphic(config, engine, parsedCue, partDefinition, adlib), priority: 1, layer: GetTimelineLayerForGraphic(config, GetFullGraphicTemplateNameFromCue(config, parsedCue)), content: { @@ -56,25 +49,25 @@ export function GetInternalGraphicContentVIZ( type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: mappedTemplate, templateData: parsedCue.graphic.textFields, - channelName: engine === 'WALL' ? 'WALL1' : 'OVL1' // TODO: TranslateEngine + channelName: engine === 'WALL' ? 'WALL1' : 'OVL1', // TODO: TranslateEngine + showId: findShowId(config, engine) } }), // Assume DSK is off by default (config table) ...EnableDSK(config, 'OVL') ]) - }) + } } export function GetPilotGraphicContentViz( config: TV2BlueprintConfig, - part: Readonly | undefined, context: IShowStyleUserContext, settings: VizPilotGeneratorSettings, parsedCue: CueDefinitionGraphic, engine: GraphicEngine, - adlib: boolean + adlib?: Adlib ): WithTimeline { - return literal>({ + return { fileName: 'PILOT_' + parsedCue.graphic.vcpid.toString(), path: parsedCue.graphic.vcpid.toString(), timelineObjects: [ @@ -82,16 +75,16 @@ export function GetPilotGraphicContentViz( id: '', enable: IsTargetingOVL(engine) || IsTargetingWall(engine) - ? GetEnableForGraphic(config, part, engine, parsedCue, false, undefined, adlib) + ? GetEnableForGraphic(config, engine, parsedCue, undefined, !!adlib) : { start: 0 }, priority: 1, layer: IsTargetingWall(engine) - ? GraphicLLayer.GraphicLLayerWall + ? SharedGraphicLLayer.GraphicLLayerWall : IsTargetingOVL(engine) - ? GraphicLLayer.GraphicLLayerPilotOverlay - : GraphicLLayer.GraphicLLayerPilot, + ? SharedGraphicLLayer.GraphicLLayerPilotOverlay + : SharedGraphicLLayer.GraphicLLayerPilot, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT, @@ -111,7 +104,7 @@ export function GetPilotGraphicContentViz( }, ...(IsTargetingFull(engine) ? { classes: ['full'] } : {}) }), - ...(IsTargetingFull(engine) ? settings.createPilotTimelineForStudio(config, context, adlib) : []) + ...(IsTargetingFull(engine) ? settings.createPilotTimelineForStudio(config, context, !!adlib) : []) ] - }) + } } diff --git a/src/tv2-common/helpers/index.ts b/src/tv2-common/helpers/index.ts index 2bc9a8494..9e36821ab 100644 --- a/src/tv2-common/helpers/index.ts +++ b/src/tv2-common/helpers/index.ts @@ -6,6 +6,8 @@ export * from './graphics/index' export * from './rundownAdLibActions' export * from './postProcessDefinitions' export * from './translation' +export * from './adLibNames' +export * from './serverResume' export function SanitizePath(path: string): string { return path.replace(/[\/\\]*$/, '') diff --git a/src/tv2-common/helpers/postProcessDefinitions.ts b/src/tv2-common/helpers/postProcessDefinitions.ts index ea643adf2..ff0db9512 100644 --- a/src/tv2-common/helpers/postProcessDefinitions.ts +++ b/src/tv2-common/helpers/postProcessDefinitions.ts @@ -23,11 +23,11 @@ function setPartTitle(partDefinition: PartDefinition) { const firstCue = partDefinition.cues[0] if ( firstCue && - [PartType.Grafik, PartType.DVE, PartType.Ekstern, PartType.Telefon, PartType.Unknown].includes(partDefinition.type) + [PartType.Grafik, PartType.DVE, PartType.REMOTE, PartType.Telefon, PartType.Unknown].includes(partDefinition.type) ) { switch (firstCue.type) { case CueType.Ekstern: - partDefinition.title = firstCue.source + partDefinition.title = firstCue.sourceDefinition.name break case CueType.DVE: partDefinition.title = firstCue.template @@ -52,7 +52,7 @@ function getExternalId(segmentId: string, partDefinition: PartDefinition, foundM switch (partDefinition.type) { case PartType.EVS: // Common pattern to see EV1 and EVS1VO in the same story. Changing from EVS1 to EVS1VO would mean a new part - id += `-${partDefinition.variant.evs}-${partDefinition.variant.isVO}` + id += `-${partDefinition.sourceDefinition.id}-${partDefinition.sourceDefinition.vo}` break case PartType.INTRO: // Intro must have a jingle cue, if it doesn't then padId will handle @@ -63,7 +63,7 @@ function getExternalId(segmentId: string, partDefinition: PartDefinition, foundM break case PartType.Kam: // No way of uniquely identifying, add some entropy from cues - id += `-${partDefinition.rawType}-${partDefinition.variant.name}-${partDefinition.cues.length}` + id += `-${partDefinition.rawType}-${partDefinition.sourceDefinition.id}-${partDefinition.cues.length}` break case PartType.VO: case PartType.Server: @@ -77,7 +77,7 @@ function getExternalId(segmentId: string, partDefinition: PartDefinition, foundM break case PartType.Grafik: case PartType.DVE: - case PartType.Ekstern: + case PartType.REMOTE: case PartType.Telefon: case PartType.Unknown: // Special cases based on cues @@ -103,7 +103,7 @@ function getExternalId(segmentId: string, partDefinition: PartDefinition, foundM break case CueType.Ekstern: // Identify based on live source. Changing live source will result in a new part - id += `-${firstCue.source}` + id += `-${firstCue.sourceDefinition.name}` break case CueType.Jingle: // Changing the jingle clip will result in a new part diff --git a/src/tv2-common/helpers/rundownAdLibActions.ts b/src/tv2-common/helpers/rundownAdLibActions.ts index 918e25acf..05402989d 100644 --- a/src/tv2-common/helpers/rundownAdLibActions.ts +++ b/src/tv2-common/helpers/rundownAdLibActions.ts @@ -1,9 +1,10 @@ -import { IBlueprintActionManifest } from '@sofie-automation/blueprints-integration' +import { IBlueprintActionManifest } from '@tv2media/blueprints-integration' import { ActionTakeWithTransition, ActionTakeWithTransitionVariant, ActionTakeWithTransitionVariantBreaker, ActionTakeWithTransitionVariantCut, + ActionTakeWithTransitionVariantDip, ActionTakeWithTransitionVariantMix, GetTagForTransition, literal, @@ -19,12 +20,16 @@ export function GetTransitionAdLibActions< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >(config: ShowStyleConfig, startingRank: number): IBlueprintActionManifest[] { - const res: IBlueprintActionManifest[] = [] + const blueprintActionManifests: IBlueprintActionManifest[] = [] if (config.showStyle.ShowstyleTransition && config.showStyle.ShowstyleTransition.length) { const defaultTransition = config.showStyle.ShowstyleTransition - const userData = ParseTransitionSetting(defaultTransition, true) + const userData: ActionTakeWithTransition = { + type: AdlibActionType.TAKE_WITH_TRANSITION, + variant: ParseTransitionString(defaultTransition), + takeNow: true + } const jingleConfig = config.showStyle.BreakerConfig.find( j => j.BreakerName === config.showStyle.ShowstyleTransition @@ -39,7 +44,7 @@ export function GetTransitionAdLibActions< alphaAtEnd = jingleConfig.EndAlpha } - res.push( + blueprintActionManifests.push( makeTransitionAction( config, userData, @@ -58,7 +63,11 @@ export function GetTransitionAdLibActions< if (config.showStyle.Transitions) { config.showStyle.Transitions.forEach((transition, i) => { if (transition.Transition && transition.Transition.length) { - const userData = ParseTransitionSetting(transition.Transition, true) + const userData: ActionTakeWithTransition = { + type: AdlibActionType.TAKE_WITH_TRANSITION, + variant: ParseTransitionString(transition.Transition), + takeNow: true + } const jingleConfig = config.showStyle.BreakerConfig.find(j => j.BreakerName === transition.Transition) let alphaAtStart: number | undefined @@ -71,7 +80,7 @@ export function GetTransitionAdLibActions< alphaAtEnd = jingleConfig.EndAlpha } - res.push( + blueprintActionManifests.push( makeTransitionAction( config, userData, @@ -87,33 +96,35 @@ export function GetTransitionAdLibActions< }) } - return res + return blueprintActionManifests } -export function ParseTransitionSetting(transitionSetting: string, takeNow: boolean): ActionTakeWithTransition { - let variant: ActionTakeWithTransitionVariant = literal({ - type: 'cut' - }) - - if (transitionSetting.match(/mix ?(\d+)/i)) { - const props = transitionSetting.match(/mix ?(\d+)/i) - variant = literal({ +export function ParseTransitionString(transitionString: string): ActionTakeWithTransitionVariant { + if (transitionString.match(/mix ?(\d+)/i)) { + const props = transitionString.match(/mix ?(\d+)/i) + return literal({ type: 'mix', frames: Number(props![1]) }) - } else if (transitionSetting.match(/cut/i)) { - // Variant already setup - } else { - variant = literal({ - type: 'breaker', - breaker: transitionSetting.toString().replace(/effekt ?/i, '') + } + + if (transitionString.match(/dip ?(\d+)/i)) { + const props = transitionString.match(/dip ?(\d+)/i) + return literal({ + type: 'dip', + frames: Number(props![1]) + }) + } + + if (transitionString.match(/cut/i)) { + return literal({ + type: 'cut' }) } - return literal({ - type: AdlibActionType.TAKE_WITH_TRANSITION, - variant, - takeNow + return literal({ + type: 'breaker', + breaker: transitionString.toString().replace(/effekt ?/i, '') }) } @@ -130,7 +141,8 @@ function makeTransitionAction( const tag = GetTagForTransition(userData.variant) const isEffekt = !!label.match(/^\d+$/) - return literal({ + return { + externalId: `${JSON.stringify(userData)}_${AdlibActionType.TAKE_WITH_TRANSITION}_${rank}`, actionId: AdlibActionType.TAKE_WITH_TRANSITION, userData, userDataManifest: {}, @@ -139,13 +151,13 @@ function makeTransitionAction( label: t(isEffekt ? `EFFEKT ${label}` : label), sourceLayerId: SharedSourceLayers.PgmAdlibJingle, outputLayerId: SharedOutputLayers.PGM, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_TAKE_WITH_TRANSITION], currentPieceTags: [tag], nextPieceTags: [tag], content: - isEffekt || !!label.match(/^MIX ?\d+$/i) || !!label.match(/^CUT$/i) + isEffekt || !!/^MIX ?\d+$/i.test(label) || !!/^CUT$/i.test(label) || !!/^DIP ?\d+$/i.test(label) ? {} : CreateJingleExpectedMedia(config, jingle, alphaAtStart ?? 0, duration ?? 0, alphaAtEnd ?? 0) } - }) + } } diff --git a/src/tv2-common/helpers/serverResume.ts b/src/tv2-common/helpers/serverResume.ts new file mode 100644 index 000000000..28d6bb96b --- /dev/null +++ b/src/tv2-common/helpers/serverResume.ts @@ -0,0 +1,234 @@ +import { + IActionExecutionContext, + IBlueprintActionTriggerMode, + IBlueprintPartInstance, + IBlueprintResolvedPieceInstance, + VTContent +} from '@tv2media/blueprints-integration' +import { PartEndStateExt, PieceMetaData, t } from 'tv2-common' +import { SharedSourceLayers } from 'tv2-constants' +import _ = require('underscore') +import { DVEPieceMetaData } from '../content' + +/** If the seek position is closer to the end of the file than this value, it will be reset to 0. */ +const REMAINING_DURATION_BEFORE_RESET = 2 * 1000 + +export interface ServerPosition { + fileName: string + lastEnd: number + isPlaying: boolean + endedWithPartInstance?: string +} + +export enum ServerSelectMode { + RESUME = 'resume', + RESET = 'reset' +} + +export function getServerSeek( + lastServerPosition: ServerPosition | undefined, + fileName: string, + mediaObjectDuration?: number, + triggerMode?: ServerSelectMode +): number { + if (triggerMode === ServerSelectMode.RESET) { + return 0 + } + if (lastServerPosition?.fileName === fileName && !lastServerPosition.isPlaying) { + if (!mediaObjectDuration) { + return lastServerPosition.lastEnd + } + const seek = lastServerPosition.lastEnd % mediaObjectDuration + const remainingDuration = mediaObjectDuration - seek + if (remainingDuration > REMAINING_DURATION_BEFORE_RESET) { + return seek + } + } + return 0 +} + +export async function getServerPosition( + context: IActionExecutionContext, + replacingCurrentPieceWithOffset?: number +): Promise { + const partInstance = await context.getPartInstance('current') + if (!partInstance) { + throw new Error('Missing current PartInstance while calculating serverOffsets') + } + + const pieceEnd = + replacingCurrentPieceWithOffset !== undefined + ? context.getCurrentTime() + replacingCurrentPieceWithOffset + : undefined + + const pieceInstances = (await context.getResolvedPieceInstances('current')) as Array< + IBlueprintResolvedPieceInstance + > + + return getServerPositionForPartInstance(partInstance, pieceInstances, pieceEnd) +} + +/** + * Calculate the offsets for clips based on the pieceinstances that have already been played. + */ +export function getServerPositionForPartInstance( + partInstance: IBlueprintPartInstance, + pieceInstances: Array>, + currentPieceEnd?: number +): ServerPosition | undefined { + currentPieceEnd = + currentPieceEnd !== undefined && partInstance.timings?.startedPlayback + ? currentPieceEnd - partInstance.timings.startedPlayback + : undefined + + const previousPartEndState = partInstance.previousPartEndState as Partial | undefined + const previousServerPosition = previousPartEndState?.serverPosition + + const currentPiecesWithServer = _.sortBy(pieceInstances.filter(shouldPreservePosition), p => p.resolvedStart) + + let currentServerPosition = + previousPartEndState?.segmentId === partInstance.segmentId ? previousServerPosition : undefined + + for (const pieceInstance of currentPiecesWithServer) { + const pieceDuration = + pieceInstance.resolvedDuration || + (currentPieceEnd !== undefined ? currentPieceEnd - pieceInstance.resolvedStart : undefined) + + const content = pieceInstance.piece.content as VTContent | undefined + if (pieceInstance.piece.sourceLayerId === SharedSourceLayers.PgmServer && content) { + currentServerPosition = getCurrentPositionFromServerPiece( + content, + pieceDuration, + previousServerPosition, + pieceInstance, + currentPieceEnd, + partInstance + ) + } else if (pieceInstance.piece.sourceLayerId === SharedSourceLayers.PgmDVEAdLib) { + updateServerPositionFromDVEPiece( + pieceInstance as IBlueprintResolvedPieceInstance, + partInstance, + pieceDuration, + currentPieceEnd, + currentServerPosition + ) + } + } + + updateServerPositionFromTransition(partInstance, currentServerPosition, currentPiecesWithServer, previousPartEndState) + + return currentServerPosition +} + +function updateServerPositionFromTransition( + partInstance: IBlueprintPartInstance, + currentServerPosition: ServerPosition | undefined, + currentPiecesWithServer: Array>, + previousPartEndState: Partial | undefined +) { + const inTransitionDuration = partInstance.part.inTransition?.previousPartKeepaliveDuration + if ( + currentServerPosition && + !currentPiecesWithServer.length && + inTransitionDuration && + currentServerPosition?.endedWithPartInstance === previousPartEndState?.partInstanceId + ) { + currentServerPosition.lastEnd += inTransitionDuration + } +} + +function updateServerPositionFromDVEPiece( + pieceInstance: IBlueprintResolvedPieceInstance, + partInstance: IBlueprintPartInstance, + pieceDuration: number | undefined, + currentPieceEnd: number | undefined, + currentServerPosition: ServerPosition | undefined +) { + const serverPlaybackTiming = pieceInstance.piece.metaData?.serverPlaybackTiming + if (serverPlaybackTiming) { + for (const timing of serverPlaybackTiming) { + const start = getStartTimeForServerInDVE(timing, partInstance, pieceInstance) + const end = getEndTimeForServerInDVE(timing, pieceDuration, partInstance, pieceInstance) + const serverEndedWithPartInstance = + !pieceInstance.resolvedDuration && currentPieceEnd !== undefined && !timing.end + if (currentServerPosition && end && start) { + currentServerPosition.lastEnd += end - start + currentServerPosition.endedWithPartInstance = serverEndedWithPartInstance ? partInstance._id : undefined + } + } + } +} + +function getStartTimeForServerInDVE( + timing: { start?: number; end?: number }, + partInstance: IBlueprintPartInstance, + pieceInstance: IBlueprintResolvedPieceInstance +) { + return ( + timing.start ?? + (partInstance.timings?.startedPlayback && partInstance.timings?.startedPlayback + pieceInstance.resolvedStart) + ) +} + +function getEndTimeForServerInDVE( + timing: { start?: number; end?: number }, + pieceDuration: number | undefined, + partInstance: IBlueprintPartInstance, + pieceInstance: IBlueprintResolvedPieceInstance +) { + return ( + timing.end ?? + (pieceDuration && partInstance.timings?.startedPlayback + ? partInstance.timings?.startedPlayback + pieceInstance.resolvedStart + pieceDuration + : undefined) + ) +} + +function getCurrentPositionFromServerPiece( + content: VTContent, + pieceDuration: number | undefined, + previousServerPosition: ServerPosition | undefined, + pieceInstance: IBlueprintResolvedPieceInstance, + currentPieceEnd: number | undefined, + partInstance: IBlueprintPartInstance +) { + const pieceSeek = content.seek ?? 0 + const pieceClipEnd = pieceSeek + (pieceDuration ?? 0) + const isPlaying = + (previousServerPosition?.fileName === content.fileName && previousServerPosition?.isPlaying) || !pieceDuration + const serverEndedWithPartInstance = !pieceInstance.resolvedDuration && currentPieceEnd !== undefined + return { + fileName: content.fileName, + lastEnd: pieceClipEnd, + isPlaying, + endedWithPartInstance: serverEndedWithPartInstance ? partInstance._id : undefined + } +} + +export function shouldPreservePosition(pieceInstance: IBlueprintResolvedPieceInstance): boolean { + return ( + !!pieceInstance.dynamicallyInserted && + (pieceInstance.piece.sourceLayerId === SharedSourceLayers.PgmServer || + (pieceInstance.piece.sourceLayerId === SharedSourceLayers.PgmDVEAdLib && + !!(pieceInstance.piece.metaData as DVEPieceMetaData | undefined)?.serverPlaybackTiming)) + ) +} + +export function getServerAdLibTriggerModes(): IBlueprintActionTriggerMode[] { + return [ + { + data: ServerSelectMode.RESUME, + display: { + _rank: 0, + label: t('Resume') + } + }, + { + data: ServerSelectMode.RESET, + display: { + _rank: 1, + label: t('From Start') + } + } + ] +} diff --git a/src/tv2-common/helpers/sisyfos.ts b/src/tv2-common/helpers/sisyfos.ts index 1e63075f4..01f382fdd 100644 --- a/src/tv2-common/helpers/sisyfos.ts +++ b/src/tv2-common/helpers/sisyfos.ts @@ -1,216 +1,149 @@ -import * as _ from 'underscore' - -import { IStudioUserContext, SourceLayerType, Timeline, TSR } from '@sofie-automation/blueprints-integration' -import { - FindSourceInfoStrict, - SisyfosEVSSource, - SourceInfo, - TV2StudioBlueprintConfigBase, - TV2StudioConfigBase -} from 'tv2-common' -import { PieceMetaData } from '../onTimelineGenerate' +import { Timeline, TSR } from '@tv2media/blueprints-integration' +import { SourceInfo, TimelineBlueprintExt } from 'tv2-common' +import { SharedSisyfosLLayer } from 'tv2-constants' +import { TV2BlueprintConfig } from '../blueprintConfig' import { literal } from '../util' -export function GetStickyForPiece( - layers: Array<{ layer: string; isPgm: 0 | 1 | 2 }>, - STICKY_LAYERS: string[] -): PieceMetaData | undefined { - return literal({ - stickySisyfosLevels: _.object( - layers - .filter(layer => STICKY_LAYERS.indexOf(layer.layer) !== -1) - .map<[string, { value: number; followsPrevious: boolean }]>(layer => { - return [ - layer.layer, - { - value: layer.isPgm, - followsPrevious: false - } - ] - }) - ) - }) +export function GetSisyfosTimelineObjForCamera( + config: TV2BlueprintConfig, + sourceInfo: SourceInfo, + minusMic: boolean, + enable?: Timeline.TimelineEnable +) { + return GetSisyfosTimelineObjForSource(config, sourceInfo, false, minusMic, enable) } -export function GetEksternMetaData( - STICKY_LAYERS: string[], - studioMics: string[], - layers?: string[] -): PieceMetaData | undefined { - return layers && layers.length - ? GetStickyForPiece( - [ - ...layers.map<{ layer: string; isPgm: 0 | 1 | 2 }>(layer => { - return { layer, isPgm: 1 } - }), - ...studioMics.map<{ layer: string; isPgm: 0 | 1 | 2 }>(l => { - return { layer: l, isPgm: 1 } - }) - ], - STICKY_LAYERS - ) - : undefined +export function GetSisyfosTimelineObjForRemote( + config: TV2BlueprintConfig, + sourceInfo: SourceInfo, + enable?: Timeline.TimelineEnable +) { + return GetSisyfosTimelineObjForSource(config, sourceInfo, false, false, enable) } -export function GetCameraMetaData( - config: TV2StudioBlueprintConfigBase, - layers?: string[] -): PieceMetaData | undefined { - return GetStickyForPiece( - [...(layers || []), ...config.studio.StudioMics].map<{ layer: string; isPgm: 0 | 1 | 2 }>(l => { - return { layer: l, isPgm: 1 } - }), - config.stickyLayers - ) +export function GetSisyfosTimelineObjForReplay(config: TV2BlueprintConfig, sourceInfo: SourceInfo, vo: boolean) { + return GetSisyfosTimelineObjForSource(config, sourceInfo, vo, true) } -export function GetSisyfosTimelineObjForEkstern( - context: IStudioUserContext, - sources: SourceInfo[], - sourceType: string, - getLayersForEkstern: (context: IStudioUserContext, sources: SourceInfo[], sourceType: string) => string[] | undefined, +export function GetSisyfosTimelineObjForServer( + config: TV2BlueprintConfig, + vo: boolean, + clipPendingLayer: string, + mediaPlayerSession: string, enable?: Timeline.TimelineEnable ): TSR.TimelineObjSisyfosAny[] { - if (!enable) { - enable = { start: 0 } + const timelineEnable = getFallbackEnable(enable) + const result: TSR.TimelineObjSisyfosAny[] = [ + literal({ + id: '', + enable: timelineEnable, + priority: 1, + layer: clipPendingLayer, + content: { + deviceType: TSR.DeviceType.SISYFOS, + type: TSR.TimelineContentTypeSisyfos.CHANNEL, + isPgm: vo ? 2 : 1 + }, + metaData: { + mediaPlayerSession + }, + classes: [] + }) + ] + if (vo) { + result.push(getStudioMicsTimelineObj(config, timelineEnable)) } + return result +} - const audioTimeline: TSR.TimelineObjSisyfosAny[] = [] - const layers = getLayersForEkstern(context, sources, sourceType) +export function GetSisyfosTimelineObjForFull( + config: TV2BlueprintConfig, + enable?: Timeline.TimelineEnable +): TSR.TimelineObjSisyfosAny[] { + const result: TSR.TimelineObjSisyfosAny[] = [] + const timelineEnable = getFallbackEnable(enable) + result.push(getStudioMicsTimelineObj(config, timelineEnable)) + return result +} - if (!layers || !layers.length) { - context.notifyUserWarning(`Could not set audio levels for ${sourceType}`) - return audioTimeline - } +export function GetSisyfosTimelineObjForTelefon( + config: TV2BlueprintConfig, + telefonLayer: string, + enable?: Timeline.TimelineEnable +): TSR.TimelineObjSisyfosAny[] { + const timelineEnable = getFallbackEnable(enable) + const result: TSR.TimelineObjSisyfosAny[] = [ + literal({ + id: '', + enable: timelineEnable, + priority: 1, + layer: telefonLayer, + content: { + deviceType: TSR.DeviceType.SISYFOS, + type: TSR.TimelineContentTypeSisyfos.CHANNEL, + isPgm: 1 + } + }) + ] + result.push(getStudioMicsTimelineObj(config, timelineEnable)) + return result +} - layers.forEach(layer => { - audioTimeline.push( +function GetSisyfosTimelineObjForSource( + config: TV2BlueprintConfig, + sourceInfo: SourceInfo, + vo: boolean, + enableStudioMicsOnlyForVo: boolean, + enable?: Timeline.TimelineEnable +): TSR.TimelineObjSisyfosAny[] { + const result: TSR.TimelineObjSisyfosAny[] = [] + const timelineEnable = getFallbackEnable(enable) + sourceInfo.sisyfosLayers?.forEach(layer => { + result.push( literal({ id: '', - enable: enable!, + enable: timelineEnable, priority: 1, layer, content: { deviceType: TSR.DeviceType.SISYFOS, type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 1 + isPgm: vo ? 2 : 1 } }) ) }) - return audioTimeline -} - -export function GetLayersForEkstern(context: IStudioUserContext, sources: SourceInfo[], sourceType: string) { - const eksternProps = sourceType.match(/^(?:LIVE|SKYPE|FEED) ?([^\s]+)(?: (.+))?$/i) - const eksternLayers: string[] = [] - if (eksternProps) { - const sourceInfo = FindSourceInfoStrict(context, sources, SourceLayerType.REMOTE, sourceType) - if (sourceInfo && sourceInfo.sisyfosLayers) { - eksternLayers.push(...sourceInfo.sisyfosLayers) - } + if (sourceInfo.useStudioMics && (!enableStudioMicsOnlyForVo || vo)) { + result.push(getStudioMicsTimelineObj(config, timelineEnable)) } - return eksternLayers + return result } -export function GetSisyfosTimelineObjForCamera( - context: IStudioUserContext, - config: { sources: SourceInfo[]; studio: { StudioMics: string[] } }, - sourceType: string, - channelLayer: string, - enable?: Timeline.TimelineEnable +function getStudioMicsTimelineObj( + config: TV2BlueprintConfig, + timelineEnable: Timeline.TimelineEnable ): TSR.TimelineObjSisyfosChannels { - if (!enable) { - enable = { start: 0 } - } - - const useMic = !sourceType.match(/^(?:KAM|CAM)(?:ERA)? (.+) minus mic(.*)$/i) - const camName = sourceType.match(/^(?:KAM|CAM)(?:ERA)? (.+)$/i) - const nonCam = !!sourceType.match(/server|telefon|full|evs/i) - const mappedChannels: TSR.TimelineObjSisyfosChannels['content']['channels'] = [] - if ((useMic && camName) || nonCam) { - const camLayers: string[] = [] - if (useMic && camName) { - const sourceInfo = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, sourceType) - if (sourceInfo) { - if (sourceInfo.sisyfosLayers) { - camLayers.push(...sourceInfo.sisyfosLayers) - } - if (sourceInfo.useStudioMics) { - camLayers.push(...config.studio.StudioMics) - } - } - } else if (nonCam) { - camLayers.push(...config.studio.StudioMics) - } - camLayers.forEach(layer => { - mappedChannels.push({ - mappedLayer: layer, - isPgm: 1 - }) + const studioMicsChannels: TSR.TimelineObjSisyfosChannels['content']['channels'] = [] + config.studio.StudioMics.forEach(layer => { + studioMicsChannels.push({ + mappedLayer: layer, + isPgm: 1 }) - } - - return literal({ + }) + return { id: '', - enable: enable ? enable : { start: 0 }, - priority: mappedChannels.length ? 2 : 0, - layer: channelLayer, + enable: timelineEnable, + priority: studioMicsChannels.length ? 2 : 0, + layer: SharedSisyfosLLayer.SisyfosGroupStudioMics, content: { deviceType: TSR.DeviceType.SISYFOS, type: TSR.TimelineContentTypeSisyfos.CHANNELS, - channels: mappedChannels, + channels: studioMicsChannels, overridePriority: 2 } - }) -} - -export function GetLayersForCamera(config: TV2StudioBlueprintConfigBase, sourceInfo: SourceInfo) { - const cameraLayers: string[] = [] - if (sourceInfo.sisyfosLayers) { - cameraLayers.push(...sourceInfo.sisyfosLayers) } - if (sourceInfo.useStudioMics) { - cameraLayers.push(...config.studio.StudioMics) - } - return cameraLayers -} - -export function getStickyLayers(studioConfig: TV2StudioConfigBase, liveAudioLayers: string[]) { - return [...studioConfig.StudioMics, ...liveAudioLayers] } -export function getLiveAudioLayers(studioConfig: TV2StudioConfigBase): string[] { - const res = new Set() - for (const src of studioConfig.SourcesRM) { - if (src.SisyfosLayers && src.KeepAudioInStudio) { - for (const layer of src.SisyfosLayers) { - res.add(layer) - } - } - } - for (const src of studioConfig.SourcesSkype) { - if (src.SisyfosLayers) { - for (const layer of src.SisyfosLayers) { - res.add(layer) - } - } - } - return Array.from(res) -} - -export function GetSisyfosTimelineObjForEVS(sourceInfo: SourceInfo, vo: boolean) { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: SisyfosEVSSource(sourceInfo.id.replace(/^DP/i, '')), - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: vo ? 2 : 1 - } - }) +function getFallbackEnable(timelineEnable: Timeline.TimelineEnable | undefined): Timeline.TimelineEnable { + return timelineEnable ?? { start: 0 } } diff --git a/src/tv2-common/helpers/translation.ts b/src/tv2-common/helpers/translation.ts index 913494931..c1ac374d8 100644 --- a/src/tv2-common/helpers/translation.ts +++ b/src/tv2-common/helpers/translation.ts @@ -1,4 +1,4 @@ -import { ITranslatableMessage } from '@sofie-automation/blueprints-integration' +import { ITranslatableMessage } from '@tv2media/blueprints-integration' export function t(key: string, args?: { [k: string]: any }): ITranslatableMessage { return { diff --git a/src/tv2-common/hotkeys/camera.ts b/src/tv2-common/hotkeys/camera.ts new file mode 100644 index 000000000..94139e9b0 --- /dev/null +++ b/src/tv2-common/hotkeys/camera.ts @@ -0,0 +1,30 @@ +import { IBlueprintTriggeredActions } from '@tv2media/blueprints-integration' +import { MakeStudioSourceHotkeys, SourceHotkeyTriggers } from './helpers' + +export type CameraHotkeyAssignments = SourceHotkeyTriggers + +function cameraHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_camera_${hotkeyType}_${index}` +} + +function cameraHotkeyName(camera: string) { + return `KAM ${camera}` +} + +export function MakeCameraHotkeys( + showStyleId: string, + sourceLayerId: string, + cameras: string[], + assignments: CameraHotkeyAssignments, + getNextRank: () => number +): IBlueprintTriggeredActions[] { + return MakeStudioSourceHotkeys( + showStyleId, + sourceLayerId, + cameras, + assignments, + getNextRank, + cameraHotkeyName, + cameraHotkeyId + ) +} diff --git a/src/tv2-common/hotkeys/clear.ts b/src/tv2-common/hotkeys/clear.ts new file mode 100644 index 000000000..0451c7a42 --- /dev/null +++ b/src/tv2-common/hotkeys/clear.ts @@ -0,0 +1,57 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' + +export type ClearLayerHotkeyAssignments = Array<{ sourceLayers: string[]; key: string; name: string }> + +function clearSourceLayerHotKeyId(showStyleId: string, sourceLayers: string[]) { + return `${showStyleId}_clear_sourcelayer_${sourceLayers.join(',')}` +} + +export function MakeClearHotkeys( + showStyleId: string, + assignments: ClearLayerHotkeyAssignments, + getNextRank: () => number +) { + return assignments.map(clearedSourceLayer => + literal({ + _id: clearSourceLayerHotKeyId(showStyleId, clearedSourceLayer.sourceLayers), + _rank: getNextRank(), + name: clearedSourceLayer.name, + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: clearedSourceLayer.key, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: clearedSourceLayer.sourceLayers + }), + literal({ + object: 'adLib', + field: 'type', + value: 'clear' + }) + ] + }) + ] + }) + ) +} diff --git a/src/tv2-common/hotkeys/dve.ts b/src/tv2-common/hotkeys/dve.ts new file mode 100644 index 000000000..0e8e4f3ba --- /dev/null +++ b/src/tv2-common/hotkeys/dve.ts @@ -0,0 +1,83 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export interface DVEHotkeyAssignments { + sommerfugl: string + morbarn: string + barnmor: string + barnMorIpad: string + '3split': string + '3barnMor': string + '2barnMor': string +} + +function dveHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_dve_layout_${hotkeyType}_${index}` +} + +export function MakeDVELayoutHotkeys( + showStyleId: string, + sourceLayerId: string, + dveLayouts: string[], + assignments: DVEHotkeyAssignments, + getNextRank: () => number +) { + return dveLayouts.map((layout, index) => { + // Try to fetch the hotkey by name, otherwise we'll create a blank trigger for unknown layouts + const hotkey = assignments[layout as keyof typeof assignments] as string | undefined + + return literal({ + _id: dveHotkeyId(showStyleId, sourceLayerId, layout, index), + _rank: getNextRank(), + name: layout, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_SELECT_DVE_LAYOUT, layout] + }), + literal({ + object: 'adLib', + field: 'pick', + value: 0 + }) + ] + }) + ] + }) + }) +} diff --git a/src/tv2-common/hotkeys/global.ts b/src/tv2-common/hotkeys/global.ts new file mode 100644 index 000000000..9b2af643a --- /dev/null +++ b/src/tv2-common/hotkeys/global.ts @@ -0,0 +1,264 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags, SharedSourceLayers } from 'tv2-constants' +import { CameraHotkeyAssignments, MakeCameraHotkeys } from './camera' +import { ClearLayerHotkeyAssignments, MakeClearHotkeys } from './clear' +import { DVEHotkeyAssignments, MakeDVELayoutHotkeys } from './dve' +import { GraphicsHotkeyAssignemnts, MakeGraphicsHotkeys } from './graphics' +import { LocalSourceHotkeyAssignments, MakeLocalSourceHotkeys } from './local' +import { MakeRemoteHotkeys, RemoteSourceHotkeyAssignments } from './remote' +import { MakeServerHotkeys, ServerHotkeyAssignments } from './server' +import { MakeSisyfosHotkeys, SisyfosHotkeyAssignments } from './sisyfos' + +export interface GlobalHotkeyAssignments { + recallLast: { + DVE: string + Live: string + } + takeWithTransition: string[] + camera: CameraHotkeyAssignments + clear: ClearLayerHotkeyAssignments + dve: DVEHotkeyAssignments + graphics: GraphicsHotkeyAssignemnts + local: LocalSourceHotkeyAssignments + remote: RemoteSourceHotkeyAssignments + feed: RemoteSourceHotkeyAssignments + server: ServerHotkeyAssignments + sisyfos: SisyfosHotkeyAssignments +} + +export interface GlobalHotkeySourceLayers { + local?: string +} + +export interface GlobalHotkeySources { + camera: string[] + remote: string[] + feed: string[] + local: string[] + dveLayouts: string[] +} + +export function MakeGlobalTriggers( + showStyleId: string, + assignments: GlobalHotkeyAssignments, + sources: GlobalHotkeySources, + layers: GlobalHotkeySourceLayers, + getNextRank: () => number +): IBlueprintTriggeredActions[] { + const cameraTriggers = MakeCameraHotkeys( + showStyleId, + SharedSourceLayers.PgmCam, + sources.camera, + assignments.camera, + getNextRank + ) + const remoteTriggers = MakeRemoteHotkeys( + showStyleId, + SharedSourceLayers.PgmLive, + sources.remote, + assignments.remote, + getNextRank, + false + ) + const feedTriggers = MakeRemoteHotkeys( + showStyleId, + SharedSourceLayers.PgmLive, + sources.feed, + assignments.feed, + getNextRank, + true + ) + const localTriggers = layers.local + ? MakeLocalSourceHotkeys(showStyleId, layers.local, sources.local, assignments.local, getNextRank) + : [] + + const dveTriggers = MakeDVELayoutHotkeys( + showStyleId, + SharedSourceLayers.PgmDVEAdLib, + sources.dveLayouts, + assignments.dve, + getNextRank + ) + const serverTriggers = MakeServerHotkeys(showStyleId, SharedSourceLayers.PgmServer, getNextRank) + const graphicsTriggers = MakeGraphicsHotkeys( + showStyleId, + SharedSourceLayers.PgmAdlibGraphicCmd, + assignments.graphics, + getNextRank + ) + + const clearTriggers = MakeClearHotkeys(showStyleId, assignments.clear, getNextRank) + const sisyfosTriggers = MakeSisyfosHotkeys( + showStyleId, + SharedSourceLayers.PgmSisyfosAdlibs, + assignments.sisyfos, + getNextRank + ) + const recallLastTriggers = [ + makeRecallLastTrigger( + SharedSourceLayers.PgmDVEAdLib, + getNextRank, + recallLastHotkeyId(showStyleId, SharedSourceLayers.PgmDVE, 'dve', 0), + 'Last DVE', + assignments.recallLast.DVE, + [AdlibTags.ADLIB_RECALL_LAST_DVE] + ), + makeRecallLastTrigger( + SharedSourceLayers.PgmLive, + getNextRank, + recallLastHotkeyId(showStyleId, SharedSourceLayers.PgmLive, 'live', 0), + 'Last Live', + assignments.recallLast.Live, + [AdlibTags.ADLIB_RECALL_LAST_LIVE] + ) + ] + const takeWithTransitionTriggers = assignments.takeWithTransition.map((key, index) => + makeTakeWithTransitionTrigger( + SharedSourceLayers.PgmAdlibJingle, + getNextRank, + takeWithTransitionHotkeyId(showStyleId, SharedSourceLayers.PgmAdlibJingle, key, index), + `Take with transition ${index + 1}`, + key, + index + ) + ) + + return [ + ...cameraTriggers, + ...remoteTriggers, + ...feedTriggers, + ...localTriggers, + ...dveTriggers, + ...serverTriggers, + ...graphicsTriggers, + ...clearTriggers, + ...sisyfosTriggers, + ...recallLastTriggers, + ...takeWithTransitionTriggers + ] +} + +function recallLastHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_recall_last_${hotkeyType}_${index}` +} + +function makeRecallLastTrigger( + sourceLayerId: string, + getNextRank: () => number, + id: string, + name: string, + hotkey: string | undefined, + tags: string[] +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: tags + }), + literal({ + object: 'adLib', + field: 'pick', + value: 0 + }) + ] + }) + ] + }) +} + +function takeWithTransitionHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_take_with_transition_${hotkeyType}_${index}` +} + +function makeTakeWithTransitionTrigger( + sourceLayerId: string, + getNextRank: () => number, + id: string, + name: string, + hotkey: string | undefined, + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_TAKE_WITH_TRANSITION] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/graphics.ts b/src/tv2-common/hotkeys/graphics.ts new file mode 100644 index 000000000..1c28e1d75 --- /dev/null +++ b/src/tv2-common/hotkeys/graphics.ts @@ -0,0 +1,109 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export interface GraphicsHotkeyAssignemnts { + altud: string + designSc: string + gfxContinue: string +} + +function graphicsHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_graphics_${hotkeyType}_${index}` +} + +export function MakeGraphicsHotkeys( + showStyleId: string, + sourceLayerId: string, + assignments: GraphicsHotkeyAssignemnts, + getNextRank: () => number +) { + return [ + makeGraphicsGlobalHotKey( + sourceLayerId, + getNextRank, + graphicsHotkeyId(showStyleId, sourceLayerId, 'alt_ud', 0), + 'overlay ALT UD', + assignments.altud, + [AdlibTags.ADLIB_GFX_ALTUD] + ), + makeGraphicsGlobalHotKey( + sourceLayerId, + getNextRank, + graphicsHotkeyId(showStyleId, sourceLayerId, 'design_sc', 0), + 'Design Style SC', + assignments.designSc, + [AdlibTags.ADLIB_DESIGN_STYLE_SC] + ), + makeGraphicsGlobalHotKey( + sourceLayerId, + getNextRank, + graphicsHotkeyId(showStyleId, sourceLayerId, 'gfx_continue', 0), + 'GFX Continue', + assignments.gfxContinue, + [AdlibTags.ADLIB_GFX_CONTINUE_FORWARD] + ) + ] +} + +function makeGraphicsGlobalHotKey( + sourceLayerId: string, + getNextRank: () => number, + id: string, + name: string, + hotkey: string | undefined, + tags: string[] +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: tags + }), + literal({ + object: 'adLib', + field: 'pick', + value: 0 + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/auxGraphics.ts b/src/tv2-common/hotkeys/helpers/auxGraphics.ts new file mode 100644 index 000000000..18e20427c --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/auxGraphics.ts @@ -0,0 +1,65 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export function MakeRouteToGraphicsEngineTrigger( + id: string, + getNextRank: () => number, + name: string, + hotkey: string | undefined, + sourceLayerId: string, + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_TO_GRAPHICS_ENGINE_AUX] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/auxStudioScreen.ts b/src/tv2-common/hotkeys/helpers/auxStudioScreen.ts new file mode 100644 index 000000000..6fa970b58 --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/auxStudioScreen.ts @@ -0,0 +1,65 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export function MakeRouteToStudioScreenTrigger( + id: string, + getNextRank: () => number, + name: string, + hotkey: string | undefined, + sourceLayerId: string, + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_TO_STUDIO_SCREEN_AUX] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/cutToBox.ts b/src/tv2-common/hotkeys/helpers/cutToBox.ts new file mode 100644 index 000000000..5530dfef7 --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/cutToBox.ts @@ -0,0 +1,67 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTagCutToBox } from 'tv2-constants' + +export function MakeCutToBoxTrigger( + id: string, + getNextRank: () => number, + name: string, + hotkey: string | undefined, + sourceLayerId: string, + tags: string[], + pick: number, + box: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTagCutToBox(box), ...tags] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/directCut.ts b/src/tv2-common/hotkeys/helpers/directCut.ts new file mode 100644 index 000000000..25a251471 --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/directCut.ts @@ -0,0 +1,65 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export function MakeDirectCutTrigger( + id: string, + getNextRank: () => number, + name: string, + hotkey: string | undefined, + sourceLayerId: string, + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], // Not enough known hotkeys -> create a blank trigger as a placeholder to be assigned later + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_CUT_DIRECT] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/index.ts b/src/tv2-common/hotkeys/helpers/index.ts new file mode 100644 index 000000000..3e6bc6165 --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/index.ts @@ -0,0 +1,2 @@ +export * from './studioSource' +export { MakeCutToBoxTrigger } from './cutToBox' diff --git a/src/tv2-common/hotkeys/helpers/queue.ts b/src/tv2-common/hotkeys/helpers/queue.ts new file mode 100644 index 000000000..c65e28bf1 --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/queue.ts @@ -0,0 +1,66 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export function MakeQueueTrigger( + id: string, + getNextRank: () => number, + name: string, + hotkey: string | undefined, + sourceLayerId: string, + tags: string[], + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_QUEUE_NEXT, ...tags] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/helpers/studioSource.ts b/src/tv2-common/hotkeys/helpers/studioSource.ts new file mode 100644 index 000000000..1298bf4ff --- /dev/null +++ b/src/tv2-common/hotkeys/helpers/studioSource.ts @@ -0,0 +1,121 @@ +import { IBlueprintTriggeredActions } from '@tv2media/blueprints-integration' +import { MakeRouteToGraphicsEngineTrigger } from './auxGraphics' +import { MakeRouteToStudioScreenTrigger } from './auxStudioScreen' +import { MakeCutToBoxTrigger } from './cutToBox' +import { MakeDirectCutTrigger } from './directCut' +import { MakeQueueTrigger } from './queue' + +export interface SourceHotkeyTriggers { + directCut: string[] + queue: string[] + cutToBox: DVEBoxTriggers + routeToStudioScreen: string[] + routeToGraphicsEngine: string[] +} + +export type DVEBoxTriggers = [string[], string[], string[], string[]] + +export function MakeStudioSourceHotkeys( + showStyleId: string, + sourceLayerId: string, + sources: string[], + hotkeys: SourceHotkeyTriggers, + getNextRank: () => number, + nameFunc: (source: string) => string, + idFunc: (showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) => string, + tags: string[] = [] +): IBlueprintTriggeredActions[] { + const directCutHotkeys: IBlueprintTriggeredActions[] = [] + const queueHotkeys: IBlueprintTriggeredActions[] = [] + const cutToBoxHotkeys: IBlueprintTriggeredActions[] = [] + const toAuxStudioScreenHotkeys: IBlueprintTriggeredActions[] = [] + const toAuxGraphicsEngineHotkeys: IBlueprintTriggeredActions[] = [] + + for (const [currentSourceIndex, source] of sources.entries()) { + const name = nameFunc(source) + + // If any are assigned, assign all + if (hotkeys.directCut.length) { + const directHotkey = hotkeys.directCut[currentSourceIndex] + directCutHotkeys.push( + MakeDirectCutTrigger( + idFunc(showStyleId, sourceLayerId, 'cut_direct', currentSourceIndex), + getNextRank, + name, + directHotkey, + sourceLayerId, + currentSourceIndex + ) + ) + } + + if (hotkeys.queue.length) { + const queueHotkey = hotkeys.queue[currentSourceIndex] + queueHotkeys.push( + MakeQueueTrigger( + idFunc(showStyleId, sourceLayerId, 'queue', currentSourceIndex), + getNextRank, + name, + queueHotkey, + sourceLayerId, + tags, + currentSourceIndex + ) + ) + } + + for (let box = 0; box < hotkeys.cutToBox.length; box++) { + if (hotkeys.cutToBox[box].length) { + const boxHotkey = hotkeys.cutToBox[box][currentSourceIndex] + cutToBoxHotkeys.push( + MakeCutToBoxTrigger( + idFunc(showStyleId, sourceLayerId, `cut_to_box_${box + 1}`, currentSourceIndex), + getNextRank, + name + ` inp ${box + 1}`, + boxHotkey, + sourceLayerId, + tags, + currentSourceIndex, + box + ) + ) + } + } + + if (hotkeys.routeToStudioScreen.length) { + const toStudioScreenHotkey = hotkeys.routeToStudioScreen[currentSourceIndex] + toAuxStudioScreenHotkeys.push( + MakeRouteToStudioScreenTrigger( + idFunc(showStyleId, sourceLayerId, `studio_screen`, currentSourceIndex), + getNextRank, + name + ` til SS`, + toStudioScreenHotkey, + sourceLayerId, + currentSourceIndex + ) + ) + } + + if (hotkeys.routeToGraphicsEngine.length) { + const toGraphicsEngineHotkey = hotkeys.routeToGraphicsEngine[currentSourceIndex] + toAuxGraphicsEngineHotkeys.push( + MakeRouteToGraphicsEngineTrigger( + idFunc(showStyleId, sourceLayerId, `graphics_engine`, currentSourceIndex), + getNextRank, + name, + toGraphicsEngineHotkey, + sourceLayerId, + currentSourceIndex + ) + ) + } + } + + return [ + ...directCutHotkeys, + ...queueHotkeys, + ...cutToBoxHotkeys, + ...toAuxStudioScreenHotkeys, + ...toAuxGraphicsEngineHotkeys + ] +} diff --git a/src/tv2-common/hotkeys/hotkey-defaults.ts b/src/tv2-common/hotkeys/hotkey-defaults.ts new file mode 100644 index 000000000..e6da72e03 --- /dev/null +++ b/src/tv2-common/hotkeys/hotkey-defaults.ts @@ -0,0 +1,229 @@ +import { SharedSourceLayers } from 'tv2-constants' +import { literal } from '../util' +import { GlobalHotkeyAssignments } from './global' +import { RundownViewHotkeyAssignments } from './rundownView' +import { ActiveSegmentHotketAssignments } from './segment' + +export interface TV2Hotkeys { + activeSegment: ActiveSegmentHotketAssignments + global: GlobalHotkeyAssignments + rundownView: RundownViewHotkeyAssignments +} + +export const defaultHotkeys: TV2Hotkeys = { + activeSegment: literal({ + lowerThirds: ['KeyA', 'KeyS', 'KeyD', 'KeyF', 'KeyG'] + }), + global: literal({ + recallLast: { + DVE: 'F10', + Live: 'Ctrl+Alt+Shift+KeyB' + }, + takeWithTransition: ['NumpadDivide', 'NumpadSubtract', 'NumpadAdd'], + camera: { + directCut: ['F1', 'F2', 'F3', 'F4', 'F5'], + queue: ['Ctrl+Shift+F1', 'Ctrl+Shift+F2', 'Ctrl+Shift+F3', 'Ctrl+Shift+F4', 'Ctrl+Shift+F5'], + cutToBox: [ + ['Shift+F1', 'Shift+F2', 'Shift+F3', 'Shift+F4', 'Shift+F5'], + ['Ctrl+F1', 'Ctrl+F2', 'Ctrl+F3', 'Ctrl+Alt+Shift+KeyA', 'Ctrl+F5'], + ['Shift+Alt+F1', 'Shift+Alt+F2', 'Shift+Alt+F3', 'Shift+Alt+F4', 'Shift+Alt+F5'], + [] + ], + routeToStudioScreen: [], + routeToGraphicsEngine: [] + }, + clear: [ + { + sourceLayers: [ + SharedSourceLayers.PgmGraphicsIdent, + SharedSourceLayers.PgmGraphicsTop, + SharedSourceLayers.PgmGraphicsLower, + SharedSourceLayers.PgmGraphicsHeadline, + SharedSourceLayers.PgmGraphicsTema, + SharedSourceLayers.PgmGraphicsOverlay, + SharedSourceLayers.PgmPilotOverlay + ], + key: 'KeyQ', + name: 'overlay ALT UD' + }, + { + sourceLayers: [SharedSourceLayers.PgmGraphicsIdent], + key: 'Ctrl+Shift+KeyA', + name: 'ovl: ident OUT' + }, + { + sourceLayers: [SharedSourceLayers.PgmGraphicsTop], + key: 'Ctrl+Shift+KeyS', + name: 'ovl: top OUT' + }, + { + sourceLayers: [SharedSourceLayers.PgmGraphicsLower], + key: 'Ctrl+Shift+KeyD', + name: 'ovl:lower OUT' + }, + { + sourceLayers: [SharedSourceLayers.PgmGraphicsHeadline], + key: 'Ctrl+Shift+KeyF', + name: 'ovl: headline OUT' + }, + { + sourceLayers: [SharedSourceLayers.PgmGraphicsTema], + key: 'Ctrl+Shift+KeyG', + name: 'ovl: tema OUT' + }, + { + sourceLayers: [SharedSourceLayers.PgmAudioBed], + key: 'Minus', + name: 'STOP soundpl.' + } + ], + dve: { + sommerfugl: 'KeyM', + morbarn: 'Comma', + barnmor: 'Period', + barnMorIpad: 'KeyN', + '3split': 'KeyC', + '3barnMor': 'KeyB', + '2barnMor': 'KeyV' + }, + graphics: { + altud: 'KeyQ', + designSc: 'Shift+KeyA', + gfxContinue: 'Space' + }, + local: { + fullAudio: { + directCut: [], + queue: ['KeyR', 'KeyI'], + cutToBox: [['Shift+KeyR', 'Shift+KeyI'], ['Ctrl+KeyR', 'Ctrl+KeyI'], ['Alt+Shift+KeyR', 'Alt+Shift+KeyI'], []], + routeToStudioScreen: [], + routeToGraphicsEngine: [] + }, + voAudio: { + directCut: [], + queue: ['KeyE', 'KeyU', 'KeyP'], + cutToBox: [ + ['Shift+KeyE', 'Shift+KeyU', 'Shift+KeyP'], + ['Ctrl+KeyE', 'Ctrl+KeyU', 'Ctrl+KeyP'], + ['Alt+Shift+KeyE', 'Alt+Shift+KeyU', 'Alt+Shift+KeyP'], + [] + ], + routeToGraphicsEngine: [], + routeToStudioScreen: [] + } + }, + remote: { + directCut: [], + queue: ['Digit1', 'Digit2', 'Digit3', 'Digit4', 'Digit5', 'Digit6', 'Digit7', 'Digit8', 'Digit9', 'Digit0'], + cutToBox: [ + [ + 'Shift+Digit1', + 'Shift+Digit2', + 'Shift+Digit3', + 'Shift+Digit4', + 'Shift+Digit5', + 'Shift+Digit6', + 'Shift+Digit7', + 'Shift+Digit8', + 'Shift+Digit9', + 'Shift+Digit0' + ], + [ + 'Ctrl+Digit1', + 'Ctrl+Digit2', + 'Ctrl+Digit3', + 'Ctrl+Digit4', + 'Ctrl+Digit5', + 'Ctrl+Digit6', + 'Ctrl+Digit7', + 'Ctrl+Digit8', + 'Ctrl+Digit9', + 'Ctrl+Digit0' + ], + [ + 'Shift+Alt+Digit1', + 'Shift+Alt+Digit2', + 'Shift+Alt+Digit3', + 'Shift+Alt+Digit4', + 'Shift+Alt+Digit5', + 'Shift+Alt+Digit6', + 'Shift+Alt+Digit7', + 'Shift+Alt+Digit8', + 'Shift+Alt+Digit9', + 'Shift+Alt+Digit0' + ], + [] + ], + routeToStudioScreen: [], + routeToGraphicsEngine: [] + }, + feed: { + directCut: [], + queue: ['Digit1', 'Digit2', 'Digit3', 'Digit4', 'Digit5', 'Digit6', 'Digit7', 'Digit8', 'Digit9', 'Digit0'], + cutToBox: [ + [ + 'Shift+Digit1', + 'Shift+Digit2', + 'Shift+Digit3', + 'Shift+Digit4', + 'Shift+Digit5', + 'Shift+Digit6', + 'Shift+Digit7', + 'Shift+Digit8', + 'Shift+Digit9', + 'Shift+Digit0' + ], + [ + 'Ctrl+Digit1', + 'Ctrl+Digit2', + 'Ctrl+Digit3', + 'Ctrl+Digit4', + 'Ctrl+Digit5', + 'Ctrl+Digit6', + 'Ctrl+Digit7', + 'Ctrl+Digit8', + 'Ctrl+Digit9', + 'Ctrl+Digit0' + ], + [ + 'Shift+Alt+Digit1', + 'Shift+Alt+Digit2', + 'Shift+Alt+Digit3', + 'Shift+Alt+Digit4', + 'Shift+Alt+Digit5', + 'Shift+Alt+Digit6', + 'Shift+Alt+Digit7', + 'Shift+Alt+Digit8', + 'Shift+Alt+Digit9', + 'Shift+Alt+Digit0' + ], + [] + ], + routeToStudioScreen: [], + routeToGraphicsEngine: [] + }, + server: { + cutToBox: [['Shift+KeyT'], ['Ctrl+Alt+Shift+KeyG'], [], []] + }, + sisyfos: { + micsUp: 'Ctrl+Alt+Shift+KeyE', + micsDown: 'Ctrl+Alt+Shift+KeyD' + } + }), + rundownView: literal({ + activate: 'Backquote', + activateRehearsal: 'Ctrl+Backquote', + deactivate: 'Ctrl+Shift+Backquote', + take: 'AnyEnter', + goToLiveLive: 'Shift+Home', + rewindSegments: 'Ctrl+Home', + resetRundown: 'Shift+Escape', + moveNextForward: 'Shift+ArrowRight', + moveNextDown: 'Shift+ArrowDown', + moveNextBack: 'Shift+ArrowLeft', + moveNextUp: 'Shift+ArrowUp', + takeSnapshot: 'Shift+Backspace', + queueNextMiniShelfAdLib: 'Tab', + queuePreviousMiniShelfAdLib: 'Shift+Tab' + }) +} diff --git a/src/tv2-common/hotkeys/index.ts b/src/tv2-common/hotkeys/index.ts new file mode 100644 index 000000000..572d5cd29 --- /dev/null +++ b/src/tv2-common/hotkeys/index.ts @@ -0,0 +1,45 @@ +import { ISourceLayer } from '@tv2media/blueprints-integration' +import { + GlobalHotkeySourceLayers, + GlobalHotkeySources, + MakeGlobalTriggers, + MakeRundownViewTriggers, + TV2Hotkeys +} from 'tv2-common' +import { MakeActiveSegmentTriggers } from './segment' + +export * from './rundownView' +export * from './global' +export * from './hotkey-defaults' + +export interface ISourceLayerWithHotKeys extends ISourceLayer { + clearKeyboardHotkey?: string + activateKeyboardHotkeys?: string + assignHotkeysToGlobalAdlibs?: boolean + activateStickyKeyboardHotkey?: string +} + +export const TRIGGER_HOTKEYS_ON_KEYUP = true + +export function MakeAllAdLibsTriggers( + showStyleId: string, + assignments: TV2Hotkeys, + globalSources: GlobalHotkeySources, + globalSourceLayers: GlobalHotkeySourceLayers +) { + let rank = 1000 + const getNextRank = () => ++rank + const rundownViewTriggers = MakeRundownViewTriggers(showStyleId, assignments.rundownView, getNextRank) + rank = 2000 + const globalTriggers = MakeGlobalTriggers( + showStyleId, + assignments.global, + globalSources, + globalSourceLayers, + getNextRank + ) + rank = 3000 + const segmentTriggers = MakeActiveSegmentTriggers(showStyleId, assignments.activeSegment, getNextRank) + + return [...rundownViewTriggers, ...globalTriggers, ...segmentTriggers] +} diff --git a/src/tv2-common/hotkeys/local.ts b/src/tv2-common/hotkeys/local.ts new file mode 100644 index 000000000..48e0e507c --- /dev/null +++ b/src/tv2-common/hotkeys/local.ts @@ -0,0 +1,49 @@ +import { IBlueprintTriggeredActions } from '@tv2media/blueprints-integration' +import { AdlibTags } from 'tv2-constants' +import { replaySourceFullAudioName, replaySourceVoAudioName } from '../helpers' +import { MakeStudioSourceHotkeys, SourceHotkeyTriggers } from './helpers' + +export interface LocalSourceHotkeyAssignments { + fullAudio: SourceHotkeyTriggers + voAudio: SourceHotkeyTriggers +} + +function localSourceFullAudioHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_local_full_audio_${hotkeyType}_${index}` +} + +function localSourceVoAudioHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_local_vo_audio_${hotkeyType}_${index}` +} + +export function MakeLocalSourceHotkeys( + showStyleId: string, + sourceLayerId: string, + localSources: string[], + assignemnts: LocalSourceHotkeyAssignments, + getNextRank: () => number +): IBlueprintTriggeredActions[] { + const fullAudioKeys = MakeStudioSourceHotkeys( + showStyleId, + sourceLayerId, + localSources, + assignemnts.fullAudio, + getNextRank, + replaySourceFullAudioName, + localSourceFullAudioHotkeyId, + [AdlibTags.ADLIB_FULL_AUDIO_LEVEL] + ) + + const voAudioKeys = MakeStudioSourceHotkeys( + showStyleId, + sourceLayerId, + localSources, + assignemnts.voAudio, + getNextRank, + replaySourceVoAudioName, + localSourceVoAudioHotkeyId, + [AdlibTags.ADLIB_VO_AUDIO_LEVEL] + ) + + return [...fullAudioKeys, ...voAudioKeys] +} diff --git a/src/tv2-common/hotkeys/remote.ts b/src/tv2-common/hotkeys/remote.ts new file mode 100644 index 000000000..752cf6a28 --- /dev/null +++ b/src/tv2-common/hotkeys/remote.ts @@ -0,0 +1,36 @@ +import { IBlueprintTriggeredActions } from '@tv2media/blueprints-integration' +import { MakeStudioSourceHotkeys, SourceHotkeyTriggers } from './helpers' + +export type RemoteSourceHotkeyAssignments = SourceHotkeyTriggers + +function remoteHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_remote_${hotkeyType}_${index}` +} + +function feedHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_feed_${hotkeyType}_${index}` +} + +function remoteHotkeyName(remote: string) { + const feed = remote.match(/^F(.+).*$/) // TODO: fix when refactoring FindSourceInfo + return feed ? `FEED ${feed[1]}` : `LIVE ${remote}` +} + +export function MakeRemoteHotkeys( + showStyleId: string, + sourceLayerId: string, + remotes: string[], + assignments: RemoteSourceHotkeyAssignments, + getNextRank: () => number, + feed: boolean +): IBlueprintTriggeredActions[] { + return MakeStudioSourceHotkeys( + showStyleId, + sourceLayerId, + remotes, + assignments, + getNextRank, + remoteHotkeyName, + feed ? feedHotkeyId : remoteHotkeyId + ) +} diff --git a/src/tv2-common/hotkeys/rundownView.ts b/src/tv2-common/hotkeys/rundownView.ts new file mode 100644 index 000000000..406fb943a --- /dev/null +++ b/src/tv2-common/hotkeys/rundownView.ts @@ -0,0 +1,362 @@ +import { + ClientActions, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + IRundownPlaylistActivateAction, + PlayoutActions, + SomeAction, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' + +export interface RundownViewHotkeyAssignments { + activate: string + activateRehearsal: string + deactivate: string + take: string + goToLiveLive: string + rewindSegments: string + resetRundown: string + moveNextForward: string + moveNextDown: string + moveNextBack: string + moveNextUp: string + takeSnapshot: string + queueNextMiniShelfAdLib: string + queuePreviousMiniShelfAdLib: string +} + +function rundownViewActionTriggerId(showStyleId: string, action: string) { + return `${showStyleId}_rundown_view_${action}` +} + +export function MakeRundownViewTriggers( + showStyleId: string, + assignments: RundownViewHotkeyAssignments, + getNextRank: () => number +): IBlueprintTriggeredActions[] { + return [ + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'activate_rundown'), + _rank: getNextRank(), + name: 'Activate Rundown', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.activate + }) + ], + actions: [ + literal({ + action: PlayoutActions.activateRundownPlaylist, + rehearsal: false, + force: false, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'activate_rundown_rehearsal'), + _rank: getNextRank(), + name: 'øve rundown', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.activateRehearsal, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.activateRundownPlaylist, + rehearsal: true, + force: false, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'deactivate_rundown'), + _rank: getNextRank(), + name: 'Deactivate rundown', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.deactivate, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.deactivateRundownPlaylist, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'take'), + _rank: getNextRank(), + name: 'Take', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.take, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.take, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'go_to_live'), + _rank: getNextRank(), + name: 'gå til aktiv linje', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.goToLiveLive, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: ClientActions.goToOnAirLine, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'rewind_segments'), + _rank: getNextRank(), + name: 'REW tidslinje', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.rewindSegments, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: ClientActions.rewindSegments, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'reset_rundown'), + _rank: getNextRank(), + name: 'Reload rundown', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.resetRundown, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.resetRundownPlaylist, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'move_next_forward'), + _rank: getNextRank(), + name: 'hist. højre SKIP', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.moveNextForward, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.moveNext, + segments: 0, + parts: 1, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'move_next_down'), + _rank: getNextRank(), + name: 'hist. ned SKIP', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.moveNextDown, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.moveNext, + segments: 1, + parts: 0, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'move_next_back'), + _rank: getNextRank(), + name: 'hist. venstre SKIP', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.moveNextBack, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.moveNext, + segments: 0, + parts: -1, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'move_next_up'), + _rank: getNextRank(), + name: 'hist. op SKIP', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.moveNextUp, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.moveNext, + segments: -1, + parts: 0, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'log_error'), + _rank: getNextRank(), + name: 'Take Snapshot', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.takeSnapshot, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: PlayoutActions.createSnapshotForDebug, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'queue_next_adlib'), + _rank: getNextRank(), + name: 'Queue Next AdLib', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.queueNextMiniShelfAdLib, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: ClientActions.miniShelfQueueAdLib, + forward: true, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }), + literal({ + _id: rundownViewActionTriggerId(showStyleId, 'queue_previous_adlib'), + _rank: getNextRank(), + name: 'Queue Previous AdLib', + triggers: [ + literal({ + type: TriggerType.hotkey, + keys: assignments.queuePreviousMiniShelfAdLib, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ], + actions: [ + literal({ + action: ClientActions.miniShelfQueueAdLib, + forward: false, + filterChain: [ + literal({ + object: 'view' + }) + ] + }) + ] + }) + ] +} diff --git a/src/tv2-common/hotkeys/segment.ts b/src/tv2-common/hotkeys/segment.ts new file mode 100644 index 000000000..742d5832f --- /dev/null +++ b/src/tv2-common/hotkeys/segment.ts @@ -0,0 +1,90 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags, SharedSourceLayers } from 'tv2-constants' + +export interface ActiveSegmentHotketAssignments { + lowerThirds: string[] +} + +function activeSegmentAdLibHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_graphics_${hotkeyType}_${index}` +} + +export function MakeActiveSegmentTriggers( + showStyleId: string, + assignments: ActiveSegmentHotketAssignments, + getNextRank: () => number +) { + return assignments.lowerThirds.map((key, index) => + makeSegmentHotKey( + SharedSourceLayers.PgmGraphicsLower, + getNextRank, + activeSegmentAdLibHotkeyId(showStyleId, SharedSourceLayers.PgmGraphicsLower, key, index), + `Lower GFX AdLib ${index + 1}`, + key, + index + ) + ) +} + +function makeSegmentHotKey( + sourceLayerId: string, + getNextRank: () => number, + id: string, + name: string, + hotkey: string | undefined, + pick: number +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'segment', + value: 'current' + }), + literal({ + object: 'adLib', + field: 'tag', + value: [AdlibTags.ADLIB_FLOW_PRODUCER] + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'pick', + value: pick + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/hotkeys/server.ts b/src/tv2-common/hotkeys/server.ts new file mode 100644 index 000000000..8df38e639 --- /dev/null +++ b/src/tv2-common/hotkeys/server.ts @@ -0,0 +1,62 @@ +import { IBlueprintTriggeredActions } from '@tv2media/blueprints-integration' +import { DVEBoxTriggers, MakeCutToBoxTrigger } from './helpers' + +const SERVER_TO_BOX_1_HOTKEYS: string[] = ['Shift+KeyT'] + +const SERVER_TO_BOX_2_HOTKEYS: string[] = ['Ctrl+Alt+Shift+KeyG'] + +const SERVER_TO_BOX_3_HOTKEYS: string[] = [] + +const SERVER_TO_BOX_4_HOTKEYS: string[] = [] + +const CUT_TO_BOX_HOTKEYS: DVEBoxTriggers = [ + SERVER_TO_BOX_1_HOTKEYS, + SERVER_TO_BOX_2_HOTKEYS, + SERVER_TO_BOX_3_HOTKEYS, + SERVER_TO_BOX_4_HOTKEYS +] + +export interface ServerHotkeyAssignments { + cutToBox: DVEBoxTriggers +} + +function serverHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_server_${hotkeyType}_${index}` +} + +function serverHotkeyName() { + return `serv` +} + +const SERVER_SOURCES = ['casparcg'] + +export function MakeServerHotkeys( + showStyleId: string, + sourceLayerId: string, + getNextRank: () => number +): IBlueprintTriggeredActions[] { + const cutToBoxHotkeys: IBlueprintTriggeredActions[] = [] + for (let currentSourceIndex = 0; currentSourceIndex < SERVER_SOURCES.length; currentSourceIndex++) { + const name = serverHotkeyName() + + for (let box = 0; box < CUT_TO_BOX_HOTKEYS.length; box++) { + if (CUT_TO_BOX_HOTKEYS[box].length) { + const boxHotkey = CUT_TO_BOX_HOTKEYS[box][currentSourceIndex] + cutToBoxHotkeys.push( + MakeCutToBoxTrigger( + serverHotkeyId(showStyleId, sourceLayerId, `cut_to_box_${box + 1}`, currentSourceIndex), + getNextRank, + name + ` inp ${box + 1}`, + boxHotkey, + sourceLayerId, + [], + currentSourceIndex, + box + ) + ) + } + } + } + + return cutToBoxHotkeys +} diff --git a/src/tv2-common/hotkeys/sisyfos.ts b/src/tv2-common/hotkeys/sisyfos.ts new file mode 100644 index 000000000..4b2f4af63 --- /dev/null +++ b/src/tv2-common/hotkeys/sisyfos.ts @@ -0,0 +1,100 @@ +import { + IAdLibFilterLink, + IAdlibPlayoutAction, + IBlueprintHotkeyTrigger, + IBlueprintTriggeredActions, + IGUIContextFilterLink, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' +import { literal, TRIGGER_HOTKEYS_ON_KEYUP } from 'tv2-common' +import { AdlibTags } from 'tv2-constants' + +export interface SisyfosHotkeyAssignments { + micsUp: string + micsDown: string +} + +function sisyfosHotkeyId(showStyleId: string, sourceLayer: string, hotkeyType: string, index: number) { + return `${showStyleId}_${sourceLayer}_dve_layout_${hotkeyType}_${index}` +} + +export function MakeSisyfosHotkeys( + showStyleId: string, + sourceLayerId: string, + assignments: SisyfosHotkeyAssignments, + getNextRank: () => number +) { + return [ + makeSisyfosHotKey( + sourceLayerId, + getNextRank, + sisyfosHotkeyId(showStyleId, sourceLayerId, 'mics_up', 0), + 'mics OP', + assignments.micsUp, + [AdlibTags.ADLIB_MICS_UP] + ), + makeSisyfosHotKey( + sourceLayerId, + getNextRank, + sisyfosHotkeyId(showStyleId, sourceLayerId, 'mics_down', 0), + 'mics NED', + assignments.micsDown, + [AdlibTags.ADLIB_MICS_DOWN] + ) + ] +} + +function makeSisyfosHotKey( + sourceLayerId: string, + getNextRank: () => number, + id: string, + name: string, + hotkey: string | undefined, + tags: string[] +) { + return literal({ + _id: id, + _rank: getNextRank(), + name, + triggers: hotkey + ? [ + literal({ + type: TriggerType.hotkey, + keys: hotkey, + up: TRIGGER_HOTKEYS_ON_KEYUP + }) + ] + : [], + actions: [ + literal({ + action: PlayoutActions.adlib, + filterChain: [ + literal({ + object: 'view' + }), + literal({ + object: 'adLib', + field: 'sourceLayerId', + value: [sourceLayerId] + }), + literal({ + object: 'adLib', + field: 'global', + value: true + }), + literal({ + object: 'adLib', + field: 'tag', + value: tags + }), + literal({ + object: 'adLib', + field: 'pick', + value: 0 + }) + ] + }) + ] + }) +} diff --git a/src/tv2-common/index.ts b/src/tv2-common/index.ts index 382b2e3e7..3d5e96e8f 100644 --- a/src/tv2-common/index.ts +++ b/src/tv2-common/index.ts @@ -1,25 +1,26 @@ export * from './actions' +export * from './blueprintConfig' +export * from './content' +export * from './cues' export * from './cueTiming' +export * from './evaluateCues' export * from './frameTime' -export * from './inewsConversion' -export * from './util' -export * from './sources' -export * from './time/partTime' export * from './getSegment' -export * from './blueprintConfig' -export * from './nextPartCue' +export * from './helpers' +export * from './hotkeys' +export * from './inewsConversion' export * from './jinglePartProperties' -export * from './evaluateCues' -export * from './transitionFromString' -export * from './transitionSettings' -export * from './cues' +export * from './layers' +export * from './migrations' +export * from './nextPartCue' +export * from './onTimelineGenerate' export * from './parts' export * from './pieces' -export * from './content' -export * from './onTimelineGenerate' -export * from './helpers' +export * from './sources' +export * from './time/partTime' +export * from './atemTransitionStyleFromString' +export * from './transitionSettings' export * from './translateEngine' -export * from './layers' export * from './types' -export * from './migrations' export * from './updatePolicies' +export * from './util' diff --git a/src/tv2-common/inewsConversion/converters/ParseBody.ts b/src/tv2-common/inewsConversion/converters/ParseBody.ts index 2ee078048..8e14270a8 100644 --- a/src/tv2-common/inewsConversion/converters/ParseBody.ts +++ b/src/tv2-common/inewsConversion/converters/ParseBody.ts @@ -1,17 +1,94 @@ -import { PostProcessDefinitions, TV2BlueprintConfig, UnparsedCue } from 'tv2-common' -import { CueType, PartType } from 'tv2-constants' -import { CueDefinition, CueDefinitionUnpairedPilot, ParseCue, UnpairedPilotToGraphic } from './ParseCue' +import { TSR } from '@tv2media/blueprints-integration' +import { + AtemTransitionStyleFromString, + CueDefinitionFromLayout, + PostProcessDefinitions, + TV2BlueprintConfig, + UnparsedCue +} from 'tv2-common' +import { CueType, PartType, SourceType } from 'tv2-constants' +import { CueDefinition, ParseCue, UnpairedPilotToGraphic } from './ParseCue' export interface PartTransition { - style: string + style: TSR.AtemTransitionStyle duration?: number } +export interface SourceDefinitionBase { + sourceType: SourceType + name?: string +} +export interface SourceDefinitionWithRaw { + raw: string +} + +export interface SourceDefinitionKam extends SourceDefinitionWithRaw { + sourceType: SourceType.KAM + /** name that appears in the Camera Mappings table (e.g. "1", "CS 3") */ + id: string + /** full name for display/logging purposes e.g. "KAM 1" */ + name: string + minusMic: boolean +} + +export interface SourceDefinitionReplay extends SourceDefinitionWithRaw { + sourceType: SourceType.REPLAY + /** id that appears in the Replay Mappings table (e.g. "EVS 1", "EPSIO") */ + id: string + /** full name for display/logging purposes e.g. "EVS 1 VO" */ + name: string + vo: boolean +} + +export enum RemoteType { + LIVE = 'LIVE', + FEED = 'FEED' +} +export interface SourceDefinitionRemote extends SourceDefinitionWithRaw { + sourceType: SourceType.REMOTE + remoteType: RemoteType + /** name that appears in the Remote Mappings table (e.g. "1", "2") */ + id: string + /** full name for display/logging purposes e.g. "LIVE 1" */ + name: string +} +export interface SourceDefinitionInvalid extends SourceDefinitionWithRaw { + sourceType: SourceType.INVALID + /** full name for display/logging purposes */ + name: string +} + +export interface SourceDefinitionServer extends SourceDefinitionBase { + sourceType: SourceType.SERVER +} + +export interface SourceDefinitionGrafik extends SourceDefinitionWithRaw { + sourceType: SourceType.GRAFIK + name: string +} + +export interface SourceDefinitionDefault extends SourceDefinitionBase { + sourceType: SourceType.DEFAULT +} + +export interface SourceDefinitionPGM extends SourceDefinitionBase { + sourceType: SourceType.PGM +} + +export type SourceDefinition = + | SourceDefinitionKam + | SourceDefinitionReplay + | SourceDefinitionRemote + | SourceDefinitionServer + | SourceDefinitionGrafik + | SourceDefinitionDefault + | SourceDefinitionPGM + | SourceDefinitionInvalid + export interface PartDefinitionBase { externalId: string type: PartType rawType: string - variant: {} effekt?: number cues: CueDefinition[] script: string @@ -27,47 +104,35 @@ export interface PartDefinitionBase { export interface PartDefinitionUnknown extends PartDefinitionBase { type: PartType.Unknown - variant: {} } - export interface PartDefinitionKam extends PartDefinitionBase { type: PartType.Kam - variant: { - name: string - } + /** Definition of the primary source */ + sourceDefinition: SourceDefinitionKam } - export interface PartDefinitionServer extends PartDefinitionBase { type: PartType.Server - variant: {} } export interface PartDefinitionTeknik extends PartDefinitionBase { type: PartType.Teknik - variant: {} } export interface PartDefinitionGrafik extends PartDefinitionBase { type: PartType.Grafik - variant: {} } export interface PartDefinitionVO extends PartDefinitionBase { type: PartType.VO - variant: {} } export interface PartDefinitionIntro extends PartDefinitionBase { type: PartType.INTRO - variant: {} } - export interface PartDefinitionEVS extends PartDefinitionBase { type: PartType.EVS - variant: { - evs: string - isVO: boolean - } + /** Definition of the primary source */ + sourceDefinition: SourceDefinitionReplay } export interface PartDefinitionDVE extends PartDefinitionBase { @@ -75,7 +140,7 @@ export interface PartDefinitionDVE extends PartDefinitionBase { } export interface PartDefinitionEkstern extends PartDefinitionBase { - type: PartType.Ekstern + type: PartType.REMOTE } export interface PartDefinitionTelefon extends PartDefinitionBase { @@ -95,19 +160,23 @@ export type PartDefinition = | PartDefinitionEkstern | PartDefinitionTelefon export type PartdefinitionTypes = - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - | Pick - -const ACCEPTED_RED_TEXT = /\b(KAM(?:\d+)?|CAM(?:\d+)?|KAMERA(?:\d+)?|CAMERA(?:\d+)?|SERVER|ATTACK|TEKNIK|GRAFIK|EVS ?\d+(?:VOV?)?|VOV?|VOSB)+\b/gi + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + | Pick + +const CAMERA_RED_TEXT = /\b[KC]AM(?:ERA)? ?(\S+)\b/i +const EVS_RED_TEXT = /\bEVS ?(\d+) ?(VOV?)?\b/i +const ACCEPTED_RED_TEXT = [/\b(SERVER|ATTACK|TEKNIK|GRAFIK|EPSIO|VOV?|VOSB)+\b/i, CAMERA_RED_TEXT, EVS_RED_TEXT] +const REMOTE_CUE = /^(LIVE|FEED) ?([^\s]+)(?: (.+))?$/i +const ENGINE_CUE = /ENGINE ?([^\s]+)/i export function ParseBody( config: TV2BlueprintConfig, @@ -118,12 +187,18 @@ export function ParseBody( fields: any, modified: number ): PartDefinition[] { - const definitions: PartDefinition[] = [] + let definitions: PartDefinition[] = [] let definition: PartDefinition = initDefinition(fields, modified, segmentName) // Handle intro segments, they have special behaviour. if (segmentName === 'INTRO') { - ;((definition as unknown) as PartDefinitionIntro).type = PartType.INTRO + definition = { + ...definition, + type: PartType.INTRO, + rawType: 'INTRO', + externalId: `${segmentId}-${definitions.length}`, + segmentExternalId: segmentId + } cues.forEach(cue => { if (cue !== null) { const parsedCue = ParseCue(cue, config) @@ -133,9 +208,6 @@ export function ParseBody( } } }) - definition.rawType = 'INTRO' - definition.externalId = `${segmentId}-${definitions.length}` - definition.segmentExternalId = segmentId definitions.push(definition) definition = initDefinition(fields, modified, segmentName) return definitions @@ -161,11 +233,11 @@ export function ParseBody( .replace(/<\/tab>/i, '') .trim() - if (typeStr && !!typeStr.match(ACCEPTED_RED_TEXT)) { + if (typeStr && ACCEPTED_RED_TEXT.some(r => r.test(typeStr))) { const inlineCues = line .replace(/<\/?p>/g, '') .split(/(.*?)<\/pi>/i) - .filter(cue => cue !== '' && !cue.match(/<\/a>/)) + .filter(cue => cue !== '' && !/<\/a>/.test(cue)) /** Hold any secondary cues in the form: `[] KAM 1` */ const secondaryInlineCues: CueDefinition[] = [] @@ -174,7 +246,7 @@ export function ParseBody( let pos = 0 let redTextFound = false while (pos < inlineCues.length && !redTextFound) { - if (inlineCues[pos].match(ACCEPTED_RED_TEXT)) { + if (ACCEPTED_RED_TEXT.some(r => r.test(inlineCues[pos]))) { redTextFound = true } else { const parsedCues = getCuesInLine(inlineCues[pos], cues, config) @@ -182,7 +254,7 @@ export function ParseBody( // Create standalone parts for primary cues. if ( isPrimaryCue(cue) && - !(cue.type === CueType.UNPAIRED_TARGET && cue.target === 'FULL' && !!typeStr.match(/GRAFIK/i)) + !(cue.type === CueType.UNPAIRED_TARGET && cue.target === 'FULL' && /GRAFIK/i.test(typeStr)) ) { if (shouldPushDefinition(definition)) { definitions.push(definition) @@ -212,7 +284,7 @@ export function ParseBody( line = line.replace(/<\/a>/g, '') const lastCue = definition.cues[definition.cues.length - 1] - if (typeStr.match(/GRAFIK/i) && lastCue && lastCue.type === CueType.UNPAIRED_TARGET && !definition.script) { + if (/GRAFIK/i.test(typeStr) && lastCue && lastCue.type === CueType.UNPAIRED_TARGET && !definition.script) { definition = makeDefinition(segmentId, definitions.length, typeStr, fields, modified, segmentName) definition.cues.push(lastCue) } else { @@ -227,7 +299,7 @@ export function ParseBody( definition.cues.push(...secondaryInlineCues) } - if (typeStr && typeStr.match(/SLUTORD/i)) { + if (typeStr && /SLUTORD/i.test(typeStr)) { if (definition.endWords) { definition.endWords += ` ${typeStr.replace(/^SLUTORD:? ?/i, '')}` } else { @@ -287,6 +359,8 @@ export function ParseBody( partDefinition.cues = partDefinition.cues.filter(c => c.type !== CueType.UNKNOWN) }) + definitions = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + return PostProcessDefinitions(definitions, segmentId) } @@ -317,7 +391,7 @@ export function FindTargetPair(partDefinition: PartDefinition): boolean { } if (nextCue.type === CueType.UNPAIRED_PILOT) { - const mosCue = nextCue as CueDefinitionUnpairedPilot + const mosCue = nextCue if (targetCue.type === CueType.UNPAIRED_TARGET) { partDefinition.cues[index] = UnpairedPilotToGraphic(mosCue, targetCue.target, targetCue) } else if (targetCue.type === CueType.Telefon) { @@ -338,7 +412,6 @@ function initDefinition(fields: any, modified: number, segmentName: string): Par externalId: '', type: PartType.Unknown, rawType: '', - variant: {}, cues: [], script: '', fields, @@ -350,7 +423,7 @@ function initDefinition(fields: any, modified: number, segmentName: string): Par /** Returns true if there is a cue in the given line. */ function cueInLine(line: string) { - return !!line.match(//gi) + return //i.test(line) } /** Returns all the cues in a given line as parsed cues. */ @@ -380,8 +453,8 @@ function getCuesInLine(line: string, cues: UnparsedCue[], config: TV2BlueprintCo } function addScript(line: string, definition: PartDefinition) { - const script = line.match(/

(.*)?<\/p>/i) - if (script && script[1] && !script[1].match(/(.*?)<\/pi>/i)) { + const script = line.match(/

(.*?)<\/p>/i) + if (script && script[1] && !/.*?<\/pi>/i.test(script[1])) { const trimscript = script[1] .replace(/<.*?>/gi, '') .replace('\n\r', '') @@ -425,7 +498,7 @@ function makeDefinitionPrimaryCue( switch (cue.type) { case CueType.Ekstern: definition = { ...definition, ...cue.transition } - definition.type = PartType.Ekstern + definition.type = PartType.REMOTE break case CueType.DVE: definition.type = PartType.DVE @@ -492,7 +565,7 @@ export function getTransitionProperties(typeStr: string): Pick = getTransitionProperties(typeStr) + const transitionAndEffekt: Pick = getTransitionProperties(typeStr) + + const sourceDefinition = getSourceDefinition(typeStr) + switch (sourceDefinition?.sourceType) { + case SourceType.KAM: + return { + type: PartType.Kam, + sourceDefinition, + ...transitionAndEffekt + } + case SourceType.REPLAY: + return { + type: PartType.EVS, + sourceDefinition, + ...transitionAndEffekt + } + default: + break + } + const tokens = stripTransitionProperties(typeStr) .replace(/100%/g, '') .trim() .split(' ') const firstToken = tokens[0] - if (firstToken.match(/KAM|CAM/i)) { - const adjacentKamNumber = tokens[0].match(/KAM(\d+)/i) - return { - type: PartType.Kam, - variant: { - name: adjacentKamNumber ? adjacentKamNumber[1] : tokens[1] - }, - ...definition - } - } else if (firstToken.match(/SERVER/i) || firstToken.match(/ATTACK/i)) { + if (/SERVER|ATTACK/i.test(firstToken)) { return { type: PartType.Server, - variant: {}, - ...definition + ...transitionAndEffekt } - } else if (firstToken.match(/TEKNIK/i)) { + } else if (/TEKNIK/i.test(firstToken)) { return { type: PartType.Teknik, - variant: {}, - ...definition + ...transitionAndEffekt } - } else if (firstToken.match(/GRAFIK/i)) { + } else if (/GRAFIK/i.test(firstToken)) { return { type: PartType.Grafik, - variant: {}, - ...definition + ...transitionAndEffekt } - } else if (typeStr.match(/EVS ?\d+(?:VOV?)?/i)) { - const strippedToken = typeStr.match(/EVS ?(\d+)(VOV?)?/i) + } else if (/VOV?|VOSB/i.test(firstToken)) { return { - type: PartType.EVS, - variant: { - evs: strippedToken && strippedToken[1] ? strippedToken[1] : '1', - isVO: !!strippedToken && !!strippedToken[2] - }, - ...definition + type: PartType.VO, + ...transitionAndEffekt } - } else if (firstToken.match(/VOV?/i)) { + } else { return { - type: PartType.VO, - variant: {}, - ...definition + type: PartType.Unknown, + ...transitionAndEffekt } - } else if (firstToken.match(/VOSB/i)) { + } +} + +export function getSourceDefinition(typeStr: string): SourceDefinition | undefined { + const strippedTypeStr = stripTransitionProperties(typeStr) + .replace(/100%/g, '') + .trim() + if (CAMERA_RED_TEXT.test(strippedTypeStr)) { + const id = strippedTypeStr.match(CAMERA_RED_TEXT)![1].toUpperCase() return { - type: PartType.VO, - variant: {}, - ...definition + sourceType: SourceType.KAM, + id, + minusMic: isMinusMic(typeStr), + raw: strippedTypeStr, + name: `KAM ${id}` } - } else { + } else if (REMOTE_CUE.test(typeStr)) { + const remoteNumber = typeStr.match(REMOTE_CUE) + const variant = remoteNumber![1].toUpperCase() as RemoteType + const id = remoteNumber![2] return { - type: PartType.Unknown, - variant: {}, - ...definition + sourceType: SourceType.REMOTE, + remoteType: variant, + id, + raw: strippedTypeStr, + name: `${variant} ${id}` + } + } else if (EVS_RED_TEXT.test(typeStr)) { + const strippedToken = typeStr.match(EVS_RED_TEXT) + const id = `EVS ${strippedToken![1].toUpperCase()}` + const vo = strippedToken![2] + return { + sourceType: SourceType.REPLAY, + id, + vo: !!vo, + raw: strippedToken![0].trim(), + name: `${id}${vo ? ' ' + vo : ''}` + } + } else if (/EPSIO/i.test(typeStr)) { + return { + sourceType: SourceType.REPLAY, + id: 'EPSIO', + vo: true, + raw: typeStr, + name: 'EPSIO' + } + } else if (ENGINE_CUE.test(typeStr)) { + const strippedToken = typeStr.match(ENGINE_CUE) + return { + sourceType: SourceType.GRAFIK, + name: strippedToken![1].toUpperCase(), + raw: typeStr + } + } else if (/DEFAULT/i.test(typeStr)) { + return { + sourceType: SourceType.DEFAULT } + } else if (/SERVER/i.test(typeStr)) { + return { + sourceType: SourceType.SERVER + } + } else if (/PGM/i.test(typeStr)) { + return { + sourceType: SourceType.PGM + } + } + return undefined +} + +export function isMinusMic(inputName: string): boolean { + return /minus mic/i.test(inputName) +} + +export function stripRedundantCuesWhenLayoutCueIsPresent(partDefinitions: PartDefinition[]): PartDefinition[] { + const hasLayoutCue: boolean = partDefinitions.some(definition => + definition.cues.some(cue => { + const cueFromLayout = cue as CueDefinitionFromLayout + return cueFromLayout.isFromLayout + }) + ) + + if (!hasLayoutCue) { + return partDefinitions } + + return partDefinitions.map(definition => { + const cues = definition.cues.filter(cue => { + if (cue.type !== CueType.GraphicDesign && cue.type !== CueType.BackgroundLoop) { + return true + } + return (cue as CueDefinitionFromLayout).isFromLayout + }) + return { + ...definition, + cues + } + }) } diff --git a/src/tv2-common/inewsConversion/converters/ParseCue.ts b/src/tv2-common/inewsConversion/converters/ParseCue.ts index b9476f8b1..fa52631e8 100644 --- a/src/tv2-common/inewsConversion/converters/ParseCue.ts +++ b/src/tv2-common/inewsConversion/converters/ParseCue.ts @@ -1,6 +1,15 @@ -import { GetInfiniteModeForGraphic, literal, TV2BlueprintConfig, UnparsedCue } from 'tv2-common' -import { CueType, GraphicEngine, PartType } from 'tv2-constants' -import { getTransitionProperties, PartDefinition, PartdefinitionTypes, stripTransitionProperties } from './ParseBody' +import { GetPieceLifespanForGraphic, literal, TableConfigSchema, TV2BlueprintConfig, UnparsedCue } from 'tv2-common' +import { CueType, GraphicEngine, PartType, SourceType } from 'tv2-constants' +import { + getSourceDefinition, + getTransitionProperties, + PartDefinition, + PartdefinitionTypes, + SourceDefinition, + SourceDefinitionInvalid, + SourceDefinitionRemote, + stripTransitionProperties +} from './ParseBody' export interface CueTime { frames?: number @@ -22,15 +31,16 @@ export interface CueDefinitionUnknown extends CueDefinitionBase { export interface CueDefinitionEkstern extends CueDefinitionBase { type: CueType.Ekstern - source: string + /** Definition of the primary source */ + sourceDefinition: SourceDefinitionRemote | SourceDefinitionInvalid transition?: Pick } export interface DVESources { - INP1?: string - INP2?: string - INP3?: string - INP4?: string + INP1?: SourceDefinition + INP2?: SourceDefinition + INP3?: SourceDefinition + INP4?: SourceDefinition } export interface CueDefinitionDVE extends CueDefinitionBase { @@ -81,7 +91,7 @@ export interface CueDefinitionClearGrafiks extends CueDefinitionBase { export interface CueDefinitionMixMinus extends CueDefinitionBase { type: CueType.MixMinus - source: string + sourceDefinition: SourceDefinition } // If unpaired when evaluated, throw warning. If target === 'FULL' create invalid part. @@ -100,17 +110,21 @@ export interface CueDefinitionUnpairedPilot extends CueDefinitionBase { engineNumber?: number } -export interface CueDefinitionBackgroundLoop extends CueDefinitionBase { +export interface CueDefinitionBackgroundLoop extends CueDefinitionBase, CueDefinitionFromLayout { type: CueType.BackgroundLoop target: 'FULL' | 'DVE' backgroundLoop: string } -export interface CueDefinitionGraphicDesign extends CueDefinitionBase { +export interface CueDefinitionGraphicDesign extends CueDefinitionBase, CueDefinitionFromLayout { type: CueType.GraphicDesign design: string } +export interface CueDefinitionFromLayout { + isFromLayout?: boolean +} + export interface GraphicInternal { type: 'internal' template: string @@ -138,13 +152,13 @@ export interface CueDefinitionGraphic extends export interface CueDefinitionRouting extends CueDefinitionBase { type: CueType.Routing target: GraphicEngine - INP?: string - INP1?: string + INP?: SourceDefinition + INP1?: SourceDefinition } export interface CueDefinitionPgmClean extends CueDefinitionBase { type: CueType.PgmClean - source: 'PGM' | string + sourceDefinition: SourceDefinition } export type CueDefinition = @@ -233,6 +247,10 @@ export function ParseCue(cue: UnparsedCue, config: TV2BlueprintConfig): CueDefin return parsePgmClean(cue) } else if (cue[0].match(/^MINUSKAM\s*=/i)) { return parseMixMinus(cue) + } else if (cue[0].match(/^DESIGN_LAYOUT=/i)) { + return parseDesignLayout(cue, config) + } else if (cue[0].match(/^DESIGN_BG=/i)) { + return parseDesignBg(cue, config) } return literal({ @@ -412,12 +430,20 @@ function parsePilot(cue: string[]): CueDefinitionUnpairedPilot | CueDefinitionGr function parseEkstern(cue: string[]): CueDefinitionEkstern | undefined { const eksternSource = stripTransitionProperties(cue[0]).match(/^EKSTERN=(.+)$/i) if (eksternSource) { + let sourceDefinition = getSourceDefinition(eksternSource[1]) + if (sourceDefinition?.sourceType !== SourceType.REMOTE) { + sourceDefinition = { + sourceType: SourceType.INVALID, + name: eksternSource[1], + raw: eksternSource[1] + } + } const transitionProperties = getTransitionProperties(cue[0]) return literal({ type: CueType.Ekstern, - source: eksternSource[1].replace(/\s+/i, ' ').trim(), iNewsCommand: 'EKSTERN', - transition: transitionProperties + transition: transitionProperties, + sourceDefinition }) } @@ -442,7 +468,7 @@ function parseDVE(cue: string[]): CueDefinitionDVE { } else if (c.match(/^INP\d+=/i)) { const input = c.match(/^(INP\d)+=(.+)$/i) if (input && input[1] && input[2]) { - dvecue.sources[input[1].toUpperCase() as keyof DVESources] = input[2] + dvecue.sources[input[1].toUpperCase() as keyof DVESources] = getSourceDefinition(input[2]) } } else if (c.match(/^BYNAVN=/i)) { const labels = c.match(/^BYNAVN=(.+)$/i) @@ -552,13 +578,13 @@ function parseAdLib(cue: string[]) { } // tslint:disable-next-line: prefer-for-of - for (let i = 0; i < cue.length; i++) { - const input = cue[i].match(/^(INP\d)+=(.+)$/i) + for (const element of cue) { + const input = element.match(/^(INP\d)+=(.+)$/i) if (input && input[1] && input[2] && adlib.inputs !== undefined) { - adlib.inputs[input[1].toString().toUpperCase() as keyof DVESources] = input[2] + adlib.inputs[input[1].toUpperCase() as keyof DVESources] = getSourceDefinition(input[2]) } - const bynavn = cue[i].match(/^BYNAVN=(.+)$/i) + const bynavn = element.match(/^BYNAVN=(.+)$/i) if (bynavn) { adlib.bynavn = bynavn[1].split(/\/|\\/i) } @@ -657,7 +683,7 @@ function parseTargetEngine( target: engineCue.target, iNewsCommand: '' } - + let hasInputs = false for (let i = 1; i < cue.length; i++) { if (isTime(cue[i])) { engineCue = { ...engineCue, ...parseTime(cue[i]) } @@ -665,16 +691,18 @@ function parseTargetEngine( const c = cue[i].split('=') const input = c[0].toString().toUpperCase() if (input === 'INP') { - routing.INP = c[1] + routing.INP = getSourceDefinition(c[1]) + hasInputs = true } if (input === 'INP1') { - routing.INP1 = c[1] + routing.INP1 = getSourceDefinition(c[1]) + hasInputs = true } } } - if (routing.INP1 !== undefined || routing.INP !== undefined) { + if (hasInputs) { engineCue.routing = routing } @@ -745,14 +773,17 @@ function parseAllOut(cue: string[]): CueDefinitionClearGrafiks { } export function parsePgmClean(cue: string[]): CueDefinitionPgmClean { + const pgmSource = cue[0].match(/^PGMCLEAN=(.+)$/i) const pgmCleanCue: CueDefinitionPgmClean = { type: CueType.PgmClean, - source: 'PGM', - iNewsCommand: 'PGMCLEAN' + iNewsCommand: 'PGMCLEAN', + sourceDefinition: { sourceType: SourceType.PGM } } - const pgmSource = cue[0].match(/^PGMCLEAN=(.+)$/i) if (pgmSource && pgmSource[1]) { - pgmCleanCue.source = pgmSource[1].toString().toUpperCase() + const sourceDefinition = getSourceDefinition(pgmSource[1]) + if (sourceDefinition) { + pgmCleanCue.sourceDefinition = sourceDefinition + } } return pgmCleanCue } @@ -762,9 +793,13 @@ export function parseMixMinus(cue: string[]): CueDefinitionMixMinus | undefined if (sourceMatch === null) { return undefined } + const sourceDefinition = getSourceDefinition(sourceMatch.groups!.source) + if (sourceDefinition === undefined) { + return undefined + } return literal({ type: CueType.MixMinus, - source: sourceMatch.groups!.source.toUpperCase(), + sourceDefinition, iNewsCommand: 'MINUSKAM' }) } @@ -841,6 +876,48 @@ export function parseTime(line: string): Pick({ + type: CueType.GraphicDesign, + design: tableConfigSchema.vizTemplateName, + iNewsCommand: layout, + start: { + frames: 1 + }, + isFromLayout: true + }) +} + +function findSchemaConfiguration(config: TV2BlueprintConfig, designIdentifier: string): TableConfigSchema | undefined { + return config.showStyle.SchemaConfig.find( + schema => schema.designIdentifier && schema.designIdentifier.toUpperCase() === designIdentifier.toUpperCase() + ) +} + +function parseDesignBg(cue: string[], config: TV2BlueprintConfig): CueDefinitionBackgroundLoop | undefined { + const array = cue[0].split('DESIGN_BG=') + const layout = array[1] + const tableConfigSchema = findSchemaConfiguration(config, layout) + if (!tableConfigSchema) { + return undefined + } + + return literal({ + type: CueType.BackgroundLoop, + target: 'DVE', + backgroundLoop: tableConfigSchema.casparCgDveBgScene, + iNewsCommand: layout, + isFromLayout: true + }) +} + /** * Creates a parent class for a part, for keeping children of the parent alive when the parent is alive. * @param studio Studio name that the part belongs to. @@ -849,7 +926,7 @@ export function parseTime(line: string): Pick - c.type === CueType.Graphic && - GraphicIsInternal(c) && - GetInfiniteModeForGraphic(c.target, config, c, IsStickyIdent(c)) + c => c.type === CueType.Graphic && GraphicIsInternal(c) && GetPieceLifespanForGraphic(c.target, config, c) ) } -export function IsStickyIdent(cue: CueDefinitionGraphic) { - return !!cue.graphic.template.match(/direkte/i) -} - export function UnpairedPilotToGraphic( pilotCue: CueDefinitionUnpairedPilot, target: GraphicEngine, diff --git a/src/tv2-common/inewsConversion/converters/__tests__/body-parser.spec.ts b/src/tv2-common/inewsConversion/converters/__tests__/body-parser.spec.ts index 448c42579..b6e578307 100644 --- a/src/tv2-common/inewsConversion/converters/__tests__/body-parser.spec.ts +++ b/src/tv2-common/inewsConversion/converters/__tests__/body-parser.spec.ts @@ -1,6 +1,11 @@ -import { IBlueprintRundownDB, PlaylistTimingType } from '@sofie-automation/blueprints-integration' -import { UnparsedCue } from 'tv2-common' -import { CueType, PartType } from 'tv2-constants' +import { IBlueprintRundownDB, PlaylistTimingType, TSR } from '@tv2media/blueprints-integration' +import { + CueDefinitionBackgroundLoop, + CueDefinitionGraphicDesign, + stripRedundantCuesWhenLayoutCueIsPresent, + UnparsedCue +} from 'tv2-common' +import { CueType, PartType, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../../../__mocks__/context' import { defaultShowStyleConfig, defaultStudioConfig } from '../../../../tv2_afvd_showstyle/__tests__/configs' import { getConfig, parseConfig as parseShowStyleConfig } from '../../../../tv2_afvd_showstyle/helpers/config' @@ -20,7 +25,10 @@ import { PartDefinitionTeknik, PartDefinitionTelefon, PartDefinitionUnknown, - PartDefinitionVO + PartDefinitionVO, + RemoteType, + SourceDefinitionKam, + SourceDefinitionRemote } from '../ParseBody' import { CueDefinition, @@ -84,21 +92,35 @@ const cueGrafik3: CueDefinitionGraphic = { const unparsedGrafik3 = ['kg bund 3'] +const SOURCE_DEFINITION_LIVE_1: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + name: 'LIVE 1', + raw: 'LIVE 1' +} const cueEkstern1: CueDefinitionEkstern = { type: CueType.Ekstern, - source: 'Live 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'EKSTERN' } -const unparsedEkstern1 = ['EKSTERN=Live 1'] +const unparsedEkstern1 = ['EKSTERN=LIVE 1'] +const SOURCE_DEFINITION_LIVE_2: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '2', + name: 'LIVE 2', + raw: 'LIVE 2' +} const cueEkstern2: CueDefinitionEkstern = { type: CueType.Ekstern, - source: 'Live 2', + sourceDefinition: SOURCE_DEFINITION_LIVE_2, iNewsCommand: 'EKSTERN' } -const unparsedEkstern2 = ['EKSTERN=Live 2'] +const unparsedEkstern2 = ['EKSTERN=LIVE 2'] const cueJingle1: CueDefinitionJingle = { type: CueType.Jingle, @@ -140,6 +162,28 @@ const cueTelefon2: CueDefinitionTelefon = { const unparsedTelefon2 = ['TELEFON=TLF 2'] +const SOURCE_DEFINITION_KAM_1: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '1', + raw: 'KAM 1', + minusMic: false, + name: 'KAM 1' +} +const SOURCE_DEFINITION_KAM_2: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '2', + raw: 'KAM 2', + minusMic: false, + name: 'KAM 2' +} +const SOURCE_DEFINITION_KAM_3: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '3', + raw: 'KAM 3', + minusMic: false, + name: 'KAM 3' +} + const RUNDOWN_EXTERNAL_ID = 'TEST.SOFIE.JEST' function makeMockContext() { @@ -190,7 +234,6 @@ describe('Body parser', () => { type: PartType.Teknik, cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: '', - variant: {}, externalId: '', rawType: 'TEKNIK', fields: {}, @@ -199,12 +242,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -212,12 +254,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern2, cueJingle1, cueJingle2, cueJingle3], - title: 'Live 2', + title: 'LIVE 2', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -240,7 +281,6 @@ describe('Body parser', () => { type: PartType.Unknown, cues: [cueGrafik1], script: 'Thid id thr trext for the next DVE\n', - variant: {}, externalId: '', rawType: '', fields: {}, @@ -249,12 +289,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: 'Script here\n', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -280,8 +319,8 @@ describe('Body parser', () => { type: CueType.DVE, template: 'MORBARN', sources: { - INP1: 'Kam 1', - INP2: 'Kam 2' + INP1: { ...SOURCE_DEFINITION_KAM_1, raw: 'Kam 1' }, + INP2: { ...SOURCE_DEFINITION_KAM_2, raw: 'Kam 2' } }, labels: ['Live', 'Odense'], iNewsCommand: 'DVE' @@ -289,7 +328,6 @@ describe('Body parser', () => { ], title: 'MORBARN', script: 'Thid id thr trext for the next DVE\n', - variant: {}, externalId: '', rawType: '', fields: {}, @@ -298,12 +336,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1, cueGrafik1], - title: 'Live 1', + title: 'LIVE 1', script: 'Script here\n', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -337,9 +374,7 @@ describe('Body parser', () => { rawType: 'KAM AR', cues: [cueJingle3], script: 'Lots more script\n', - variant: { - name: 'AR' - }, + sourceDefinition: { sourceType: SourceType.KAM, id: 'AR', raw: 'KAM AR', minusMic: false, name: 'KAM AR' }, externalId: '', fields: {}, modified: 0, @@ -351,7 +386,6 @@ describe('Body parser', () => { rawType: 'SERVER', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -359,12 +393,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -372,12 +405,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern2, cueJingle1, cueJingle2], - title: 'Live 2', + title: 'LIVE 2', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -401,9 +433,7 @@ describe('Body parser', () => { rawType: 'CAMERA 1', cues: [], script: 'Her står em masse tekst\n', - variant: { - name: '1' - }, + sourceDefinition: { sourceType: SourceType.KAM, id: '1', raw: 'CAMERA 1', minusMic: false, name: 'KAM 1' }, externalId: '', fields, modified: 0, @@ -426,9 +456,7 @@ describe('Body parser', () => { rawType: 'KAM 1', cues: [], script: '', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', fields: {}, modified: 0, @@ -440,7 +468,6 @@ describe('Body parser', () => { rawType: '100%GRAFIK', cues: [cueGrafik1], script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -448,12 +475,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1, cueGrafik3], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -476,9 +502,7 @@ describe('Body parser', () => { rawType: 'KAM 1', cues: [], script: '', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', fields: {}, modified: 0, @@ -501,7 +525,6 @@ describe('Body parser', () => { rawType: 'ATTACK', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -515,9 +538,7 @@ describe('Body parser', () => { cues: [], script: 'Long script. Long script. Long script. Long script. Long script. Long script. Long script. Long script. Long script. Long script. Long script. Long script.\n', - variant: { - name: '4' - }, + sourceDefinition: { sourceType: SourceType.KAM, id: '4', raw: 'KAM 4', minusMic: false, name: 'KAM 4' }, externalId: '', fields: {}, modified: 0, @@ -540,9 +561,7 @@ describe('Body parser', () => { rawType: 'KAM 2', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: 'Some script\n', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, externalId: '', fields: {}, modified: 0, @@ -550,12 +569,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -578,9 +596,7 @@ describe('Body parser', () => { rawType: 'KAM 2', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: 'Some script.\nSome more script with "a quote"\nYet more script, this time it\'s a question?\n', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, externalId: '', fields: {}, modified: 0, @@ -588,12 +604,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -616,9 +631,7 @@ describe('Body parser', () => { rawType: 'KAM 2', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: 'Question?\n', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, externalId: '', fields: {}, modified: 0, @@ -626,12 +639,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -654,9 +666,7 @@ describe('Body parser', () => { rawType: 'KAM 1', cues: [], script: 'Some script.\n', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', fields: {}, modified: 0, @@ -668,7 +678,6 @@ describe('Body parser', () => { rawType: 'VO', cues: [cueGrafik1, cueGrafik2], script: 'More script.\nEven more\nMore script again.\n', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -691,9 +700,7 @@ describe('Body parser', () => { rawType: 'KAM 1', cues: [], script: 'Some script.\n', - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', fields: {}, modified: 0, @@ -705,7 +712,6 @@ describe('Body parser', () => { rawType: 'VOV', cues: [cueGrafik1, cueGrafik2], script: 'More script.\nEven more\nMore script again.\n', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -728,9 +734,7 @@ describe('Body parser', () => { rawType: 'KAM 3', cues: [cueGrafik1, cueGrafik2], script: "Here is our correspondant.\nWhat's going on over there?\n.\n", - variant: { - name: '3' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_3, externalId: '', fields: {}, modified: 0, @@ -768,7 +772,6 @@ describe('Body parser', () => { rawType: '', cues: [cueGrafik1, cueGrafik2, cueGrafik3], script: "What's going on over there?\n", - variant: {}, externalId: '', fields: {}, modified: 0, @@ -776,12 +779,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -789,12 +791,11 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern2], - title: 'Live 2', + title: 'LIVE 2', script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -817,7 +818,6 @@ describe('Body parser', () => { rawType: 'INTRO', cues: [cueGrafik1], script: '', - variant: {}, externalId: '', fields: {}, modified: 0, @@ -848,9 +848,7 @@ describe('Body parser', () => { type: PartType.Kam, rawType: 'KAM 2', script: 'Hallo, I wnat to tell you......\n', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, cues: [cueGrafik1], fields, modified: 0, @@ -862,7 +860,6 @@ describe('Body parser', () => { type: PartType.Server, rawType: 'SERVER', script: '', - variant: {}, cues: [cueGrafik2, cueGrafik3, cueJingle1, cueJingle2, cueJingle3], fields, modified: 0, @@ -874,9 +871,7 @@ describe('Body parser', () => { type: PartType.Kam, rawType: 'KAM 2', script: '', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, cues: [], fields, modified: 0, @@ -889,9 +884,7 @@ describe('Body parser', () => { type: PartType.Kam, rawType: 'KAM 2', script: '', - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, cues: [], fields, modified: 0, @@ -923,11 +916,10 @@ describe('Body parser', () => { literal([ literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', fields, modified: 0, @@ -936,11 +928,10 @@ describe('Body parser', () => { }), literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern2], - title: 'Live 2', + title: 'LIVE 2', script: '', fields, modified: 0, @@ -950,9 +941,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: 'Single line of script\n', @@ -964,7 +953,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [cueGrafik2, cueGrafik3, cueJingle1, cueJingle2, cueJingle3], script: '', @@ -976,7 +964,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [cueTelefon1], script: '', @@ -988,7 +975,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [cueTelefon2], script: '', @@ -1001,9 +987,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, rawType: 'KAM 2', cues: [], script: 'And some script.\n', @@ -1026,7 +1010,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.VO, - variant: {}, effekt: 0, rawType: 'VO', cues: [cueGrafik1], @@ -1050,9 +1033,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, effekt: 1, rawType: 'KAM 1', cues: [], @@ -1065,7 +1046,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [cueGrafik1, cueGrafik2], script: 'STORT BILLEDE AF STUDIE\n', @@ -1088,7 +1068,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [cueJingle1], title: '1', @@ -1120,9 +1099,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, rawType: 'KAM 2', cues: [], script: 'Hallo, I wnat to tell you......\nHEREEEELLLLOOOK\nYES\n', @@ -1134,7 +1111,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: literal([ literal>({ @@ -1191,9 +1167,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: '', @@ -1205,9 +1179,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: '', @@ -1220,9 +1192,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: '', @@ -1249,9 +1219,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: 'Skriv spib her\n', @@ -1263,7 +1231,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [ literal({ @@ -1344,11 +1311,9 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, transition: { - style: 'MIX', + style: TSR.AtemTransitionStyle.MIX, duration: 200 }, rawType: 'KAM 1', @@ -1362,7 +1327,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [ literal({ @@ -1439,7 +1403,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.VO, - variant: {}, effekt: 0, rawType: 'VOSB', cues: [cueGrafik1], @@ -1463,7 +1426,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.VO, - variant: {}, effekt: 0, rawType: 'VOSB', cues: [cueGrafik1], @@ -1499,9 +1461,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [ literal>({ @@ -1528,7 +1488,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Grafik, - variant: {}, rawType: '100%GRAFIK', cues: [ literal>({ @@ -1580,9 +1539,12 @@ describe('Body parser', () => { externalId: '', type: PartType.EVS, rawType: 'EVS 1', - variant: { - evs: '1', - isVO: false + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 1', + name: 'EVS 1', + raw: 'EVS 1', + vo: false }, cues: [cueGrafik1, cueGrafik2, cueGrafik3], fields, @@ -1604,9 +1566,12 @@ describe('Body parser', () => { externalId: '', type: PartType.EVS, rawType: 'EVS1VOV', - variant: { - evs: '1', - isVO: true + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 1', + name: 'EVS 1 VOV', + raw: 'EVS1VOV', + vo: true }, cues: [cueGrafik1, cueGrafik2, cueGrafik3], fields, @@ -1618,6 +1583,86 @@ describe('Body parser', () => { ]) }) + test('test 27c: accepts spaces in EVS VO red text', () => { + const body27 = + '\r\n

EVS 1 VO

\r\n

EVS 2VO

\r\n

EVS3VO

\r\n

EVS4 VO

\r\n' + const result = ParseBody(config, '00000000001', 'test-segment', body27, [], fields, 0) + expect(stripExternalId(result)).toEqual([ + literal({ + externalId: '', + type: PartType.EVS, + rawType: 'EVS 1 VO', + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 1', + name: 'EVS 1 VO', + raw: 'EVS 1 VO', + vo: true + }, + cues: [], + fields, + modified: 0, + script: '', + storyName: 'test-segment', + segmentExternalId: '00000000001' + }), + literal({ + externalId: '', + type: PartType.EVS, + rawType: 'EVS 2VO', + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 2', + name: 'EVS 2 VO', + raw: 'EVS 2VO', + vo: true + }, + cues: [], + fields, + modified: 0, + script: '', + storyName: 'test-segment', + segmentExternalId: '00000000001' + }), + literal({ + externalId: '', + type: PartType.EVS, + rawType: 'EVS3VO', + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 3', + name: 'EVS 3 VO', + raw: 'EVS3VO', + vo: true + }, + cues: [], + fields, + modified: 0, + script: '', + storyName: 'test-segment', + segmentExternalId: '00000000001' + }), + literal({ + externalId: '', + type: PartType.EVS, + rawType: 'EVS4 VO', + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 4', + name: 'EVS 4 VO', + raw: 'EVS4 VO', + vo: true + }, + cues: [], + fields, + modified: 0, + script: '', + storyName: 'test-segment', + segmentExternalId: '00000000001' + }) + ]) + }) + test('test 28', () => { const body28 = '\r\n

****SERVER****

\r\n

---

\r\n

\r\n

SLUTORD:... bare mega fedt

\r\n

\r\n

Big body of comment text. Big body of comment text. Big body of comment text. Big body of comment text. Big body of comment text. Big body of comment text. Big body of comment text. Big body of comment text.

\r\n

\r\n

****LIVE****

\r\n

\r\n

\r\n

Some Script here

\r\n

\r\n' @@ -1633,7 +1678,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [ literal>({ @@ -1676,15 +1720,14 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.DVE, - variant: {}, rawType: '', cues: [ literal({ type: CueType.DVE, template: 'SOMMERFUGL', sources: { - INP1: 'KAM 1', - INP2: 'LIVE 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_LIVE_2 }, labels: ['Rodovre'], iNewsCommand: 'DVE' @@ -1699,16 +1742,9 @@ describe('Body parser', () => { }), literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', - cues: [ - literal({ - type: CueType.Ekstern, - source: 'LIVE 2', - iNewsCommand: 'EKSTERN' - }) - ], + cues: [cueEkstern2], title: 'LIVE 2', script: 'Some Script here\n', fields, @@ -1740,11 +1776,10 @@ describe('Body parser', () => { literal([ literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern1], - title: 'Live 1', + title: 'LIVE 1', script: '', fields, modified: 0, @@ -1753,11 +1788,10 @@ describe('Body parser', () => { }), literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', cues: [cueEkstern2], - title: 'Live 2', + title: 'LIVE 2', script: '', fields, modified: 0, @@ -1767,9 +1801,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', cues: [], script: 'Some script.\n', @@ -1781,7 +1813,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [cueGrafik2, cueGrafik3, cueJingle1, cueJingle2, cueJingle3], script: '', @@ -1793,7 +1824,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [cueTelefon1], script: '', @@ -1805,7 +1835,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Telefon, - variant: {}, rawType: '', cues: [cueTelefon2], script: '', @@ -1818,9 +1847,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, rawType: 'KAM 2', cues: [], script: 'Some script.\n', @@ -1848,15 +1875,14 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.DVE, - variant: {}, rawType: '', cues: [ literal({ type: CueType.DVE, template: 'SOMMERFUGL', sources: { - INP1: 'KAM 1', - INP2: 'LIVE 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_LIVE_2 }, labels: ['Rodovre'], iNewsCommand: 'DVE' @@ -1871,16 +1897,9 @@ describe('Body parser', () => { }), literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', - cues: [ - literal({ - type: CueType.Ekstern, - source: 'LIVE 2', - iNewsCommand: 'EKSTERN' - }) - ], + cues: [cueEkstern2], title: 'LIVE 2', script: 'And some script\n', fields, @@ -1891,7 +1910,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [ literal>({ @@ -1949,7 +1967,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal>({ @@ -1993,15 +2010,14 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.DVE, - variant: {}, rawType: '', cues: [ literal({ type: CueType.DVE, template: 'SOMMERFUGL', sources: { - INP1: 'KAM 1', - INP2: 'LIVE 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_LIVE_2 }, labels: ['Rodovre'], iNewsCommand: 'DVE' @@ -2016,16 +2032,9 @@ describe('Body parser', () => { }), literal({ externalId: '', - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, rawType: '', - cues: [ - literal({ - type: CueType.Ekstern, - source: 'LIVE 2', - iNewsCommand: 'EKSTERN' - }) - ], + cues: [cueEkstern2], script: 'Some script\n', title: 'LIVE 2', fields, @@ -2036,7 +2045,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Server, - variant: {}, rawType: 'SERVER', cues: [], script: '', @@ -2056,9 +2064,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: { ...SOURCE_DEFINITION_KAM_1, raw: 'KAM1' }, rawType: 'KAM1', cues: [], script: '', @@ -2089,7 +2095,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal({ @@ -2158,9 +2163,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: { ...SOURCE_DEFINITION_KAM_1, raw: 'Kam 1' }, rawType: 'Kam 1', cues: [ literal({ @@ -2170,7 +2173,7 @@ describe('Body parser', () => { routing: { type: CueType.Routing, target: 'OVL', - INP: 'LIVE 2', + INP: SOURCE_DEFINITION_LIVE_2, iNewsCommand: '' }, start: { @@ -2224,7 +2227,6 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Grafik, - variant: {}, externalId: '', rawType: '100% GRAFIK', cues: [ @@ -2261,9 +2263,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', rawType: 'KAM 1', cues: [], @@ -2275,7 +2275,6 @@ describe('Body parser', () => { }), literal({ type: PartType.Server, - variant: {}, externalId: '', rawType: 'SERVER', cues: [], @@ -2287,9 +2286,7 @@ describe('Body parser', () => { }), literal({ type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, externalId: '', rawType: 'KAM 2', cues: [], @@ -2310,9 +2307,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', rawType: 'KAM 1', cues: [], @@ -2324,17 +2319,10 @@ describe('Body parser', () => { segmentExternalId: '00000000001' }), literal({ - type: PartType.Ekstern, - variant: {}, + type: PartType.REMOTE, externalId: '', rawType: '', - cues: [ - literal({ - type: CueType.Ekstern, - source: 'LIVE 1', - iNewsCommand: 'EKSTERN' - }) - ], + cues: [cueEkstern1], title: 'LIVE 1', script: '', fields: {}, @@ -2344,9 +2332,7 @@ describe('Body parser', () => { }), literal({ type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, externalId: '', rawType: 'KAM 2', cues: [], @@ -2385,9 +2371,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, rawType: 'KAM 1', fields, modified: 0, @@ -2415,9 +2399,7 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Kam, - variant: { - name: '2' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_2, rawType: 'KAM 2', cues: [ literal>({ @@ -2457,7 +2439,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal>({ @@ -2472,8 +2453,8 @@ describe('Body parser', () => { routing: { type: CueType.Routing, target: 'FULL', - INP: '', - INP1: '', + INP: undefined, + INP1: undefined, iNewsCommand: '' }, engineNumber: 4, @@ -2523,7 +2504,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal>({ @@ -2538,7 +2518,7 @@ describe('Body parser', () => { routing: { type: CueType.Routing, target: 'FULL', - INP1: '', + INP1: undefined, iNewsCommand: '' }, iNewsCommand: 'GRAFIK', @@ -2557,7 +2537,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal>({ @@ -2572,7 +2551,7 @@ describe('Body parser', () => { routing: { type: CueType.Routing, target: 'FULL', - INP1: '', + INP1: undefined, iNewsCommand: '' }, iNewsCommand: 'GRAFIK', @@ -2604,7 +2583,6 @@ describe('Body parser', () => { literal({ externalId: '', type: PartType.Unknown, - variant: {}, rawType: '', cues: [ literal>({ @@ -2613,7 +2591,7 @@ describe('Body parser', () => { routing: { type: CueType.Routing, target: 'WALL', - INP1: 'EVS 1', + INP1: { sourceType: SourceType.REPLAY, name: 'EVS 1', id: 'EVS 1', raw: 'EVS 1', vo: false }, iNewsCommand: '' }, graphic: { @@ -2650,9 +2628,12 @@ describe('Body parser', () => { externalId: '', type: PartType.EVS, rawType: 'EVS 1', - variant: { - evs: '1', - isVO: false + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: 'EVS 1', + name: 'EVS 1', + raw: 'EVS 1', + vo: false }, effekt: 1, cues: [cueGrafik1, cueGrafik2, cueGrafik3], @@ -2672,18 +2653,11 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ externalId: '', - type: PartType.Ekstern, + type: PartType.REMOTE, title: 'LIVE 1', rawType: '', - variant: {}, effekt: 1, - cues: [ - literal({ - type: CueType.Ekstern, - source: 'LIVE 1', - iNewsCommand: 'EKSTERN' - }) - ], + cues: [cueEkstern1], fields, modified: 0, script: '', @@ -2712,9 +2686,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal>({ @@ -2759,9 +2731,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal>({ @@ -2813,9 +2783,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal({ @@ -2861,9 +2829,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -2876,7 +2842,6 @@ describe('Body parser', () => { literal({ type: PartType.Unknown, externalId: '', - variant: {}, cues: [ literal>({ type: CueType.Graphic, @@ -2922,9 +2887,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -2937,7 +2900,6 @@ describe('Body parser', () => { literal({ type: PartType.Grafik, externalId: '', - variant: {}, title: 'LgfxWeb/-ETKAEM_07-05-2019_17:55:42', cues: [ literal>({ @@ -2983,9 +2945,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -2998,7 +2958,6 @@ describe('Body parser', () => { literal({ type: PartType.Unknown, externalId: '', - variant: {}, cues: [ literal({ type: CueType.UNPAIRED_TARGET, @@ -3017,7 +2976,6 @@ describe('Body parser', () => { literal({ type: PartType.Grafik, externalId: '', - variant: {}, cues: [ literal({ type: CueType.UNPAIRED_PILOT, @@ -3057,9 +3015,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal>({ @@ -3104,9 +3060,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal>({ @@ -3151,9 +3105,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -3165,7 +3117,6 @@ describe('Body parser', () => { }), literal({ type: PartType.Unknown, - variant: {}, externalId: '', cues: [ literal({ @@ -3219,9 +3170,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -3233,7 +3182,6 @@ describe('Body parser', () => { }), literal({ type: PartType.Unknown, - variant: {}, externalId: '', cues: [ literal({ @@ -3287,9 +3235,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [], rawType: 'KAM 1', @@ -3301,7 +3247,6 @@ describe('Body parser', () => { }), literal({ type: PartType.Unknown, - variant: {}, externalId: '', cues: [ literal({ @@ -3320,7 +3265,6 @@ describe('Body parser', () => { }), literal({ type: PartType.Unknown, - variant: {}, externalId: '', cues: [ literal>({ @@ -3372,9 +3316,7 @@ describe('Body parser', () => { expect(stripExternalId(result)).toEqual([ literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: SOURCE_DEFINITION_KAM_1, externalId: '', cues: [ literal>({ @@ -3402,7 +3344,6 @@ describe('Body parser', () => { }), literal({ type: PartType.VO, - variant: {}, externalId: '', cues: [ literal>({ @@ -3432,8 +3373,171 @@ describe('Body parser', () => { }) /** END Merging Cues From Config */ + + describe('removeDuplicateDesignCues', () => { + it('has no no cues, does nothing', () => { + const definitions: PartDefinition[] = [createPartDefinition(), createPartDefinition()] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result).toEqual(definitions) + }) + + it('has a designCue from layout and a regular design cue, removes the regular design cue', () => { + const designFromLayout = 'designFromLayout' + const definitions: PartDefinition[] = [ + createPartDefinition([ + createDesignCueDefinition(designFromLayout, true), + createDesignCueDefinition('regularDesign') + ]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result[0].cues).toHaveLength(1) + const graphicDesignCue: CueDefinitionGraphicDesign = result[0].cues[0] as CueDefinitionGraphicDesign + expect(graphicDesignCue.design).toEqual(designFromLayout) + }) + + it('only have a regular design cue, does nothing', () => { + const definitions: PartDefinition[] = [createPartDefinition([createDesignCueDefinition('someDesign')])] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result).toEqual(definitions) + }) + + it('only have a layout design cue, does nothing', () => { + const definitions: PartDefinition[] = [ + createPartDefinition([createDesignCueDefinition('designFromLayout', true)]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result).toEqual(definitions) + }) + + it('has a regular design, layout design and two other random cues, only removes the regular design cue', () => { + const regularDesign = 'regularDesignCue' + const definitions: PartDefinition[] = [ + createPartDefinition([ + createDesignCueDefinition('designFromLayout', true), + createDesignCueDefinition(regularDesign), + createUnknownCueDefinition(), + createUnknownCueDefinition() + ]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + const cues = result[0].cues + expect(cues).toHaveLength(3) + const regularDesignCue = cues.find(cue => { + const designCue = cue as CueDefinitionGraphicDesign + if (!designCue.design) { + return false + } + return designCue.design === regularDesign + }) + expect(regularDesignCue).toBeUndefined() + }) + + it('has a regular design cue in one partDefinition, has a layout cue in another partDefinition, remove the regular designCue', () => { + const layoutDesign = 'designFromLayout' + const definitions: PartDefinition[] = [ + createPartDefinition([createDesignCueDefinition(layoutDesign, true)]), + createPartDefinition([createDesignCueDefinition('regularDesign')]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + const cues: CueDefinition[] = result.flatMap(definition => definition.cues) + expect(cues).toHaveLength(1) + const graphicCue = cues[0] as CueDefinitionGraphicDesign + expect(graphicCue.design).toBe(layoutDesign) + }) + + it('has layout background cue and regular background cue, remove regular background cue', () => { + const layoutBackground = 'layoutBackground' + const definitions: PartDefinition[] = [ + createPartDefinition([ + createBackgroundLoopCueDefinition(layoutBackground, true), + createBackgroundLoopCueDefinition('regularBackground') + ]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result[0].cues).toHaveLength(1) + const backgroundCue: CueDefinitionBackgroundLoop = result[0].cues[0] as CueDefinitionBackgroundLoop + expect(backgroundCue.backgroundLoop).toBe(layoutBackground) + }) + + it('only have a regular background cue, does nothing', () => { + const definitions: PartDefinition[] = [ + createPartDefinition([createBackgroundLoopCueDefinition('regularBackground')]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result).toEqual(definitions) + }) + + it('only have a layout background cue, does nothing', () => { + const definitions: PartDefinition[] = [ + createPartDefinition([createBackgroundLoopCueDefinition('layoutBackground', true)]) + ] + + const result: PartDefinition[] = stripRedundantCuesWhenLayoutCueIsPresent(definitions) + + expect(result).toEqual(definitions) + }) + }) }) +function createPartDefinition(cues?: CueDefinition[]): PartDefinition { + if (!cues) { + cues = [] + } + return { + externalId: `externalId_${Math.random() * 1000}`, + cues, + type: PartType.Grafik, + script: '', + fields: {}, + modified: 123, + storyName: 'someName', + segmentExternalId: `segmentExternalId_${Math.random() * 1000}`, + rawType: '' + } +} + +function createDesignCueDefinition(design: string, isFromLayout?: boolean): CueDefinition { + return { + type: CueType.GraphicDesign, + design, + iNewsCommand: '', + isFromLayout + } +} + +function createBackgroundLoopCueDefinition(backgroundLoop: string, isFromLayout?: boolean): CueDefinition { + return { + type: CueType.BackgroundLoop, + target: 'DVE', + backgroundLoop, + isFromLayout, + iNewsCommand: '' + } +} + +function createUnknownCueDefinition(): CueDefinition { + return { + type: CueType.UNKNOWN, + iNewsCommand: '' + } +} + export function stripExternalId(definitions: PartDefinition[]) { return definitions.map(def => { return { ...def, ...{ externalId: '' } } diff --git a/src/tv2-common/inewsConversion/converters/__tests__/cue-parser.spec.ts b/src/tv2-common/inewsConversion/converters/__tests__/cue-parser.spec.ts index 562e92c25..385fa803d 100644 --- a/src/tv2-common/inewsConversion/converters/__tests__/cue-parser.spec.ts +++ b/src/tv2-common/inewsConversion/converters/__tests__/cue-parser.spec.ts @@ -1,5 +1,6 @@ -import { IBlueprintRundownDB, PlaylistTimingType } from '@sofie-automation/blueprints-integration' -import { CueType } from 'tv2-constants' +import { IBlueprintRundownDB, PlaylistTimingType, TSR } from '@tv2media/blueprints-integration' +import { RemoteType, SourceDefinitionKam, SourceDefinitionRemote } from 'tv2-common' +import { CueType, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../../../__mocks__/context' import { defaultShowStyleConfig, defaultStudioConfig } from '../../../../tv2_afvd_showstyle/__tests__/configs' import { getConfig, parseConfig as parseShowStyleConfig } from '../../../../tv2_afvd_showstyle/helpers/config' @@ -33,6 +34,35 @@ import { const RUNDOWN_EXTERNAL_ID = 'TEST.SOFIE.JEST' +const SOURCE_DEFINITION_KAM_1: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '1', + raw: 'KAM 1', + minusMic: false, + name: 'KAM 1' +} +const SOURCE_DEFINITION_KAM_2: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '2', + raw: 'KAM 2', + minusMic: false, + name: 'KAM 2' +} +const SOURCE_DEFINITION_LIVE_1: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + name: 'LIVE 1', + raw: 'LIVE 1' +} +const SOURCE_DEFINITION_LIVE_2: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '2', + name: 'LIVE 2', + raw: 'LIVE 2' +} + function makeMockContext() { const rundown = literal({ externalId: RUNDOWN_EXTERNAL_ID, @@ -330,26 +360,6 @@ describe('Cue parser', () => { ) }) - test('Grafik (kg) - Inline first text field, blank time', () => { - const cueGrafik = ['kg bund TEXT MORETEXT', 'some@email.fakeTLD', ';x.xx'] - const result = ParseCue(cueGrafik, config) - expect(result).toEqual( - literal>({ - type: CueType.Graphic, - target: 'OVL', - - graphic: { - type: 'internal', - template: 'bund', - cue: 'kg', - textFields: ['TEXT MORETEXT', 'some@email.fakeTLD'] - }, - adlib: true, - iNewsCommand: 'kg' - }) - ) - }) - test('Grafik (kg) - Multiline text fields', () => { const cueGrafik = ['kg bund', 'TEXT MORETEXT', 'some@email.fakeTLD', ';0.02'] const result = ParseCue(cueGrafik, config) @@ -569,6 +579,26 @@ describe('Cue parser', () => { ) }) + test('Grafik (kg) - direkte - create adlib', () => { + const cueGrafik = ['#kg direkte KØBENHAVN', ';x.xx'] + const result = ParseCue(cueGrafik, config) + expect(result).toEqual( + literal>({ + type: CueType.Graphic, + target: 'OVL', + + graphic: { + type: 'internal', + template: 'direkte', + cue: '#kg', + textFields: ['KØBENHAVN'] + }, + adlib: true, + iNewsCommand: '#kg' + }) + ) + }) + test('Grafik (kg) - BillederFra_logo', () => { const cueGrafik = ['#kg BillederFra_logo KØBENHAVN', ';0.01'] const result = ParseCue(cueGrafik, config) @@ -728,6 +758,35 @@ describe('Cue parser', () => { ) }) + test('MOS object manual', () => { + const cueMOS = [ + '*cg4 pilotdata', + 'LgfxWeb/18-AARIG_02-03-2022_13:15:42/Mosart=L|M|00:10', + 'VCPID=2762780', + 'ContinueCount=1', + 'LgfxWeb/18-AARIG_02-03-2022_13:15:42/Mosart=L|M|00:10' + ] + const result = ParseCue(cueMOS, config) + expect(result).toEqual( + literal>({ + type: CueType.Graphic, + adlib: true, + end: { + seconds: 10 + }, + engineNumber: 4, + graphic: { + type: 'pilot', + name: 'LgfxWeb/18-AARIG_02-03-2022_13:15:42', + vcpid: 2762780, + continueCount: 1 + }, + iNewsCommand: 'VCP', + target: 'OVL' + }) + ) + }) + test('MOS object with timing - adlib + O', () => { const cueMOS = [ ']] S3.0 M 0 [[', @@ -856,8 +915,8 @@ describe('Cue parser', () => { routing: { type: CueType.Routing, target: 'FULL', - INP1: '', - INP: '', + INP1: undefined, + INP: undefined, iNewsCommand: '' }, iNewsCommand: 'GRAFIK', @@ -964,7 +1023,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.Ekstern, - source: 'LIVE 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'EKSTERN', transition: {} }) @@ -977,7 +1036,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.Ekstern, - source: 'LIVE 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'EKSTERN', transition: { effekt: 1 @@ -992,11 +1051,11 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.Ekstern, - source: 'LIVE 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'EKSTERN', transition: { transition: { - style: 'MIX', + style: TSR.AtemTransitionStyle.MIX, duration: 10 } } @@ -1011,7 +1070,7 @@ describe('Cue parser', () => { literal({ type: CueType.DVE, template: 'sommerfugl', - sources: { INP1: 'KAM 1', INP2: 'LIVE 1' }, + sources: { INP1: SOURCE_DEFINITION_KAM_1, INP2: SOURCE_DEFINITION_LIVE_1 }, labels: ['Odense', 'København'], iNewsCommand: 'DVE' }) @@ -1025,7 +1084,7 @@ describe('Cue parser', () => { literal({ type: CueType.DVE, template: 'sommerfugl', - sources: { INP1: 'KAM 1', INP2: 'LIVE 1' }, + sources: { INP1: SOURCE_DEFINITION_KAM_1, INP2: SOURCE_DEFINITION_LIVE_1 }, labels: ['Odense', 'København'], iNewsCommand: 'DVE' }) @@ -1039,7 +1098,7 @@ describe('Cue parser', () => { literal({ type: CueType.DVE, template: 'sommerfugl', - sources: { INP1: 'KAM 1', INP2: 'LIVE 1' }, + sources: { INP1: SOURCE_DEFINITION_KAM_1, INP2: SOURCE_DEFINITION_LIVE_1 }, labels: ['Odense', 'København'], iNewsCommand: 'DVE' }) @@ -1238,7 +1297,7 @@ describe('Cue parser', () => { literal({ type: CueType.AdLib, variant: 'MORBARN', - inputs: { INP1: 'LIVE 1', INP2: 'KAM 1' }, + inputs: { INP1: SOURCE_DEFINITION_LIVE_1, INP2: SOURCE_DEFINITION_KAM_1 }, iNewsCommand: 'ADLIBPIX' }) ) @@ -1405,7 +1464,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.PgmClean, - source: 'LIVE 1', + sourceDefinition: { ...SOURCE_DEFINITION_LIVE_1, raw: 'Live 1' }, iNewsCommand: 'PGMCLEAN' }) ) @@ -1441,7 +1500,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAM 1', + sourceDefinition: SOURCE_DEFINITION_KAM_1, iNewsCommand: 'MINUSKAM' }) ) @@ -1453,7 +1512,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAM 2', + sourceDefinition: SOURCE_DEFINITION_KAM_2, iNewsCommand: 'MINUSKAM' }) ) @@ -1465,7 +1524,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAMERA 1', + sourceDefinition: { ...SOURCE_DEFINITION_KAM_1, raw: 'KAMERA 1' }, iNewsCommand: 'MINUSKAM' }) ) @@ -1477,7 +1536,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAMERA 2', + sourceDefinition: { ...SOURCE_DEFINITION_KAM_2, raw: 'KAMERA 2' }, iNewsCommand: 'MINUSKAM' }) ) @@ -1489,7 +1548,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'LIVE 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'MINUSKAM' }) ) @@ -1501,7 +1560,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'LIVE 2', + sourceDefinition: SOURCE_DEFINITION_LIVE_2, iNewsCommand: 'MINUSKAM' }) ) @@ -1513,7 +1572,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'SERVER', + sourceDefinition: { sourceType: SourceType.SERVER }, iNewsCommand: 'MINUSKAM' }) ) @@ -1525,7 +1584,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'SERVER', + sourceDefinition: { sourceType: SourceType.SERVER }, iNewsCommand: 'MINUSKAM' }) ) @@ -1537,7 +1596,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'LIVE 1', + sourceDefinition: SOURCE_DEFINITION_LIVE_1, iNewsCommand: 'MINUSKAM' }) ) @@ -1549,7 +1608,7 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'LIVE 2', + sourceDefinition: SOURCE_DEFINITION_LIVE_2, iNewsCommand: 'MINUSKAM' }) ) @@ -1567,19 +1626,19 @@ describe('Cue parser', () => { expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAM 2', + sourceDefinition: { ...SOURCE_DEFINITION_KAM_2, raw: 'Kam 2' }, iNewsCommand: 'MINUSKAM' }) ) }) - test('minuskam = Kam 3 ', () => { - const minusKamCue = ['minuskam = Kam 3 '] + test('minuskam = Kam 2 ', () => { + const minusKamCue = ['minuskam = Kam 2 '] const result = ParseCue(minusKamCue, config) expect(result).toEqual( literal({ type: CueType.MixMinus, - source: 'KAM 3', + sourceDefinition: { ...SOURCE_DEFINITION_KAM_2, raw: 'Kam 2' }, iNewsCommand: 'MINUSKAM' }) ) diff --git a/src/tv2-common/inewsConversion/converters/__tests__/find-target-pair.spec.ts b/src/tv2-common/inewsConversion/converters/__tests__/find-target-pair.spec.ts index 76418a3f0..68475b6ca 100644 --- a/src/tv2-common/inewsConversion/converters/__tests__/find-target-pair.spec.ts +++ b/src/tv2-common/inewsConversion/converters/__tests__/find-target-pair.spec.ts @@ -13,7 +13,6 @@ describe('Find target pair', () => { test('TargetEngine + Pilot', () => { const part = literal({ type: PartType.Unknown, - variant: {}, externalId: '00001', script: '', rawType: '', @@ -43,7 +42,6 @@ describe('Find target pair', () => { }) const expectedResult = literal({ type: PartType.Unknown, - variant: {}, externalId: '00001', script: '', rawType: '', @@ -78,7 +76,6 @@ describe('Find target pair', () => { test('TLF + Pilot', () => { const part = literal({ type: PartType.Unknown, - variant: {}, externalId: '00001', script: '', rawType: '', @@ -107,7 +104,6 @@ describe('Find target pair', () => { }) const expectedResult = literal({ type: PartType.Unknown, - variant: {}, externalId: '00001', script: '', rawType: '', diff --git a/src/tv2-common/inewsConversion/converters/__tests__/part-to-parent-class.spec.ts b/src/tv2-common/inewsConversion/converters/__tests__/part-to-parent-class.spec.ts index 2b0da76f1..6a55df041 100644 --- a/src/tv2-common/inewsConversion/converters/__tests__/part-to-parent-class.spec.ts +++ b/src/tv2-common/inewsConversion/converters/__tests__/part-to-parent-class.spec.ts @@ -1,19 +1,24 @@ import { literal } from 'tv2-common' -import { CueType, PartType } from 'tv2-constants' -import { PartDefinitionEkstern } from '../ParseBody' +import { CueType, PartType, SourceType } from 'tv2-constants' +import { PartDefinitionEkstern, RemoteType } from '../ParseBody' import { CueDefinitionEkstern, PartToParentClass } from '../ParseCue' describe('PartToParentClass', () => { it('Creates class for Ekstern', () => { const partDefinition = literal({ - type: PartType.Ekstern, - variant: '', + type: PartType.REMOTE, externalId: '', rawType: '', cues: [ literal({ type: CueType.Ekstern, - source: 'Live 1', + sourceDefinition: { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + raw: 'Live 1', + name: 'LIVE 1' + }, iNewsCommand: 'EKSTERN' }) ], diff --git a/src/tv2-common/jinglePartProperties.ts b/src/tv2-common/jinglePartProperties.ts index c55420213..d16da3f78 100644 --- a/src/tv2-common/jinglePartProperties.ts +++ b/src/tv2-common/jinglePartProperties.ts @@ -1,4 +1,4 @@ -import { IBlueprintPart, IShowStyleUserContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintPart, IShowStyleUserContext } from '@tv2media/blueprints-integration' import { CueType } from 'tv2-constants' import { TableConfigItemBreakers, TV2BlueprintConfigBase, TV2StudioConfigBase } from './blueprintConfig' import { TimeFromFrames } from './frameTime' @@ -8,12 +8,7 @@ export function GetJinglePartProperties, part: PartDefinition -): - | Pick< - IBlueprintPart, - 'autoNext' | 'expectedDuration' | 'prerollDuration' | 'autoNextOverlap' | 'disableOutTransition' - > - | {} { +): Pick | {} { if (part.cues) { const cue = part.cues.find(c => c.type === CueType.Jingle) as CueDefinitionJingle if (cue) { @@ -26,28 +21,22 @@ export function GetJinglePartProperties( - config: TV2BlueprintConfigBase, +export function GetJinglePartPropertiesFromTableValue( realBreaker: TableConfigItemBreakers -): Pick< - IBlueprintPart, - 'autoNext' | 'expectedDuration' | 'prerollDuration' | 'autoNextOverlap' | 'disableOutTransition' -> { +): Pick { + const expectedDuration = Math.max(0, TimeFromFrames(Number(realBreaker.Duration) - Number(realBreaker.StartAlpha))) + const autoNextOverlap = Math.min(expectedDuration, TimeFromFrames(Number(realBreaker.EndAlpha))) return { - expectedDuration: - TimeFromFrames(Number(realBreaker.Duration)) - - TimeFromFrames(Number(realBreaker.EndAlpha)) - - TimeFromFrames(Number(realBreaker.StartAlpha)), - prerollDuration: config.studio.CasparPrerollDuration + TimeFromFrames(Number(realBreaker.StartAlpha)), - autoNextOverlap: TimeFromFrames(Number(realBreaker.EndAlpha)), - disableOutTransition: false, - autoNext: realBreaker.Autonext === true + expectedDuration, + autoNextOverlap, + autoNext: realBreaker.Autonext === true, + disableNextInTransition: false } } diff --git a/src/tv2-common/layers/sourceLayers.ts b/src/tv2-common/layers/sourceLayers.ts index 6f747b444..e52a0b919 100644 --- a/src/tv2-common/layers/sourceLayers.ts +++ b/src/tv2-common/layers/sourceLayers.ts @@ -1,7 +1,6 @@ -import { ISourceLayer, SourceLayerType } from '@sofie-automation/blueprints-integration' +import { ISourceLayer, SourceLayerType } from '@tv2media/blueprints-integration' import { ATEMModel } from '../../types/atem' import { GetDSKCount } from '../helpers' -import { literal } from '../util' /** * Get the sourcelayer name for a given DSK. @@ -12,7 +11,7 @@ export function SourceLayerAtemDSK(i: number): string { } function GetSourceLayerDefaultsForDSK(i: number): ISourceLayer { - return literal({ + return { _id: SourceLayerAtemDSK(i), _rank: 22, name: `DSK${i + 1} off`, @@ -21,16 +20,13 @@ function GetSourceLayerDefaultsForDSK(i: number): ISourceLayer { exclusiveGroup: '', isRemoteInput: false, isGuestInput: false, - activateKeyboardHotkeys: '', - clearKeyboardHotkey: ',', - assignHotkeysToGlobalAdlibs: true, + isClearable: true, isSticky: false, - activateStickyKeyboardHotkey: '', isQueueable: false, isHidden: true, allowDisable: false, onPresenterScreen: false - }) + } } export function GetDSKSourceLayerNames(atemModel: ATEMModel): string[] { diff --git a/src/tv2-common/layers/timelineLayers.ts b/src/tv2-common/layers/timelineLayers.ts index 98c9da1eb..0e1188edf 100644 --- a/src/tv2-common/layers/timelineLayers.ts +++ b/src/tv2-common/layers/timelineLayers.ts @@ -1,12 +1,8 @@ -import { BlueprintMapping, BlueprintMappings, LookaheadMode, TSR } from '@sofie-automation/blueprints-integration' +import { BlueprintMapping, BlueprintMappings, LookaheadMode, TSR } from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import { ATEMModel } from '../../types/atem' import { GetDSKCount } from '../helpers' -export function SisyfosEVSSource(i: number | string) { - return `sisyfos_source_evs_${i}` -} - export function AbstractLLayerServerEnable(i: number) { return `server_enable_${i}` } diff --git a/src/tv2-common/migrations/__tests__/dve-config-folder.spec.ts b/src/tv2-common/migrations/__tests__/dve-config-folder.spec.ts index ac0674149..612b23498 100644 --- a/src/tv2-common/migrations/__tests__/dve-config-folder.spec.ts +++ b/src/tv2-common/migrations/__tests__/dve-config-folder.spec.ts @@ -1,4 +1,4 @@ -import { ConfigItemValue, TableConfigItemValue } from '@sofie-automation/blueprints-integration' +import { ConfigItemValue, TableConfigItemValue } from '@tv2media/blueprints-integration' import { literal, StripFolderFromDVEConfig } from 'tv2-common' import { MockShowstyleMigrationContext } from './migrationContext.mock' diff --git a/src/tv2-common/migrations/__tests__/migrationContext.mock.ts b/src/tv2-common/migrations/__tests__/migrationContext.mock.ts index 34b01d378..252686982 100644 --- a/src/tv2-common/migrations/__tests__/migrationContext.mock.ts +++ b/src/tv2-common/migrations/__tests__/migrationContext.mock.ts @@ -1,15 +1,16 @@ import { ConfigItemValue, IBlueprintShowStyleVariant, + IBlueprintTriggeredActions, IOutputLayer, ISourceLayer, MigrationContextShowStyle, OmitId, ShowStyleVariantPart -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' export class MockShowstyleMigrationContext implements MigrationContextShowStyle { - public variants: IBlueprintShowStyleVariant[] + public variants: IBlueprintShowStyleVariant[] = [] public configs: Map = new Map() public getAllVariants(): IBlueprintShowStyleVariant[] { @@ -82,4 +83,20 @@ export class MockShowstyleMigrationContext implements MigrationContextShowStyle public removeVariantConfig(variantId: string, configId: string): void { throw new Error(`Function not implemented in mock: 'removeVariantConfig' args: ${variantId}, '${configId}}`) } + + public getAllTriggeredActions(): IBlueprintTriggeredActions[] { + throw new Error(`Function not implemented in mock: 'getAllTriggeredActions'`) + } + public getTriggeredAction(triggeredActionsId: string): IBlueprintTriggeredActions | undefined { + throw new Error(`Function not implemented in mock: 'getTriggeredAction' args: ${triggeredActionsId}`) + } + public setTriggeredAction(triggeredActions: IBlueprintTriggeredActions): void { + throw new Error(`Function not implemented in mock: 'setTriggeredAction' args: ${triggeredActions}`) + } + public removeTriggeredAction(triggeredActionsId: string): void { + throw new Error(`Function not implemented in mock: 'removeTriggeredAction' args: ${triggeredActionsId}`) + } + public getTriggeredActionId(triggeredActionId: string): string { + throw new Error(`Function not implemented in mock: 'getTriggeredActionId' args: ${triggeredActionId}`) + } } diff --git a/src/tv2-common/migrations/__tests__/soundbed-config-audio-folder.spec.ts b/src/tv2-common/migrations/__tests__/soundbed-config-audio-folder.spec.ts index 4453bb29f..98696b9ba 100644 --- a/src/tv2-common/migrations/__tests__/soundbed-config-audio-folder.spec.ts +++ b/src/tv2-common/migrations/__tests__/soundbed-config-audio-folder.spec.ts @@ -1,4 +1,4 @@ -import { ConfigItemValue, TableConfigItemValue } from '@sofie-automation/blueprints-integration' +import { ConfigItemValue, TableConfigItemValue } from '@tv2media/blueprints-integration' import { literal, StripFolderFromAudioBedConfig } from 'tv2-common' import { MockShowstyleMigrationContext } from './migrationContext.mock' diff --git a/src/tv2-common/migrations/addKeepAudio.ts b/src/tv2-common/migrations/addKeepAudio.ts index 618109282..c6629842c 100644 --- a/src/tv2-common/migrations/addKeepAudio.ts +++ b/src/tv2-common/migrations/addKeepAudio.ts @@ -1,13 +1,8 @@ -import { - MigrationContextStudio, - MigrationStepStudio, - TableConfigItemValue -} from '@sofie-automation/blueprints-integration' +import { MigrationContextStudio, MigrationStepStudio, TableConfigItemValue } from '@tv2media/blueprints-integration' import * as _ from 'underscore' -import { literal } from '../util' export function AddKeepAudio(versionStr: string, configName: string): MigrationStepStudio { - const res = literal({ + const res: MigrationStepStudio = { id: `${versionStr}.studioConfig.addKeepAudio.${configName}`, version: versionStr, canBeRunAutomatically: true, @@ -33,7 +28,7 @@ export function AddKeepAudio(versionStr: string, configName: string): MigrationS context.setConfig(configName, configVal) } } - }) + } return res } diff --git a/src/tv2-common/migrations/forceSourceLayerToDefaultsBase.ts b/src/tv2-common/migrations/forceSourceLayerToDefaultsBase.ts index bea898eb4..137fad578 100644 --- a/src/tv2-common/migrations/forceSourceLayerToDefaultsBase.ts +++ b/src/tv2-common/migrations/forceSourceLayerToDefaultsBase.ts @@ -1,19 +1,15 @@ -import { - ISourceLayer, - MigrationContextShowStyle, - MigrationStepShowStyle -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +import { ISourceLayer, MigrationContextShowStyle, MigrationStepShowStyle } from '@tv2media/blueprints-integration' import _ = require('underscore') export function forceSourceLayerToDefaultsBase( sourcelayerDefaults: ISourceLayer[], versionStr: string, + showStyleId: string, layer: string, overrideSteps?: string[] ): MigrationStepShowStyle { - return literal({ - id: `${versionStr}.sourcelayer.defaults.${layer}.forced`, + return { + id: `${versionStr}.${showStyleId}.sourcelayer.defaults.${layer}.forced`, version: versionStr, canBeRunAutomatically: true, overrideSteps, @@ -46,5 +42,5 @@ export function forceSourceLayerToDefaultsBase( context.insertSourceLayer(layer, defaultVal) } } - }) + } } diff --git a/src/tv2-common/migrations/graphic-defaults.ts b/src/tv2-common/migrations/graphic-defaults.ts index 7fa372547..87ec64d88 100644 --- a/src/tv2-common/migrations/graphic-defaults.ts +++ b/src/tv2-common/migrations/graphic-defaults.ts @@ -156,10 +156,10 @@ export const DEFAULT_GRAPHICS: TV2ShowstyleBlueprintConfigBase['GFXTemplates'] = INewsName: 'bundright', VizTemplate: 'bund_right', VizDestination: 'OVL1', - OutType: 'S', + OutType: '', IsDesign: false, - SourceLayer: 'studio0_graphicsTema', - LayerMapping: 'graphic_overlay_tema' + SourceLayer: 'studio0_graphicsLower', + LayerMapping: 'graphic_overlay_lower' }, { INewsCode: 'KG=', diff --git a/src/tv2-common/migrations/hotkeys.ts b/src/tv2-common/migrations/hotkeys.ts new file mode 100644 index 000000000..de3283127 --- /dev/null +++ b/src/tv2-common/migrations/hotkeys.ts @@ -0,0 +1,114 @@ +import { + IBlueprintTriggeredActions, + ISourceLayer, + MigrationContextShowStyle, + MigrationStepShowStyle +} from '@tv2media/blueprints-integration' +import { + defaultHotkeys, + GlobalHotkeySourceLayers, + GlobalHotkeySources, + ISourceLayerWithHotKeys, + literal, + MakeAllAdLibsTriggers +} from 'tv2-common' +import _ = require('underscore') + +function shortcutsAreDifferent( + defaultShortcut: IBlueprintTriggeredActions, + existingShortcut: IBlueprintTriggeredActions +) { + const nameDiffers = existingShortcut.name !== defaultShortcut.name + const actionsDiffer = !_.isEqual(existingShortcut.actions, defaultShortcut.actions) + const triggersDiffer = !_.isEqual(existingShortcut.triggers, defaultShortcut.triggers) + return nameDiffers || actionsDiffer || triggersDiffer +} + +export function GetDefaultAdLibTriggers( + versionStr: string, + showStyleId: string, + sourceLayers: GlobalHotkeySourceLayers, + getGlobalHotkeySources: (context: MigrationContextShowStyle) => GlobalHotkeySources, + forceToDefaults: boolean +): MigrationStepShowStyle { + return literal({ + id: `${versionStr}.migrateShortcutsToAdLibTriggers${forceToDefaults ? '.defaults' : ''}.${showStyleId}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextShowStyle) => { + const shortcutsDefaults = MakeAllAdLibsTriggers( + showStyleId, + defaultHotkeys, + getGlobalHotkeySources(context), + sourceLayers + ) + + return shortcutsDefaults.some(defaultShortcut => { + const existingShortcut = context.getTriggeredAction(defaultShortcut._id) + + if (!existingShortcut) { + return true + } + + return forceToDefaults && shortcutsAreDifferent(defaultShortcut, existingShortcut) + }) + }, + migrate: (context: MigrationContextShowStyle) => { + const shortcutsDefaults = MakeAllAdLibsTriggers( + showStyleId, + defaultHotkeys, + getGlobalHotkeySources(context), + sourceLayers + ) + + for (const newShortcut of shortcutsDefaults) { + const existingShortcut = context.getTriggeredAction(newShortcut._id) + const needsMigration = + !existingShortcut || (forceToDefaults && shortcutsAreDifferent(existingShortcut, newShortcut)) + if (needsMigration) { + context.setTriggeredAction(newShortcut) + } + } + } + }) +} + +export function RemoveOldShortcuts( + versionStr: string, + showStyleId: string, + sourceLayerDefaults: ISourceLayer[] +): MigrationStepShowStyle { + return { + id: `${versionStr}.migrateShortcutsToAdLibTriggers.${showStyleId}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextShowStyle) => { + const sourceLayers = sourceLayerDefaults.map(sourceLayer => context.getSourceLayer(sourceLayer._id)) as Array< + ISourceLayerWithHotKeys | undefined + > + + return sourceLayers.some( + sourceLayer => + !!sourceLayer?.clearKeyboardHotkey || + !!sourceLayer?.activateKeyboardHotkeys || + !!sourceLayer?.activateStickyKeyboardHotkey || + sourceLayer?.assignHotkeysToGlobalAdlibs !== undefined + ) + }, + migrate: (context: MigrationContextShowStyle) => { + for (const sourceLayer of sourceLayerDefaults) { + const coreSourceLayer = context.getSourceLayer(sourceLayer._id) as ISourceLayerWithHotKeys | undefined + if (!coreSourceLayer) { + continue + } + + coreSourceLayer.clearKeyboardHotkey = undefined + coreSourceLayer.activateKeyboardHotkeys = undefined + coreSourceLayer.activateStickyKeyboardHotkey = undefined + coreSourceLayer.assignHotkeysToGlobalAdlibs = undefined + + context.updateSourceLayer(sourceLayer._id, coreSourceLayer) + } + } + } +} diff --git a/src/tv2-common/migrations/index.ts b/src/tv2-common/migrations/index.ts index e057e8153..33e1da474 100644 --- a/src/tv2-common/migrations/index.ts +++ b/src/tv2-common/migrations/index.ts @@ -6,22 +6,23 @@ import { MigrationStepShowStyle, MigrationStepStudio, TableConfigItemValue -} from '@sofie-automation/blueprints-integration' -import { TableConfigItemGFXTemplates } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { TableConfigItemGFXTemplates, TableConfigItemSourceMappingWithSisyfos } from 'tv2-common' import _ = require('underscore') import { literal } from '../util' export * from './moveSourcesToTable' export * from './addKeepAudio' -export * from './shortcuts' export * from './transitions' export * from './graphic-defaults' export * from './manifestWithMediaFlow' export * from './sourceManifest' +export * from './sourceLayers' export * from './forceSourceLayerToDefaultsBase' +export * from './hotkeys' export function RenameStudioConfig(versionStr: string, studio: string, from: string, to: string): MigrationStepStudio { - return literal({ + return { id: `${versionStr}.studioConfig.rename.${from}.${studio}`, version: versionStr, canBeRunAutomatically: true, @@ -40,7 +41,7 @@ export function RenameStudioConfig(versionStr: string, studio: string, from: str context.removeConfig(from) } - }) + } } export function renameSourceLayer( @@ -49,7 +50,7 @@ export function renameSourceLayer( from: string, to: string ): MigrationStepShowStyle { - return literal({ + return { id: `${versionStr}.renameSourceLayer.${studioId}.${from}.${to}`, version: versionStr, canBeRunAutomatically: true, @@ -68,12 +69,12 @@ export function renameSourceLayer( context.insertSourceLayer(to, existing) context.removeSourceLayer(from) } - }) + } } -export function removeSourceLayer(versionStr: string, studioId: string, layer: string) { +export function removeSourceLayer(versionStr: string, studioId: string, layer: string): MigrationStepShowStyle { return literal({ - id: `${versionStr}.renameSourceLayer.${studioId}.${layer}`, + id: `${versionStr}.removeSourceLayer.${studioId}.${layer}`, version: versionStr, canBeRunAutomatically: true, validate: (context: MigrationContextShowStyle) => { @@ -93,8 +94,12 @@ export function removeSourceLayer(versionStr: string, studioId: string, layer: s }) } -export function AddGraphicToGFXTable(versionStr: string, studio: string, config: TableConfigItemGFXTemplates) { - return literal({ +export function AddGraphicToGFXTable( + versionStr: string, + studio: string, + config: TableConfigItemGFXTemplates +): MigrationStepShowStyle { + return { id: `${versionStr}.gfxConfig.add${config.INewsName}.${studio}`, version: versionStr, canBeRunAutomatically: true, @@ -117,7 +122,72 @@ export function AddGraphicToGFXTable(versionStr: string, studio: string, config: context.setBaseConfig('GFXTemplates', (existing as unknown) as ConfigItemValue) } - }) + } +} + +export function addSourceToSourcesConfig( + versionStr: string, + studio: string, + configId: string, + source: TableConfigItemSourceMappingWithSisyfos +): MigrationStepStudio { + return { + id: `${versionStr}.studioConfig.addReplaySource.${source.SourceName}.${studio}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextStudio) => { + const config = (context.getConfig(configId) as unknown) as TableConfigItemSourceMappingWithSisyfos[] + + if (!config) { + return false + } + return !config.find(s => s.SourceName === source.SourceName) + }, + migrate: (context: MigrationContextStudio) => { + const config = (context.getConfig(configId) as unknown) as TableConfigItemSourceMappingWithSisyfos[] + config.push(source) + context.setConfig(configId, (config as unknown) as ConfigItemValue) + } + } +} + +export function changeGFXTemplate( + versionStr: string, + studio: string, + oldConfig: Partial, + config: Partial +): MigrationStepShowStyle { + const keysToUpdate = Object.keys(config).join('_') + return { + id: `${versionStr}.gfxConfig.change_${keysToUpdate}.${studio}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextShowStyle) => { + const gfxTemplates = (context.getBaseConfig('GFXTemplates') as unknown) as + | TableConfigItemGFXTemplates[] + | undefined + + if (!gfxTemplates || !gfxTemplates.length) { + return false + } + + return gfxTemplates.some(g => isGfxTemplateSubset(g, oldConfig)) + }, + migrate: (context: MigrationContextShowStyle) => { + let existing = (context.getBaseConfig('GFXTemplates') as unknown) as TableConfigItemGFXTemplates[] + + existing = existing.map(g => (isGfxTemplateSubset(g, oldConfig) ? { ...g, ...config } : g)) + + context.setBaseConfig('GFXTemplates', (existing as unknown) as ConfigItemValue) + } + } +} + +function isGfxTemplateSubset( + superset: Partial, + subset: Partial +): boolean { + return Object.keys(subset).every((key: keyof TableConfigItemGFXTemplates) => superset[key] === subset[key]) } export function SetLayerNamesToDefaults( @@ -128,40 +198,38 @@ export function SetLayerNamesToDefaults( const migrations: MigrationStepStudio[] = [] for (const [layerId, mapping] of Object.entries(mappings)) { - migrations.push( - literal({ - id: `${versionStr}.studioConfig.setLayerName.${layerId}.${studio}`, - version: versionStr, - canBeRunAutomatically: true, - validate: (context: MigrationContextStudio) => { - const configVal = context.getMapping(layerId) - - if (!configVal) { - return false - } - - return configVal.layerName !== mapping.layerName - }, - migrate: (context: MigrationContextStudio) => { - const configVal = context.getMapping(layerId) + migrations.push({ + id: `${versionStr}.studioConfig.setLayerName.${layerId}.${studio}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextStudio) => { + const configVal = context.getMapping(layerId) + + if (!configVal) { + return false + } - if (!configVal) { - return - } + return configVal.layerName !== mapping.layerName + }, + migrate: (context: MigrationContextStudio) => { + const configVal = context.getMapping(layerId) - configVal.layerName = mapping.layerName - context.removeMapping(layerId) - context.insertMapping(layerId, configVal) + if (!configVal) { + return } - }) - ) + + configVal.layerName = mapping.layerName + context.removeMapping(layerId) + context.insertMapping(layerId, configVal) + } + }) } return migrations } -export function SetConfigTo(versionStr: string, studio: string, id: string, value: any) { - return literal({ +export function SetConfigTo(versionStr: string, studio: string, id: string, value: any): MigrationStepStudio { + return { id: `${versionStr}.config.valueSet.${studio}.${id}`, version: versionStr, canBeRunAutomatically: true, @@ -178,11 +246,11 @@ export function SetConfigTo(versionStr: string, studio: string, id: string, valu migrate: (context: MigrationContextStudio) => { context.setConfig(id, value) } - }) + } } -export function RemoveConfig(versionStr: string, studio: string, id: string) { - return literal({ +export function RemoveConfig(versionStr: string, studio: string, id: string): MigrationStepStudio { + return { id: `${versionStr}.config.valueSet.${studio}.${id}`, version: versionStr, canBeRunAutomatically: true, @@ -192,7 +260,7 @@ export function RemoveConfig(versionStr: string, studio: string, id: string) { migrate: (context: MigrationContextStudio) => { context.removeConfig(id) } - }) + } } const SOUNDBED_REGEX = /^audio\/(.*)/i @@ -222,7 +290,7 @@ export function StripFolderFromShowStyleConfig( configFields: string[], regex: RegExp ): MigrationStepShowStyle { - return literal({ + return { id: `${versionStr}.normalizeFolders.${studio}.${configId}`, version: versionStr, canBeRunAutomatically: true, @@ -264,5 +332,39 @@ export function StripFolderFromShowStyleConfig( context.setBaseConfig(configId, configTableValue) } - }) + } +} + +export function PrefixEvsWithEvs( + versionStr: string, + studio: string, + configId: string, + evsSourceNumber: string +): MigrationStepStudio { + return { + id: `${versionStr}.prefixEvs${evsSourceNumber}WithEvs.${studio}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextStudio) => { + const config = (context.getConfig(configId) as unknown) as TableConfigItemSourceMappingWithSisyfos[] + + if (!config || config.find(value => value.SourceName === `EVS ${evsSourceNumber}`) !== undefined) { + return false + } + + return config.find(value => value.SourceName === evsSourceNumber) !== undefined + }, + migrate: (context: MigrationContextStudio) => { + const config = (context.getConfig(configId) as unknown) as TableConfigItemSourceMappingWithSisyfos[] + const index: number = config.findIndex(value => value.SourceName === evsSourceNumber) + if (index === -1) { + return + } + const evsSource = config[index] + + evsSource.SourceName = `EVS ${evsSource.SourceName}` + config[index] = evsSource + context.setConfig(configId, (config as unknown) as ConfigItemValue) + } + } } diff --git a/src/tv2-common/migrations/manifestWithMediaFlow.ts b/src/tv2-common/migrations/manifestWithMediaFlow.ts index 8bf70e218..5f3d4f112 100644 --- a/src/tv2-common/migrations/manifestWithMediaFlow.ts +++ b/src/tv2-common/migrations/manifestWithMediaFlow.ts @@ -1,4 +1,4 @@ -import { ConfigManifestEntry, ConfigManifestEntryType } from '@sofie-automation/blueprints-integration' +import { ConfigManifestEntry, ConfigManifestEntryType } from '@tv2media/blueprints-integration' export function MakeConfigWithMediaFlow( name: string, diff --git a/src/tv2-common/migrations/moveSourcesToTable.ts b/src/tv2-common/migrations/moveSourcesToTable.ts index 5c98637c6..bc8c5cd49 100644 --- a/src/tv2-common/migrations/moveSourcesToTable.ts +++ b/src/tv2-common/migrations/moveSourcesToTable.ts @@ -1,8 +1,4 @@ -import { - MigrationContextStudio, - MigrationStepStudio, - TableConfigItemValue -} from '@sofie-automation/blueprints-integration' +import { MigrationContextStudio, MigrationStepStudio, TableConfigItemValue } from '@tv2media/blueprints-integration' import { parseMapStr, TableConfigItemSourceMapping, TableConfigItemSourceMappingWithSisyfos } from 'tv2-common' import * as _ from 'underscore' import { literal } from '../util' @@ -14,7 +10,7 @@ export function MoveSourcesToTable( getSisyfosLayersForMigration: (configName: string, val: string) => string[], studioMics?: boolean ): MigrationStepStudio { - const res = literal({ + return { id: `${versionStr}.studioConfig.moveToTable.${configName}`, version: versionStr, canBeRunAutomatically: true, @@ -56,13 +52,11 @@ export function MoveSourcesToTable( context.setConfig(configName, table) } } - }) - - return res + } } export function MoveClipSourcePath(versionStr: string, studio: string): MigrationStepStudio { - const res = literal({ + return { id: `${versionStr}.studioConfig.moveClipSourcePath.${studio}`, version: versionStr, canBeRunAutomatically: true, @@ -80,7 +74,5 @@ export function MoveClipSourcePath(versionStr: string, studio: string): Migratio context.removeConfig('ClipSourcePath') } } - }) - - return res + } } diff --git a/src/tv2-common/migrations/shortcuts.ts b/src/tv2-common/migrations/shortcuts.ts deleted file mode 100644 index ecd10b5f0..000000000 --- a/src/tv2-common/migrations/shortcuts.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { - ISourceLayer, - MigrationContextShowStyle, - MigrationStepShowStyle -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' - -export function SetShortcutListMigrationStep( - versionStr: string, - sourceLayerId: string, - newValue: string -): MigrationStepShowStyle { - return literal({ - id: `${versionStr}.remapShortcuts.${sourceLayerId}`, - version: versionStr, - canBeRunAutomatically: true, - validate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) - - if (!sourceLayer) { - return `Sourcelayer ${sourceLayerId} does not exists` - } - - return sourceLayer.activateKeyboardHotkeys !== newValue - }, - migrate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) as ISourceLayer - - sourceLayer.activateKeyboardHotkeys = newValue - - context.updateSourceLayer(sourceLayerId, sourceLayer) - } - }) -} - -export function SetSourceLayerNameMigrationStep( - versionStr: string, - sourceLayerId: string, - newValue: string -): MigrationStepShowStyle { - return literal({ - id: `${versionStr}.remapSourceLayerName.${sourceLayerId}`, - version: versionStr, - canBeRunAutomatically: true, - validate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) - - if (!sourceLayer) { - return `Sourcelayer ${sourceLayerId} does not exists` - } - - return sourceLayer.name !== newValue - }, - migrate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) as ISourceLayer - - sourceLayer.name = newValue - - context.updateSourceLayer(sourceLayerId, sourceLayer) - } - }) -} - -export function SetClearShortcutListTransitionStep( - versionStr: string, - sourceLayerId: string, - newValue: string -): MigrationStepShowStyle[] { - return [ - literal({ - id: `${versionStr}.remapClearShortcuts.${sourceLayerId}`, - version: versionStr, - canBeRunAutomatically: true, - validate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) - - if (!sourceLayer) { - return `Sourcelayer ${sourceLayerId} does not exists` - } - - return sourceLayer.clearKeyboardHotkey !== newValue - }, - migrate: (context: MigrationContextShowStyle) => { - const sourceLayer = context.getSourceLayer(sourceLayerId) as ISourceLayer - - sourceLayer.clearKeyboardHotkey = newValue - - context.updateSourceLayer(sourceLayerId, sourceLayer) - } - }) - ] -} diff --git a/src/tv2-common/migrations/sourceLayers.ts b/src/tv2-common/migrations/sourceLayers.ts new file mode 100644 index 000000000..84b613346 --- /dev/null +++ b/src/tv2-common/migrations/sourceLayers.ts @@ -0,0 +1,39 @@ +import { ISourceLayer, MigrationContextShowStyle, MigrationStepShowStyle } from '@tv2media/blueprints-integration' +import { WithValuesOfTypes } from 'tv2-common' +import _ = require('underscore') + +export type WithPrimitiveValues = WithValuesOfTypes + +export function SetSourceLayerProperties( + versionStr: string, + sourceLayerId: string, + newValues: Omit>, '_id'> +): MigrationStepShowStyle { + return { + id: `${versionStr}.setSourceLayerProperties.${Object.keys(newValues).join('_')}.${sourceLayerId}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextShowStyle) => { + const sourceLayer = context.getSourceLayer(sourceLayerId) + + if (!sourceLayer) { + // nothing to migrate + // getSourceLayerDefaultsMigrationSteps should create this layer later + return false + } + + return !_.isMatch(sourceLayer, newValues) + }, + migrate: (context: MigrationContextShowStyle) => { + context.updateSourceLayer(sourceLayerId, newValues) + } + } +} + +export function SetSourceLayerName( + versionStr: string, + sourceLayerId: string, + newValue: string +): MigrationStepShowStyle { + return SetSourceLayerProperties(versionStr, sourceLayerId, { name: newValue }) +} diff --git a/src/tv2-common/migrations/sourceManifest.ts b/src/tv2-common/migrations/sourceManifest.ts index b96856b39..3d180ebaa 100644 --- a/src/tv2-common/migrations/sourceManifest.ts +++ b/src/tv2-common/migrations/sourceManifest.ts @@ -1,13 +1,14 @@ -import { ConfigManifestEntryTable, ConfigManifestEntryType, TSR } from '@sofie-automation/blueprints-integration' +import { ConfigManifestEntryTable, ConfigManifestEntryType, TSR } from '@tv2media/blueprints-integration' import { literal } from '../util' export function MakeConfigForSources( name: string, displayName: string, - withKeepAudio: boolean, + wantsToPersistAudio: boolean, + acceptPersistAudio: boolean, defaultVal: ConfigManifestEntryTable['defaultVal'] ): ConfigManifestEntryTable { - return literal({ + return { id: `Sources${name}`, name: `${displayName} Mapping`, description: `${displayName} number to ATEM input and Sisyfos layer`, @@ -28,7 +29,7 @@ export function MakeConfigForSources( id: 'AtemSource', name: 'ATEM input', description: `ATEM vision mixer input for ${displayName} input`, - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 1 @@ -55,19 +56,34 @@ export function MakeConfigForSources( defaultVal: true, rank: 3 }, - ...(withKeepAudio + ...(wantsToPersistAudio ? [ literal({ - id: 'KeepAudioInStudio', - name: 'Keep audio in Studio', - description: 'Keep audio in Studio', + id: 'WantsToPersistAudio', + name: 'Wants To Persist Audio', + description: + 'Tells the system that it wants to persist the audio. If the next piece accepts persistence, the audio will be persisted', type: ConfigManifestEntryType.BOOLEAN, required: true, - defaultVal: true, + defaultVal: false, rank: 4 }) ] + : []), + ...(acceptPersistAudio + ? [ + literal({ + id: 'AcceptPersistAudio', + name: 'Accept Persist Audio', + description: + 'Accept the persistence of audio from the previous piece if that piece wants to persist audio', + type: ConfigManifestEntryType.BOOLEAN, + required: false, + defaultVal: false, + rank: 5 + }) + ] : []) ] - }) + } } diff --git a/src/tv2-common/migrations/transitions.ts b/src/tv2-common/migrations/transitions.ts index fd283db50..c6e7e353b 100644 --- a/src/tv2-common/migrations/transitions.ts +++ b/src/tv2-common/migrations/transitions.ts @@ -1,9 +1,9 @@ -import { MigrationContextShowStyle, MigrationStepShowStyle } from '@sofie-automation/blueprints-integration' +import { MigrationContextShowStyle, MigrationStepShowStyle } from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import { TableConfigItemAdLibTransitions } from '../blueprintConfig' export function SetShowstyleTransitionMigrationStep(versionStr: string, newValue: string): MigrationStepShowStyle { - return literal({ + return { id: `${versionStr}.setShowstyleTransition`, version: versionStr, canBeRunAutomatically: true, @@ -19,7 +19,7 @@ export function SetShowstyleTransitionMigrationStep(versionStr: string, newValue migrate: (context: MigrationContextShowStyle) => { context.setBaseConfig('ShowstyleTransition', newValue) } - }) + } } type TransitionsTableValue = TableConfigItemAdLibTransitions & { _id: string; [key: string]: string } @@ -31,49 +31,47 @@ export function UpsertValuesIntoTransitionTable( const steps: MigrationStepShowStyle[] = [] values.forEach(val => { - steps.push( - literal({ - id: `${versionStr}.insertTransition.${val.Transition.replace(/[\s\W]/g, '_')}`, - version: versionStr, - canBeRunAutomatically: true, - validate: (context: MigrationContextShowStyle) => { - const table = (context.getBaseConfig('Transitions') as unknown) as TransitionsTableValue[] | undefined + steps.push({ + id: `${versionStr}.insertTransition.${val.Transition.replace(/[\s\W]/g, '_')}`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextShowStyle) => { + const table = (context.getBaseConfig('Transitions') as unknown) as TransitionsTableValue[] | undefined - if (!table) { - return `Transitions table does not exists` - } + if (!table) { + return `Transitions table does not exists` + } - const existingVal = table.find(v => v.Transition === val.Transition) + const existingVal = table.find(v => v.Transition === val.Transition) - if (!existingVal) { - return `Transition "${val.Transition}" does not exist` - } + if (!existingVal) { + return `Transition "${val.Transition}" does not exist` + } - return existingVal.Transition !== val.Transition - }, - migrate: (context: MigrationContextShowStyle) => { - const table = (context.getBaseConfig('Transitions') as unknown) as TransitionsTableValue[] | undefined + return existingVal.Transition !== val.Transition + }, + migrate: (context: MigrationContextShowStyle) => { + const table = (context.getBaseConfig('Transitions') as unknown) as TransitionsTableValue[] | undefined - if (!table) { - context.setBaseConfig('Transitions', [ - literal({ - _id: val.Transition.replace(/\W\s/g, '_'), - Transition: val.Transition - }) - ]) - } else { - table.push( - literal({ - _id: val.Transition.replace(/\W\s/g, '_'), - Transition: val.Transition - }) - ) + if (!table) { + context.setBaseConfig('Transitions', [ + literal({ + _id: val.Transition.replace(/\W\s/g, '_'), + Transition: val.Transition + }) + ]) + } else { + table.push( + literal({ + _id: val.Transition.replace(/\W\s/g, '_'), + Transition: val.Transition + }) + ) - context.setBaseConfig('Transitions', table) - } + context.setBaseConfig('Transitions', table) } - }) - ) + } + }) }) return steps diff --git a/src/tv2-common/onTimelineGenerate.ts b/src/tv2-common/onTimelineGenerate.ts index 9527fdf74..9d6fe0a8b 100644 --- a/src/tv2-common/onTimelineGenerate.ts +++ b/src/tv2-common/onTimelineGenerate.ts @@ -1,6 +1,7 @@ import { BlueprintResultTimeline, GraphicsContent, + IBlueprintPartInstance, IBlueprintResolvedPieceInstance, IRundownContext, IShowStyleContext, @@ -10,20 +11,22 @@ import { TimelineObjectCoreExt, TimelinePersistentState, TSR -} from '@sofie-automation/blueprints-integration' -import { CasparPlayerClip } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { ActionSelectFullGrafik, ActionSelectJingle, ActionSelectServerClip, CasparPlayerClip } from 'tv2-common' import { AbstractLLayer, TallyTags } from 'tv2-constants' import * as _ from 'underscore' import { SisyfosLLAyer } from '../tv2_afvd_studio/layers' -import { OfftubeSisyfosLLayer } from '../tv2_offtube_studio/layers' // TODO: REMOVE import { TV2BlueprintConfigBase, TV2StudioConfigBase } from './blueprintConfig' -import { ABSourceLayers, assignMediaPlayers } from './helpers' +import { ABSourceLayers, assignMediaPlayers, getServerPositionForPartInstance, ServerPosition } from './helpers' export interface PartEndStateExt { - stickySisyfosLevels: { [key: string]: 0 | 1 | 2 | undefined } + sisyfosPersistMetaData: SisyfosPersistMetaData mediaPlayerSessions: { [layer: string]: string[] } isJingle?: boolean fullFileName?: string + serverPosition?: ServerPosition + segmentId?: string + partInstanceId: string } export interface MediaPlayerClaim { @@ -34,13 +37,13 @@ export interface MediaPlayerClaim { export interface TimelinePersistentStateExt { activeMediaPlayers: { [player: string]: MediaPlayerClaim[] | undefined } + isNewSegment?: boolean } export interface TimelineBlueprintExt extends TimelineObjectCoreExt { /** Metadata for use by the OnTimelineGenerate or other callbacks */ metaData?: { context?: string - sisyfosPersistLevel?: boolean mediaPlayerSession?: string dveAdlibEnabler?: string // Used to restore the original while rule after lookahead templateData?: any @@ -49,17 +52,36 @@ export interface TimelineBlueprintExt extends TimelineObjectCoreExt { } export interface PieceMetaData { - transition?: { - isEffekt?: boolean - isMix?: boolean - isJingle?: boolean - } - stickySisyfosLevels?: { [key: string]: { value: number; followsPrevious: boolean } } + sisyfosPersistMetaData?: SisyfosPersistMetaData mediaPlayerSessions?: string[] mediaPlayerOptional?: boolean modifiedByAction?: boolean } +export interface GraphicPieceMetaData extends PieceMetaData { + belongsToRemotePart?: boolean +} + +export interface JinglePieceMetaData extends PieceMetaData { + userData: ActionSelectJingle +} + +export interface FullPieceMetaData extends PieceMetaData { + userData: ActionSelectFullGrafik +} + +export interface ServerPieceMetaData extends PieceMetaData { + userData: ActionSelectServerClip +} + +export interface SisyfosPersistMetaData { + sisyfosLayers: string[] + wantsToPersistAudio?: boolean + acceptPersistAudio?: boolean + previousPersistMetaDataForCurrentPiece?: SisyfosPersistMetaData + isPieceInjectedInPart?: boolean +} + export interface PartMetaData { segmentExternalId: string /** If set, part has been modified by an action */ @@ -74,26 +96,28 @@ export function onTimelineGenerate< timeline: OnGenerateTimelineObj[], previousPersistentState: TimelinePersistentState | undefined, previousPartEndState: PartEndState | undefined, - resolvedPieces: IBlueprintResolvedPieceInstance[], + resolvedPieces: Array>, getConfig: (context: IShowStyleContext) => ShowStyleConfig, sourceLayers: ABSourceLayers, _casparLayerClipPending: string, _atemLayerNext: string ): Promise { const previousPartEndState2 = previousPartEndState as PartEndStateExt | undefined + const persistentState: TimelinePersistentStateExt = { + activeMediaPlayers: {}, + isNewSegment: context.previousPartInstance?.segmentId !== context.currentPartInstance?.segmentId + } const config = getConfig(context) - copyPreviousSisyfosLevels( - context, - timeline, - previousPartEndState2 ? previousPartEndState2.stickySisyfosLevels : {}, - resolvedPieces - ) - - const persistentState: TimelinePersistentStateExt = { - activeMediaPlayers: {} + if (!persistentState.isNewSegment || isAnyPieceInjectedIntoPart(resolvedPieces, context)) { + const sisyfosPersistedLevelsTimelineObject = createSisyfosPersistedLevelsTimelineObject( + resolvedPieces, + previousPartEndState2 ? previousPartEndState2.sisyfosPersistMetaData.sisyfosLayers : [] + ) + timeline.push(sisyfosPersistedLevelsTimelineObject) } + const previousPersistentState2 = previousPersistentState as TimelinePersistentStateExt | undefined timeline = processServerLookaheads(context, timeline, resolvedPieces, sourceLayers) @@ -136,9 +160,7 @@ function processServerLookaheads( return ( [sourceLayers.Caspar.ClipPending, CasparPlayerClip(1), CasparPlayerClip(2)].includes(layer) && !obj.isLookahead && - resolvedPieces.some( - p => p._id === obj.pieceInstanceId && (p as any).partInstanceId === context.currentPartInstance?._id - ) + resolvedPieces.some(p => p._id === obj.pieceInstanceId && p.partInstanceId === context.currentPartInstance?._id) ) }) @@ -181,35 +203,53 @@ function processServerLookaheads( }) } +function isAnyPieceInjectedIntoPart( + resolvedPieces: Array>, + context: ITimelineEventContext +) { + return resolvedPieces + .filter(piece => piece.partInstanceId === context.currentPartInstance?._id) + .some(piece => { + return piece.piece.metaData?.sisyfosPersistMetaData?.isPieceInjectedInPart + }) +} + export function getEndStateForPart( _context: IRundownContext, _previousPersistentState: TimelinePersistentState | undefined, - previousPartEndState: PartEndState | undefined, - resolvedPieces: IBlueprintResolvedPieceInstance[], + partInstance: IBlueprintPartInstance, + resolvedPieces: Array>, time: number ): PartEndState { const endState: PartEndStateExt = { - stickySisyfosLevels: {}, - mediaPlayerSessions: {} + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + mediaPlayerSessions: {}, + segmentId: partInstance.segmentId, + partInstanceId: partInstance._id } - - const previousPartEndState2 = previousPartEndState as Partial | undefined + const previousPartEndState = partInstance?.previousPartEndState as Partial const activePieces = resolvedPieces.filter( p => _.isNumber(p.piece.enable.start) && p.piece.enable && - (p.piece.enable.start as number) <= time && - (!p.piece.enable.duration || p.piece.enable.start + (p.piece.enable.duration as number) >= time) + p.piece.enable.start <= time && + (!p.piece.enable.duration || p.piece.enable.start + p.piece.enable.duration >= time) ) - for (const piece of activePieces) { - preservePieceSisfosLevel(endState, previousPartEndState2, piece) - } + const previousPersistentState: TimelinePersistentStateExt = _previousPersistentState as TimelinePersistentStateExt + endState.sisyfosPersistMetaData.sisyfosLayers = findLayersToPersist( + activePieces, + !previousPersistentState.isNewSegment && previousPartEndState && previousPartEndState.sisyfosPersistMetaData + ? previousPartEndState.sisyfosPersistMetaData.sisyfosLayers + : [] + ) for (const piece of activePieces) { if (piece.piece.metaData) { - const meta = (piece.piece.metaData as PieceMetaData).mediaPlayerSessions + const meta = piece.piece.metaData.mediaPlayerSessions if (meta && meta.length) { endState.mediaPlayerSessions[piece.piece.sourceLayerId] = meta } @@ -224,6 +264,8 @@ export function getEndStateForPart( } } + endState.serverPosition = getServerPositionForPartInstance(partInstance, resolvedPieces, time) + return endState } @@ -250,125 +292,78 @@ function dveBoxLookaheadUseOriginalEnable(timeline: OnGenerateTimelineObj[]) { } } -export function preservePieceSisfosLevel( - endState: PartEndStateExt, - previousPartEndState: Partial | undefined, - piece: IBlueprintResolvedPieceInstance -) { - const metaData = piece.piece.metaData as PieceMetaData | undefined - if (metaData) { - // Loop through rm level persistance - if (metaData.stickySisyfosLevels) { - for (const key of Object.keys(metaData.stickySisyfosLevels)) { - const values = metaData.stickySisyfosLevels[key] - - // Follow the previous state, if specified, or start with this exposed value - endState.stickySisyfosLevels[key] = - values.followsPrevious && - previousPartEndState && - previousPartEndState.stickySisyfosLevels && - previousPartEndState.stickySisyfosLevels[key] - ? previousPartEndState.stickySisyfosLevels[key] - : (values.value as 0 | 1 | 2 | undefined) - } +export function createSisyfosPersistedLevelsTimelineObject( + resolvedPieces: Array>, + previousSisyfosLayersThatWantsToBePersisted: SisyfosPersistMetaData['sisyfosLayers'] +): TSR.TimelineObjSisyfosChannels { + const layersToPersist = findLayersToPersist(resolvedPieces, previousSisyfosLayersThatWantsToBePersisted) + return { + id: 'sisyfosPersistenceObject', + enable: { + start: 0 + }, + layer: SisyfosLLAyer.SisyfosPersistedLevels, + content: { + deviceType: TSR.DeviceType.SISYFOS, + type: TSR.TimelineContentTypeSisyfos.CHANNELS, + overridePriority: 1, + channels: layersToPersist.map(layer => { + return { + mappedLayer: layer, + isPgm: 1 + } + }) } } } -function isSisyfosPersistObject(obj: TSR.TimelineObjSisyfosChannels & TimelineBlueprintExt) { - return ( - (obj.layer === OfftubeSisyfosLLayer.SisyfosPersistedLevels || obj.layer === SisyfosLLAyer.SisyfosPersistedLevels) && - obj.content.deviceType === TSR.DeviceType.SISYFOS && - obj.content.type === TSR.TimelineContentTypeSisyfos.CHANNELS && - obj.metaData?.sisyfosPersistLevel && - !obj.id.match(/previous/i) && - !obj.id.match(/future/) - ) -} - -export function copyPreviousSisyfosLevels( - _context: IRundownContext, - timelineObjs: OnGenerateTimelineObj[], - previousLevels: PartEndStateExt['stickySisyfosLevels'], - resolvedPieces: IBlueprintResolvedPieceInstance[] -) { - const objectsLookingToPersistLevels: Array = (timelineObjs as Array< - TSR.TimelineObjSisyfosChannels & TimelineBlueprintExt & OnGenerateTimelineObj - >).filter(isSisyfosPersistObject) - - // This needs to look at previous pieces within the part, to make it work for adlibs - // Pieces should be ordered, we shall assume that - const groupedPieces = _.groupBy(resolvedPieces, p => p.resolvedStart) - const sisyfosObjectsByPiece = _.groupBy(objectsLookingToPersistLevels, o => o.pieceInstanceId) - - for (const k of Object.keys(groupedPieces)) { - const pieces = groupedPieces[k] - const pieceIds = _.pluck(pieces, '_id') // getPieceGroupId(p._id)) - // Find all the objs that start here - const objs = _.flatten(Object.values(_.pick(sisyfosObjectsByPiece, pieceIds))) - // Stop if no objects - if (objs.length === 0) { - continue - } - - // Find the active pieces before this time - const time = pieces[0].resolvedStart +function findLayersToPersist( + pieces: Array>, + sisyfosLayersThatWantsToBePersisted: string[] +): string[] { + const sortedPieces = pieces + .filter(piece => piece.piece.metaData?.sisyfosPersistMetaData) + .sort((a, b) => b.resolvedStart - a.resolvedStart) - // Start of part - if (time !== 0) { - // Calculate the previous 'state' - const activePieces = resolvedPieces.filter(p => { - const start = p.resolvedStart // Core should be always setting this to a number - const duration = p.resolvedDuration - - // Piece must start before target, and end at or after target starts - return start < time && (duration === undefined || start + duration >= time) - }) + if (sortedPieces.length === 0) { + return [] + } - const newPreviousLevels: PartEndStateExt['stickySisyfosLevels'] = {} - for (const piece of activePieces) { - const metadata = piece.piece.metaData as PieceMetaData | undefined - if (metadata && metadata.stickySisyfosLevels) { - for (const id of Object.keys(metadata.stickySisyfosLevels)) { - // context.notifyUserWarning( - // `New level from ${piece._id} for ${id} of ${JSON.stringify(val)} (last was ${previousLevels[id]})` - // ) - if (newPreviousLevels[id]) { - // context.notifyUserWarning('duplicate level, going with the first!' + id) - } else { - const val = metadata.stickySisyfosLevels[id] - newPreviousLevels[id] = - val.followsPrevious && previousLevels[id] !== undefined - ? previousLevels[id] - : (val.value as 0 | 1 | 2 | undefined) - } - } - } - } + const firstPieceMetaData = sortedPieces[0].piece.metaData! + if (!firstPieceMetaData.sisyfosPersistMetaData!.acceptPersistAudio) { + return firstPieceMetaData.sisyfosPersistMetaData!.wantsToPersistAudio + ? firstPieceMetaData.sisyfosPersistMetaData!.sisyfosLayers + : [] + } - // Apply newly calculated levels - previousLevels = newPreviousLevels + const layersToPersist: string[] = [] + for (let i = 0; i < sortedPieces.length; i++) { + const pieceMetaData = sortedPieces[i].piece.metaData! + const sisyfosPersistMetaData: SisyfosPersistMetaData = pieceMetaData.sisyfosPersistMetaData! + if (sisyfosPersistMetaData.wantsToPersistAudio) { + layersToPersist.push(...sisyfosPersistMetaData.sisyfosLayers) } - const allChannels = [] - // Apply newly calculated levels - for (const sisyfosObj of objs) { - const contentObj = sisyfosObj.content - for (const channel of contentObj.channels) { - const previousVal = previousLevels[channel.mappedLayer] - if (previousVal !== undefined) { - channel.isPgm = previousVal - allChannels.push(channel) - } - } + if (doesMetaDataNotAcceptPersistAudioDeep(sisyfosPersistMetaData)) { + break } - // Apply all persisted levels to all objects in case there's more than one object - for (const sisyfosObj of objs) { - sisyfosObj.content.channels = allChannels + + if (i === sortedPieces.length - 1) { + layersToPersist.push(...sisyfosLayersThatWantsToBePersisted) } } + + return Array.from(new Set(layersToPersist)) +} + +function doesMetaDataNotAcceptPersistAudioDeep(metaData: SisyfosPersistMetaData): boolean { + if (!metaData.acceptPersistAudio) { + return true + } + if (metaData.previousPersistMetaDataForCurrentPiece) { + return doesMetaDataNotAcceptPersistAudioDeep(metaData.previousPersistMetaDataForCurrentPiece) + } + return false } export function disablePilotWipeAfterJingle( diff --git a/src/tv2-common/parts/effekt.ts b/src/tv2-common/parts/effekt.ts index cdb206eee..68a4cef3f 100644 --- a/src/tv2-common/parts/effekt.ts +++ b/src/tv2-common/parts/effekt.ts @@ -1,19 +1,22 @@ import { IBlueprintPart, IBlueprintPiece, + IBlueprintPieceType, IShowStyleUserContext, PieceLifespan, TimelineObjectCoreExt, TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { + ActionTakeWithTransitionVariantDip, ActionTakeWithTransitionVariantMix, EnableDSK, GetTagForTransition, literal, PartDefinition, + PieceMetaData, TimeFromFrames, TimelineBlueprintExt, TV2BlueprintConfigBase, @@ -21,7 +24,6 @@ import { } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import { TV2BlueprintConfig } from '../blueprintConfig' -import { PieceMetaData } from '../onTimelineGenerate' import { JoinAssetToFolder, JoinAssetToNetworkPath } from '../util' /** Has to be executed before calling EvaluateCues, as some cues may depend on it */ @@ -35,13 +37,7 @@ export function CreateEffektForPartBase( casparLayer: string sisyfosLayer: string } -): - | Pick< - IBlueprintPart, - 'transitionDuration' | 'transitionKeepaliveDuration' | 'transitionPrerollDuration' | 'autoNext' - > - | Pick - | {} { +): Pick | {} { const effekt = partDefinition.effekt const transition = partDefinition.transition @@ -57,15 +53,28 @@ export function CreateEffektForPartBase( ) return ret ?? {} - } else if (transition !== undefined && transition.duration !== undefined) { - if (transition.style.match(/mix/i)) { - return CreateMixForPartInner(pieces, partDefinition.externalId, transition.duration, layers) ?? {} - } else { - return {} - } - } else { + } + + if (transition === undefined || transition.duration === undefined) { return {} } + + if (transition.style === TSR.AtemTransitionStyle.MIX) { + const blueprintPiece: IBlueprintPiece = + CreateMixTransitionBlueprintPieceForPart(partDefinition.externalId, transition.duration, layers.sourceLayer) ?? {} + + pieces.push(blueprintPiece) + return CreateInTransitionForAtemTransitionStyle(transition.duration) + } + + if (transition.style === TSR.AtemTransitionStyle.DIP) { + const blueprintPiece: IBlueprintPiece = + CreateDipTransitionBlueprintPieceForPart(partDefinition.externalId, transition.duration, layers.sourceLayer) ?? {} + pieces.push(blueprintPiece) + return CreateInTransitionForAtemTransitionStyle(transition.duration) + } + + return {} } export function CreateEffektForPartInner< @@ -83,12 +92,7 @@ export function CreateEffektForPartInner< sisyfosLayer: string }, label: string -): - | Pick< - IBlueprintPart, - 'transitionDuration' | 'transitionKeepaliveDuration' | 'transitionPrerollDuration' | 'autoNext' - > - | false { +): Pick | false { if (!config.showStyle.BreakerConfig) { context.notifyUserWarning(`Jingles have not been configured`) return false @@ -114,122 +118,141 @@ export function CreateEffektForPartInner< const fileName = JoinAssetToFolder(config.studio.JingleFolder, file) - pieces.push( - literal({ - externalId, - name: label, - enable: { start: 0, duration: TimeFromFrames(Number(effektConfig.Duration)) }, - outputLayerId: SharedOutputLayers.JINGLE, - sourceLayerId: layers.sourceLayer, - lifespan: PieceLifespan.WithinPart, - isTransition: true, - metaData: literal({ - transition: { - isEffekt: true - } - }), - content: literal>({ - fileName, - path: JoinAssetToNetworkPath( - config.studio.JingleNetworkBasePath, - config.studio.JingleFolder, - file, - config.studio.JingleFileExtension - ), // full path on the source network storage - mediaFlowIds: [config.studio.JingleMediaFlowId], - previewFrame: Number(effektConfig.StartAlpha), - ignoreMediaObjectStatus: config.studio.JingleIgnoreStatus, - ignoreBlackFrames: true, - ignoreFreezeFrame: true, - timelineObjects: literal([ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: layers.casparLayer, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: fileName - } - }), - ...EnableDSK(config, 'JINGLE', { start: Number(config.studio.CasparPrerollDuration) }), - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: layers.sisyfosLayer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 1 - } - }) - ]) - }) + pieces.push({ + externalId, + name: label, + enable: { start: 0, duration: TimeFromFrames(Number(effektConfig.Duration)) }, + outputLayerId: SharedOutputLayers.JINGLE, + sourceLayerId: layers.sourceLayer, + lifespan: PieceLifespan.WithinPart, + pieceType: IBlueprintPieceType.InTransition, + content: literal>({ + fileName, + path: JoinAssetToNetworkPath( + config.studio.JingleNetworkBasePath, + config.studio.JingleFolder, + file, + config.studio.JingleFileExtension + ), // full path on the source network storage + mediaFlowIds: [config.studio.JingleMediaFlowId], + previewFrame: Number(effektConfig.StartAlpha), + ignoreMediaObjectStatus: config.studio.JingleIgnoreStatus, + ignoreBlackFrames: true, + ignoreFreezeFrame: true, + timelineObjects: literal([ + literal({ + id: '', + enable: { + start: 0 + }, + priority: 1, + layer: layers.casparLayer, + content: { + deviceType: TSR.DeviceType.CASPARCG, + type: TSR.TimelineContentTypeCasparCg.MEDIA, + file: fileName + } + }), + ...EnableDSK(config, 'JINGLE', { start: Number(config.studio.CasparPrerollDuration) }), + literal({ + id: '', + enable: { + start: 0 + }, + priority: 1, + layer: layers.sisyfosLayer, + content: { + deviceType: TSR.DeviceType.SISYFOS, + type: TSR.TimelineContentTypeSisyfos.CHANNEL, + isPgm: 1 + } + }) + ]) }) - ) + }) return { - transitionDuration: TimeFromFrames(Number(effektConfig.Duration)) + config.studio.CasparPrerollDuration, - transitionKeepaliveDuration: TimeFromFrames(Number(effektConfig.StartAlpha)) + config.studio.CasparPrerollDuration, - transitionPrerollDuration: - TimeFromFrames(Number(effektConfig.Duration)) - - TimeFromFrames(Number(effektConfig.EndAlpha)) + - config.studio.CasparPrerollDuration, + inTransition: { + blockTakeDuration: TimeFromFrames(Number(effektConfig.Duration)) + config.studio.CasparPrerollDuration, + previousPartKeepaliveDuration: + TimeFromFrames(Number(effektConfig.StartAlpha)) + config.studio.CasparPrerollDuration, + partContentDelayDuration: + TimeFromFrames(Number(effektConfig.Duration)) - + TimeFromFrames(Number(effektConfig.EndAlpha)) + + config.studio.CasparPrerollDuration + }, autoNext: false } } -export function CreateMixForPartInner( - pieces: IBlueprintPiece[], +export function CreateMixTransitionBlueprintPieceForPart( externalId: string, durationInFrames: number, - layers: { - sourceLayer: string - casparLayer: string - sisyfosLayer: string + sourceLayer: string +): IBlueprintPiece { + const tags = [ + GetTagForTransition( + literal({ + type: 'mix', + frames: durationInFrames + }) + ) + ] + const effectName: string = 'mix' + return createEffectBlueprintPiece(durationInFrames, externalId, effectName, sourceLayer, tags) +} + +function createEffectBlueprintPiece( + durationInFrames: number, + externalId: string, + name: string, + sourceLayer: string, + tags: string[] +): IBlueprintPiece { + return { + enable: { + start: 0, + duration: Math.max(TimeFromFrames(durationInFrames), 1000) + }, + externalId, + name: `${name.toUpperCase()} ${durationInFrames}`, + sourceLayerId: sourceLayer, + outputLayerId: SharedOutputLayers.JINGLE, + lifespan: PieceLifespan.WithinPart, + tags, + content: { + timelineObjects: [], + ignoreMediaObjectStatus: true + } } -): Pick { - pieces.push( - literal({ - enable: { - start: 0, - duration: Math.max(TimeFromFrames(durationInFrames), 1000) - }, - externalId, - name: `MIX ${durationInFrames}`, - sourceLayerId: layers.sourceLayer, - outputLayerId: SharedOutputLayers.JINGLE, - lifespan: PieceLifespan.WithinPart, - metaData: literal({ - transition: { - isMix: true - } - }), - tags: [ - GetTagForTransition( - literal({ - type: 'mix', - frames: durationInFrames - }) - ) - ], - content: { - timelineObjects: [], - ignoreMediaObjectStatus: true - } - }) - ) +} +export function CreateInTransitionForAtemTransitionStyle( + durationInFrames: number +): Pick { const transitionDuration = TimeFromFrames(durationInFrames) - return { - transitionKeepaliveDuration: transitionDuration, - transitionDuration + inTransition: { + previousPartKeepaliveDuration: transitionDuration, + blockTakeDuration: transitionDuration, + partContentDelayDuration: 0 + } } } + +export function CreateDipTransitionBlueprintPieceForPart( + externalId: string, + durationInFrames: number, + sourceLayer: string +): IBlueprintPiece { + const tags = [ + GetTagForTransition( + literal({ + type: 'dip', + frames: durationInFrames + }) + ) + ] + const effectName: string = 'dip' + return createEffectBlueprintPiece(durationInFrames, externalId, effectName, sourceLayer, tags) +} diff --git a/src/tv2-common/parts/invalid.ts b/src/tv2-common/parts/invalid.ts index 7d0bc726b..b7b1a2cf8 100644 --- a/src/tv2-common/parts/invalid.ts +++ b/src/tv2-common/parts/invalid.ts @@ -1,17 +1,18 @@ -import { BlueprintResultPart, IBlueprintPart } from '@sofie-automation/blueprints-integration' -import { literal, PartDefinition } from 'tv2-common' +import { BlueprintResultPart, IBlueprintPart } from '@tv2media/blueprints-integration' +import { PartDefinition } from 'tv2-common' export function CreatePartInvalid(ingestPart: PartDefinition, externalIdSuffix?: string): BlueprintResultPart { - const part = literal({ + const part: IBlueprintPart = { externalId: ingestPart.externalId + (externalIdSuffix ? `_${externalIdSuffix}` : ''), title: ingestPart.rawType || 'Unknown', metaData: {}, invalid: true - }) + } return { part, adLibPieces: [], - pieces: [] + pieces: [], + actions: [] } } diff --git a/src/tv2-common/parts/kam.ts b/src/tv2-common/parts/kam.ts index 25a7625f9..ebd6bdbc1 100644 --- a/src/tv2-common/parts/kam.ts +++ b/src/tv2-common/parts/kam.ts @@ -1,5 +1,5 @@ -import { BlueprintResultPart, IBlueprintPart, IShowStyleUserContext } from '@sofie-automation/blueprints-integration' -import { literal, PartDefinition, PartTime, TV2BlueprintConfigBase, TV2StudioConfigBase } from 'tv2-common' +import { BlueprintResultPart, IBlueprintPart, IShowStyleUserContext } from '@tv2media/blueprints-integration' +import { PartDefinition, PartTime, TV2BlueprintConfigBase, TV2StudioConfigBase } from 'tv2-common' export function CreatePartKamBase< StudioConfig extends TV2StudioConfigBase, @@ -12,18 +12,19 @@ export function CreatePartKamBase< ): { part: BlueprintResultPart; duration: number; invalid?: true } { const partTime = PartTime(config, partDefinition, totalWords, false) - const part = literal({ + const part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.rawType, metaData: {}, expectedDuration: partTime > 0 ? partTime : 0 - }) + } return { part: { part, pieces: [], - adLibPieces: [] + adLibPieces: [], + actions: [] }, duration: partTime } diff --git a/src/tv2-common/parts/server.ts b/src/tv2-common/parts/server.ts index 7b1d2e07b..56dd40854 100644 --- a/src/tv2-common/parts/server.ts +++ b/src/tv2-common/parts/server.ts @@ -6,27 +6,25 @@ import { PieceLifespan, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CutToServer, GetTagForServer, GetTagForServerNext, MakeContentServer, MakeContentServerSourceLayers, - PieceMetaData + PieceMetaData, + ServerPieceMetaData } from 'tv2-common' import { AdlibActionType, PartType, SharedOutputLayers, TallyTags } from 'tv2-constants' import { ActionSelectServerClip } from '../actions' import { TV2BlueprintConfigBase, TV2StudioConfigBase } from '../blueprintConfig' -import { GetVTContentProperties } from '../content' +import { getSourceDuration, GetVTContentProperties } from '../content' +import { getServerSeek, ServerPosition, ServerSelectMode } from '../helpers' import { PartDefinition } from '../inewsConversion' -import { literal, SanitizeString } from '../util' +import { SanitizeString } from '../util' import { CreatePartInvalid } from './invalid' -interface PieceMetaDataServer { - userData: ActionSelectServerClip -} - export interface ServerPartProps { voLayer: boolean voLevels: boolean @@ -35,6 +33,18 @@ export interface ServerPartProps { tapeTime: number adLibPix: boolean session?: string + actionTriggerMode?: ServerSelectMode + lastServerPosition?: ServerPosition +} + +export interface ServerContentProps { + seek?: number + /** Clip duration from mediaObject or tapeTime */ + clipDuration: number | undefined + /** Clip duration as in `clipDuration` but with postroll subtracted */ + sourceDuration: number | undefined + mediaPlayerSession: string + file: string } export type ServerPartLayers = { @@ -48,54 +58,60 @@ export type ServerPartLayers = { } } & MakeContentServerSourceLayers -export function CreatePartServerBase< +export async function CreatePartServerBase< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( context: IShowStyleUserContext, config: ShowStyleConfig, partDefinition: PartDefinition, - props: ServerPartProps, + partProps: ServerPartProps, layers: ServerPartLayers -): { part: BlueprintResultPart; file: string; duration: number; invalid?: true } { +): Promise<{ part: BlueprintResultPart; file: string; duration: number; invalid?: true }> { if (isVideoIdMissing(partDefinition)) { context.notifyUserWarning('Video ID not set!') return { part: CreatePartInvalid(partDefinition), file: '', duration: 0, invalid: true } } const file = getVideoId(partDefinition) - const mediaObjectDuration = context.hackGetMediaObjectDuration(file) + const mediaObjectDurationSec = await context.hackGetMediaObjectDuration(file) + const mediaObjectDuration = mediaObjectDurationSec && mediaObjectDurationSec * 1000 const sourceDuration = getSourceDuration(mediaObjectDuration, config.studio.ServerPostrollDuration) - const duration = getDuration(mediaObjectDuration, sourceDuration, props) + const duration = getDuration(mediaObjectDuration, sourceDuration, partProps) const sanitisedScript = getScriptWithoutLineBreaks(partDefinition) - const actualDuration = getActualDuration(duration, sanitisedScript, props) + const actualDuration = getActualDuration(duration, sanitisedScript, partProps) + + const contentProps: ServerContentProps = { + seek: getServerSeek(partProps.lastServerPosition, file, mediaObjectDuration, partProps.actionTriggerMode), + clipDuration: mediaObjectDuration ?? partProps.tapeTime * 1000, + mediaPlayerSession: SanitizeString(`segment_${partProps.session ?? partDefinition.segmentExternalId}_${file}`), + sourceDuration, + file + } const displayTitle = getDisplayTitle(partDefinition) - const basePart = getBasePart(partDefinition, displayTitle, actualDuration, file, config.studio.CasparPrerollDuration) - const mediaPlayerSession = SanitizeString(`segment_${props.session ?? partDefinition.segmentExternalId}_${file}`) + const basePart = getBasePart(partDefinition, displayTitle, actualDuration, file) - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] const serverSelectionBlueprintPiece = getServerSelectionBlueprintPiece( partDefinition, - file, actualDuration, - props, + partProps, + contentProps, layers, - sourceDuration, - mediaPlayerSession, context, - config + config, + config.studio.CasparPrerollDuration ) const pgmBlueprintPiece = getPgmBlueprintPiece( partDefinition, - file, - props, + partProps, + contentProps, layers, - sourceDuration, - mediaPlayerSession, - config + config, + config.studio.CasparPrerollDuration ) pieces.push(serverSelectionBlueprintPiece) @@ -105,7 +121,8 @@ export function CreatePartServerBase< part: { part: basePart, adLibPieces: [], - pieces + pieces, + actions: [] }, file, duration: actualDuration @@ -120,23 +137,16 @@ function getVideoId(partDefinition: PartDefinition): string { return partDefinition.fields.videoId ? partDefinition.fields.videoId : '' } -function getSourceDuration( - mediaObjectDuration: number | undefined, - serverPostrollDuration: number -): number | undefined { - return mediaObjectDuration !== undefined ? mediaObjectDuration * 1000 - serverPostrollDuration : undefined -} - function getDuration( mediaObjectDuration: number | undefined, sourceDuration: number | undefined, - props: ServerPartProps + partProps: ServerPartProps ): number { return ( (mediaObjectDuration !== undefined && - ((props.voLayer && props.totalWords <= 0) || !props.voLayer) && + ((partProps.voLayer && partProps.totalWords <= 0) || !partProps.voLayer) && sourceDuration) || - props.tapeTime * 1000 || + partProps.tapeTime * 1000 || 0 ) } @@ -162,15 +172,13 @@ function getBasePart( partDefinition: PartDefinition, displayTitle: string, actualDuration: number, - fileId: string, - casparPrerollDuration: number + fileId: string ): IBlueprintPart { return { externalId: partDefinition.externalId, title: displayTitle, metaData: {}, expectedDuration: actualDuration || 1000, - prerollDuration: casparPrerollDuration, hackListenToMediaObjectUpdates: [{ mediaId: fileId.toUpperCase() }] } } @@ -179,16 +187,16 @@ function getUserData( partDefinition: PartDefinition, file: string, actualDuration: number, - props: ServerPartProps + partProps: ServerPartProps ): ActionSelectServerClip { return { type: AdlibActionType.SELECT_SERVER_CLIP, file, partDefinition, duration: actualDuration, - voLayer: props.voLayer, - voLevels: props.voLevels, - adLibPix: props.adLibPix + voLayer: partProps.voLayer, + voLevels: partProps.voLevels, + adLibPix: partProps.adLibPix } } @@ -197,18 +205,14 @@ function getContentServerElement< ShowStyleConfig extends TV2BlueprintConfigBase >( partDefinition: PartDefinition, - file: string, - props: ServerPartProps, + partProps: ServerPartProps, + contentProps: ServerContentProps, layers: ServerPartLayers, - sourceDuration: number | undefined, - mediaPlayerSession: string, context: IShowStyleUserContext, config: ShowStyleConfig ): WithTimeline { return MakeContentServer( context, - file, - mediaPlayerSession, partDefinition, config, { @@ -216,16 +220,14 @@ function getContentServerElement< ClipPending: layers.Caspar.ClipPending }, Sisyfos: { - ClipPending: layers.Sisyfos.ClipPending, - StudioMicsGroup: layers.Sisyfos.StudioMicsGroup + ClipPending: layers.Sisyfos.ClipPending }, ATEM: { ServerLookaheadAux: layers.ATEM.ServerLookaheadAux } }, - props.adLibPix, - props.voLevels, - sourceDuration + partProps, + contentProps ) } @@ -234,41 +236,36 @@ function getServerSelectionBlueprintPiece< ShowStyleConfig extends TV2BlueprintConfigBase >( partDefinition: PartDefinition, - file: string, actualDuration: number, - props: ServerPartProps, + partProps: ServerPartProps, + contentProps: ServerContentProps, layers: ServerPartLayers, - sourceDuration: number | undefined, - mediaPlayerSession: string, context: IShowStyleUserContext, - config: ShowStyleConfig -): IBlueprintPiece { - const userDataElement = getUserData(partDefinition, file, actualDuration, props) - const contentServerElement = getContentServerElement( - partDefinition, - file, - props, - layers, - sourceDuration, - mediaPlayerSession, - context, - config - ) + config: ShowStyleConfig, + prerollDuration: number +): IBlueprintPiece { + const userDataElement = getUserData(partDefinition, contentProps.file, actualDuration, partProps) + const contentServerElement = getContentServerElement(partDefinition, partProps, contentProps, layers, context, config) - return literal({ + return { externalId: partDefinition.externalId, - name: file, + name: contentProps.file, enable: { start: 0 }, outputLayerId: SharedOutputLayers.SEC, sourceLayerId: layers.SourceLayer.SelectedServer, lifespan: PieceLifespan.OutOnSegmentEnd, - metaData: literal({ - mediaPlayerSessions: [mediaPlayerSession], - userData: userDataElement - }), + metaData: { + mediaPlayerSessions: [contentProps.mediaPlayerSession], + userData: userDataElement, + sisyfosPersistMetaData: { + sisyfosLayers: [], + acceptPersistAudio: partProps.adLibPix && partProps.voLevels + } + }, content: contentServerElement, - tags: [GetTagForServerNext(partDefinition.segmentExternalId, file, props.voLayer)] - }) + tags: [GetTagForServerNext(partDefinition.segmentExternalId, contentProps.file, partProps.voLayer)], + prerollDuration + } } function getPgmBlueprintPiece< @@ -276,27 +273,30 @@ function getPgmBlueprintPiece< ShowStyleConfig extends TV2BlueprintConfigBase >( partDefinition: PartDefinition, - file: string, - props: ServerPartProps, + partProps: ServerPartProps, + contentProps: ServerContentProps, layers: ServerPartLayers, - sourceDuration: number | undefined, - mediaPlayerSession: string, - config: ShowStyleConfig -): IBlueprintPiece { - return literal({ + config: ShowStyleConfig, + prerollDuration: number +): IBlueprintPiece { + return { externalId: partDefinition.externalId, - name: file, + name: contentProps.file, enable: { start: 0 }, outputLayerId: SharedOutputLayers.PGM, sourceLayerId: layers.SourceLayer.PgmServer, lifespan: PieceLifespan.WithinPart, - metaData: literal({ - mediaPlayerSessions: [mediaPlayerSession] - }), + metaData: { + mediaPlayerSessions: [contentProps.mediaPlayerSession] + }, content: { - ...GetVTContentProperties(config, file, sourceDuration), - timelineObjects: CutToServer(mediaPlayerSession, partDefinition, config, layers.AtemLLayer.MEPgm) + ...GetVTContentProperties(config, contentProps), + timelineObjects: CutToServer(contentProps.mediaPlayerSession, partDefinition, config, layers.AtemLLayer.MEPgm) }, - tags: [GetTagForServer(partDefinition.segmentExternalId, file, props.voLayer), TallyTags.SERVER_IS_LIVE] - }) + tags: [ + GetTagForServer(partDefinition.segmentExternalId, contentProps.file, partProps.voLayer), + TallyTags.SERVER_IS_LIVE + ], + prerollDuration + } } diff --git a/src/tv2-common/pieces/adlibServer.ts b/src/tv2-common/pieces/adlibServer.ts index 6fe83ea0d..411786821 100644 --- a/src/tv2-common/pieces/adlibServer.ts +++ b/src/tv2-common/pieces/adlibServer.ts @@ -1,6 +1,7 @@ -import { IBlueprintActionManifest } from '@sofie-automation/blueprints-integration' +import { IBlueprintActionManifest, IShowStyleUserContext } from '@tv2media/blueprints-integration' import { ActionSelectServerClip, + getSourceDuration, GetTagForServer, GetTagForServerNext, GetVTContentProperties, @@ -11,17 +12,18 @@ import { TV2StudioConfigBase } from 'tv2-common' import { AdlibActionType, AdlibTags, SharedOutputLayers } from 'tv2-constants' -import { t } from '../helpers' +import { getServerAdLibTriggerModes, t } from '../helpers' export interface AdlibServerOfftubeOptions { /** By passing in this object, you're creating a server according to the OFFTUBE showstyle. */ isOfftube: boolean } -export function CreateAdlibServer< +export async function CreateAdlibServer< StudioConfig extends TV2StudioConfigBase, ShowStyleConfig extends TV2BlueprintConfigBase >( + context: IShowStyleUserContext, config: ShowStyleConfig, rank: number, partDefinition: PartDefinition, @@ -29,16 +31,20 @@ export function CreateAdlibServer< voLayer: boolean, voLevels: boolean, sourceLayers: ServerPartLayers, - duration: number, tagAsAdlib: boolean -): IBlueprintActionManifest { - return literal({ +): Promise { + const mediaObjectDurationSec = await context.hackGetMediaObjectDuration(file) + const mediaObjectDuration = mediaObjectDurationSec && mediaObjectDurationSec * 1000 + const sourceDuration = getSourceDuration(mediaObjectDuration, config.studio.ServerPostrollDuration) + + return { + externalId: partDefinition.externalId + '-adLib-server', actionId: AdlibActionType.SELECT_SERVER_CLIP, userData: literal({ type: AdlibActionType.SELECT_SERVER_CLIP, file, partDefinition, - duration, + duration: sourceDuration ?? 0, voLayer, voLevels, adLibPix: tagAsAdlib @@ -49,7 +55,11 @@ export function CreateAdlibServer< label: t(`${partDefinition.storyName}`), sourceLayerId: sourceLayers.SourceLayer.PgmServer, outputLayerId: SharedOutputLayers.PGM, - content: GetVTContentProperties(config, file, duration), + content: GetVTContentProperties(config, { + file, + clipDuration: mediaObjectDuration, + sourceDuration + }), tags: [ tagAsAdlib || voLayer ? AdlibTags.OFFTUBE_ADLIB_SERVER : AdlibTags.OFFTUBE_100pc_SERVER, AdlibTags.ADLIB_KOMMENTATOR, @@ -58,6 +68,7 @@ export function CreateAdlibServer< currentPieceTags: [GetTagForServer(partDefinition.segmentExternalId, file, !!voLayer)], nextPieceTags: [GetTagForServerNext(partDefinition.segmentExternalId, file, !!voLayer)], uniquenessId: `${voLayer ? 'vo' : 'server'}_${partDefinition.storyName}_${file}` - } - }) + }, + triggerModes: getServerAdLibTriggerModes() + } } diff --git a/src/tv2-common/pieces/script.ts b/src/tv2-common/pieces/script.ts index 49cdb4bd4..66830e66a 100644 --- a/src/tv2-common/pieces/script.ts +++ b/src/tv2-common/pieces/script.ts @@ -1,10 +1,9 @@ -import { IBlueprintPiece, PieceLifespan, ScriptContent, WithTimeline } from '@sofie-automation/blueprints-integration' +import { IBlueprintPiece, PieceLifespan, ScriptContent, WithTimeline } from '@tv2media/blueprints-integration' import { literal, PartDefinition } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' const PREVIEW_CHARACTERS = 30 -// export function AddScript(part: PartDefinition, pieces: IBlueprintPiece[], duration: number, slutord: boolean) { export function AddScript(part: PartDefinition, pieces: IBlueprintPiece[], duration: number, sourceLayerId: string) { if (!pieces.length) { return @@ -16,29 +15,27 @@ export function AddScript(part: PartDefinition, pieces: IBlueprintPiece[], durat } if (script.length) { const stripLength = Math.min(PREVIEW_CHARACTERS, script.length) - pieces.push( - literal({ - externalId: part.externalId, - name: script.slice(0, stripLength), - enable: { - start: 0 - }, - outputLayerId: SharedOutputLayers.MANUS, - sourceLayerId, - lifespan: PieceLifespan.WithinPart, - content: literal>({ - firstWords: script.slice(0, stripLength), - lastWords: script - .replace(/\n/gi, ' ') - .trim() - .slice(script.length - stripLength) - ?.trim(), - fullScript: script, - sourceDuration: duration, - lastModified: part.modified * 1000, - timelineObjects: [] - }) + pieces.push({ + externalId: part.externalId, + name: script.slice(0, stripLength), + enable: { + start: 0 + }, + outputLayerId: SharedOutputLayers.MANUS, + sourceLayerId, + lifespan: PieceLifespan.WithinPart, + content: literal>({ + firstWords: script.slice(0, stripLength), + lastWords: script + .replace(/\n/gi, ' ') + .trim() + .slice(script.length - stripLength) + ?.trim(), + fullScript: script, + sourceDuration: duration, + lastModified: part.modified * 1000, + timelineObjects: [] }) - ) + }) } } diff --git a/src/tv2-common/pieces/tags.ts b/src/tv2-common/pieces/tags.ts index 63c7a5a8a..0a244359a 100644 --- a/src/tv2-common/pieces/tags.ts +++ b/src/tv2-common/pieces/tags.ts @@ -1,5 +1,6 @@ import { ActionTakeWithTransitionVariant, CueDefinitionDVE, SanitizeString } from 'tv2-common' import { TallyTags } from 'tv2-constants' +import { SourceDefinitionKam, SourceDefinitionRemote } from '../inewsConversion' export function GetTagForTransition(variant: ActionTakeWithTransitionVariant) { let tag = `${TallyTags.TAKE_WITH_TRANSITION}_${variant.type.toUpperCase()}` @@ -9,6 +10,7 @@ export function GetTagForTransition(variant: ActionTakeWithTransitionVariant) { tag += variant.breaker break case 'mix': + case 'dip': tag += variant.frames break default: @@ -18,12 +20,12 @@ export function GetTagForTransition(variant: ActionTakeWithTransitionVariant) { return tag } -export function GetTagForKam(name: string) { - return `${TallyTags.KAM}_${SanitizeString(name)}` +export function GetTagForKam(sourceDefinition: SourceDefinitionKam) { + return `${TallyTags.KAM}_${SanitizeString(sourceDefinition.name)}` } -export function GetTagForLive(name: string) { - return `${TallyTags.LIVE}_${SanitizeString(name)}` +export function GetTagForLive(sourceDefinition: SourceDefinitionRemote) { + return `${TallyTags.LIVE}_${SanitizeString(sourceDefinition.name)}` } export function GetTagForServer(segmentExternalId: string, clip: string, vo: boolean) { diff --git a/src/tv2-common/sources.ts b/src/tv2-common/sources.ts index d1f702221..a3f0f6615 100644 --- a/src/tv2-common/sources.ts +++ b/src/tv2-common/sources.ts @@ -1,8 +1,17 @@ import * as _ from 'underscore' -import { IStudioContext, SourceLayerType } from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +import { IStudioContext, SourceLayerType } from '@tv2media/blueprints-integration' +import { SourceType } from 'tv2-constants' +import { SourceMapping } from './blueprintConfig' +import { + RemoteType, + SourceDefinition, + SourceDefinitionKam, + SourceDefinitionRemote, + SourceDefinitionReplay +} from './inewsConversion' import { TableConfigItemSourceMappingWithSisyfos } from './types' +import { assertUnreachable } from './util' // TODO: BEGONE! export function parseMapStr( @@ -49,106 +58,103 @@ export function parseMapStr( export function ParseMappingTable( studioConfig: TableConfigItemSourceMappingWithSisyfos[], type: SourceInfoType, - idPrefix?: string + sourceLayerType: SourceLayerType ): SourceInfo[] { return studioConfig.map(conf => ({ type, - id: `${idPrefix || ''}${conf.SourceName}`, + id: conf.SourceName, port: conf.AtemSource, sisyfosLayers: conf.SisyfosLayers, - useStudioMics: conf.StudioMics + useStudioMics: conf.StudioMics, + wantsToPersistAudio: conf.WantsToPersistAudio, + acceptPersistAudio: conf.AcceptPersistAudio, + sourceLayerType })) } +/** + * Types of sources in the mappings + * Note: these values are used for display purposes as well + */ +export enum SourceInfoType { + KAM = 'KAM', + FEED = 'FEED', + LIVE = 'LIVE', + REPLAY = 'REPLAY' +} -export type SourceInfoType = - | SourceLayerType.CAMERA - | SourceLayerType.REMOTE - | SourceLayerType.AUDIO - | SourceLayerType.VT - | SourceLayerType.GRAPHICS - | SourceLayerType.UNKNOWN - | SourceLayerType.LOCAL export interface SourceInfo { type: SourceInfoType + sourceLayerType: SourceLayerType id: string port: number ptzDevice?: string sisyfosLayers?: string[] useStudioMics?: boolean + wantsToPersistAudio?: boolean + acceptPersistAudio?: boolean } -export function FindSourceInfo(sources: SourceInfo[], type: SourceInfoType, id: string): SourceInfo | undefined { - id = id.replace(/\s+/i, ' ').trim() - switch (type) { - case SourceLayerType.CAMERA: - const cameraName = id.match(/^(?:KAM|CAM)(?:ERA)? ?(.+)$/i) - if (cameraName === undefined || cameraName === null) { - return undefined - } - - return _.find(sources, s => s.type === type && s.id === cameraName[1].replace(/minus mic/i, '').trim()) - case SourceLayerType.REMOTE: - const remoteName = id - .replace(/VO/i, '') - .replace(/\s/g, '') - .match(/^(?:LIVE|SKYPE|FEED) ?(.+).*$/i) - if (!remoteName) { - return undefined - } - if (id.match(/^LIVE/i)) { - return _.find(sources, s => s.type === type && s.id === remoteName[1]) - } else if (id.match(/^FEED/i)) { - return _.find(sources, s => s.type === type && s.id === `F${remoteName[1]}`) - } else { - // Skype - return _.find(sources, s => s.type === type && s.id === `S${remoteName[1]}`) - } - case SourceLayerType.LOCAL: - const dpName = id - .replace(/VO/i, '') - .replace(/\s/g, '') - .match(/^(?:EVS) ?(.+).*$/i) - if (!dpName) { - return undefined - } - return _.find(sources, s => s.type === SourceLayerType.LOCAL && s.id === `DP${dpName[1]}`) +export function findSourceInfo(sources: SourceMapping, sourceDefinition: SourceDefinition): SourceInfo | undefined { + let arrayToSearchIn: SourceInfo[] + switch (sourceDefinition.sourceType) { + case SourceType.KAM: + arrayToSearchIn = sources.cameras + break + case SourceType.REMOTE: + arrayToSearchIn = sourceDefinition.remoteType === RemoteType.LIVE ? sources.lives : sources.feeds + break + case SourceType.REPLAY: + arrayToSearchIn = sources.replays + break default: return undefined } + return _.find(arrayToSearchIn, s => s.id === sourceDefinition.id) } -export function FindSourceInfoStrict( - _context: IStudioContext, - sources: SourceInfo[], - type: SourceInfoType, - id: string -): SourceInfo | undefined { - return FindSourceInfo(sources, type, id) -} - -export function FindSourceByName(context: IStudioContext, sources: SourceInfo[], name: string): SourceInfo | undefined { - name = (name + '').toLowerCase() - - if (name.indexOf('k') === 0 || name.indexOf('c') === 0) { - return FindSourceInfoStrict(context, sources, SourceLayerType.CAMERA, name) - } - - // TODO: This will be different for TV 2 - if (name.indexOf('r') === 0) { - return FindSourceInfoStrict(context, sources, SourceLayerType.REMOTE, name) - } - - // R35: context.notifyUserWarning(`Invalid source name "${name}"`) - return undefined -} - -export function GetInputValue(context: IStudioContext, sources: SourceInfo[], name: string): number { - let input = 1000 - const source = FindSourceByName(context, sources, name) - - if (source !== undefined) { - input = literal(source).port +export function SourceInfoToSourceDefinition( + sourceInfo: SourceInfo +): SourceDefinitionKam | SourceDefinitionRemote | SourceDefinitionReplay { + switch (sourceInfo.type) { + case SourceInfoType.KAM: { + const name = `KAM ${sourceInfo.id}` + return { + sourceType: SourceType.KAM, + id: sourceInfo.id, + raw: name, + minusMic: false, + name + } + } + case SourceInfoType.LIVE: { + const name = `LIVE ${sourceInfo.id}` + return { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: sourceInfo.id, + raw: name, + name + } + } + case SourceInfoType.FEED: { + const name = `FEED ${sourceInfo.id}` + return { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.FEED, + id: sourceInfo.id, + raw: name, + name + } + } + case SourceInfoType.REPLAY: + return { + sourceType: SourceType.REPLAY, + id: sourceInfo.id, + raw: sourceInfo.id, + name: sourceInfo.id, + vo: false + } + default: + assertUnreachable(sourceInfo.type) } - - return input } diff --git a/src/tv2-common/transitionSettings.ts b/src/tv2-common/transitionSettings.ts index 9554fc813..03ea8e525 100644 --- a/src/tv2-common/transitionSettings.ts +++ b/src/tv2-common/transitionSettings.ts @@ -1,20 +1,43 @@ -import { TSR } from '@sofie-automation/blueprints-integration' -import { PartDefinition } from 'tv2-common' +import { TSR } from '@tv2media/blueprints-integration' +import { PartDefinition, TV2BlueprintConfig } from 'tv2-common' +import { AtemSourceIndex } from '../types/atem' -export function TransitionSettings(part: PartDefinition): TSR.AtemTransitionSettings { - if (part.transition && part.transition.duration) { - if (part.transition.style === 'WIPE') { - return { - wipe: { - rate: part.transition.duration - } - } +export function TransitionSettings(config: TV2BlueprintConfig, part: PartDefinition): TSR.AtemTransitionSettings { + if (!part.transition || !part.transition.duration) { + return {} + } + + if (part.transition.style === TSR.AtemTransitionStyle.WIPE) { + return WipeTransitionSettings(part.transition.duration) + } + + if (part.transition.style === TSR.AtemTransitionStyle.DIP) { + return DipTransitionSettings(config, part.transition.duration) + } + return MixTransitionSettings(part.transition.duration) +} + +function WipeTransitionSettings(rate: number): TSR.AtemTransitionSettings { + return { + wipe: { + rate } - return { - mix: { - rate: part.transition.duration - } + } +} + +export function DipTransitionSettings(config: TV2BlueprintConfig, rate: number): TSR.AtemTransitionSettings { + return { + dip: { + rate, + input: config.studio?.AtemSource?.Dip ?? AtemSourceIndex.Col2 + } + } +} + +export function MixTransitionSettings(rate: number): TSR.AtemTransitionSettings { + return { + mix: { + rate } } - return {} } diff --git a/src/tv2-common/types/config.ts b/src/tv2-common/types/config.ts index 86fba44a4..65d66b271 100644 --- a/src/tv2-common/types/config.ts +++ b/src/tv2-common/types/config.ts @@ -8,12 +8,10 @@ export interface TableConfigItemSourceMapping { export type TableConfigItemSourceMappingWithSisyfos = { SisyfosLayers: string[] StudioMics: boolean + WantsToPersistAudio?: boolean + AcceptPersistAudio?: boolean } & TableConfigItemSourceMapping -export type TableConfigItemSourceMappingWithSisyfosAndKeepAudio = { - KeepAudioInStudio: boolean -} & TableConfigItemSourceMappingWithSisyfos - export interface TableConfigItemDSK { /** 0-based */ Number: number diff --git a/src/tv2-common/types/inews.ts b/src/tv2-common/types/inews.ts index 5773bcc87..21ca5f707 100644 --- a/src/tv2-common/types/inews.ts +++ b/src/tv2-common/types/inews.ts @@ -7,6 +7,7 @@ export interface INewsFields { totalTime?: string // number cumeTime?: string // number backTime?: string // @number (seconds since midnight) + layout?: string } export interface INewsMetaData { @@ -36,6 +37,7 @@ export interface INewsStory { export interface INewsPayload { iNewsStory?: INewsStory untimed?: boolean + initializeShows?: string[] } export type UnparsedCue = string[] | null diff --git a/src/tv2-common/updatePolicies/adlibs.ts b/src/tv2-common/updatePolicies/adlibs.ts index ce41d51a9..241113ee7 100644 --- a/src/tv2-common/updatePolicies/adlibs.ts +++ b/src/tv2-common/updatePolicies/adlibs.ts @@ -2,7 +2,7 @@ import { BlueprintSyncIngestNewData, BlueprintSyncIngestPartInstance, ISyncIngestUpdateToPartInstanceContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { PieceMetaData } from 'tv2-common' import _ = require('underscore') diff --git a/src/tv2-common/updatePolicies/partProperties.ts b/src/tv2-common/updatePolicies/partProperties.ts index a1796d54a..eb5277864 100644 --- a/src/tv2-common/updatePolicies/partProperties.ts +++ b/src/tv2-common/updatePolicies/partProperties.ts @@ -3,7 +3,7 @@ import { BlueprintSyncIngestPartInstance, IBlueprintMutatablePart, ISyncIngestUpdateToPartInstanceContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import _ = require('underscore') type Complete = { @@ -15,10 +15,7 @@ const partPropertiesToOmit = [ 'externalId', 'autoNext', 'autoNextOverlap', - 'prerollDuration', - 'transitionPrerollDuration', - 'transitionKeepaliveDuration', - 'transitionDuration', + 'inTransition', 'disableOutTransition', 'shouldNotifyCurrentPlayingPart' ] as const @@ -33,7 +30,9 @@ const clearedMutatablePart: Complete>) { return pieceInstances.reduce<{ @@ -13,6 +13,17 @@ function groupPieceInstances(pieceInstances: Array(o: T) { return o @@ -7,10 +8,12 @@ export function assertUnreachable(_never: never): never { throw new Error('Switch validation failed, look for assertUnreachable(...)') } +// tslint:disable-next-line: prettier +export type WithValuesOfTypes = { [P in keyof T as T[P] extends Q | undefined ? P : never]: T[P] } export type OptionalExceptFor = Partial & Pick export type EmptyBaseObj = OptionalExceptFor, 'layer' | 'enable' | 'classes'> export function createEmptyObject(obj: EmptyBaseObj): TSR.TimelineObjEmpty { - return literal({ + return { id: '', priority: 0, ...obj, @@ -18,7 +21,7 @@ export function createEmptyObject(obj: EmptyBaseObj): TSR.TimelineObjEmpty { deviceType: TSR.DeviceType.ABSTRACT, type: 'empty' } - }) + } } /** @@ -84,3 +87,7 @@ export function JoinAssetToNetworkPath( return `${networkPathWithWindowsPaths}\\${folderWithWindowsPaths}\\${assetFileWithWindowsPaths}.${extensionWithoutLeadingDot}` } + +export function generateExternalId(context: ICommonContext, action: ActionBase): string { + return context.getHashId(JSON.stringify(action), false) +} \ No newline at end of file diff --git a/src/tv2-constants/enums.ts b/src/tv2-constants/enums.ts index e94757989..d7f0f6605 100644 --- a/src/tv2-constants/enums.ts +++ b/src/tv2-constants/enums.ts @@ -45,10 +45,23 @@ export const enum PartType { INTRO = 'INTRO', EVS = 'EVS', DVE = 'DVE', - Ekstern = 'Ekstern', + REMOTE = 'Ekstern', Telefon = 'Telefon' } +export const enum SourceType { + KAM = 'KAM', + SERVER = 'SERVER', + VO = 'VO', + TEKNIK = 'TEKNIK', + GRAFIK = 'GRAFIK', + REPLAY = 'REPLAY', + REMOTE = 'REMOTE', + DEFAULT = 'DEFAULT', + PGM = 'PGM', + INVALID = 'INVALID' +} + export enum Enablers { OFFTUBE_ENABLE_FULL = 'offtube_enable_full', OFFTUBE_ENABLE_SERVER_LOOKAHEAD = 'offtube_enable_server_lookahead' @@ -66,11 +79,43 @@ export enum AdlibTags { ADLIB_FLOW_PRODUCER = 'flow_producer', ADLIB_STATIC_BUTTON = 'static_button', ADLIB_KOMMENTATOR = 'kommentator', - ADLIB_NO_NEXT_HIGHLIGHT = 'no_next_highlight' + ADLIB_NO_NEXT_HIGHLIGHT = 'no_next_highlight', + ADLIB_CUT_DIRECT = 'cut_direct', + ADLIB_QUEUE_NEXT = 'queue_next', + ADLIB_VO_AUDIO_LEVEL = 'vo_audio_level', + ADLIB_FULL_AUDIO_LEVEL = 'full_audio_level', + ADLIB_TO_STUDIO_SCREEN_AUX = 'to_studio_screen_aux', + ADLIB_TO_GRAPHICS_ENGINE_AUX = 'to_graphics_engine_aux', + ADLIB_CUT_TO_BOX_1 = 'cut_to_box_1', + ADLIB_CUT_TO_BOX_2 = 'cut_to_box_2', + ADLIB_CUT_TO_BOX_3 = 'cut_to_box_3', + ADLIB_CUT_TO_BOX_4 = 'cut_to_box_4', + ADLIB_GFX_ALTUD = 'gfx_altud', + ADLIB_GFX_LOAD = 'gfx_load', + ADLIB_GFX_CONTINUE_FORWARD = 'gfx_continue_forward', + ADLIB_DSK_ON = 'dsk_on', + ADLIB_DSK_OFF = 'dsk_off', + ADLIB_MICS_UP = 'mics_up', + ADLIB_MICS_DOWN = 'mics_down', + ADLIBS_RESYNC_SISYFOS = 'resync_sisyfos', + ADLIB_DESIGN_STYLE_SC = 'design_style_sc', + ADLIB_STOP_AUDIO_BED = 'stop_audio_bed', + ADLIB_RECALL_LAST_LIVE = 'recall_last_live', + ADLIB_RECALL_LAST_DVE = 'recall_last_dve', + ADLIB_SELECT_DVE_LAYOUT = 'select_dve_layout', + ADLIB_TAKE_WITH_TRANSITION = 'take_with_transition', + ADLIB_FADE_DOWN_PERSISTED_AUDIO_LEVELS = 'fade_down_persisted_audio_levels' +} + +/** + * Generates a tag for a 'cut to box' adlib + * @param box Box number (0-indexed) + */ +export function AdlibTagCutToBox(box: number): AdlibTags { + return `cut_to_box_${box + 1}` as AdlibTags } export enum ControlClasses { - ShowIdentGraphic = 'show_ident_graphic', /** Indicates that a DVE is currently on air */ DVEOnAir = 'dve_on_air', ServerOnAir = 'server_on_air', @@ -101,7 +146,8 @@ export enum AdlibActionType { CLEAR_GRAPHICS = 'clear_graphics', TAKE_WITH_TRANSITION = 'take_with_transition', RECALL_LAST_LIVE = 'recall_last_live', - RECALL_LAST_DVE = 'recall_last_dve' + RECALL_LAST_DVE = 'recall_last_dve', + FADE_DOWN_PERSISTED_AUDIO_LEVELS = 'fade_down_persisted_audio_levels' } export enum TallyTags { @@ -125,7 +171,7 @@ export enum TallyTags { JINGLE_IS_LIVE = 'JINGLE_IS_LIVE' } -export enum GraphicLLayer { +export enum SharedGraphicLLayer { GraphicLLayerOverlay = 'graphic_overlay', // <= viz_layer_overlay GraphicLLayerOverlayIdent = 'graphic_overlay_ident', // <= viz_layer_overlay_ident GraphicLLayerOverlayTopt = 'graphic_overlay_topt', // <= viz_layer_overlay_topt @@ -138,7 +184,8 @@ export enum GraphicLLayer { GraphicLLayerFullLoop = 'graphic_full_loop', GraphicLLayerAdLibs = 'graphic_adlibs', // <= viz_layer_adlibs GraphicLLayerWall = 'graphic_wall', // <= viz_layer_wall - GraphicLLayerLocators = 'graphic_locators' + GraphicLLayerLocators = 'graphic_locators', + GraphicLLayerConcept = 'graphic_concept' } export enum AbstractLLayer { @@ -160,7 +207,8 @@ export enum SharedCasparLLayer { export enum SharedSisyfosLLayer { SisyfosSourceAudiobed = 'sisyfos_source_audiobed', - SisyfosResync = 'sisyfos_resync' + SisyfosResync = 'sisyfos_resync', + SisyfosGroupStudioMics = 'sisyfos_group_studio_mics' } export enum SharedOutputLayers { @@ -187,7 +235,6 @@ export enum SharedSourceLayers { // Graphics PgmGraphicsIdent = 'studio0_graphicsIdent', - PgmGraphicsIdentPersistent = 'studio0_graphicsIdent_persistent', PgmGraphicsTop = 'studio0_graphicsTop', PgmGraphicsLower = 'studio0_graphicsLower', PgmGraphicsHeadline = 'studio0_graphicsHeadline', @@ -206,11 +253,6 @@ export enum SharedSourceLayers { PgmAdlibGraphicCmd = 'studio0_adlib_graphic_cmd', // shortcuts PgmAdlibJingle = 'studio0_adlib_jingle', - PgmDVEBox1 = 'studio0_dve_box1', - PgmDVEBox2 = 'studio0_dve_box2', - PgmDVEBox3 = 'studio0_dve_box3', - PgmDVEBox4 = 'studio0_dve_box4', - // Selected Sources SelectedServer = 'studio0_selected_clip', SelectedVoiceOver = 'studio0_selected_voiceover', diff --git a/src/tv2_afvd_showstyle/__tests__/actions.spec.ts b/src/tv2_afvd_showstyle/__tests__/actions.spec.ts index 830e01a09..b84748084 100644 --- a/src/tv2_afvd_showstyle/__tests__/actions.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/actions.spec.ts @@ -6,9 +6,9 @@ import { IBlueprintPieceInstance, PieceLifespan, TSR -} from '@sofie-automation/blueprints-integration' -import { ActionCutToCamera, ActionTakeWithTransition, literal } from 'tv2-common' -import { AdlibActionType, NoteType, SharedOutputLayers } from 'tv2-constants' +} from '@tv2media/blueprints-integration' +import { ActionCutToCamera, ActionTakeWithTransition, literal, SourceDefinitionKam } from 'tv2-common' +import { AdlibActionType, NoteType, SharedOutputLayers, SourceType } from 'tv2-constants' import { ActionExecutionContext } from '../../__mocks__/context' import { parseConfig as parseStudioConfig } from '../../tv2_afvd_studio/helpers/config' import { AtemLLayer } from '../../tv2_afvd_studio/layers' @@ -25,6 +25,13 @@ const CURRENT_PART_ID = 'MOCK_PART_CURRENT' const CURRENT_PART_EXTERNAL_ID = `${CURRENT_PART_ID}_EXTERNAL` const NEXT_PART_ID = 'MOCK_PART_CURRENT' const NEXT_PART_EXTERNAL_ID = `${CURRENT_PART_ID}_EXTERNAL` +const SOURCE_DEFINITION_KAM_1: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '1', + raw: 'Kam 1', + minusMic: false, + name: 'KAM 1' +} const currentPartMock: IBlueprintPartInstance = { _id: CURRENT_PART_ID, @@ -362,29 +369,44 @@ const evsPieceInstance_Effekt: IBlueprintPieceInstance = { partInstanceId: '' } -function getCameraPiece(context: ActionExecutionContext, part: 'current' | 'next'): IBlueprintPieceInstance { - const piece = context.getPieceInstances(part).find(p => p.piece.sourceLayerId === SourceLayer.PgmCam) +async function getCameraPiece( + context: ActionExecutionContext, + part: 'current' | 'next' +): Promise { + const piece = await context + .getPieceInstances(part) + .then(pieceInstance => pieceInstance.find(p => p.piece.sourceLayerId === SourceLayer.PgmCam)) expect(piece).toBeTruthy() return piece! } -function getEVSPiece(context: ActionExecutionContext, part: 'current' | 'next'): IBlueprintPieceInstance { - const piece = context.getPieceInstances(part).find(p => p.piece.sourceLayerId === SourceLayer.PgmLocal) +async function getEVSPiece( + context: ActionExecutionContext, + part: 'current' | 'next' +): Promise { + const piece = await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === SourceLayer.PgmLocal)) expect(piece).toBeTruthy() return piece! } -function getTransitionPiece(context: ActionExecutionContext, part: 'current' | 'next'): IBlueprintPieceInstance { - const piece = context.getPieceInstances(part).find(p => p.piece.sourceLayerId === SourceLayer.PgmJingle) +async function getTransitionPiece( + context: ActionExecutionContext, + part: 'current' | 'next' +): Promise { + const piece = await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === SourceLayer.PgmJingle)) expect(piece).toBeTruthy() return piece! } function getATEMMEObj(piece: IBlueprintPieceInstance): TSR.TimelineObjAtemME { - const atemObj = (piece.piece.content!.timelineObjects as TSR.TSRTimelineObj[]).find( + const atemObj = (piece.piece.content.timelineObjects as TSR.TSRTimelineObj[]).find( obj => obj.layer === AtemLLayer.AtemMEProgram && obj.content.deviceType === TSR.DeviceType.ATEM && @@ -485,13 +507,16 @@ function makeMockContext( } } -function checkPartExistsWithProperties( +async function checkPartExistsWithProperties( context: ActionExecutionContext, part: 'current' | 'next', props: Partial ) { - const partInstance = context.getPartInstance(part)! - expect(partInstance).toBeTruthy() + const partInstance = await context.getPartInstance(part)! + + if (partInstance === undefined) { + fail('PartInstances must not be undefined') + } for (const k in props) { if (k in partInstance.part) { @@ -503,10 +528,10 @@ function checkPartExistsWithProperties( } describe('Take with CUT', () => { - it('Sets the take flag', () => { + it('Sets the take flag', async () => { const context = makeMockContext('cut', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -519,18 +544,18 @@ describe('Take with CUT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`CUT`) expectTakeAfterExecute(context) }) - it('Changes MIX on part to CUT', () => { + it('Changes MIX on part to CUT', async () => { const context = makeMockContext('mix', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -543,18 +568,18 @@ describe('Take with CUT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`CUT`) expectTakeAfterExecute(context) }) - it('Removes EFFEKT from Next', () => { + it('Removes EFFEKT from Next', async () => { const context = makeMockContext('mix', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -567,20 +592,20 @@ describe('Take with CUT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`CUT`) expectTakeAfterExecute(context) }) }) describe('Take with MIX', () => { - it('Adds MIX to part with CUT as default', () => { + it('Adds MIX to part with CUT as default', async () => { const context = makeMockContext('cut', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -594,21 +619,25 @@ describe('Take with MIX', () => { ) expectNoWarningsOrErrors(context) - checkPartExistsWithProperties(context, 'next', { - transitionKeepaliveDuration: 800 + await checkPartExistsWithProperties(context, 'next', { + inTransition: { + previousPartKeepaliveDuration: 800, + blockTakeDuration: 800, + partContentDelayDuration: 0 + } }) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToMixOver(camPiece, 20) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`MIX 20`) expectTakeAfterExecute(context) }) - it('Changes MIX on part with MIX as default', () => { + it('Changes MIX on part with MIX as default', async () => { const context = makeMockContext('mix', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -622,18 +651,18 @@ describe('Take with MIX', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToMixOver(camPiece, 20) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`MIX 20`) expectTakeAfterExecute(context) }) - it('Removes EFFEKT from Next', () => { + it('Removes EFFEKT from Next', async () => { const context = makeMockContext('mix', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -647,20 +676,20 @@ describe('Take with MIX', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToMixOver(camPiece, 20) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`MIX 20`) expectTakeAfterExecute(context) }) }) describe('Take with EFFEKT', () => { - it('Adds EFFEKT to part with CUT as default', () => { + it('Adds EFFEKT to part with CUT as default', async () => { const context = makeMockContext('cut', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -674,18 +703,18 @@ describe('Take with EFFEKT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`EFFEKT 1`) expectTakeAfterExecute(context) }) - it('Removes MIX from Next', () => { + it('Removes MIX from Next', async () => { const context = makeMockContext('mix', 'cam', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -699,18 +728,18 @@ describe('Take with EFFEKT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`EFFEKT 1`) expectTakeAfterExecute(context) }) - it('Adds EFFEKT to KAM when on EVS', () => { + it('Adds EFFEKT to KAM when on EVS', async () => { const context = makeMockContext('cut', 'evs', 'cam') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -724,18 +753,18 @@ describe('Take with EFFEKT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`EFFEKT 1`) expectTakeAfterExecute(context) }) - it('Adds EFFEKT to EVS when on KAM', () => { + it('Adds EFFEKT to EVS when on KAM', async () => { const context = makeMockContext('cut', 'cam', 'evs') - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.TAKE_WITH_TRANSITION, literal({ @@ -749,23 +778,23 @@ describe('Take with EFFEKT', () => { ) expectNoWarningsOrErrors(context) - const camPiece = getEVSPiece(context, 'next') + const camPiece = await getEVSPiece(context, 'next') expectATEMToCut(camPiece) - const transitionPiece = getTransitionPiece(context, 'next') + const transitionPiece = await getTransitionPiece(context, 'next') expect(transitionPiece.piece.name).toBe(`EFFEKT 1`) expectTakeAfterExecute(context) }) }) describe('Camera shortcuts on server', () => { - it('It cuts directly to a camera on a server', () => { + it('It cuts directly to a camera on a server', async () => { const context = makeMockContext('cut', 'cam', 'cam') context.currentPieceInstances = [ - literal({ + { _id: 'serverPieceInstance', - piece: literal({ + piece: { _id: 'Server Current', enable: { start: 0 @@ -778,37 +807,37 @@ describe('Camera shortcuts on server', () => { content: { timelineObjects: [] } - }), + }, partInstanceId: '' - }) + } ] context.nextPart = undefined context.nextPieceInstances = [] - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.CUT_TO_CAMERA, literal({ type: AdlibActionType.CUT_TO_CAMERA, queue: false, - name: '1' + sourceDefinition: SOURCE_DEFINITION_KAM_1 }) ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expect(camPiece.piece.name).toEqual('KAM 1') expect(context.takeAfterExecute).toEqual(true) }) - it('It queues a camera without taking it', () => { + it('It queues a camera without taking it', async () => { const context = makeMockContext('cut', 'cam', 'cam') context.currentPieceInstances = [ - literal({ + { _id: 'serverPieceInstance', - piece: literal({ + piece: { _id: 'Server Current', enable: { start: 0 @@ -821,39 +850,39 @@ describe('Camera shortcuts on server', () => { content: { timelineObjects: [] } - }), + }, partInstanceId: '' - }) + } ] context.nextPart = undefined context.nextPieceInstances = [] - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.CUT_TO_CAMERA, literal({ type: AdlibActionType.CUT_TO_CAMERA, queue: true, - name: '1' + sourceDefinition: SOURCE_DEFINITION_KAM_1 }) ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expect(camPiece.piece.name).toEqual('KAM 1') expect(context.takeAfterExecute).toEqual(false) }) }) describe('Camera shortcuts on VO', () => { - it('It cuts directly to a camera on a VO', () => { + it('It cuts directly to a camera on a VO', async () => { const context = makeMockContext('cut', 'cam', 'cam') context.currentPieceInstances = [ - literal({ + { _id: 'voPieceInstance', - piece: literal({ + piece: { _id: 'VO Current', enable: { start: 0 @@ -866,37 +895,37 @@ describe('Camera shortcuts on VO', () => { content: { timelineObjects: [] } - }), + }, partInstanceId: '' - }) + } ] context.nextPart = undefined context.nextPieceInstances = [] - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.CUT_TO_CAMERA, literal({ type: AdlibActionType.CUT_TO_CAMERA, queue: false, - name: '1' + sourceDefinition: SOURCE_DEFINITION_KAM_1 }) ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expect(camPiece.piece.name).toEqual('KAM 1') expect(context.takeAfterExecute).toEqual(true) }) - it('It queues a camera without taking it', () => { + it('It queues a camera without taking it', async () => { const context = makeMockContext('cut', 'cam', 'cam') context.currentPieceInstances = [ - literal({ + { _id: 'voPieceInstance', - piece: literal({ + piece: { _id: 'VO Current', enable: { start: 0 @@ -909,26 +938,26 @@ describe('Camera shortcuts on VO', () => { content: { timelineObjects: [] } - }), + }, partInstanceId: '' - }) + } ] context.nextPart = undefined context.nextPieceInstances = [] - executeActionAFVD( + await executeActionAFVD( context, AdlibActionType.CUT_TO_CAMERA, literal({ type: AdlibActionType.CUT_TO_CAMERA, queue: true, - name: '1' + sourceDefinition: SOURCE_DEFINITION_KAM_1 }) ) expectNoWarningsOrErrors(context) - const camPiece = getCameraPiece(context, 'next') + const camPiece = await getCameraPiece(context, 'next') expect(camPiece.piece.name).toEqual('KAM 1') expect(context.takeAfterExecute).toEqual(false) }) diff --git a/src/tv2_afvd_showstyle/__tests__/addScript.spec.ts b/src/tv2_afvd_showstyle/__tests__/addScript.spec.ts index bb7db4c71..37d317676 100644 --- a/src/tv2_afvd_showstyle/__tests__/addScript.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/addScript.spec.ts @@ -1,6 +1,6 @@ -import { IBlueprintPiece, PieceLifespan, ScriptContent, WithTimeline } from '@sofie-automation/blueprints-integration' +import { IBlueprintPiece, PieceLifespan, ScriptContent, WithTimeline } from '@tv2media/blueprints-integration' import { AddScript, literal, PartDefinitionKam } from 'tv2-common' -import { PartType, SharedOutputLayers } from 'tv2-constants' +import { PartType, SharedOutputLayers, SourceType } from 'tv2-constants' import { SourceLayer } from '../layers' describe('addScript', () => { @@ -8,8 +8,12 @@ describe('addScript', () => { const part = literal({ externalId: '00000000001-0', type: PartType.Kam, - variant: { - name: '2' + sourceDefinition: { + sourceType: SourceType.KAM, + id: '2', + raw: 'KAM 2', + name: 'KAM 2', + minusMic: false }, rawType: 'KAM 2', cues: [], diff --git a/src/tv2_afvd_showstyle/__tests__/baseline.spec.ts b/src/tv2_afvd_showstyle/__tests__/baseline.spec.ts index fccd5041b..48f483953 100644 --- a/src/tv2_afvd_showstyle/__tests__/baseline.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/baseline.spec.ts @@ -1,5 +1,3 @@ -import { ExtendedIngestRundown } from '@sofie-automation/blueprints-integration' -import { ShowStyleUserContext } from '../../__mocks__/context' import { checkAllLayers } from './layers-check' // @ts-ignore @@ -8,55 +6,85 @@ global.VERSION = 'test' global.VERSION_TSR = 'test' // @ts-ignore global.VERSION_INTEGRATION = 'test' + +import { ExtendedIngestRundown, IGetRundownContext, TSR } from '@tv2media/blueprints-integration' +import { GetRundownContext } from '../../__mocks__/context' +import { SharedGraphicLLayer } from '../../tv2-constants' import { parseConfig as parseStudioConfig } from '../../tv2_afvd_studio/helpers/config' import mappingsDefaults from '../../tv2_afvd_studio/migrations/mappings-defaults' import { parseConfig as parseShowStyleConfig } from '../helpers/config' import Blueprints from '../index' import { defaultShowStyleConfig, defaultStudioConfig } from './configs' -const configs = [{ id: 'default', studioConfig: defaultStudioConfig, showStyleConfig: defaultShowStyleConfig }] +const configSpec = { id: 'default', studioConfig: defaultStudioConfig, showStyleConfig: defaultShowStyleConfig } const RUNDOWN_ID = 'test_rundown' const SEGMENT_ID = 'test_segment' const PART_ID = 'test_part' - describe('Baseline', () => { - for (const configSpec of configs) { - test('Config: ' + configSpec.id, () => { - expect(configSpec.studioConfig).toBeTruthy() - expect(configSpec.showStyleConfig).toBeTruthy() - - const rundown: ExtendedIngestRundown = { - externalId: 'abc', - name: 'Mock RO', - type: 'mock', - payload: {}, - segments: [], - coreData: undefined - } - - const mockContext = new ShowStyleUserContext( - rundown.name, - mappingsDefaults, - parseStudioConfig, - parseShowStyleConfig, - RUNDOWN_ID, - SEGMENT_ID, - PART_ID - ) - mockContext.studioConfig = configSpec.studioConfig as any - mockContext.showStyleConfig = configSpec.showStyleConfig as any - - const res = Blueprints.getRundown(mockContext, rundown) - - expect(res).not.toBeNull() - expect(res.baseline.timelineObjects).not.toHaveLength(0) - expect(res.globalAdLibPieces).not.toHaveLength(0) - - checkAllLayers(mockContext, res.globalAdLibPieces, res.baseline.timelineObjects) - - // ensure there were no warnings - expect(mockContext.getNotes()).toEqual([]) - }) - } + test('Config: ' + configSpec.id, async () => { + expect(configSpec.studioConfig).toBeTruthy() + expect(configSpec.showStyleConfig).toBeTruthy() + + const mockRundown: ExtendedIngestRundown = createMockRundown() + const mockContext: GetRundownContext = createMockContext(mockRundown.name) + + const result = await Blueprints.getRundown(mockContext, mockRundown) + if (result === null) { + throw new Error('result must not be null') + } + + expect(result.baseline.timelineObjects).not.toHaveLength(0) + expect(result.globalAdLibPieces).not.toHaveLength(0) + + checkAllLayers(mockContext, result.globalAdLibPieces, result.baseline.timelineObjects) + + // ensure there were no warnings + expect(mockContext.getNotes()).toEqual([]) + }) + + test('SetConcept timeline object is created in base rundown', async () => { + const mockRundown: ExtendedIngestRundown = createMockRundown() + const mockContext: IGetRundownContext = createMockContext(mockRundown.name) + + const rundown = await Blueprints.getRundown(mockContext, mockRundown) + if (rundown === null) { + fail('Result is not allowed to null') + } + + const result = rundown.baseline.timelineObjects.filter( + timelineObject => + timelineObject.layer === SharedGraphicLLayer.GraphicLLayerConcept && + timelineObject.content.deviceType === TSR.DeviceType.VIZMSE + ) + + expect(result).toHaveLength(1) + }) }) + +function createMockRundown(): ExtendedIngestRundown { + return { + externalId: 'abc', + name: 'Mock RO', + type: 'mock', + payload: {}, + segments: [], + coreData: undefined + } +} + +function createMockContext(rundownName: string): GetRundownContext { + const mockContext = new GetRundownContext( + rundownName, + mappingsDefaults, + parseStudioConfig, + parseShowStyleConfig, + RUNDOWN_ID, + SEGMENT_ID, + PART_ID + ) + mockContext.studioConfig = configSpec.studioConfig as any + mockContext.showStyleConfig = configSpec.showStyleConfig as any + + return mockContext +} diff --git a/src/tv2_afvd_showstyle/__tests__/blueprint.spec.ts b/src/tv2_afvd_showstyle/__tests__/blueprint.spec.ts index ef71cb181..acce40bf4 100644 --- a/src/tv2_afvd_showstyle/__tests__/blueprint.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/blueprint.spec.ts @@ -1,32 +1,17 @@ import { BlueprintResultSegment, - IBlueprintActionManifest, IBlueprintActionManifestDisplayContent, IngestSegment -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { INewsStory, literal, UnparsedCue } from 'tv2-common' import { SharedSourceLayers } from 'tv2-constants' -import { SegmentUserContext } from '../../__mocks__/context' -import { defaultShowStyleConfig, defaultStudioConfig } from '../../tv2_afvd_showstyle/__tests__/configs' -import { parseConfig as parseStudioConfig } from '../../tv2_afvd_studio/helpers/config' -import mappingsDefaults from '../../tv2_afvd_studio/migrations/mappings-defaults' +import { makeMockAFVDContext, SegmentUserContext } from '../../__mocks__/context' +import { SisyfosLLAyer } from '../../tv2_afvd_studio/layers' import { getSegment } from '../getSegment' -import { parseConfig as parseShowStyleConfig } from '../helpers/config' import { SourceLayer } from '../layers' const SEGMENT_EXTERNAL_ID = '00000000' -function makeMockContext(preventOverlay?: boolean) { - const mockContext = new SegmentUserContext('test', mappingsDefaults, parseStudioConfig, parseShowStyleConfig) - mockContext.studioConfig = - preventOverlay === undefined - ? defaultStudioConfig - : ({ ...defaultStudioConfig, PreventOverlayWithFull: preventOverlay } as any) - mockContext.showStyleConfig = defaultShowStyleConfig as any - - return mockContext -} - function makeIngestSegment(cues: UnparsedCue[], body: string) { return literal({ externalId: SEGMENT_EXTERNAL_ID, @@ -66,10 +51,10 @@ function expectAllPartsToBeValid(result: BlueprintResultSegment) { } describe('AFVD Blueprint', () => { - it('Accepts KAM CS 3', () => { + it('Accepts KAM CS 3', async () => { const ingestSegment = makeIngestSegment([], `\r\nKam CS 3\r\n`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -82,10 +67,10 @@ describe('AFVD Blueprint', () => { expect(kamPart.pieces[0].name).toEqual('CS 3 (JINGLE)') }) - it('Accepts KAM CS3', () => { + it('Accepts KAM CS3', async () => { const ingestSegment = makeIngestSegment([], `\r\nKam CS3\r\n`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -98,7 +83,7 @@ describe('AFVD Blueprint', () => { expect(kamPart.pieces[0].name).toEqual('CS 3 (JINGLE)') }) - it('Shows warning for Pilot without destination', () => { + it('Shows warning for Pilot without destination', async () => { const ingestSegment = makeIngestSegment( [ [ @@ -111,8 +96,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['Graphic found without target engine']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -126,13 +111,13 @@ describe('AFVD Blueprint', () => { expect(kamPart.actions).toHaveLength(0) }) - it('Creates invalid part for standalone GRAFIK=FULL', () => { + it('Creates invalid part for standalone GRAFIK=FULL', async () => { const ingestSegment = makeIngestSegment( [['GRAFIK=FULL']], `\r\nKam 1\r\n

Some script

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after GRAFIK cue']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -149,7 +134,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.part.invalid).toBe(true) }) - it('Creates graphic for GRAFIK=FULL with Pilot', () => { + it('Creates graphic for GRAFIK=FULL with Pilot', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -163,8 +148,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -186,14 +171,14 @@ describe('AFVD Blueprint', () => { ]) expect(fullPart.adLibPieces).toHaveLength(0) expect(fullPart.actions).toHaveLength(1) - const fullAdlibAction = fullPart.actions![0] as IBlueprintActionManifest + const fullAdlibAction = fullPart.actions[0] expect(fullAdlibAction).toBeTruthy() expect((fullAdlibAction.display as IBlueprintActionManifestDisplayContent).sourceLayerId).toBe( SharedSourceLayers.PgmPilot ) }) - it("Doesn't merge MOSART=L with GRAFIK=FULL", () => { + it("Doesn't merge MOSART=L with GRAFIK=FULL", async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -208,8 +193,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after GRAFIK cue']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -226,7 +211,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.part.invalid).toBe(true) }) - it('Creates full when cues are correct and shows warning when OVL with FULL is disabled', () => { + it('Creates full when cues are correct and shows warning when OVL with FULL is disabled', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -248,8 +233,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['Cannot create overlay graphic with FULL']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -267,7 +252,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.pieces).toHaveLength(2) expect(fullPart.adLibPieces).toHaveLength(0) expect(fullPart.actions).toHaveLength(1) - const fullAdlibAction = fullPart.actions![0] as IBlueprintActionManifest + const fullAdlibAction = fullPart.actions[0] expect(fullAdlibAction).toBeTruthy() expect((fullAdlibAction.display as IBlueprintActionManifestDisplayContent).sourceLayerId).toBe( SharedSourceLayers.PgmPilot @@ -278,7 +263,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Creates full when cues are correct and creates overlay when allowed', () => { + it('Creates full when cues are correct and creates overlay when allowed', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -300,8 +285,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n

\r\n

\r\n` ) - const context = makeMockContext(false) - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext({ PreventOverlayWithFull: false }) + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -319,7 +304,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.pieces).toHaveLength(3) expect(fullPart.adLibPieces).toHaveLength(0) expect(fullPart.actions).toHaveLength(1) - const fullAdlibAction = fullPart.actions![0] as IBlueprintActionManifest + const fullAdlibAction = fullPart.actions[0] expect(fullAdlibAction).toBeTruthy() expect((fullAdlibAction.display as IBlueprintActionManifestDisplayContent).sourceLayerId).toBe( SharedSourceLayers.PgmPilot @@ -331,7 +316,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Creates graphic for GRAFIK=FULL with Pilot with space', () => { + it('Creates graphic for GRAFIK=FULL with Pilot with space', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -346,8 +331,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -370,14 +355,14 @@ describe('AFVD Blueprint', () => { expect(fullPart.adLibPieces).toHaveLength(0) expect(fullPart.actions).toHaveLength(1) expect(fullPart.actions).toHaveLength(1) - const fullAdlibAction = fullPart.actions![0] as IBlueprintActionManifest + const fullAdlibAction = fullPart.actions[0] expect(fullAdlibAction).toBeTruthy() expect((fullAdlibAction.display as IBlueprintActionManifestDisplayContent).sourceLayerId).toBe( SharedSourceLayers.PgmPilot ) }) - it("Creates invalid part for GRAFIK=FULL with Pilot with 'notes'", () => { + it("Creates invalid part for GRAFIK=FULL with Pilot with 'notes'", async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -392,8 +377,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after GRAFIK cue', 'Graphic found without target engine']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -413,7 +398,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.actions).toHaveLength(0) }) - it('Creates invalid part for GRAFIK=FULL with Pilot and bund in between', () => { + it('Creates invalid part for GRAFIK=FULL with Pilot and bund in between', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -428,8 +413,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

Some script

\r\n

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after GRAFIK cue', 'Graphic found without target engine']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -449,7 +434,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.actions).toHaveLength(0) }) - it('Creates invalid part and show warning when GRAFIK=FULL and Pilot in different parts', () => { + it('Creates invalid part and show warning when GRAFIK=FULL and Pilot in different parts', async () => { const ingestSegment = makeIngestSegment( [ ['GRAFIK=FULL'], @@ -463,8 +448,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\nKam 2\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after GRAFIK cue', 'Graphic found without target engine']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(3) @@ -491,7 +476,7 @@ describe('AFVD Blueprint', () => { expect(kamPart2.actions).toHaveLength(0) }) - it('Creates overlay graphic for MOSART=L', () => { + it('Creates overlay graphic for MOSART=L', async () => { const ingestSegment = makeIngestSegment( [ [ @@ -505,8 +490,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -524,7 +509,7 @@ describe('AFVD Blueprint', () => { expect(kamPart.actions).toHaveLength(0) }) - it('Creates wall graphic for MOSART=W', () => { + it('Creates wall graphic for MOSART=W', async () => { const ingestSegment = makeIngestSegment( [ [ @@ -538,8 +523,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -557,7 +542,7 @@ describe('AFVD Blueprint', () => { expect(kamPart.actions).toHaveLength(0) }) - it('Creates full graphic for MOSART=F', () => { + it('Creates full graphic for MOSART=F', async () => { const ingestSegment = makeIngestSegment( [ [ @@ -571,8 +556,8 @@ describe('AFVD Blueprint', () => { ], `\r\nKam 1\r\n

Some script

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -590,7 +575,7 @@ describe('AFVD Blueprint', () => { expect(fullPart.pieces).toHaveLength(2) expect(fullPart.adLibPieces).toHaveLength(0) expect(fullPart.actions).toHaveLength(1) - const fullAdlibAction = fullPart.actions![0] as IBlueprintActionManifest + const fullAdlibAction = fullPart.actions[0] expect(fullAdlibAction).toBeTruthy() expect((fullAdlibAction.display as IBlueprintActionManifestDisplayContent).sourceLayerId).toBe( SharedSourceLayers.PgmPilot @@ -601,7 +586,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Loads graphic on wall, and loop on wall in next part', () => { + it('Loads graphic on wall, and loop on wall in next part', async () => { const ingestSegment = makeIngestSegment( [ ['SS=SC-STILLS', ';0.00.01'], @@ -616,8 +601,8 @@ describe('AFVD Blueprint', () => { ], `\r\n

Kam 1

\r\n

\r\n

\r\n

Some script

\r\n

Kam 2

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -641,7 +626,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Shows warning for missing wall graphic', () => { + it('Shows warning for missing wall graphic', async () => { const ingestSegment = makeIngestSegment( [ ['SS=SC-STILLS', ';0.00.01'], @@ -649,8 +634,8 @@ describe('AFVD Blueprint', () => { ], `\r\n

Kam 1

\r\n

\r\n

Some script

\r\n

Kam 2

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after SS cue']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -667,7 +652,7 @@ describe('AFVD Blueprint', () => { expect(kamPart1.pieces.map(p => p.sourceLayerId)).toEqual([SharedSourceLayers.PgmCam, SharedSourceLayers.PgmScript]) }) - it('Shows warning for missing wall graphic with MOSART=L', () => { + it('Shows warning for missing wall graphic with MOSART=L', async () => { const ingestSegment = makeIngestSegment( [ ['SS=SC-STILLS', ';0.00.01'], @@ -682,8 +667,8 @@ describe('AFVD Blueprint', () => { ], `\r\n

Kam 1

\r\n

\r\n

\r\n

Some script

\r\n

Kam 2

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after SS cue']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -707,7 +692,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Shows warning for graphic in wrong place', () => { + it('Shows warning for graphic in wrong place', async () => { const ingestSegment = makeIngestSegment( [ ['SS=SC-STILLS', ';0.00.01'], @@ -722,8 +707,8 @@ describe('AFVD Blueprint', () => { ], `\r\n

Kam 1

\r\n

\r\n

Some script

\r\n

Kam 2

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, ['No graphic found after SS cue', 'Graphic found without target engine']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(2) @@ -743,7 +728,7 @@ describe('AFVD Blueprint', () => { ]) }) - it('Changes design and background loops', () => { + it('Changes design and background loops', async () => { const ingestSegment = makeIngestSegment( [ ['KG=DESIGN_FODBOLD_20', ';0.00.01'], @@ -752,8 +737,8 @@ describe('AFVD Blueprint', () => { ], `\r\n

KAM 1

\r\n

\r\n

\r\n

\r\n

Some script

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -771,10 +756,10 @@ describe('AFVD Blueprint', () => { ]) }) - it('Creates Live1', () => { + it('Creates Live1', async () => { const ingestSegment = makeIngestSegment([['EKSTERN=LIVE1']], `\r\n

\r\n

`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -786,10 +771,10 @@ describe('AFVD Blueprint', () => { expect(livePart1.pieces.map(p => p.sourceLayerId)).toEqual([SharedSourceLayers.PgmLive]) }) - it('Creates Live 1', () => { + it('Creates Live 1', async () => { const ingestSegment = makeIngestSegment([['EKSTERN=LIVE 1']], `\r\n

\r\n

`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -801,10 +786,10 @@ describe('AFVD Blueprint', () => { expect(livePart1.pieces.map(p => p.sourceLayerId)).toEqual([SharedSourceLayers.PgmLive]) }) - it('Creates Feed1', () => { + it('Creates Feed1', async () => { const ingestSegment = makeIngestSegment([['EKSTERN=FEED1']], `\r\n

\r\n

`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -816,10 +801,10 @@ describe('AFVD Blueprint', () => { expect(feedPart1.pieces.map(p => p.sourceLayerId)).toEqual([SharedSourceLayers.PgmLive]) }) - it('Creates Feed 1', () => { + it('Creates Feed 1', async () => { const ingestSegment = makeIngestSegment([['EKSTERN=FEED 1']], `\r\n

\r\n

`) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) @@ -831,23 +816,24 @@ describe('AFVD Blueprint', () => { expect(feedPart1.pieces.map(p => p.sourceLayerId)).toEqual([SharedSourceLayers.PgmLive]) }) - it('Creates invalid part for EKSTERN=LIVE', () => { + it('Creates invalid part for EKSTERN=LIVE', async () => { const ingestSegment = makeIngestSegment( [['EKSTERN=LIVE'], ['#kg direkte ODDER', ';0.00']], `\r\n

***LIVE***

\r\n

\r\n

\r\n` ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) - expectNotesToBe(context, ['No source entered for EKSTERN']) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) + + expectNotesToBe(context, ['EKSTERN source is not valid: "LIVE"']) expect(result.segment.isHidden).toBe(false) expect(result.parts).toHaveLength(1) expect(result.parts[0].part.invalid).toBe(true) }) - it('Creates effekt for KAM 1 EFFEKT 1', () => { + it('Creates effekt for KAM 1 EFFEKT 1', async () => { const ingestSegment = makeIngestSegment([], '\r\n

KAM 1 EFFEKT 1

\r\n') - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expectAllPartsToBeValid(result) expect(result.segment.isHidden).toBe(false) @@ -860,10 +846,10 @@ describe('AFVD Blueprint', () => { expect(kamPart1.pieces[0].name).toBe('EFFEKT 1') }) - it('Creates mix for KAM 1 MIX 5', () => { + it('Creates mix for KAM 1 MIX 5', async () => { const ingestSegment = makeIngestSegment([], '\r\n

KAM 1 MIX 5

\r\n') - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expectAllPartsToBeValid(result) expect(result.segment.isHidden).toBe(false) @@ -876,13 +862,13 @@ describe('AFVD Blueprint', () => { expect(kamPart1.pieces[0].name).toBe('MIX 5') }) - it('Creates mix for EKSTERN=LIVE 1 EFFEKT 1', () => { + it('Creates mix for EKSTERN=LIVE 1 EFFEKT 1', async () => { const ingestSegment = makeIngestSegment( [['EKSTERN=LIVE 1 EFFEKT 1']], '\r\n

***LIVE***

\r\n

\r\n' ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expectAllPartsToBeValid(result) expect(result.segment.isHidden).toBe(false) @@ -898,13 +884,13 @@ describe('AFVD Blueprint', () => { expect(livePart1.pieces[0].name).toBe('EFFEKT 1') }) - it('Creates mix for EKSTERN=LIVE 1 MIX 10', () => { + it('Creates mix for EKSTERN=LIVE 1 MIX 10', async () => { const ingestSegment = makeIngestSegment( [['EKSTERN=LIVE 1 MIX 10']], '\r\n

***LIVE***

\r\n

\r\n' ) - const context = makeMockContext() - const result = getSegment(context, ingestSegment) + const context = makeMockAFVDContext() + const result = await getSegment(context, ingestSegment) expectNotesToBe(context, []) expectAllPartsToBeValid(result) expect(result.segment.isHidden).toBe(false) @@ -919,4 +905,114 @@ describe('AFVD Blueprint', () => { ]) expect(livePart1.pieces[0].name).toBe('MIX 10') }) + + it('Enables studio mics for LIVE when useStudioMics is enabled', async () => { + const ingestSegment = makeIngestSegment([['EKSTERN=LIVE 1']], '\r\n

\r\n') + const context = makeMockAFVDContext({ + SourcesRM: [ + { + SourceName: '1', + AtemSource: 10, + SisyfosLayers: [], + StudioMics: true, + WantsToPersistAudio: false + } + ] + }) + const result = await getSegment(context, ingestSegment) + const livePart = result.parts[0] + const livePiece = livePart.pieces[0] + const studioMicsObject = livePiece.content.timelineObjects.find( + t => t.layer === SisyfosLLAyer.SisyfosGroupStudioMics + ) + expect(studioMicsObject).toBeDefined() + }) + + it('Does not enable studio mics for LIVE when useStudioMics is disabled', async () => { + const ingestSegment = makeIngestSegment([['EKSTERN=LIVE 1']], '\r\n

\r\n') + const context = makeMockAFVDContext({ + SourcesRM: [ + { + SourceName: '1', + AtemSource: 10, + SisyfosLayers: [], + StudioMics: false, + WantsToPersistAudio: false + } + ] + }) + const result = await getSegment(context, ingestSegment) + const livePart = result.parts[0] + const livePiece = livePart.pieces[0] + const studioMicsObject = livePiece.content.timelineObjects.find( + t => t.layer === SisyfosLLAyer.SisyfosGroupStudioMics + ) + expect(studioMicsObject).toBeUndefined() + }) + + it('Enables studio mics for KAM when useStudioMics is enabled', async () => { + const ingestSegment = makeIngestSegment([], '\r\n

KAM 1

\r\n') + const context = makeMockAFVDContext({ + SourcesCam: [ + { + SourceName: '1', + AtemSource: 1, + SisyfosLayers: [], + StudioMics: true, + WantsToPersistAudio: false + } + ] + }) + const result = await getSegment(context, ingestSegment) + const livePart = result.parts[0] + const livePiece = livePart.pieces[0] + const studioMicsObject = livePiece.content.timelineObjects.find( + t => t.layer === SisyfosLLAyer.SisyfosGroupStudioMics + ) + expect(studioMicsObject).toBeDefined() + }) + + it('Does not enable studio mics for KAM minus mic when useStudioMics is enabled', async () => { + const ingestSegment = makeIngestSegment([], '\r\n

KAM 1 minus mic

\r\n') + const context = makeMockAFVDContext({ + SourcesCam: [ + { + SourceName: '1', + AtemSource: 1, + SisyfosLayers: [], + StudioMics: true, + WantsToPersistAudio: false + } + ] + }) + const result = await getSegment(context, ingestSegment) + const livePart = result.parts[0] + const livePiece = livePart.pieces[0] + const studioMicsObject = livePiece.content.timelineObjects.find( + t => t.layer === SisyfosLLAyer.SisyfosGroupStudioMics + ) + expect(studioMicsObject).toBeUndefined() + }) + + it('Does not enable studio mics for KAM when useStudioMics is disabled', async () => { + const ingestSegment = makeIngestSegment([], '\r\n

KAM 1

\r\n') + const context = makeMockAFVDContext({ + SourcesCam: [ + { + SourceName: '1', + AtemSource: 1, + SisyfosLayers: [], + StudioMics: false, + WantsToPersistAudio: false + } + ] + }) + const result = await getSegment(context, ingestSegment) + const livePart = result.parts[0] + const livePiece = livePart.pieces[0] + const studioMicsObject = livePiece.content.timelineObjects.find( + t => t.layer === SisyfosLLAyer.SisyfosGroupStudioMics + ) + expect(studioMicsObject).toBeUndefined() + }) }) diff --git a/src/tv2_afvd_showstyle/__tests__/config-manifest.spec.ts b/src/tv2_afvd_showstyle/__tests__/config-manifest.spec.ts index e512fac98..9e7358d75 100644 --- a/src/tv2_afvd_showstyle/__tests__/config-manifest.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/config-manifest.spec.ts @@ -12,7 +12,10 @@ const blankShowStyleConfig: ShowStyleConfig = { LYDConfig: [], CasparCGLoadingClip: '', Transitions: [{ Transition: '1' }, { Transition: '2' }], - ShowstyleTransition: 'CUT' + ShowstyleTransition: 'CUT', + SelectedGraphicsSetupName: '', + GraphicsSetups: [], + SchemaConfig: [] } describe('Config Manifest', () => { diff --git a/src/tv2_afvd_showstyle/__tests__/configs.ts b/src/tv2_afvd_showstyle/__tests__/configs.ts index 345df7b0d..a073fb317 100644 --- a/src/tv2_afvd_showstyle/__tests__/configs.ts +++ b/src/tv2_afvd_showstyle/__tests__/configs.ts @@ -1,4 +1,4 @@ -import { literal, parseMapStr } from 'tv2-common' +import { literal, parseMapStr, TableConfigGraphicsSetup } from 'tv2-common' import { defaultDSKConfig, StudioConfig } from '../../tv2_afvd_studio/helpers/config' import { ShowStyleConfig } from '../helpers/config' import { DefaultBreakerConfig } from './breakerConfigDefault' @@ -10,10 +10,9 @@ function getSisyfosLayers(configName: string, id: string): string[] { return [] case 'SourcesRM': case 'SourcesFeed': - case 'SourcesSkype': return ['sisyfos_source_live_' + id] case 'SourcesDelayedPlayback': - return ['sisyfos_source_evs_' + id] + return ['sisyfos_source_' + id.toLowerCase().replace(' ', '_')] } return [] @@ -24,13 +23,13 @@ function prepareConfig( conf: string, configName: string, studioMics: boolean, - keepAudioInStudio?: boolean + wantsToPersistAudio?: boolean ): Array<{ SourceName: string AtemSource: number SisyfosLayers: string[] StudioMics: boolean - KeepAudioInStudio: boolean + wantsToPersistAudio: boolean }> { return parseMapStr(undefined, conf, true).map(c => { return { @@ -38,11 +37,21 @@ function prepareConfig( AtemSource: c.val, SisyfosLayers: getSisyfosLayers(configName, c.id), StudioMics: studioMics, - KeepAudioInStudio: keepAudioInStudio ?? false + wantsToPersistAudio: wantsToPersistAudio ?? false } }) } +export const OVL_SHOW_ID = 'ovl-show-id' +export const FULL_SHOW_ID = 'full-show-id' +export const DEFAULT_GRAPHICS_SETUP: TableConfigGraphicsSetup = { + Name: 'SomeProfile', + VcpConcept: 'SomeConcept', + OvlShowId: OVL_SHOW_ID, + FullShowId: FULL_SHOW_ID, + DveLayoutFolder: 'folder/path' +} + // in here will be some mock configs that can be referenced paired with ro's for the tests export const defaultStudioConfig: StudioConfig = { ClipMediaFlowId: '', @@ -80,10 +89,9 @@ export const defaultStudioConfig: StudioConfig = { true ), // TODO: prepareConfig is legacy code, refactor when refactoring FindSourceInfo - SourcesSkype: prepareConfig('1:1,2:2,3:3,4:4,5:5,6:6,7:7', 'SourcesSkype', false), SourcesRM: prepareConfig('1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,10:10', 'SourcesRM', false, true), SourcesFeed: prepareConfig('1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,10:10', 'SourcesFeed', false, true), - SourcesDelayedPlayback: prepareConfig('1:5,2:5', 'SourcesDelayedPlayback', false), + SourcesReplay: prepareConfig('EVS 1:5,EVS 2:5,EPSIO:5', 'SourcesDelayedPlayback', false), StudioMics: [ 'sisyfos_source_Host_1_st_a', 'sisyfos_source_Host_2_st_a', @@ -98,7 +106,8 @@ export const defaultStudioConfig: StudioConfig = { SplitArtF: 30, SplitArtK: 32, Default: 2001, - Continuity: 2002 + Continuity: 2002, + Dip: 2002 }, SofieHostURL: '', ABMediaPlayers: [ @@ -255,6 +264,16 @@ export const defaultShowStyleConfig: ShowStyleConfig = { FadeOut: 0 } ], + SelectedGraphicsSetupName: 'SomeProfile', + GraphicsSetups: [DEFAULT_GRAPHICS_SETUP], Transitions: [{ Transition: '1' }, { Transition: '2' }], - ShowstyleTransition: 'CUT' + ShowstyleTransition: 'CUT', + SchemaConfig: [] +} + +export const EMPTY_SOURCE_CONFIG = { + cameras: [], + lives: [], + feeds: [], + replays: [] } diff --git a/src/tv2_afvd_showstyle/__tests__/layers-check.ts b/src/tv2_afvd_showstyle/__tests__/layers-check.ts index 6b8e26c0d..7b99f7217 100644 --- a/src/tv2_afvd_showstyle/__tests__/layers-check.ts +++ b/src/tv2_afvd_showstyle/__tests__/layers-check.ts @@ -6,9 +6,9 @@ import { IShowStyleUserContext, TimelineObjectCoreExt, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' -import { GetDSKSourceLayerNames, literal } from 'tv2-common' +import { GetDSKSourceLayerNames } from 'tv2-common' import mappingsDefaults, { getMediaPlayerMappings } from '../../tv2_afvd_studio/migrations/mappings-defaults' import { ATEMModel } from '../../types/atem' import { getConfig } from '../helpers/config' @@ -33,10 +33,10 @@ export function checkAllLayers( .sort() const allOutputLayers = _.map(OutputlayerDefaults, m => m._id) - const allMappings = literal({ + const allMappings: BlueprintMappings = { ...mappingsDefaults, ...getMediaPlayerMappings(config.mediaPlayers) - }) + } const validateObject = (obj: TimelineObjectCoreExt) => { const isAbstract = obj.content.deviceType === TSR.DeviceType.ABSTRACT diff --git a/src/tv2_afvd_showstyle/__tests__/regressions.spec.ts b/src/tv2_afvd_showstyle/__tests__/regressions.spec.ts index debe1e12c..5178d61e8 100644 --- a/src/tv2_afvd_showstyle/__tests__/regressions.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/regressions.spec.ts @@ -1,6 +1,6 @@ import * as _ from 'underscore' -import { BlueprintResultSegment, PieceLifespan, TimelineObjectCoreExt } from '@sofie-automation/blueprints-integration' +import { BlueprintResultSegment, PieceLifespan, TimelineObjectCoreExt } from '@tv2media/blueprints-integration' // @ts-ignore global.VERSION = 'test' @@ -112,7 +112,8 @@ describe('regressions-migrations', () => { ] } } - ] + ], + actions: [] } ] } @@ -216,7 +217,8 @@ describe('regressions-migrations', () => { ] } } - ] + ], + actions: [] } ] } diff --git a/src/tv2_afvd_showstyle/__tests__/rundown_story_exception.spec.ts b/src/tv2_afvd_showstyle/__tests__/rundown_story_exception.spec.ts index 79415d52c..92c4abbdb 100644 --- a/src/tv2_afvd_showstyle/__tests__/rundown_story_exception.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/rundown_story_exception.spec.ts @@ -1,10 +1,6 @@ import * as _ from 'underscore' -import { - ExtendedIngestRundown, - IBlueprintPieceGeneric, - IBlueprintRundownDB -} from '@sofie-automation/blueprints-integration' +import { ExtendedIngestRundown, IBlueprintPieceGeneric } from '@tv2media/blueprints-integration' import { defaultShowStyleConfig, defaultStudioConfig } from './configs' import { checkAllLayers } from './layers-check' @@ -14,23 +10,22 @@ global.VERSION = 'test' global.VERSION_TSR = 'test' // @ts-ignore global.VERSION_INTEGRATION = 'test' -import { INewsStory, literal } from 'tv2-common' -import { SegmentUserContext, ShowStyleUserContext } from '../../__mocks__/context' + +import { INewsStory } from 'tv2-common' +import { SegmentUserContext } from '../../__mocks__/context' import { parseConfig as parseStudioConfig, StudioConfig } from '../../tv2_afvd_studio/helpers/config' import mappingsDefaults from '../../tv2_afvd_studio/migrations/mappings-defaults' import { parseConfig as parseShowStyleConfig, ShowStyleConfig } from '../helpers/config' import Blueprints from '../index' -// More ROs can be listed here to make them part of the basic blueprint doesnt crash test +const onAirRundownRelativePath = '../../../rundowns/on-air.json' + +// More ROs can be listed here to make them part of the basic blueprint const rundowns: Array<{ ro: string; studioConfig: StudioConfig; showStyleConfig: ShowStyleConfig }> = [ - { ro: '../../../rundowns/on-air.json', studioConfig: defaultStudioConfig, showStyleConfig: defaultShowStyleConfig } + { ro: onAirRundownRelativePath, studioConfig: defaultStudioConfig, showStyleConfig: defaultShowStyleConfig } ] -const RUNDOWN_ID = 'test_rundown' -const SEGMENT_ID = 'test_segment' -const PART_ID = 'test_part' - -describe('Rundown exceptions', () => { +describe('Generate rundowns without error', () => { for (const roSpec of rundowns) { const roData = require(roSpec.ro) as ExtendedIngestRundown test('Valid file: ' + roSpec.ro, () => { @@ -39,34 +34,15 @@ describe('Rundown exceptions', () => { expect(roData.type).toEqual('inews') }) - const showStyleContext = new ShowStyleUserContext( - 'mockRo', - mappingsDefaults, - parseStudioConfig, - parseShowStyleConfig, - RUNDOWN_ID, - SEGMENT_ID, - PART_ID - ) - // can I do this?: - showStyleContext.studioConfig = roSpec.studioConfig as any - showStyleContext.showStyleConfig = roSpec.showStyleConfig as any - const blueprintRundown = Blueprints.getRundown(showStyleContext, roData) - const rundown = literal({ - ...blueprintRundown.rundown, - _id: 'mockRo', - showStyleVariantId: 'mock' - }) - for (const segment of roData.segments) { - test('Rundown segment: ' + roSpec.ro + ' - ' + rundown.externalId, async () => { + test(`Rundown segment: ${segment.name} - ${roSpec.ro} - ${roData.externalId}`, async () => { const mockContext = new SegmentUserContext('test', mappingsDefaults, parseStudioConfig, parseShowStyleConfig) mockContext.studioConfig = roSpec.studioConfig as any mockContext.showStyleConfig = roSpec.showStyleConfig as any const iNewsStory: INewsStory | undefined = segment.payload?.iNewsStory - const res = Blueprints.getSegment(mockContext, segment) + const res = await Blueprints.getSegment(mockContext, segment) if (iNewsStory && iNewsStory.fields.pageNumber && iNewsStory.fields.pageNumber.trim()) { expect(res.segment.identifier).toEqual(iNewsStory.fields.pageNumber.trim()) } diff --git a/src/tv2_afvd_showstyle/__tests__/syncIngestChangesToPartInstance.spec.ts b/src/tv2_afvd_showstyle/__tests__/syncIngestChangesToPartInstance.spec.ts index ed2e74107..5264bd907 100644 --- a/src/tv2_afvd_showstyle/__tests__/syncIngestChangesToPartInstance.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/syncIngestChangesToPartInstance.spec.ts @@ -7,7 +7,7 @@ import { IBlueprintRundownDB, PieceLifespan, PlaylistTimingType -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import { SyncIngestUpdateToPartInstanceContext } from '../../__mocks__/context' @@ -58,9 +58,14 @@ function makePartinstance( }) } -function makeSoundBed(id: string, name: string): IBlueprintPieceInstance { +function makeSoundBed( + id: string, + name: string, + instanceProps?: Partial +): IBlueprintPieceInstance { return literal>({ _id: id, + ...instanceProps, piece: { _id: '', enable: { @@ -146,11 +151,19 @@ describe('Sync Ingest Changes To Part Instances', () => { it('Syncs part properties', () => { const context = makeMockContext() const existingPartInstance: BlueprintSyncIngestPartInstance = literal({ - partInstance: makePartinstance({ title: 'Kam 1', budgetDuration: 2000, transitionPrerollDuration: 200 }), + partInstance: makePartinstance({ + title: 'Kam 1', + budgetDuration: 2000, + inTransition: { partContentDelayDuration: 200, previousPartKeepaliveDuration: 0, blockTakeDuration: 0 } + }), pieceInstances: [] }) const newPart: BlueprintSyncIngestNewData = literal({ - part: makePart({ title: 'Kam 2', budgetDuration: 1000, transitionPrerollDuration: 500 }), + part: makePart({ + title: 'Kam 2', + budgetDuration: 1000, + inTransition: { partContentDelayDuration: 500, previousPartKeepaliveDuration: 0, blockTakeDuration: 0 } + }), pieceInstances: [], adLibPieces: [], actions: [], @@ -158,8 +171,38 @@ describe('Sync Ingest Changes To Part Instances', () => { }) syncIngestUpdateToPartInstance(context, existingPartInstance, newPart, 'current') - expect(context.updatedPartInstance?.part.transitionPrerollDuration).toBeUndefined() + expect(context.updatedPartInstance?.part.inTransition).toBeUndefined() expect(context.updatedPartInstance?.part.budgetDuration).toBe(1000) expect(context.updatedPartInstance?.part.title).toBe('Kam 2') }) + + it('Does not remove adlib instances or infinite continuations', () => { + const context = makeMockContext() + const existingPartInstance: BlueprintSyncIngestPartInstance = literal({ + partInstance: makePartinstance({ title: 'Soundbed' }), + pieceInstances: [ + makeSoundBed('someId1', 'SN_Intro', { adLibSourceId: 'someAdLib' }), + makeSoundBed('someId2', 'SN_Intro', { infinite: { infinitePieceId: 'someInfinite', fromPreviousPart: true } }), + makeSoundBed('someId3', 'SN_Intro', { + infinite: { infinitePieceId: 'someInfinite', fromPreviousPart: false, fromPreviousPlayhead: true } + }), + makeSoundBed('someId4', 'SN_Intro', { + infinite: { infinitePieceId: 'someInfinite', fromPreviousPart: false, fromHold: true } + }), + makeSoundBed('someId5', 'SN_Intro', { dynamicallyInserted: 1649158767173 }) + ] + }) + const newPart: BlueprintSyncIngestNewData = literal({ + part: makePart({ title: 'Soundbed' }), + pieceInstances: [], + adLibPieces: [], + actions: [], + referencedAdlibs: [] + }) + syncIngestUpdateToPartInstance(context, existingPartInstance, newPart, 'current') + + expect(context.removedPieceInstances).toStrictEqual([]) + expect(context.syncedPieceInstances).toStrictEqual([]) + expect(context.updatedPieceInstances).toStrictEqual([]) + }) }) diff --git a/src/tv2_afvd_showstyle/__tests__/transitions.spec.ts b/src/tv2_afvd_showstyle/__tests__/transitions.spec.ts index 0c56de315..a8097cee3 100644 --- a/src/tv2_afvd_showstyle/__tests__/transitions.spec.ts +++ b/src/tv2_afvd_showstyle/__tests__/transitions.spec.ts @@ -4,7 +4,7 @@ import { IBlueprintPiece, IngestSegment, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { fail } from 'assert' import { TimeFromFrames } from 'tv2-common' import * as _ from 'underscore' @@ -97,10 +97,12 @@ function checkPartExistsWithProperties(segment: BlueprintResultSegment, props: P function getTransitionProperties(effekt: ShowStyleConfig['BreakerConfig'][0]): Partial { const preroll = defaultStudioConfig.CasparPrerollDuration as number return { - transitionDuration: TimeFromFrames(Number(effekt.Duration)) + preroll, - transitionKeepaliveDuration: TimeFromFrames(Number(effekt.StartAlpha)) + preroll, - transitionPrerollDuration: - TimeFromFrames(Number(effekt.Duration)) - TimeFromFrames(Number(effekt.EndAlpha)) + preroll + inTransition: { + blockTakeDuration: TimeFromFrames(Number(effekt.Duration)) + preroll, + previousPartKeepaliveDuration: TimeFromFrames(Number(effekt.StartAlpha)) + preroll, + partContentDelayDuration: + TimeFromFrames(Number(effekt.Duration)) - TimeFromFrames(Number(effekt.EndAlpha)) + preroll + } } } @@ -128,13 +130,13 @@ function testNotes(context: SegmentUserContext) { } describe('Primary Cue Transitions Without Config', () => { - it('Cuts by default for KAM', () => { + it('Cuts by default for KAM', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

KAM 1

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -144,13 +146,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds effekt to KAM', () => { + it('Adds effekt to KAM', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

KAM 1 EFFEKT 2

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -162,13 +164,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds mix to KAM', () => { + it('Adds mix to KAM', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

KAM 1 Mix 11

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -176,19 +178,23 @@ describe('Primary Cue Transitions Without Config', () => { const atemCutObj = getATEMMEObj(piece) checkPartExistsWithProperties(segment, { - transitionKeepaliveDuration: 440 + inTransition: { + previousPartKeepaliveDuration: 440, + partContentDelayDuration: 0, + blockTakeDuration: 440 + } }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.MIX) expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(11) }) - it('Cuts by default for EVS1', () => { + it('Cuts by default for EVS1', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS 1

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -198,13 +204,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds effekt to EVS1', () => { + it('Adds effekt to EVS1', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS 1 EFFEKT 1

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -215,13 +221,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds mix to EVS1', () => { + it('Adds mix to EVS1', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS 1 Mix 15

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -229,19 +235,23 @@ describe('Primary Cue Transitions Without Config', () => { const atemCutObj = getATEMMEObj(piece) checkPartExistsWithProperties(segment, { - transitionKeepaliveDuration: 600 + inTransition: { + previousPartKeepaliveDuration: 600, + partContentDelayDuration: 0, + blockTakeDuration: 600 + } }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.MIX) expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(15) }) - it('Cuts by default for EVS1VO', () => { + it('Cuts by default for EVS1VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS1VO

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -251,13 +261,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds effekt to EVS1VO', () => { + it('Adds effekt to EVS1VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS 1VO EFFEKT 1

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -268,13 +278,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds mix to EVS1VO', () => { + it('Adds mix to EVS1VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

EVS 1 VO Mix 25

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -282,36 +292,39 @@ describe('Primary Cue Transitions Without Config', () => { const atemCutObj = getATEMMEObj(piece) checkPartExistsWithProperties(segment, { - transitionKeepaliveDuration: 1000 + inTransition: { + previousPartKeepaliveDuration: 1000, + partContentDelayDuration: 0, + blockTakeDuration: 1000 + } }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.MIX) expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(25) }) - it('Cuts by default for SERVER', () => { + it('Cuts by default for SERVER', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

SERVER

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmServer) const atemCutObj = getATEMMEObj(piece) - checkPartExistsWithProperties(segment, { prerollDuration: defaultStudioConfig.CasparPrerollDuration as number }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds effekt to SERVER', () => { + it('Adds effekt to SERVER', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

SERVER EFFEKT 2

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -322,13 +335,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds mix to SERVER', () => { + it('Adds mix to SERVER', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

SERVER Mix 20

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -336,37 +349,39 @@ describe('Primary Cue Transitions Without Config', () => { const atemCutObj = getATEMMEObj(piece) checkPartExistsWithProperties(segment, { - prerollDuration: defaultStudioConfig.CasparPrerollDuration as number, - transitionKeepaliveDuration: 800 + inTransition: { + previousPartKeepaliveDuration: 800, + partContentDelayDuration: 0, + blockTakeDuration: 800 + } }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.MIX) expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(20) }) - it('Cuts by default for VO', () => { + it('Cuts by default for VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

VO

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) const piece = getPieceOnLayerFromPart(segment, SourceLayer.PgmVoiceOver) const atemCutObj = getATEMMEObj(piece) - checkPartExistsWithProperties(segment, { prerollDuration: defaultStudioConfig.CasparPrerollDuration as number }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds effekt to VO', () => { + it('Adds effekt to VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

VO EFFEKT 1

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -377,13 +392,13 @@ describe('Primary Cue Transitions Without Config', () => { expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.CUT) }) - it('Adds mix to VO', () => { + it('Adds mix to VO', async () => { const ingestSegment = _.clone(templateSegment) ingestSegment.payload.iNewsStory.body = '\r\n

VO Mix 20

' const context = makeMockContextWithoutTransitionsConfig() - const segment = getSegment(context, ingestSegment) + const segment = await getSegment(context, ingestSegment) testNotes(context) @@ -391,8 +406,11 @@ describe('Primary Cue Transitions Without Config', () => { const atemCutObj = getATEMMEObj(piece) checkPartExistsWithProperties(segment, { - prerollDuration: defaultStudioConfig.CasparPrerollDuration as number, - transitionKeepaliveDuration: 800 + inTransition: { + previousPartKeepaliveDuration: 800, + partContentDelayDuration: 0, + blockTakeDuration: 800 + } }) expect(atemCutObj.content.me.transition).toBe(TSR.AtemTransitionStyle.MIX) expect(atemCutObj.content.me.transitionSettings?.mix?.rate).toBe(20) diff --git a/src/tv2_afvd_showstyle/actions.ts b/src/tv2_afvd_showstyle/actions.ts index ad297d9c0..beebb70f6 100644 --- a/src/tv2_afvd_showstyle/actions.ts +++ b/src/tv2_afvd_showstyle/actions.ts @@ -1,4 +1,4 @@ -import { ActionUserData, IActionExecutionContext } from '@sofie-automation/blueprints-integration' +import { ActionUserData, IActionExecutionContext } from '@tv2media/blueprints-integration' import { executeAction } from 'tv2-common' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../tv2_afvd_studio/layers' import { getConfig } from './helpers/config' @@ -9,8 +9,13 @@ import { createJingleContentAFVD } from './helpers/pieces/jingle' import { SourceLayer } from './layers' import { postProcessPieceTimelineObjects } from './postProcessTimelineObjects' -export function executeActionAFVD(context: IActionExecutionContext, actionId: string, userData: ActionUserData): void { - executeAction( +export async function executeActionAFVD( + context: IActionExecutionContext, + actionId: string, + userData: ActionUserData, + triggerMode?: string +): Promise { + await executeAction( context, { getConfig, @@ -38,8 +43,7 @@ export function executeActionAFVD(context: IActionExecutionContext, actionId: st Sisyfos: { ClipPending: SisyfosLLAyer.SisyfosSourceClipPending, Effekt: SisyfosLLAyer.SisyfosSourceJingle, - StudioMics: SisyfosLLAyer.SisyfosGroupStudioMics, - PersistedLevels: SisyfosLLAyer.SisyfosPersistedLevels + StudioMics: SisyfosLLAyer.SisyfosGroupStudioMics }, Atem: { MEProgram: AtemLLayer.AtemMEProgram, @@ -59,15 +63,11 @@ export function executeActionAFVD(context: IActionExecutionContext, actionId: st }, SELECTED_ADLIB_LAYERS: [SourceLayer.SelectedServer, SourceLayer.SelectedVoiceOver] }, - ServerAudioLayers: [ - SisyfosLLAyer.SisyfosSourceClipPending, - SisyfosLLAyer.SisyfosSourceServerA, - SisyfosLLAyer.SisyfosSourceServerB - ], createJingleContent: createJingleContentAFVD, pilotGraphicSettings: pilotGeneratorSettingsAFVD }, actionId, - userData + userData, + triggerMode ) } diff --git a/src/tv2_afvd_showstyle/config-manifests.ts b/src/tv2_afvd_showstyle/config-manifests.ts index 9270ced2f..259a7c995 100644 --- a/src/tv2_afvd_showstyle/config-manifests.ts +++ b/src/tv2_afvd_showstyle/config-manifests.ts @@ -1,97 +1,285 @@ -import { ConfigManifestEntry, ConfigManifestEntryType, TSR } from '@sofie-automation/blueprints-integration' +import { ConfigManifestEntry, ConfigManifestEntryType, TSR } from '@tv2media/blueprints-integration' import { DEFAULT_GRAPHICS } from 'tv2-common' -export const showStyleConfigManifest: ConfigManifestEntry[] = [ - { - id: 'MakeAdlibsForFulls', - name: 'Make Adlibs for FULL graphics', - description: '', - type: ConfigManifestEntryType.BOOLEAN, - defaultVal: true, - required: false - }, - { - id: 'CasparCGLoadingClip', - name: 'CasparCG Loading Clip', - description: 'Clip to play when media is loading', - type: ConfigManifestEntryType.STRING, - defaultVal: 'LoadingLoop', - required: true - }, +export const dveStylesManifest: ConfigManifestEntry = { + id: 'DVEStyles', + name: 'DVE Layouts', + description: '', + type: ConfigManifestEntryType.TABLE, + required: false, + defaultVal: [ + { + _id: '', + DVEName: 'sommerfugl', + DVEInputs: '1:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":11,"x":-800,"y":60,"size":500,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":1,"x":800,"y":60,"size":500,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "width": "963px", "text-transform": "uppercase", "overflow": "hidden", "top": "764px" }, "locator1": { "left": "960px", "padding-left": "50px", "padding-right": "120px", "text-align": "right" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px" } }', + DVEGraphicsKey: 'dve/sommerfuglK', + DVEGraphicsFrame: 'dve/sommerfugl' + }, + { + _id: '', + DVEName: 'morbarn', + DVEInputs: '3:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":false,"source":12,"x":-500,"y":140,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1000},"1":{"enabled":true,"source":2001,"x":1080,"y":-240,"size":320,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":true,"source":2,"x":-460,"y":100,"size":720,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":true,"cropTop":0,"cropBottom":119,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "1300px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "width": "624px" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "width": "1300px" } }', + DVEGraphicsKey: 'dve/morbarnK', + DVEGraphicsFrame: 'dve/morbarn' + }, + { + _id: '', + DVEName: 'barnmor', + DVEInputs: '2:INP2;1:INP1', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":13,"x":-1080,"y":-240,"size":320,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":3,"x":460,"y":100,"size":720,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":false,"source":2001,"x":-460,"y":130,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1230},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "624px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "width": "1300px" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "width": "624px" } }', + DVEGraphicsKey: 'dve/barnmorK', + DVEGraphicsFrame: 'dve/barnmor' + }, + { + _id: '', + DVEName: 'barnMorIpad', + DVEInputs: '1:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":11,"x":-850,"y":-250,"size":350,"cropped":true,"cropTop":240,"cropBottom":530,"cropLeft":550,"cropRight":2580},"1":{"enabled":true,"source":10,"x":507,"y":130,"size":800,"cropped":true,"cropTop":250,"cropBottom":0,"cropLeft":4380,"cropRight":4170},"2":{"enabled":false,"source":2001,"x":-460,"y":130,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1230},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "733px", "padding-left": "50px", "padding-right": "50px", "text-align": "right", "width": "1014px" }, "locator2": { "left": "118px", "padding-left": "50px", "padding-right": "50px", "width": "624px" } }', + DVEGraphicsKey: 'dve/barnipadK', + DVEGraphicsFrame: 'dve/barnipad' + }, + { + _id: '', + DVEName: '3split', + DVEInputs: '1:INP1;2:INP2;3:INP3', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2,"x":-1050,"y":100,"size":700,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":8500},"1":{"enabled":true,"source":3,"x":160,"y":100,"size":700,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":6200,"cropRight":10600},"2":{"enabled":true,"source":1000,"x":1080,"y":100,"size":700,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":true,"source":2001,"x":758,"y":-425,"size":417,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "width": "640px", "text-transform": "uppercase", "top": "848px" }, "locator1": { "left": "1280px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "overflow": "hidden" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "overflow": "hidden" } }', + DVEGraphicsKey: 'dve/3splitK', + DVEGraphicsFrame: 'dve/3split' + }, + { + _id: '', + DVEName: '3barnMor', + DVEInputs: '1:INP1;2:INP2;3:INP3;4:INP4', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2002,"x":-1055,"y":-390,"size":230,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":700},"1":{"enabled":true,"source":2,"x":358,"y":0,"size":680,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":400,"cropRight":0},"2":{"enabled":true,"source":4,"x":-1055,"y":10,"size":230,"cropped":true,"cropTop":500,"cropBottom":200,"cropLeft":0,"cropRight":700},"3":{"enabled":true,"source":1000,"x":-1055,"y":400,"size":230,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":700}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: '{}', + DVEGraphicsKey: 'dve/3barnMorK', + DVEGraphicsFrame: 'dve/3barnMor' + }, + { + _id: '', + DVEName: '2barnMor', + DVEInputs: '1:INP1;2:INP2;3:INP3', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2,"x":-1050,"y":-200,"size":330,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":3,"x":540,"y":100,"size":670,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":true,"source":2,"x":-1050,"y":400,"size":330,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":true,"source":2001,"x":758,"y":-425,"size":417,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: '{}', + DVEGraphicsKey: 'dve/2barnMorK', + DVEGraphicsFrame: 'dve/2barnMor' + } + ], + columns: [ + { + id: 'DVEName', + name: 'DVE name', + description: 'The name as it will appear in iNews', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 0 + }, + { + id: 'DVEInputs', + name: 'Box inputs', + description: 'I.e.: 1:INP1;2:INP3; as an example to chose which ATEM boxes to assign iNews inputs to', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '1:INP1;2:INP2;3:INP3;4:INP4', + rank: 1 + }, + { + id: 'DVEJSON', + name: 'DVE config', + description: 'DVE config pulled from ATEM', + type: ConfigManifestEntryType.JSON, + required: true, + defaultVal: '{}', + rank: 2 + }, + { + id: 'DVEGraphicsTemplateJSON', + name: 'CasparCG template config', + description: 'Position (and style) data for the boxes in the CasparCG template', + type: ConfigManifestEntryType.JSON, + required: true, + defaultVal: '{}', + rank: 4 + }, + { + id: 'DVEGraphicsKey', + name: 'CasparCG key file', + description: 'Key file for DVE', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 5 + }, + { + id: 'DVEGraphicsFrame', + name: 'CasparCG frame file', + description: 'Frames file for caspar', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 6 + } + ] +} + +const graphicsSetups: ConfigManifestEntry[] = [ { - id: 'DVEStyles', - name: 'DVE Layouts', - description: '', + id: 'GraphicsSetups', + name: 'Graphics Setups', + description: 'Possible graphics setups', type: ConfigManifestEntryType.TABLE, required: false, - defaultVal: [ - { - _id: '', - DVEName: '', - DVEInputs: '', - DVEJSON: '{}', - DVEGraphicsTemplateJSON: '{}', - DVEGraphicsKey: '', - DVEGraphicsFrame: '' - } - ], + defaultVal: [], columns: [ { - id: 'DVEName', - name: 'DVE name', - description: 'The name as it will appear in iNews', + id: 'Name', + name: 'Name', + description: 'The code as it will appear in iNews', type: ConfigManifestEntryType.STRING, required: true, defaultVal: '', rank: 0 }, { - id: 'DVEInputs', - name: 'Box inputs', - description: 'I.e.: 1:INP1;2:INP3; as an example to chose which ATEM boxes to assign iNews inputs to', - type: ConfigManifestEntryType.STRING, + id: 'VcpConcept', + name: 'VCP Concept', + rank: 1, required: true, - defaultVal: '1:INP1;2:INP2;3:INP3;4:INP4', - rank: 1 + defaultVal: '', + hint: '', + description: '', + type: ConfigManifestEntryType.STRING }, { - id: 'DVEJSON', - name: 'DVE config', - description: 'DVE config pulled from ATEM', - type: ConfigManifestEntryType.JSON, + id: 'OvlShowId', + name: 'Overlay Show-ID', + rank: 2, required: true, - defaultVal: '{}', - rank: 2 + defaultVal: '', + hint: '', + description: 'UUID of the show used for OVL channel', + type: ConfigManifestEntryType.STRING }, { - id: 'DVEGraphicsTemplateJSON', - name: 'CasparCG template config', - description: 'Position (and style) data for the boxes in the CasparCG template', - type: ConfigManifestEntryType.JSON, + id: 'FullShowId', + name: 'Fullscreen Show-ID', + rank: 3, required: true, - defaultVal: '{}', - rank: 4 + defaultVal: '', + hint: '', + description: 'UUID of the show used for FULL and WALL channels', + type: ConfigManifestEntryType.STRING }, { - id: 'DVEGraphicsKey', - name: 'CasparCG key file', - description: 'Key file for DVE', - type: ConfigManifestEntryType.STRING, + id: 'DveLayoutFolder', + name: 'DVE layout folder', + rank: 4, required: true, defaultVal: '', - rank: 5 + hint: '', + description: 'Path to the folder containing the layouts for DVEs', + type: ConfigManifestEntryType.STRING + } + ], + hint: '' + }, + { + id: 'SelectedGraphicsSetupName', + name: 'Graphic Setup name', + description: 'Name of the Graphic Setup that should be used', + type: ConfigManifestEntryType.STRING, + required: false, + defaultVal: '' + } +] + +export const schemaConfigManifest: ConfigManifestEntry[] = [ + { + id: 'SchemaConfig', + name: 'Skema', + description: 'The values for the Skema and Design combinations', + type: ConfigManifestEntryType.TABLE, + required: false, + defaultVal: [], + columns: [ + { + id: 'schemaName', + name: 'Skema', + description: 'The name of the Skema', + rank: 0, + required: true, + defaultVal: '', + type: ConfigManifestEntryType.STRING }, { - id: 'DVEGraphicsFrame', - name: 'CasparCG frame file', - description: 'Frames file for caspar', - type: ConfigManifestEntryType.STRING, + id: 'designIdentifier', + name: 'Design', + description: 'The identifier of the Design', + rank: 1, required: true, defaultVal: '', - rank: 6 + type: ConfigManifestEntryType.STRING + }, + { + id: 'vizTemplateName', + name: 'Viz Template Name', + description: 'The name of the Viz template', + rank: 2, + required: true, + defaultVal: '', + type: ConfigManifestEntryType.STRING + }, + { + id: 'casparCgDveBgScene', + name: 'CasparCG DVE Bg Scene', + description: 'The dveBgScene', + defaultVal: '', + rank: 3, + required: true, + type: ConfigManifestEntryType.STRING } ] + } +] + +export const showStyleConfigManifest: ConfigManifestEntry[] = [ + { + id: 'MakeAdlibsForFulls', + name: 'Make Adlibs for FULL graphics', + description: '', + type: ConfigManifestEntryType.BOOLEAN, + defaultVal: true, + required: false + }, + { + id: 'CasparCGLoadingClip', + name: 'CasparCG Loading Clip', + description: 'Clip to play when media is loading', + type: ConfigManifestEntryType.STRING, + defaultVal: 'LoadingLoop', + required: true }, + dveStylesManifest, { /* Graphic template setup @@ -195,6 +383,8 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ } ] }, + ...graphicsSetups, + ...schemaConfigManifest, { /* Wipes Config @@ -223,7 +413,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EffektNumber', name: 'Effekt Number', description: 'The Effect Number', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 0 @@ -241,7 +431,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'Duration', name: 'Effekt Duration', description: 'Duration of the effekt', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 2 @@ -250,7 +440,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'StartAlpha', name: 'Alpha at Start', description: 'Number of frames of alpha at start', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 3 @@ -259,7 +449,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EndAlpha', name: 'Alpha at End', description: 'Number of frames of alpha at end', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 4 @@ -314,7 +504,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'Duration', name: 'Effekt Duration', description: 'Duration of the effekt', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 2 @@ -323,7 +513,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'StartAlpha', name: 'Alpha at Start', description: 'Number of frames of alpha at start', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 3 @@ -332,7 +522,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EndAlpha', name: 'Alpha at End', description: 'Number of frames of alpha at end', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 4 @@ -361,7 +551,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'DefaultTemplateDuration', name: 'Default Template Duration', description: 'Default Template Duration', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 4 }, @@ -406,7 +596,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'FadeIn', name: 'Fade In', description: 'ms duration to fade in file', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1000, rank: 2 @@ -415,7 +605,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'FadeOut', name: 'Fade Out', description: 'ms duration to fade out file', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1000, rank: 3 diff --git a/src/tv2_afvd_showstyle/getRundown.ts b/src/tv2_afvd_showstyle/getRundown.ts index c063bcd16..cb605c4df 100644 --- a/src/tv2_afvd_showstyle/getRundown.ts +++ b/src/tv2_afvd_showstyle/getRundown.ts @@ -4,21 +4,20 @@ import { GraphicsContent, IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintRundown, - IBlueprintShowStyleVariant, IngestRundown, IShowStyleUserContext, IStudioUserContext, PieceLifespan, PlaylistTimingType, - SourceLayerType, + TimelineObjectCoreExt, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionClearGraphics, ActionCutSourceToBox, ActionCutToCamera, + ActionFadeDownPersistedAudioLevels, ActionRecallLastDVE, ActionRecallLastLive, ActionSelectDVELayout, @@ -28,72 +27,77 @@ import { CreateGraphicBaseline, CreateLYDBaseline, FindDSKJingle, - GetEksternMetaData, - GetLayersForEkstern, - GetSisyfosTimelineObjForCamera, - GetSisyfosTimelineObjForEkstern, + generateExternalId, + GetSisyfosTimelineObjForRemote, + GetSisyfosTimelineObjForReplay, GetTransitionAdLibActions, literal, + PieceMetaData, + replaySourceName, + SourceDefinitionKam, SourceInfo, - t, - TimelineBlueprintExt + SourceInfoToSourceDefinition, + SourceInfoType, + t } from 'tv2-common' -import { AdlibActionType, AdlibTags, CONSTANTS, GraphicLLayer, SharedOutputLayers, TallyTags } from 'tv2-constants' +import { + AdlibActionType, + AdlibTagCutToBox, + AdlibTags, + CONSTANTS, + SharedGraphicLLayer, + SharedOutputLayers, + SourceType, + TallyTags +} from 'tv2-constants' import * as _ from 'underscore' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../tv2_afvd_studio/layers' import { SisyfosChannel, sisyfosChannels } from '../tv2_afvd_studio/sisyfosChannels' import { AtemSourceIndex } from '../types/atem' import { BlueprintConfig, getConfig as getShowStyleConfig } from './helpers/config' -import { boxLayers } from './helpers/content/dve' +import { NUMBER_OF_DVE_BOXES } from './helpers/content/dve' import { SourceLayer } from './layers' import { postProcessPieceTimelineObjects } from './postProcessTimelineObjects' -export function getShowStyleVariantId( - _context: IStudioUserContext, - showStyleVariants: IBlueprintShowStyleVariant[], - _ingestRundown: IngestRundown -): string | null { - const variant = _.first(showStyleVariants) - - if (variant) { - return variant._id - } - return null -} - export function getRundown(context: IShowStyleUserContext, ingestRundown: IngestRundown): BlueprintResultRundown { const config = getShowStyleConfig(context) return { - rundown: literal({ + rundown: { externalId: ingestRundown.externalId, name: ingestRundown.name, timing: { type: PlaylistTimingType.None } - }), - globalAdLibPieces: getGlobalAdLibPiecesAFKD(context, config), + }, + globalAdLibPieces: getGlobalAdLibPiecesAFVD(context, config), globalActions: getGlobalAdlibActionsAFVD(context, config), baseline: getBaseline(config) } } -function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: BlueprintConfig): IBlueprintAdLibPiece[] { - function makeEVSAdLibs(info: SourceInfo, rank: number, vo: boolean): IBlueprintAdLibPiece[] { - const res: IBlueprintAdLibPiece[] = [] +function getGlobalAdLibPiecesAFVD(context: IStudioUserContext, config: BlueprintConfig): IBlueprintAdLibPiece[] { + function makeEVSAdLibs(info: SourceInfo, rank: number, vo: boolean): Array> { + const res: Array> = [] res.push({ externalId: 'delayed', - name: `EVS ${info.id.replace(/dp/i, '')}${vo ? ' VO' : ''}`, + name: replaySourceName(info.id, vo), _rank: rank, sourceLayerId: SourceLayer.PgmLocal, outputLayerId: SharedOutputLayers.PGM, expectedDuration: 0, lifespan: PieceLifespan.WithinPart, toBeQueued: true, - metaData: GetEksternMetaData(config.stickyLayers, config.studio.StudioMics, info.sisyfosLayers), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: info.sisyfosLayers ?? [], + acceptPersistAudio: vo + } + }, + tags: [AdlibTags.ADLIB_QUEUE_NEXT, vo ? AdlibTags.ADLIB_VO_AUDIO_LEVEL : AdlibTags.ADLIB_FULL_AUDIO_LEVEL], content: { ignoreMediaObjectStatus: true, - timelineObjects: _.compact([ + timelineObjects: [ literal({ id: '', enable: { while: '1' }, @@ -109,57 +113,16 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint }, classes: ['adlib_deparent'] }), - ...(info.sisyfosLayers || []).map(l => { - return literal({ - id: '', - enable: { while: '1' }, - priority: 1, - layer: l, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: vo ? 2 : 1 - } - }) - }), - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: SisyfosLLAyer.SisyfosPersistedLevels, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNELS, - overridePriority: 1, - channels: config.stickyLayers - .filter(layer => !info.sisyfosLayers || !info.sisyfosLayers.includes(layer)) - .map(layer => { - return { - mappedLayer: layer, - isPgm: 0 - } - }) - }, - metaData: { - sisyfosPersistLevel: true - } - }), - GetSisyfosTimelineObjForCamera(context, config, 'evs', SisyfosLLAyer.SisyfosGroupStudioMics) - ]) + ...GetSisyfosTimelineObjForReplay(config, info, vo) + ] } }) - return res } - function makeRemoteAdLibs(info: SourceInfo, rank: number): IBlueprintAdLibPiece[] { - const res: IBlueprintAdLibPiece[] = [] - const eksternSisyfos = [ - ...GetSisyfosTimelineObjForEkstern(context, config.sources, `Live ${info.id}`, GetLayersForEkstern), - GetSisyfosTimelineObjForCamera(context, config, 'telefon', SisyfosLLAyer.SisyfosGroupStudioMics) - ] + function makeRemoteAdLibs(info: SourceInfo, rank: number): Array> { + const res: Array> = [] + const eksternSisyfos = GetSisyfosTimelineObjForRemote(config, info) res.push({ externalId: 'live', name: `LIVE ${info.id}`, @@ -169,13 +132,16 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint expectedDuration: 0, lifespan: PieceLifespan.WithinPart, toBeQueued: true, - metaData: GetEksternMetaData( - config.stickyLayers, - config.studio.StudioMics, - GetLayersForEkstern(context, config.sources, `Live ${info.id}`) - ), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: info.sisyfosLayers ?? [], + wantsToPersistAudio: info.wantsToPersistAudio, + acceptPersistAudio: info.acceptPersistAudio + } + }, + tags: [AdlibTags.ADLIB_QUEUE_NEXT], content: { - timelineObjects: _.compact([ + timelineObjects: [ literal({ id: '', enable: { while: '1' }, @@ -191,53 +157,8 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint }, classes: ['adlib_deparent'] }), - ...eksternSisyfos, - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: SisyfosLLAyer.SisyfosPersistedLevels, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNELS, - overridePriority: 1, - channels: config.stickyLayers - .filter(layer => eksternSisyfos.map(obj => obj.layer).indexOf(layer) === -1) - .filter(layer => config.liveAudio.indexOf(layer) === -1) - .map(layer => { - return literal({ - mappedLayer: layer, - isPgm: 0 - }) - }) - }, - metaData: { - sisyfosPersistLevel: true - } - }), - // Force server to be muted (for adlibbing over DVE) - ...[ - SisyfosLLAyer.SisyfosSourceClipPending, - SisyfosLLAyer.SisyfosSourceServerA, - SisyfosLLAyer.SisyfosSourceServerB - ].map(layer => { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 2, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - } - }) - }) - ]) + ...eksternSisyfos + ] } }) @@ -245,8 +166,8 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint } // aux adlibs - function makeRemoteAuxStudioAdLibs(info: SourceInfo, rank: number): IBlueprintAdLibPiece[] { - const res: IBlueprintAdLibPiece[] = [] + function makeRemoteAuxStudioAdLibs(info: SourceInfo, rank: number): Array> { + const res: Array> = [] res.push({ externalId: 'auxstudio', name: info.id + '', @@ -255,13 +176,16 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint outputLayerId: SharedOutputLayers.AUX, expectedDuration: 0, lifespan: PieceLifespan.OutOnShowStyleEnd, - metaData: GetEksternMetaData( - config.stickyLayers, - config.studio.StudioMics, - GetLayersForEkstern(context, config.sources, `Live ${info.id}`) - ), + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: info.sisyfosLayers ?? [], + wantsToPersistAudio: info.wantsToPersistAudio, + acceptPersistAudio: info.acceptPersistAudio + } + }, + tags: [AdlibTags.ADLIB_TO_STUDIO_SCREEN_AUX], content: { - timelineObjects: _.compact([ + timelineObjects: [ literal({ id: '', enable: { while: '1' }, @@ -275,7 +199,7 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint } } }) - ]) + ] } }) @@ -286,78 +210,78 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint let globalRank = 1000 - config.sources - .filter(u => u.type === SourceLayerType.REMOTE) - .slice(0, 10) // the first x cameras to create live-adlibs from + config.sources.lives + .slice(0, 10) // the first x lives to create live-adlibs from .forEach(o => { adlibItems.push(...makeRemoteAdLibs(o, globalRank++)) }) - config.sources - .filter(u => u.type === SourceLayerType.REMOTE) + config.sources.lives .slice(0, 10) // the first x lives to create AUX1 (studio) adlibs .forEach(o => { adlibItems.push(...makeRemoteAuxStudioAdLibs(o, globalRank++)) }) - config.sources - .filter(u => u.type === SourceLayerType.LOCAL) - .forEach(o => { + config.sources.replays.forEach(o => { + if (!/EPSIO/i.test(o.id)) { adlibItems.push(...makeEVSAdLibs(o, globalRank++, false)) - adlibItems.push(...makeEVSAdLibs(o, globalRank++, true)) - adlibItems.push({ - externalId: 'delayedaux', - name: `EVS in studio aux`, - _rank: globalRank++, - sourceLayerId: SourceLayer.AuxStudioScreen, - outputLayerId: SharedOutputLayers.AUX, - expectedDuration: 0, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: { - timelineObjects: _.compact([ - literal({ - id: '', - enable: { while: '1' }, - priority: 1, - layer: AtemLLayer.AtemAuxAR, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.AUX, - aux: { - input: o.port - } + } + adlibItems.push(...makeEVSAdLibs(o, globalRank++, true)) + adlibItems.push({ + externalId: 'delayedaux', + name: `EVS in studio aux`, + _rank: globalRank++, + sourceLayerId: SourceLayer.AuxStudioScreen, + outputLayerId: SharedOutputLayers.AUX, + expectedDuration: 0, + lifespan: PieceLifespan.OutOnShowStyleEnd, + tags: [AdlibTags.ADLIB_TO_STUDIO_SCREEN_AUX], + content: { + timelineObjects: [ + literal({ + id: '', + enable: { while: '1' }, + priority: 1, + layer: AtemLLayer.AtemAuxAR, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.AUX, + aux: { + input: o.port } - }) - ]) - } - }) - adlibItems.push({ - externalId: 'delayedaux', - name: `EVS in viz aux`, - _rank: globalRank++, - sourceLayerId: SourceLayer.VizFullIn1, - outputLayerId: SharedOutputLayers.AUX, - expectedDuration: 0, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: { - timelineObjects: _.compact([ - literal({ - id: '', - enable: { while: '1' }, - priority: 1, - layer: AtemLLayer.AtemAuxVizOvlIn1, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.AUX, - aux: { - input: o.port - } + } + }) + ] + } + }) + adlibItems.push({ + externalId: 'delayedaux', + name: `EVS in viz aux`, + _rank: globalRank++, + sourceLayerId: SourceLayer.VizFullIn1, + outputLayerId: SharedOutputLayers.AUX, + expectedDuration: 0, + lifespan: PieceLifespan.OutOnShowStyleEnd, + tags: [AdlibTags.ADLIB_TO_GRAPHICS_ENGINE_AUX], + content: { + timelineObjects: [ + literal({ + id: '', + enable: { while: '1' }, + priority: 1, + layer: AtemLLayer.AtemAuxVizOvlIn1, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.AUX, + aux: { + input: o.port } - }) - ]) - } - }) + } + }) + ] + } }) + }) // the rank (order) of adlibs on SourceLayer.PgmAdlibVizCmd is important, to ensure keyboard shortcuts adlibItems.push({ @@ -368,9 +292,9 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint outputLayerId: SharedOutputLayers.SEC, expectedDuration: 1000, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_GFX_LOAD], content: { - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: 'loadAllElements', enable: { @@ -378,7 +302,7 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint duration: 1000 }, priority: 100, - layer: GraphicLLayer.GraphicLLayerAdLibs, + layer: SharedGraphicLLayer.GraphicLLayerAdLibs, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.LOAD_ALL_ELEMENTS @@ -396,9 +320,9 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint outputLayerId: SharedOutputLayers.SEC, expectedDuration: 1000, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_GFX_CONTINUE_FORWARD], content: { - timelineObjects: _.compact([ + timelineObjects: [ literal({ id: '', enable: { @@ -406,15 +330,15 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint duration: 1000 }, priority: 100, - layer: GraphicLLayer.GraphicLLayerAdLibs, + layer: SharedGraphicLLayer.GraphicLLayerAdLibs, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.CONTINUE, direction: 1, - reference: GraphicLLayer.GraphicLLayerPilot + reference: SharedGraphicLLayer.GraphicLLayerPilot } }) - ]) + ] } }) @@ -428,7 +352,7 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint sourceLayerId: SourceLayer.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_MICS_UP], expectedDuration: 0, content: { timelineObjects: [ @@ -458,7 +382,7 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint sourceLayerId: SourceLayer.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_MICS_DOWN], expectedDuration: 0, content: { timelineObjects: [ @@ -488,10 +412,10 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint sourceLayerId: SourceLayer.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIBS_RESYNC_SISYFOS], expectedDuration: 1000, content: { - timelineObjects: _.compact([ + timelineObjects: [ literal({ id: '', enable: { start: 0 }, @@ -503,52 +427,61 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint resync: true } }) - ]) + ] } }) // viz styles and dve backgrounds - adlibItems.push( - literal({ + function makeDesignAdLib(): IBlueprintAdLibPiece { + const timelineObjects: TimelineObjectCoreExt[] = [ + literal({ + id: '', + enable: { start: 0 }, + priority: 110, + layer: CasparLLayer.CasparCGDVELoop, + content: { + deviceType: TSR.DeviceType.CASPARCG, + type: TSR.TimelineContentTypeCasparCg.MEDIA, + file: 'dve/BG_LOADER_SC', + loop: true + } + }) + ] + if (config.studio.GraphicsType === 'VIZ') { + timelineObjects.push( + literal({ + id: '', + enable: { start: 0 }, + priority: 110, + layer: SharedGraphicLLayer.GraphicLLayerDesign, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, + templateName: 'BG_LOADER_SC', + templateData: [], + showId: config.selectedGraphicsSetup.OvlShowId + } + }) + ) + } + const adLibPiece: IBlueprintAdLibPiece = { _rank: 301, externalId: 'dve-design-sc', name: 'DVE Design SC', outputLayerId: SharedOutputLayers.SEC, sourceLayerId: SourceLayer.PgmDesign, lifespan: PieceLifespan.OutOnShowStyleEnd, + tags: [AdlibTags.ADLIB_DESIGN_STYLE_SC], content: literal>({ fileName: 'BG_LOADER_SC', path: 'BG_LOADER_SC', ignoreMediaObjectStatus: true, - timelineObjects: _.compact([ - literal({ - id: '', - enable: { start: 0 }, - priority: 110, - layer: GraphicLLayer.GraphicLLayerDesign, - content: { - deviceType: TSR.DeviceType.VIZMSE, - type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, - templateName: 'BG_LOADER_SC', - templateData: [] - } - }), - literal({ - id: '', - enable: { start: 0 }, - priority: 110, - layer: CasparLLayer.CasparCGDVELoop, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: 'dve/BG_LOADER_SC', - loop: true - } - }) - ]) + timelineObjects }) - }) - ) + } + return adLibPiece + } + adlibItems.push(makeDesignAdLib()) adlibItems.push({ externalId: 'stopAudioBed', @@ -558,6 +491,7 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint outputLayerId: 'musik', expectedDuration: 1000, lifespan: PieceLifespan.WithinPart, + tags: [AdlibTags.ADLIB_STOP_AUDIO_BED], content: { timelineObjects: [ literal({ @@ -583,175 +517,188 @@ function getGlobalAdLibPiecesAFKD(context: IStudioUserContext, config: Blueprint } function getGlobalAdlibActionsAFVD(_context: IStudioUserContext, config: BlueprintConfig): IBlueprintActionManifest[] { - const res: IBlueprintActionManifest[] = [] + const blueprintActions: IBlueprintActionManifest[] = [] let globalRank = 1000 - function makeAdlibBoxesActions(info: SourceInfo, type: 'Kamera' | 'Live' | 'Feed', rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - const feed = type === 'Live' && info.id.match(/^F(.+).*$/) // TODO: fix when refactoring FindSourceInfo - const name = feed ? `Feed ${feed[1]}` : `${type} ${info.id}` - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name, - port: info.port, - sourceType: info.type, - box - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`${name} to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: SharedOutputLayers.SEC, - content: {}, - tags: [] - } - }) - ) - }) - } + function makeAdlibBoxesActions(info: SourceInfo, rank: number) { + for (let box = 0; box < NUMBER_OF_DVE_BOXES; box++) { + const name = `${info.type} ${info.id}` + const layer = info.type === SourceInfoType.KAM ? SourceLayer.PgmCam : SourceLayer.PgmLive - function makeAdlibBoxesActionsDirectPlayback(info: SourceInfo, vo: boolean, rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name: `EVS ${info.id.replace(/dp/i, '')}${vo ? ' VO' : ''}`, - port: info.port, - sourceType: info.type, - box, - vo - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`EVS ${info.id.replace(/dp/i, '')}${vo ? ' VO' : ''} to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: SharedOutputLayers.SEC, - content: {}, - tags: [] - } - }) - ) - }) + const userData: ActionCutSourceToBox = { + type: AdlibActionType.CUT_SOURCE_TO_BOX, + name, + box, + sourceDefinition: SourceInfoToSourceDefinition(info) + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_SOURCE_TO_BOX, + userData, + userDataManifest: {}, + display: { + _rank: rank + 0.1 * box, + label: t(`${name} inp ${box + 1}`), + sourceLayerId: layer, + outputLayerId: SharedOutputLayers.SEC, + content: {}, + tags: [AdlibTagCutToBox(box)] + } + }) + } } - function makeServerAdlibBoxesActions(rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name: `SERVER`, - port: -1, - sourceType: SourceLayerType.VT, - box, - server: true - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`Server to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: SharedOutputLayers.SEC, - content: {}, - tags: [] - } - }) - ) - }) + function makeAdlibBoxesActionsReplay(info: SourceInfo, rank: number, vo: boolean) { + for (let box = 0; box < NUMBER_OF_DVE_BOXES; box++) { + const name = replaySourceName(info.id, vo) + const userData: ActionCutSourceToBox = { + type: AdlibActionType.CUT_SOURCE_TO_BOX, + name, + box, + sourceDefinition: { + sourceType: SourceType.REPLAY, + id: info.id, + vo, + raw: '', + name + } + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_SOURCE_TO_BOX, + userData, + userDataManifest: {}, + display: { + _rank: rank + 0.1 * box, + label: t(`${name} inp ${box + 1}`), + sourceLayerId: SourceLayer.PgmLocal, + outputLayerId: SharedOutputLayers.SEC, + content: {}, + tags: [AdlibTagCutToBox(box), vo ? AdlibTags.ADLIB_VO_AUDIO_LEVEL : AdlibTags.ADLIB_FULL_AUDIO_LEVEL] + } + }) + } } - function makeCutCameraActions(info: SourceInfo, queue: boolean, rank: number) { - res.push( - literal({ - actionId: AdlibActionType.CUT_TO_CAMERA, - userData: literal({ - type: AdlibActionType.CUT_TO_CAMERA, - queue, - name: info.id - }), + function makeServerAdlibBoxesActions(rank: number) { + for (let box = 0; box < NUMBER_OF_DVE_BOXES; box++) { + const userData: ActionCutSourceToBox = { + type: AdlibActionType.CUT_SOURCE_TO_BOX, + name: `SERVER`, + box, + sourceDefinition: { sourceType: SourceType.SERVER } + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_SOURCE_TO_BOX, + userData, userDataManifest: {}, display: { - _rank: rank, - label: t(`KAM ${info.id}`), - sourceLayerId: SourceLayer.PgmCam, - outputLayerId: SharedOutputLayers.PGM, - content: {} + _rank: rank + 0.1 * box, + label: t(`Server inp ${box + 1}`), + sourceLayerId: SourceLayer.PgmServer, + outputLayerId: SharedOutputLayers.SEC, + content: {}, + tags: [AdlibTagCutToBox(box)] } }) - ) + } } - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + function makeCutCameraActions(info: SourceInfo, queue: boolean, rank: number) { + const sourceDefinition = SourceInfoToSourceDefinition(info) as SourceDefinitionKam + const userData: ActionCutToCamera = { + type: AdlibActionType.CUT_TO_CAMERA, + queue, + sourceDefinition + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_TO_CAMERA, + userData, + userDataManifest: {}, + display: { + _rank: rank, + label: t(sourceDefinition.name), + sourceLayerId: SourceLayer.PgmCam, + outputLayerId: SharedOutputLayers.PGM, + content: {}, + tags: queue ? [AdlibTags.ADLIB_QUEUE_NEXT] : [AdlibTags.ADLIB_CUT_DIRECT] + } + }) + } + + config.sources.cameras .slice(0, 5) // the first x cameras to create INP1/2/3 cam-adlibs from .forEach(o => { makeCutCameraActions(o, false, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + config.sources.cameras .slice(0, 5) // the first x cameras to create preview cam-adlibs from .forEach(o => { makeCutCameraActions(o, true, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + config.sources.cameras .slice(0, 5) // the first x cameras to dve actions from .forEach(o => { - makeAdlibBoxesActions(o, 'Kamera', globalRank++) + makeAdlibBoxesActions(o, globalRank++) }) - res.push( - literal({ + function makeRecallLastLiveAction() { + const userData: ActionRecallLastLive = { + type: AdlibActionType.RECALL_LAST_LIVE + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.RECALL_LAST_LIVE, - userData: literal({ - type: AdlibActionType.RECALL_LAST_LIVE - }), + userData, userDataManifest: {}, display: { _rank: 1, label: t('Last Live'), sourceLayerId: SourceLayer.PgmLive, - outputLayerId: SharedOutputLayers.PGM + outputLayerId: SharedOutputLayers.PGM, + tags: [AdlibTags.ADLIB_RECALL_LAST_LIVE] } }) - ) + } + + makeRecallLastLiveAction() - config.sources - .filter(u => u.type === SourceLayerType.REMOTE) + config.sources.lives .slice(0, 10) // the first x remote to create INP1/2/3 live-adlibs from .forEach(o => { - makeAdlibBoxesActions(o, o.id.match(/^F/) ? 'Feed' : 'Live', globalRank++) + makeAdlibBoxesActions(o, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.LOCAL) + config.sources.feeds .slice(0, 10) // the first x remote to create INP1/2/3 live-adlibs from .forEach(o => { - makeAdlibBoxesActionsDirectPlayback(o, false, globalRank++) - makeAdlibBoxesActionsDirectPlayback(o, true, globalRank++) + makeAdlibBoxesActions(o, globalRank++) }) + config.sources.replays.forEach(o => { + if (!/EPSIO/i.test(o.id)) { + makeAdlibBoxesActionsReplay(o, globalRank++, false) + } + makeAdlibBoxesActionsReplay(o, globalRank++, true) + }) + makeServerAdlibBoxesActions(globalRank++) - res.push( - literal({ + function makeClearGraphicsAction(): IBlueprintActionManifest { + const userData: ActionClearGraphics = { + type: AdlibActionType.CLEAR_GRAPHICS, + sendCommands: true, + label: 'GFX Clear' + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.CLEAR_GRAPHICS, - userData: literal({ - type: AdlibActionType.CLEAR_GRAPHICS, - sendCommands: true, - label: 'GFX Clear' - }), + userData, userDataManifest: {}, display: { _rank: 300, @@ -763,14 +710,19 @@ function getGlobalAdlibActionsAFVD(_context: IStudioUserContext, config: Bluepri currentPieceTags: [TallyTags.GFX_CLEAR], nextPieceTags: [TallyTags.GFX_CLEAR] } - }), - literal({ + } + } + + function makeClearGraphicsAltudAction(): IBlueprintActionManifest { + const userData: ActionClearGraphics = { + type: AdlibActionType.CLEAR_GRAPHICS, + sendCommands: false, + label: 'GFX Altud' + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.CLEAR_GRAPHICS, - userData: literal({ - type: AdlibActionType.CLEAR_GRAPHICS, - sendCommands: false, - label: 'GFX Altud' - }), + userData, userDataManifest: {}, display: { _rank: 400, @@ -778,52 +730,72 @@ function getGlobalAdlibActionsAFVD(_context: IStudioUserContext, config: Bluepri sourceLayerId: SourceLayer.PgmAdlibGraphicCmd, outputLayerId: SharedOutputLayers.SEC, content: {}, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_GFX_ALTUD], currentPieceTags: [TallyTags.GFX_ALTUD], nextPieceTags: [TallyTags.GFX_ALTUD] } - }) - ) + } + } - res.push(...GetTransitionAdLibActions(config, 800)) + blueprintActions.push(makeClearGraphicsAction(), makeClearGraphicsAltudAction()) - res.push( - literal({ - actionId: AdlibActionType.RECALL_LAST_DVE, - userData: literal({ - type: AdlibActionType.RECALL_LAST_DVE - }), + blueprintActions.push(...GetTransitionAdLibActions(config, 800)) + + const recallLastLiveDveUserData: ActionRecallLastDVE = { + type: AdlibActionType.RECALL_LAST_DVE + } + blueprintActions.push({ + externalId: generateExternalId(_context, recallLastLiveDveUserData), + actionId: AdlibActionType.RECALL_LAST_DVE, + userData: recallLastLiveDveUserData, + userDataManifest: {}, + display: { + _rank: 1, + label: t('Last DVE'), + sourceLayerId: SourceLayer.PgmDVEAdLib, + outputLayerId: 'pgm', + tags: [AdlibTags.ADLIB_RECALL_LAST_DVE] + } + }) + + _.each(config.showStyle.DVEStyles, (dveConfig, i) => { + const userData: ActionSelectDVELayout = { + type: AdlibActionType.SELECT_DVE_LAYOUT, + config: dveConfig + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.SELECT_DVE_LAYOUT, + userData, userDataManifest: {}, display: { - _rank: 1, - label: t('Last DVE'), + _rank: 200 + i, + label: t(dveConfig.DVEName), sourceLayerId: SourceLayer.PgmDVEAdLib, - outputLayerId: 'pgm' + outputLayerId: SharedOutputLayers.PGM, + tags: [AdlibTags.ADLIB_SELECT_DVE_LAYOUT, dveConfig.DVEName] } }) - ) + }) - _.each(config.showStyle.DVEStyles, (dveConfig, i) => { - // const boxSources = ['', '', '', ''] - res.push( - literal({ - actionId: AdlibActionType.SELECT_DVE_LAYOUT, - userData: literal({ - type: AdlibActionType.SELECT_DVE_LAYOUT, - config: dveConfig - }), - userDataManifest: {}, - display: { - _rank: 200 + i, - label: t(dveConfig.DVEName), - sourceLayerId: SourceLayer.PgmDVEAdLib, - outputLayerId: SharedOutputLayers.PGM - } - }) - ) + const fadeDownPersistedAudioLevelsUserData: ActionFadeDownPersistedAudioLevels = { + type: AdlibActionType.FADE_DOWN_PERSISTED_AUDIO_LEVELS + } + blueprintActions.push({ + externalId: generateExternalId(_context, fadeDownPersistedAudioLevelsUserData), + actionId: AdlibActionType.FADE_DOWN_PERSISTED_AUDIO_LEVELS, + userData: fadeDownPersistedAudioLevelsUserData, + userDataManifest: {}, + display: { + _rank: 300, + label: t('Fade down persisted audio levels'), + sourceLayerId: SourceLayer.PgmSisyfosAdlibs, + outputLayerId: SharedOutputLayers.SEC, + tags: [AdlibTags.ADLIB_FADE_DOWN_PERSISTED_AUDIO_LEVELS] + } }) - return res + return blueprintActions } function getBaseline(config: BlueprintConfig): BlueprintResultBaseline { @@ -1106,7 +1078,7 @@ function getBaseline(config: BlueprintConfig): BlueprintResultBaseline { id: '', enable: { start: 0 }, priority: 2, // Take priority over anything trying to set the template on the Viz version of this layer - layer: GraphicLLayer.GraphicLLayerFullLoop, + layer: SharedGraphicLLayer.GraphicLLayerFullLoop, content: { deviceType: TSR.DeviceType.CASPARCG, type: TSR.TimelineContentTypeCasparCg.ROUTE, @@ -1165,7 +1137,18 @@ function getBaseline(config: BlueprintConfig): BlueprintResultBaseline { } }) }) - : []) + : []), + + literal({ + id: '', + enable: { while: '1' }, + layer: SharedGraphicLLayer.GraphicLLayerConcept, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.CONCEPT, + concept: config.selectedGraphicsSetup.VcpConcept + } + }) ] } } diff --git a/src/tv2_afvd_showstyle/getSegment.ts b/src/tv2_afvd_showstyle/getSegment.ts index 3795bfeaf..bb910eedc 100644 --- a/src/tv2_afvd_showstyle/getSegment.ts +++ b/src/tv2_afvd_showstyle/getSegment.ts @@ -8,13 +8,14 @@ import { PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { getSegmentBase, literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { getSegmentBase, INewsPayload, literal } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import * as _ from 'underscore' import { StudioConfig } from '../tv2_afvd_studio/helpers/config' import { AtemLLayer } from '../tv2_afvd_studio/layers' import { BlueprintConfig as ShowStyleConfig, getConfig } from './helpers/config' +import { CreateShowLifecyclePieces } from './helpers/pieces/showLifecycle' import { SourceLayer } from './layers' import { CreatePartEVS } from './parts/evs' import { CreatePartGrafik } from './parts/grafik' @@ -25,10 +26,14 @@ import { CreatePartServer } from './parts/server' import { CreatePartTeknik } from './parts/teknik' import { CreatePartUnknown } from './parts/unknown' import { postProcessPartTimelineObjects } from './postProcessTimelineObjects' -export function getSegment(context: ISegmentUserContext, ingestSegment: IngestSegment): BlueprintResultSegment { +export async function getSegment( + context: ISegmentUserContext, + ingestSegment: IngestSegment +): Promise { const config = getConfig(context) + const segmentPayload = ingestSegment.payload as INewsPayload | undefined - const result: BlueprintResultSegment = getSegmentBase(context, ingestSegment, { + const result: BlueprintResultSegment = await getSegmentBase(context, ingestSegment, { getConfig, CreatePartContinuity, CreatePartUnknown, @@ -45,6 +50,10 @@ export function getSegment(context: ISegmentUserContext, ingestSegment: IngestSe const blueprintParts = result.parts + if (segmentPayload) { + insertSpecialPieces(config, blueprintParts, segmentPayload) + } + postProcessPartTimelineObjects(context, config, blueprintParts) return { @@ -53,8 +62,8 @@ export function getSegment(context: ISegmentUserContext, ingestSegment: IngestSe } } -export function CreatePartContinuity(config: ShowStyleConfig, ingestSegment: IngestSegment) { - return literal({ +export function CreatePartContinuity(config: ShowStyleConfig, ingestSegment: IngestSegment): BlueprintResultPart { + return { part: { externalId: `${ingestSegment.externalId}-CONTINUITY`, title: 'CONTINUITY', @@ -73,7 +82,7 @@ export function CreatePartContinuity(config: ShowStyleConfig, ingestSegment: Ing content: literal>({ studioLabel: '', switcherInput: config.studio.AtemSource.Continuity, - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: '', enable: { @@ -94,6 +103,35 @@ export function CreatePartContinuity(config: ShowStyleConfig, ingestSegment: Ing }) }) ], - adLibPieces: [] - }) + adLibPieces: [], + actions: [] + } +} + +function insertSpecialPieces( + config: ShowStyleConfig, + blueprintParts: BlueprintResultPart[], + segmentPayload: INewsPayload +) { + // Insert cue-independent pieces + + if (!blueprintParts.length || config.studio.GraphicsType !== 'VIZ') { + return + } + + const graphicsSetupsToInitialize = segmentPayload?.initializeShows + if (graphicsSetupsToInitialize) { + const showsToInitialize = new Set() + const allShows = new Set() + config.showStyle.GraphicsSetups.forEach(graphicsSetup => { + allShows.add(graphicsSetup.FullShowId) + allShows.add(graphicsSetup.OvlShowId) + if (graphicsSetupsToInitialize.includes(graphicsSetup.Name)) { + showsToInitialize.add(graphicsSetup.FullShowId) + showsToInitialize.add(graphicsSetup.OvlShowId) + } + }) + const showsToCleanup = Array.from(allShows).filter(show => !showsToInitialize.has(show)) + CreateShowLifecyclePieces(config, blueprintParts[0], Array.from(showsToInitialize), showsToCleanup) + } } diff --git a/src/tv2_afvd_showstyle/helpers/config.ts b/src/tv2_afvd_showstyle/helpers/config.ts index 5b10e902c..f5e7d4c36 100644 --- a/src/tv2_afvd_showstyle/helpers/config.ts +++ b/src/tv2_afvd_showstyle/helpers/config.ts @@ -3,21 +3,45 @@ import { ICommonContext, IShowStyleContext, TableConfigItemValue -} from '@sofie-automation/blueprints-integration' -import { TV2ShowstyleBlueprintConfigBase } from 'tv2-common' -import * as _ from 'underscore' +} from '@tv2media/blueprints-integration' +import { TableConfigGraphicsSetup, TV2ShowstyleBlueprintConfigBase } from 'tv2-common' import { BlueprintConfig as BlueprintConfigBase } from '../../tv2_afvd_studio/helpers/config' export interface BlueprintConfig extends BlueprintConfigBase { showStyle: ShowStyleConfig + selectedGraphicsSetup: TableConfigGraphicsSetup } export interface ShowStyleConfig extends TV2ShowstyleBlueprintConfigBase { WipesConfig: TableConfigItemValue + SelectedGraphicsSetupName: string + GraphicsSetups: TableConfigGraphicsSetup[] } -export function parseConfig(_context: ICommonContext, config: IBlueprintConfig): any { - return { showStyle: config } +function findGraphicsSetup(context: ICommonContext, config: ShowStyleConfig): TableConfigGraphicsSetup { + const foundTableConfigGraphicsSetup: TableConfigGraphicsSetup | undefined = config.GraphicsSetups.find( + tableConfigGraphicsSetup => tableConfigGraphicsSetup.Name === config.SelectedGraphicsSetupName + ) + if (!foundTableConfigGraphicsSetup) { + context.logWarning(`No graphics setup found for profile: ${config.SelectedGraphicsSetupName}`) + return { + Name: '', + VcpConcept: '', + OvlShowId: '', + FullShowId: '', + DveLayoutFolder: '' + } + } + return foundTableConfigGraphicsSetup +} + +export function parseConfig(context: ICommonContext, rawConfig: IBlueprintConfig): any { + const showstyleConfig = (rawConfig as unknown) as ShowStyleConfig + const selectedGraphicsSetup = findGraphicsSetup(context, showstyleConfig) + return { + showStyle: showstyleConfig, + selectedGraphicsSetup + } } export function getConfig(context: IShowStyleContext): BlueprintConfig { diff --git a/src/tv2_afvd_showstyle/helpers/content/dve.ts b/src/tv2_afvd_showstyle/helpers/content/dve.ts index 1947b4afa..8e8cfd6f2 100644 --- a/src/tv2_afvd_showstyle/helpers/content/dve.ts +++ b/src/tv2_afvd_showstyle/helpers/content/dve.ts @@ -1,26 +1,9 @@ -import { IShowStyleUserContext, SplitsContent, WithTimeline } from '@sofie-automation/blueprints-integration' -import { - CueDefinitionDVE, - DVEConfigInput, - DVEOptions, - DVESources, - GetLayersForEkstern, - GetSisyfosTimelineObjForEkstern, - MakeContentDVEBase, - PartDefinition -} from 'tv2-common' -import * as _ from 'underscore' +import { IShowStyleUserContext, SplitsContent, WithTimeline } from '@tv2media/blueprints-integration' +import { CueDefinitionDVE, DVEConfigInput, DVEOptions, MakeContentDVEBase, PartDefinition } from 'tv2-common' import { BlueprintConfig } from '../../../tv2_afvd_showstyle/helpers/config' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../../../tv2_afvd_studio/layers' -import { SourceLayer } from '../../layers' -export const boxLayers: DVESources = { - INP1: SourceLayer.PgmDVEBox1, - INP2: SourceLayer.PgmDVEBox2, - INP3: SourceLayer.PgmDVEBox3, - INP4: SourceLayer.PgmDVEBox4 -} -export const boxMappings = [AtemLLayer.AtemSSrcBox1, AtemLLayer.AtemSSrcBox2, AtemLLayer.AtemSSrcBox3] +export const NUMBER_OF_DVE_BOXES = 4 export const AFVD_DVE_GENERATOR_OPTIONS: DVEOptions = { dveLayers: { @@ -35,30 +18,14 @@ export const AFVD_DVE_GENERATOR_OPTIONS: DVEOptions = { }, SisyfosLLayer: { ClipPending: SisyfosLLAyer.SisyfosSourceClipPending, - StudioMics: SisyfosLLAyer.SisyfosGroupStudioMics, - PersistedLevels: SisyfosLLAyer.SisyfosPersistedLevels + StudioMics: SisyfosLLAyer.SisyfosGroupStudioMics }, CasparLLayer: { ClipPending: CasparLLayer.CasparPlayerClipPending } }, - dveTimelineGenerators: { - GetSisyfosTimelineObjForEkstern, - GetLayersForEkstern - }, - boxLayers: { - INP1: SourceLayer.PgmDVEBox1, - INP2: SourceLayer.PgmDVEBox2, - INP3: SourceLayer.PgmDVEBox3, - INP4: SourceLayer.PgmDVEBox4 - }, boxMappings: [AtemLLayer.AtemSSrcBox1, AtemLLayer.AtemSSrcBox2, AtemLLayer.AtemSSrcBox3, AtemLLayer.AtemSSrcBox4], - AUDIO_LAYERS: Object.keys(SisyfosLLAyer), - EXCLUDED_LAYERS: [ - SisyfosLLAyer.SisyfosSourceClipPending, - SisyfosLLAyer.SisyfosSourceServerA, - SisyfosLLAyer.SisyfosSourceServerB - ] + AUDIO_LAYERS: Object.keys(SisyfosLLAyer) } export function MakeContentDVE( @@ -69,7 +36,7 @@ export function MakeContentDVE( dveConfig: DVEConfigInput | undefined, addClass?: boolean, adlib?: boolean -): { content: WithTimeline; valid: boolean; stickyLayers: string[] } { +): { content: WithTimeline; valid: boolean } { return MakeContentDVEBase( context, config, diff --git a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/grafikViz.spec.ts b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/grafikViz.spec.ts index 98519d22d..81fa9afbd 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/grafikViz.spec.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/grafikViz.spec.ts @@ -2,27 +2,28 @@ import { GraphicsContent, IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AtemLLayerDSK, CueDefinitionGraphic, GraphicInternal, + GraphicPieceMetaData, GraphicPilot, literal, - PartDefinitionKam + PartDefinitionKam, + PieceMetaData } from 'tv2-common' -import { AbstractLLayer, AdlibTags, CueType, GraphicLLayer, PartType, SharedOutputLayers } from 'tv2-constants' +import { AdlibTags, CueType, PartType, SharedGraphicLLayer, SharedOutputLayers, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../../../__mocks__/context' -import { BlueprintConfig, parseConfig as parseStudioConfig } from '../../../../tv2_afvd_studio/helpers/config' +import { parseConfig as parseStudioConfig } from '../../../../tv2_afvd_studio/helpers/config' import mappingsDefaults from '../../../../tv2_afvd_studio/migrations/mappings-defaults' -import { defaultShowStyleConfig, defaultStudioConfig } from '../../../__tests__/configs' +import { defaultShowStyleConfig, defaultStudioConfig, OVL_SHOW_ID } from '../../../__tests__/configs' import { SourceLayer } from '../../../layers' -import { getConfig, parseConfig as parseShowStyleConfig } from '../../config' +import { BlueprintConfig, getConfig, parseConfig as parseShowStyleConfig } from '../../config' import { EvaluateCueGraphic } from '../graphic' function makeMockContext() { @@ -37,9 +38,7 @@ const config = getConfig(makeMockContext()) const dummyPart = literal({ type: PartType.Kam, - variant: { - name: '1' - }, + sourceDefinition: { sourceType: SourceType.KAM, id: '1', raw: 'Kam 1', minusMic: false, name: 'KAM 1' }, externalId: '0001', rawType: 'Kam 1', cues: [], @@ -50,11 +49,6 @@ const dummyPart = literal({ segmentExternalId: '' }) -const dummyBlueprintPart: IBlueprintPart = { - title: 'Kam 1', - externalId: '0001' -} - const dskEnableObj = literal({ id: '', enable: { @@ -106,18 +100,16 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'bund - Odense\n - Copenhagen', enable: { @@ -125,6 +117,12 @@ describe('grafik piece', () => { duration: 4000 }, lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: false + }, outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, content: literal>({ @@ -138,13 +136,14 @@ describe('grafik piece', () => { while: '!.full' }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -175,15 +174,13 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(adLibPieces).toEqual([ literal({ @@ -191,12 +188,16 @@ describe('grafik piece', () => { externalId: partId, name: 'bund - Odense\n - Copenhagen', lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, uniquenessId: 'gfx_bund - Odense\n - Copenhagen_studio0_graphicsLower_overlay_commentator', expectedDuration: 5000, tags: [AdlibTags.ADLIB_KOMMENTATOR], - noHotKey: true, content: literal>({ fileName: 'bund', path: 'bund', @@ -208,13 +209,14 @@ describe('grafik piece', () => { while: '!.full' }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -226,6 +228,11 @@ describe('grafik piece', () => { externalId: partId, name: 'bund - Odense\n - Copenhagen', lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, uniquenessId: 'gfx_bund - Odense\n - Copenhagen_studio0_graphicsLower_overlay_flow', @@ -242,13 +249,14 @@ describe('grafik piece', () => { while: '!.full' }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -281,15 +289,13 @@ describe('grafik piece', () => { EvaluateCueGraphic( newConfig, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(adLibPieces).toEqual([ literal({ @@ -297,12 +303,16 @@ describe('grafik piece', () => { externalId: partId, name: 'bund - Odense\n - Copenhagen', lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, uniquenessId: 'gfx_bund - Odense\n - Copenhagen_studio0_graphicsLower_overlay_commentator', tags: [AdlibTags.ADLIB_KOMMENTATOR], expectedDuration: 5000, - noHotKey: true, content: literal>({ fileName: 'bund', path: 'bund', @@ -314,13 +324,14 @@ describe('grafik piece', () => { start: 0 }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -332,6 +343,11 @@ describe('grafik piece', () => { externalId: partId, name: 'bund - Odense\n - Copenhagen', lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, uniquenessId: 'gfx_bund - Odense\n - Copenhagen_studio0_graphicsLower_overlay_flow', @@ -348,13 +364,14 @@ describe('grafik piece', () => { start: 0 }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -387,18 +404,16 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'bund - Odense\n - Copenhagen', enable: { @@ -406,6 +421,12 @@ describe('grafik piece', () => { duration: 4000 }, lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: false + }, outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, content: literal>({ @@ -419,13 +440,14 @@ describe('grafik piece', () => { while: '!.full' }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -461,24 +483,28 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'bund - Odense\n - Copenhagen', enable: { start: 10000 }, lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: false + }, outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsLower, content: literal>({ @@ -492,13 +518,14 @@ describe('grafik piece', () => { while: `.studio0_parent_camera_1 & !.adlib_deparent & !.full` }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -531,26 +558,30 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'direkte - KØBENHAVN', enable: { start: 0 }, - lifespan: PieceLifespan.OutOnSegmentEnd, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: false + }, outputLayerId: SharedOutputLayers.OVERLAY, - sourceLayerId: SourceLayer.PgmGraphicsIdentPersistent, + sourceLayerId: SourceLayer.PgmGraphicsIdent, content: literal>({ fileName: 'direkte', path: 'direkte', @@ -562,42 +593,19 @@ describe('grafik piece', () => { while: `.studio0_parent_camera_1 & !.adlib_deparent & !.full` }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayIdent, + layer: SharedGraphicLLayer.GraphicLLayerOverlayIdent, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'direkte', templateData: ['KØBENHAVN'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj ]) }) - }), - literal({ - externalId: partId, - name: 'direkte - KØBENHAVN', - enable: { - start: 0 - }, - lifespan: PieceLifespan.WithinPart, - outputLayerId: SharedOutputLayers.OVERLAY, - sourceLayerId: SourceLayer.PgmGraphicsIdent, - content: { - timelineObjects: [ - literal({ - id: '', - enable: { - while: '1' - }, - layer: AbstractLLayer.IdentMarker, - content: { - deviceType: TSR.DeviceType.ABSTRACT - } - }) - ] - } }) ]) }) @@ -625,18 +633,16 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'arkiv - unnamed org', enable: { @@ -644,6 +650,12 @@ describe('grafik piece', () => { duration: 4000 }, lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + }, + belongsToRemotePart: false + }, outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsIdent, content: literal>({ @@ -657,13 +669,14 @@ describe('grafik piece', () => { while: `!.full` }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayIdent, + layer: SharedGraphicLLayer.GraphicLLayerOverlayIdent, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'arkiv', templateData: ['unnamed org'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -694,15 +707,13 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - dummyBlueprintPart, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) expect(adLibPieces).toEqual([ literal({ @@ -710,12 +721,16 @@ describe('grafik piece', () => { externalId: partId, name: 'tlftoptlive - Line 1\n - Line 2', lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsTop, expectedDuration: 5000, tags: ['kommentator'], uniquenessId: 'gfx_tlftoptlive - Line 1\n - Line 2_studio0_graphicsTop_overlay_commentator', - noHotKey: true, content: literal>({ fileName: 'tlftoptlive', path: 'tlftoptlive', @@ -727,13 +742,14 @@ describe('grafik piece', () => { while: `!.full` }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayTopt, + layer: SharedGraphicLLayer.GraphicLLayerOverlayTopt, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'tlftoptlive', templateData: ['Line 1', 'Line 2'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -745,9 +761,13 @@ describe('grafik piece', () => { externalId: partId, name: 'tlftoptlive - Line 1\n - Line 2', lifespan: PieceLifespan.OutOnSegmentEnd, + metaData: literal({ + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }), outputLayerId: SharedOutputLayers.OVERLAY, sourceLayerId: SourceLayer.PgmGraphicsTop, - expectedDuration: 4000, tags: ['flow_producer'], uniquenessId: 'gfx_tlftoptlive - Line 1\n - Line 2_studio0_graphicsTop_overlay_flow', content: literal>({ @@ -761,13 +781,14 @@ describe('grafik piece', () => { while: `!.full` }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayTopt, + layer: SharedGraphicLLayer.GraphicLLayerOverlayTopt, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'tlftoptlive', templateData: ['Line 1', 'Line 2'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), dskEnableObj @@ -777,59 +798,7 @@ describe('grafik piece', () => { ]) }) - it('Applies delay to WALL graphics when part has prerollDuration', () => { - const partWithPreroll: IBlueprintPart = { - title: 'Server', - externalId: '0001', - prerollDuration: 1000 - } - const cue: CueDefinitionGraphic = { - type: CueType.Graphic, - target: 'WALL', - graphic: { - type: 'pilot', - name: '', - vcpid: 1234567890, - continueCount: -1 - }, - iNewsCommand: 'GRAFIK' - } - - const pieces: IBlueprintPiece[] = [] - const adLibPieces: IBlueprintAdLibPiece[] = [] - const actions: IBlueprintActionManifest[] = [] - const partId = '0000000001' - - EvaluateCueGraphic( - config, - makeMockContext(), - partWithPreroll, - pieces, - adLibPieces, - actions, - partId, - cue, - cue.adlib ? cue.adlib : false, - dummyPart, - 0 - ) - const piece = pieces[0] - expect(piece).toBeTruthy() - const tlObj = (piece.content?.timelineObjects as TSR.TSRTimelineObj[]).find( - obj => - obj.content.deviceType === TSR.DeviceType.VIZMSE && - obj.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT - ) as TSR.TimelineObjVIZMSEElementInternal | undefined - expect(tlObj).toBeTruthy() - expect(tlObj?.enable).toEqual({ start: 1000 }) - }) - - it('Applies delay to WALL graphics when part has transitionPrerollDuration', () => { - const partWithPreroll: IBlueprintPart = { - title: 'Kam 1', - externalId: '0001', - transitionPrerollDuration: 2000 - } + it('WALL graphics have enable equal while 1', () => { const cue: CueDefinitionGraphic = { type: CueType.Graphic, target: 'WALL', @@ -850,15 +819,13 @@ describe('grafik piece', () => { EvaluateCueGraphic( config, makeMockContext(), - partWithPreroll, pieces, adLibPieces, actions, partId, cue, - cue.adlib ? cue.adlib : false, dummyPart, - 0 + cue.adlib ? { rank: 0 } : undefined ) const piece = pieces[0] expect(piece).toBeTruthy() @@ -868,6 +835,6 @@ describe('grafik piece', () => { obj.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT ) as TSR.TimelineObjVIZMSEElementInternal | undefined expect(tlObj).toBeTruthy() - expect(tlObj?.enable).toEqual({ start: 2000 }) + expect(tlObj?.enable).toEqual({ while: '1' }) }) }) diff --git a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/lyd.spec.ts b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/lyd.spec.ts index 31eb9935a..53fdaea3a 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/lyd.spec.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/lyd.spec.ts @@ -2,12 +2,18 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, IBlueprintPiece, - PieceLifespan -} from '@sofie-automation/blueprints-integration' + PieceLifespan, + TSR +} from '@tv2media/blueprints-integration' import { CueDefinitionLYD, EvaluateLYD, literal, ParseCue, PartDefinitionKam } from 'tv2-common' -import { NoteType, PartType } from 'tv2-constants' +import { AdlibTags, NoteType, PartType, SharedOutputLayers, SharedSourceLayers, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../../../__mocks__/context' -import { defaultShowStyleConfig, defaultStudioConfig } from '../../../../tv2_afvd_showstyle/__tests__/configs' +import { + DEFAULT_GRAPHICS_SETUP, + defaultShowStyleConfig, + defaultStudioConfig, + EMPTY_SOURCE_CONFIG +} from '../../../../tv2_afvd_showstyle/__tests__/configs' import { defaultDSKConfig, parseConfig as parseStudioConfig, @@ -24,45 +30,42 @@ function makeMockContext() { return mockContext } -const config = getConfig(makeMockContext()) +const CONFIG = getConfig(makeMockContext()) +const MOCK_PART = literal({ + type: PartType.Kam, + sourceDefinition: { sourceType: SourceType.KAM, id: '1', raw: 'Kam 1', minusMic: false, name: 'KAM 1' }, + externalId: '0001', + rawType: 'Kam 1', + cues: [], + script: '', + storyName: '', + fields: {}, + modified: 0, + segmentExternalId: '' +}) describe('lyd', () => { test('Lyd with no out time', () => { - const parsedCue = ParseCue(['LYD=SN_INTRO', ';0.00'], config) as CueDefinitionLYD + const parsedCue = ParseCue(['LYD=SN_INTRO', ';0.00'], CONFIG) as CueDefinitionLYD const pieces: IBlueprintPiece[] = [] const adlibPieces: IBlueprintAdLibPiece[] = [] const actions: IBlueprintActionManifest[] = [] - const mockPart = literal({ - type: PartType.Kam, - variant: { - name: '1' - }, - externalId: '0001', - rawType: 'Kam 1', - cues: [], - script: '', - storyName: '', - fields: {}, - modified: 0, - segmentExternalId: '' - }) EvaluateLYD( makeMockContext(), { showStyle: (defaultShowStyleConfig as unknown) as ShowStyleConfig, studio: (defaultStudioConfig as unknown) as StudioConfig, - sources: [], + sources: EMPTY_SOURCE_CONFIG, mediaPlayers: [], - stickyLayers: [], - liveAudio: [], - dsk: defaultDSKConfig + dsk: defaultDSKConfig, + selectedGraphicsSetup: DEFAULT_GRAPHICS_SETUP }, pieces, adlibPieces, actions, parsedCue, - mockPart + MOCK_PART ) expect(pieces[0].enable).toEqual( @@ -75,41 +78,26 @@ describe('lyd', () => { }) test('Lyd with out time', () => { - const parsedCue = ParseCue(['LYD=SN_INTRO', ';0.00-0.10'], config) as CueDefinitionLYD + const parsedCue = ParseCue(['LYD=SN_INTRO', ';0.00-0.10'], CONFIG) as CueDefinitionLYD const pieces: IBlueprintPiece[] = [] const adlibPieces: IBlueprintAdLibPiece[] = [] const actions: IBlueprintActionManifest[] = [] - const mockPart = literal({ - type: PartType.Kam, - variant: { - name: '1' - }, - externalId: '0001', - rawType: 'Kam 1', - cues: [], - script: '', - storyName: '', - fields: {}, - modified: 0, - segmentExternalId: '' - }) EvaluateLYD( makeMockContext(), { showStyle: (defaultShowStyleConfig as unknown) as ShowStyleConfig, studio: (defaultStudioConfig as unknown) as StudioConfig, - sources: [], + sources: EMPTY_SOURCE_CONFIG, mediaPlayers: [], - stickyLayers: [], - liveAudio: [], - dsk: defaultDSKConfig + dsk: defaultDSKConfig, + selectedGraphicsSetup: DEFAULT_GRAPHICS_SETUP }, pieces, adlibPieces, actions, parsedCue, - mockPart + MOCK_PART ) expect(pieces[0].enable).toEqual( @@ -123,24 +111,10 @@ describe('lyd', () => { }) test('Lyd not configured', () => { - const parsedCue = ParseCue(['LYD=SN_MISSING', ';0.00-0.10'], config) as CueDefinitionLYD + const parsedCue = ParseCue(['LYD=SN_MISSING', ';0.00-0.10'], CONFIG) as CueDefinitionLYD const pieces: IBlueprintPiece[] = [] const adlibPieces: IBlueprintAdLibPiece[] = [] const actions: IBlueprintActionManifest[] = [] - const mockPart = literal({ - type: PartType.Kam, - variant: { - name: '1' - }, - externalId: '0001', - rawType: 'Kam 1', - cues: [], - script: '', - storyName: '', - fields: {}, - modified: 0, - segmentExternalId: '' - }) const context = makeMockContext() @@ -149,21 +123,99 @@ describe('lyd', () => { { showStyle: (defaultShowStyleConfig as unknown) as ShowStyleConfig, studio: (defaultStudioConfig as unknown) as StudioConfig, - sources: [], + sources: EMPTY_SOURCE_CONFIG, mediaPlayers: [], - stickyLayers: [], - liveAudio: [], - dsk: defaultDSKConfig + dsk: defaultDSKConfig, + selectedGraphicsSetup: DEFAULT_GRAPHICS_SETUP }, pieces, adlibPieces, actions, parsedCue, - mockPart + MOCK_PART ) expect(pieces.length).toEqual(0) expect(context.getNotes().length).toEqual(1) expect(context.getNotes()[0].type).toEqual(NoteType.NOTIFY_USER_WARNING) }) + + test('Lyd adlib', () => { + const parsedCue = ParseCue(['LYD=SN_INTRO', ';x.xx'], CONFIG) as CueDefinitionLYD + const pieces: IBlueprintPiece[] = [] + const adlibPieces: IBlueprintAdLibPiece[] = [] + const actions: IBlueprintActionManifest[] = [] + + EvaluateLYD( + makeMockContext(), + { + showStyle: (defaultShowStyleConfig as unknown) as ShowStyleConfig, + studio: (defaultStudioConfig as unknown) as StudioConfig, + sources: EMPTY_SOURCE_CONFIG, + mediaPlayers: [], + dsk: defaultDSKConfig, + selectedGraphicsSetup: DEFAULT_GRAPHICS_SETUP + }, + pieces, + adlibPieces, + actions, + parsedCue, + MOCK_PART, + true + ) + + expect(adlibPieces.length).toEqual(1) + expect(adlibPieces[0]).toMatchObject( + literal>({ + name: 'SN_INTRO', + outputLayerId: SharedOutputLayers.MUSIK, + sourceLayerId: SharedSourceLayers.PgmAudioBed, + lifespan: PieceLifespan.OutOnRundownChange, + tags: [AdlibTags.ADLIB_FLOW_PRODUCER] + }) + ) + }) + + it("should fade, studio audio bed folder is configured, audio file should evaluate to 'empty'", () => { + const parsedCue = ParseCue(['LYD=FADE 100', ';0.00'], CONFIG) as CueDefinitionLYD + const pieces: IBlueprintPiece[] = [] + const adLibPieces: IBlueprintAdLibPiece[] = [] + const actions: IBlueprintActionManifest[] = [] + + CONFIG.studio.AudioBedFolder = 'audio' + + EvaluateLYD(makeMockContext(), CONFIG, pieces, adLibPieces, actions, parsedCue, MOCK_PART) + + expect(pieces).toHaveLength(1) + const timelineObject: TSR.TimelineObjCCGMedia = pieces[0].content.timelineObjects[0] as TSR.TimelineObjCCGMedia + const file = timelineObject.content.file + expect(file).toBe('empty') + }) + + it('should play audio, studio audio bed is configured, audio file should be prepended with the configured audio bed', () => { + const iNewsName = 'ATP_soundbed' + const parsedCue = ParseCue([`LYD=${iNewsName}`, ';0.00'], CONFIG) as CueDefinitionLYD + const pieces: IBlueprintPiece[] = [] + const adLibPieces: IBlueprintAdLibPiece[] = [] + const actions: IBlueprintActionManifest[] = [] + + const audioBedFolder = 'audio' + CONFIG.studio.AudioBedFolder = audioBedFolder + + const fileName: string = 'someFileName' + CONFIG.showStyle.LYDConfig = [ + { + _id: 'someId', + INewsName: iNewsName, + FileName: fileName + } + ] + + EvaluateLYD(makeMockContext(), CONFIG, pieces, adLibPieces, actions, parsedCue, MOCK_PART) + + expect(pieces).toHaveLength(1) + const timelineObject: TSR.TimelineObjCCGMedia = pieces[0].content.timelineObjects[0] as TSR.TimelineObjCCGMedia + const file = timelineObject.content.file + expect(file).toBe(`${audioBedFolder}/${fileName}`) + }) }) diff --git a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/telefon.spec.ts b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/telefon.spec.ts index b2ea6cafe..fb075a18d 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/__tests__/telefon.spec.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/__tests__/telefon.spec.ts @@ -2,23 +2,28 @@ import { GraphicsContent, IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AtemLLayerDSK, CueDefinitionGraphic, CueDefinitionTelefon, GraphicInternal, + GraphicPieceMetaData, literal, PartDefinitionKam } from 'tv2-common' -import { CueType, GraphicLLayer, PartType, SharedOutputLayers } from 'tv2-constants' +import { CueType, PartType, SharedGraphicLLayer, SharedOutputLayers, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../../../__mocks__/context' -import { defaultShowStyleConfig, defaultStudioConfig } from '../../../../tv2_afvd_showstyle/__tests__/configs' +import { + DEFAULT_GRAPHICS_SETUP, + defaultShowStyleConfig, + defaultStudioConfig, + OVL_SHOW_ID +} from '../../../../tv2_afvd_showstyle/__tests__/configs' import { SourceLayer } from '../../../../tv2_afvd_showstyle/layers' import { defaultDSKConfig, @@ -36,8 +41,12 @@ mockContext.showStyleConfig = defaultShowStyleConfig as any const dummyPart = literal({ type: PartType.Kam, - variant: { - name: '1' + sourceDefinition: { + sourceType: SourceType.KAM, + id: '1', + raw: 'Kam 1', + minusMic: false, + name: 'KAM 2' }, externalId: '0001', rawType: 'Kam 1', @@ -49,11 +58,6 @@ const dummyPart = literal({ segmentExternalId: '' }) -const dummyBlueprintPart: IBlueprintPart = { - title: 'Kam 1', - externalId: '0001' -} - describe('telefon', () => { test('telefon with vizObj', () => { const cue: CueDefinitionTelefon = { @@ -83,14 +87,17 @@ describe('telefon', () => { { showStyle: (defaultShowStyleConfig as unknown) as ShowStyleConfig, studio: (defaultStudioConfig as unknown) as StudioConfig, - sources: [], + sources: { + cameras: [], + lives: [], + feeds: [], + replays: [] + }, mediaPlayers: [], - stickyLayers: [], - liveAudio: [], - dsk: defaultDSKConfig + dsk: defaultDSKConfig, + selectedGraphicsSetup: DEFAULT_GRAPHICS_SETUP }, mockContext, - dummyBlueprintPart, pieces, adLibPieces, actions, @@ -99,15 +106,21 @@ describe('telefon', () => { cue ) expect(pieces).toEqual([ - literal({ + literal>({ externalId: partId, name: 'TLF 1', enable: { start: 0 }, outputLayerId: SharedOutputLayers.OVERLAY, - sourceLayerId: SourceLayer.PgmGraphicsTLF, + sourceLayerId: SourceLayer.PgmGraphicsLower, lifespan: PieceLifespan.WithinPart, + metaData: { + belongsToRemotePart: false, + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, content: literal>({ fileName: 'bund', path: 'bund', @@ -119,13 +132,14 @@ describe('telefon', () => { while: '!.full' }, priority: 1, - layer: GraphicLLayer.GraphicLLayerOverlayLower, + layer: SharedGraphicLLayer.GraphicLLayerOverlayLower, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: 'bund', templateData: ['Odense', 'Copenhagen'], - channelName: 'OVL1' + channelName: 'OVL1', + showId: OVL_SHOW_ID } }), literal({ diff --git a/src/tv2_afvd_showstyle/helpers/pieces/adlib.ts b/src/tv2_afvd_showstyle/helpers/pieces/adlib.ts index e2c485f8e..3c2864882 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/adlib.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/adlib.ts @@ -4,7 +4,7 @@ import { IBlueprintAdLibPiece, IShowStyleUserContext, PieceLifespan -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectDVE, CreateAdlibServer, @@ -24,10 +24,10 @@ import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../../../tv2_afvd_studi import { SourceLayer } from '../../layers' import { MakeContentDVE } from '../content/dve' -export function EvaluateAdLib( +export async function EvaluateAdLib( context: IShowStyleUserContext, config: BlueprintConfig, - adLibPieces: IBlueprintAdLibPiece[], + adLibPieces: Array>, actions: IBlueprintActionManifest[], mediaSubscriptions: HackPartMediaObjectSubscription[], partId: string, @@ -43,19 +43,15 @@ export function EvaluateAdLib( return } - const sourceDuration = Math.max( - (context.hackGetMediaObjectDuration(file) || 0) * 1000 - config.studio.ServerPostrollDuration, - 0 - ) - actions.push( - CreateAdlibServer( + await CreateAdlibServer( + context, config, rank, partDefinition, file, false, - false, + true, { SourceLayer: { PgmServer: SourceLayer.PgmServer, @@ -65,15 +61,13 @@ export function EvaluateAdLib( ClipPending: CasparLLayer.CasparPlayerClipPending }, Sisyfos: { - ClipPending: SisyfosLLAyer.SisyfosSourceClipPending, - StudioMicsGroup: SisyfosLLAyer.SisyfosGroupStudioMics + ClipPending: SisyfosLLAyer.SisyfosSourceClipPending }, AtemLLayer: { MEPgm: AtemLLayer.AtemMEProgram }, ATEM: {} }, - sourceDuration, true ) ) @@ -106,43 +100,31 @@ export function EvaluateAdLib( const content = MakeContentDVE(context, config, partDefinition, cueDVE, rawTemplate, false, true) - let sticky: { [key: string]: { value: number; followsPrevious: boolean } } = {} - - content.stickyLayers.forEach(layer => { - sticky = { - ...sticky, - [layer]: { - value: 1, - followsPrevious: false + adLibPieces.push({ + _rank: rank, + externalId: partId, + name: `DVE: ${parsedCue.variant}`, + sourceLayerId: SourceLayer.PgmDVE, + outputLayerId: SharedOutputLayers.PGM, + uniquenessId: getUniquenessIdDVE(cueDVE), + toBeQueued: true, + content: content.content, + invalid: !content.valid, + lifespan: PieceLifespan.WithinPart, + metaData: literal({ + sources: cueDVE.sources, + config: rawTemplate, + userData: literal({ + type: AdlibActionType.SELECT_DVE, + config: cueDVE, + videoId: partDefinition.fields.videoId, + segmentExternalId: partDefinition.segmentExternalId + }), + sisyfosPersistMetaData: { + sisyfosLayers: [] } - } + }), + tags: [AdlibTags.ADLIB_FLOW_PRODUCER] }) - - adLibPieces.push( - literal({ - _rank: rank, - externalId: partId, - name: `DVE: ${parsedCue.variant}`, - sourceLayerId: SourceLayer.PgmDVE, - outputLayerId: SharedOutputLayers.PGM, - uniquenessId: getUniquenessIdDVE(cueDVE), - toBeQueued: true, - content: content.content, - invalid: !content.valid, - lifespan: PieceLifespan.WithinPart, - metaData: literal({ - stickySisyfosLevels: sticky, - sources: cueDVE.sources, - config: rawTemplate, - userData: literal({ - type: AdlibActionType.SELECT_DVE, - config: cueDVE, - videoId: partDefinition.fields.videoId, - segmentExternalId: partDefinition.segmentExternalId - }) - }), - tags: [AdlibTags.ADLIB_FLOW_PRODUCER] - }) - ) } } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/clearGrafiks.ts b/src/tv2_afvd_showstyle/helpers/pieces/clearGrafiks.ts index ff45dcc5f..202258d60 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/clearGrafiks.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/clearGrafiks.ts @@ -4,11 +4,11 @@ import { IBlueprintPiece, PieceLifespan, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CreateTimingEnable, CueDefinitionClearGrafiks, GetDefaultOut, literal } from 'tv2-common' -import { GraphicLLayer, SharedOutputLayers } from 'tv2-constants' +import { SharedGraphicLLayer, SharedOutputLayers } from 'tv2-constants' +import { BlueprintConfig } from '../../../tv2_afvd_showstyle/helpers/config' import { SourceLayer } from '../../../tv2_afvd_showstyle/layers' -import { BlueprintConfig } from '../../../tv2_afvd_studio/helpers/config' export function EvaluateClearGrafiks( config: BlueprintConfig, @@ -25,13 +25,11 @@ export function EvaluateClearGrafiks( ;[ SourceLayer.PgmGraphicsIdent, - SourceLayer.PgmGraphicsIdentPersistent, SourceLayer.PgmGraphicsTop, SourceLayer.PgmGraphicsLower, SourceLayer.PgmGraphicsHeadline, SourceLayer.PgmGraphicsTema, - SourceLayer.PgmGraphicsOverlay, - SourceLayer.PgmGraphicsTLF + SourceLayer.PgmGraphicsOverlay ].forEach(sourceLayerId => { pieces.push({ externalId: partId, @@ -50,33 +48,32 @@ export function EvaluateClearGrafiks( }) }) - pieces.push( - literal({ - externalId: partId, - name: 'CLEAR', - ...CreateTimingEnable(parsedCue, GetDefaultOut(config)), - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SourceLayer.PgmAdlibGraphicCmd, - lifespan: PieceLifespan.WithinPart, - content: { - timelineObjects: config.studio.HTMLGraphics - ? [ - literal({ - id: '', - enable: { - start: 0, - duration: 1000 - }, - priority: 100, - layer: GraphicLLayer.GraphicLLayerAdLibs, - content: { - deviceType: TSR.DeviceType.VIZMSE, - type: TSR.TimelineContentTypeVizMSE.CLEAR_ALL_ELEMENTS - } - }) - ] - : [] - } - }) - ) + pieces.push({ + externalId: partId, + name: 'CLEAR', + ...CreateTimingEnable(parsedCue, GetDefaultOut(config)), + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.PgmAdlibGraphicCmd, + lifespan: PieceLifespan.WithinPart, + content: { + timelineObjects: config.studio.HTMLGraphics + ? [ + literal({ + id: '', + enable: { + start: 0, + duration: 1000 + }, + priority: 100, + layer: SharedGraphicLLayer.GraphicLLayerAdLibs, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.CLEAR_ALL_ELEMENTS, + showId: config.selectedGraphicsSetup.OvlShowId + } + }) + ] + : [] + } + }) } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/design.ts b/src/tv2_afvd_showstyle/helpers/pieces/design.ts index 2208ad5ff..09d8c7764 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/design.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/design.ts @@ -3,13 +3,12 @@ import { IBlueprintAdLibPiece, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { CueDefinitionGraphicDesign, EvaluateDesignBase } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { CueDefinitionGraphicDesign, EvaluateDesignBase, TV2BlueprintConfig } from 'tv2-common' import * as _ from 'underscore' -import { BlueprintConfig } from '../../../tv2_afvd_studio/helpers/config' export function EvaluateCueDesign( - config: BlueprintConfig, + config: TV2BlueprintConfig, context: ISegmentUserContext, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], diff --git a/src/tv2_afvd_showstyle/helpers/pieces/dve.ts b/src/tv2_afvd_showstyle/helpers/pieces/dve.ts index 9021e68c2..0a5e4ee7b 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/dve.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/dve.ts @@ -4,7 +4,7 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectDVE, AddParentClass, @@ -15,11 +15,9 @@ import { getUniquenessIdDVE, literal, PartDefinition, - PieceMetaData, TemplateIsValid } from 'tv2-common' import { AdlibActionType, SharedOutputLayers } from 'tv2-constants' -import * as _ from 'underscore' import { BlueprintConfig } from '../../../tv2_afvd_showstyle/helpers/config' import { SourceLayer } from '../../../tv2_afvd_showstyle/layers' import { MakeContentDVE } from '../content/dve' @@ -63,7 +61,7 @@ export function EvaluateDVE( if (content.valid) { if (adlib) { adlibPieces.push( - literal({ + literal>({ _rank: rank || 0, externalId: partDefinition.externalId, name: `${partDefinition.storyName} DVE: ${parsedCue.template}`, @@ -73,8 +71,8 @@ export function EvaluateDVE( lifespan: PieceLifespan.WithinPart, toBeQueued: true, content: content.content, - adlibPreroll: Number(config.studio.CasparPrerollDuration) || 0, - metaData: literal({ + prerollDuration: Number(config.studio.CasparPrerollDuration) || 0, + metaData: { sources: parsedCue.sources, config: rawTemplate, userData: literal({ @@ -82,8 +80,11 @@ export function EvaluateDVE( config: parsedCue, videoId: partDefinition.fields.videoId, segmentExternalId: partDefinition.segmentExternalId - }) - }) + }), + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + } }) ) } else { @@ -91,7 +92,7 @@ export function EvaluateDVE( start = start ? start : 0 const end = parsedCue.end ? CalculateTime(parsedCue.end) : undefined pieces.push( - literal({ + literal>({ externalId: partDefinition.externalId, name: `DVE: ${parsedCue.template}`, enable: { @@ -103,18 +104,21 @@ export function EvaluateDVE( lifespan: PieceLifespan.WithinPart, toBeQueued: true, content: content.content, - adlibPreroll: Number(config.studio.CasparPrerollDuration) || 0, - metaData: literal({ + prerollDuration: Number(config.studio.CasparPrerollDuration) || 0, + metaData: { mediaPlayerSessions: [partDefinition.segmentExternalId], sources: parsedCue.sources, config: rawTemplate, - userData: literal({ + userData: { type: AdlibActionType.SELECT_DVE, config: parsedCue, videoId: partDefinition.fields.videoId, segmentExternalId: partDefinition.segmentExternalId - }) - }) + }, + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + } }) ) } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/ekstern.ts b/src/tv2_afvd_showstyle/helpers/pieces/ekstern.ts index e5ca36aae..ac382dc39 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/ekstern.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/ekstern.ts @@ -4,18 +4,23 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { CueDefinitionEkstern, EvaluateEksternBase, PartDefinition } from 'tv2-common' -import { BlueprintConfig } from '../../../tv2_afvd_studio/helpers/config' -import { AtemLLayer, SisyfosLLAyer } from '../../../tv2_afvd_studio/layers' +} from '@tv2media/blueprints-integration' +import { + CueDefinitionEkstern, + EvaluateEksternBase, + PartDefinition, + PieceMetaData, + TV2BlueprintConfig +} from 'tv2-common' +import { AtemLLayer } from '../../../tv2_afvd_studio/layers' import { SourceLayer } from '../../layers' export function EvaluateEkstern( context: ISegmentUserContext, - config: BlueprintConfig, + config: TV2BlueprintConfig, part: IBlueprintPart, - pieces: IBlueprintPiece[], - adlibPieces: IBlueprintAdLibPiece[], + pieces: Array>, + adlibPieces: Array>, _actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionEkstern, @@ -38,9 +43,6 @@ export function EvaluateEkstern( }, ATEM: { MEProgram: AtemLLayer.AtemMEProgram - }, - Sisyfos: { - StudioMics: SisyfosLLAyer.SisyfosGroupStudioMics } }, adlib, diff --git a/src/tv2_afvd_showstyle/helpers/pieces/evaluateCues.ts b/src/tv2_afvd_showstyle/helpers/pieces/evaluateCues.ts index 0d4200f1a..46dc27b6f 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/evaluateCues.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/evaluateCues.ts @@ -5,7 +5,7 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CueDefinition, EvaluateCueMixMinus, @@ -26,7 +26,7 @@ import { EvaluateJingle } from './jingle' import { EvaluateCueRouting } from './routing' import { EvaluateTelefon } from './telefon' -export function EvaluateCues( +export async function EvaluateCues( context: ISegmentUserContext, config: BlueprintConfig, part: IBlueprintPart, @@ -38,7 +38,7 @@ export function EvaluateCues( partDefinition: PartDefinition, options: EvaluateCuesOptions ) { - EvaluateCuesBase( + await EvaluateCuesBase( { EvaluateCueAdLib: EvaluateAdLib, EvaluateCueClearGrafiks: EvaluateClearGrafiks, diff --git a/src/tv2_afvd_showstyle/helpers/pieces/graphic.ts b/src/tv2_afvd_showstyle/helpers/pieces/graphic.ts index 3b69f4020..dbd656b19 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/graphic.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/graphic.ts @@ -1,11 +1,11 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { + Adlib, CreateInternalGraphic, CueDefinitionGraphic, GraphicInternalOrPilot, @@ -20,47 +20,31 @@ import { EvaluateCueRouting } from './routing' export function EvaluateCueGraphic( config: BlueprintConfig, context: ISegmentUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionGraphic, - adlib: boolean, partDefinition: PartDefinition, - rank?: number + adlib?: Adlib ) { if (parsedCue.routing) { EvaluateCueRouting(config, context, pieces, adlibPieces, actions, partId, parsedCue.routing) } if (GraphicIsInternal(parsedCue)) { - CreateInternalGraphic( - config, - context, - part, - pieces, - adlibPieces, - actions, - partId, - parsedCue, - adlib, - partDefinition, - rank - ) + CreateInternalGraphic(config, context, pieces, adlibPieces, partId, parsedCue, partDefinition, adlib) } else if (GraphicIsPilot(parsedCue)) { EvaluateCueGraphicPilot( config, context, - part, pieces, adlibPieces, actions, partId, parsedCue, - adlib, partDefinition.segmentExternalId, - rank + adlib ) } } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/graphicBackgroundLoop.ts b/src/tv2_afvd_showstyle/helpers/pieces/graphicBackgroundLoop.ts index c0b45c8ef..3e39ff3de 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/graphicBackgroundLoop.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/graphicBackgroundLoop.ts @@ -6,13 +6,14 @@ import { PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CalculateTime, CueDefinitionBackgroundLoop, literal } from 'tv2-common' -import { GraphicLLayer, SharedOutputLayers } from 'tv2-constants' +} from '@tv2media/blueprints-integration' +import { CalculateTime, CueDefinitionBackgroundLoop, literal, TV2BlueprintConfig } from 'tv2-common' +import { SharedGraphicLLayer, SharedOutputLayers } from 'tv2-constants' import { CasparLLayer } from '../../../tv2_afvd_studio/layers' import { SourceLayer } from '../../layers' export function EvaluateCueBackgroundLoop( + config: TV2BlueprintConfig, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], _actions: IBlueprintActionManifest[], @@ -27,80 +28,72 @@ export function EvaluateCueBackgroundLoop( const fileName = parsedCue.backgroundLoop const path = `dve/${fileName}` if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name: fileName, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SourceLayer.PgmDVEBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName, - path, - ignoreMediaObjectStatus: true, - timelineObjects: dveLoopTimeline(path) - }) + adlibPieces.push({ + _rank: rank || 0, + externalId: partId, + name: fileName, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.PgmDVEBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName, + path, + ignoreMediaObjectStatus: true, + timelineObjects: dveLoopTimeline(path) }) - ) + }) } else { - pieces.push( - literal({ - externalId: partId, - name: fileName, - enable: { - start - }, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SourceLayer.PgmDVEBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName, - path, - ignoreMediaObjectStatus: true, - timelineObjects: dveLoopTimeline(path) - }) + pieces.push({ + externalId: partId, + name: fileName, + enable: { + start + }, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.PgmDVEBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName, + path, + ignoreMediaObjectStatus: true, + timelineObjects: dveLoopTimeline(path) }) - ) + }) } } else { // Full if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name: parsedCue.backgroundLoop, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SourceLayer.PgmFullBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName: parsedCue.backgroundLoop, - path: parsedCue.backgroundLoop, - ignoreMediaObjectStatus: true, - timelineObjects: fullLoopTimeline(parsedCue) - }) + adlibPieces.push({ + _rank: rank || 0, + externalId: partId, + name: parsedCue.backgroundLoop, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.PgmFullBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName: parsedCue.backgroundLoop, + path: parsedCue.backgroundLoop, + ignoreMediaObjectStatus: true, + timelineObjects: fullLoopTimeline(config, parsedCue) }) - ) + }) } else { - pieces.push( - literal({ - externalId: partId, - name: parsedCue.backgroundLoop, - enable: { - start - }, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: SourceLayer.PgmFullBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName: parsedCue.backgroundLoop, - path: parsedCue.backgroundLoop, - ignoreMediaObjectStatus: true, - timelineObjects: fullLoopTimeline(parsedCue) - }) + pieces.push({ + externalId: partId, + name: parsedCue.backgroundLoop, + enable: { + start + }, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.PgmFullBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName: parsedCue.backgroundLoop, + path: parsedCue.backgroundLoop, + ignoreMediaObjectStatus: true, + timelineObjects: fullLoopTimeline(config, parsedCue) }) - ) + }) } } } @@ -122,18 +115,19 @@ function dveLoopTimeline(path: string): TSR.TSRTimelineObj[] { ] } -function fullLoopTimeline(parsedCue: CueDefinitionBackgroundLoop): TSR.TSRTimelineObj[] { +function fullLoopTimeline(config: TV2BlueprintConfig, parsedCue: CueDefinitionBackgroundLoop): TSR.TSRTimelineObj[] { return [ literal({ id: '', enable: { start: 0 }, priority: 1, - layer: GraphicLLayer.GraphicLLayerFullLoop, + layer: SharedGraphicLLayer.GraphicLLayerFullLoop, content: { deviceType: TSR.DeviceType.VIZMSE, type: TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL, templateName: parsedCue.backgroundLoop, - templateData: [] + templateData: [], + showId: config.selectedGraphicsSetup.FullShowId } }) ] diff --git a/src/tv2_afvd_showstyle/helpers/pieces/graphicPilot.ts b/src/tv2_afvd_showstyle/helpers/pieces/graphicPilot.ts index 2bd25bc82..d0a68e0da 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/graphicPilot.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/graphicPilot.ts @@ -1,26 +1,24 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, IShowStyleUserContext, IStudioUserContext, - SourceLayerType, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { + Adlib, CreatePilotGraphic, CueDefinitionGraphic, EnableDSK, FindDSKFullGFX, - GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForFull, GraphicPilot, literal, PilotGeneratorSettings, - SisyfosEVSSource, - SourceInfo + TV2BlueprintConfig } from 'tv2-common' -import { AtemLLayer, SisyfosLLAyer } from '../../../tv2_afvd_studio/layers' +import { AtemLLayer } from '../../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../config' export const pilotGeneratorSettingsAFVD: PilotGeneratorSettings = { @@ -29,37 +27,31 @@ export const pilotGeneratorSettingsAFVD: PilotGeneratorSettings = { } export function EvaluateCueGraphicPilot( - config: BlueprintConfig, + config: TV2BlueprintConfig, context: IShowStyleUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionGraphic, - adlib: boolean, segmentExternalId: string, - rank?: number + adlib?: Adlib ) { - CreatePilotGraphic( + CreatePilotGraphic(pieces, adlibPieces, actions, { config, context, - part, - pieces, - adlibPieces, - actions, + engine: parsedCue.target, partId, parsedCue, - pilotGeneratorSettingsAFVD, + settings: pilotGeneratorSettingsAFVD, adlib, - rank ?? 0, segmentExternalId - ) + }) } function makeStudioTimelineViz( config: BlueprintConfig, - context: IStudioUserContext, + _context: IStudioUserContext, adlib: boolean ): TSR.TSRTimelineObj[] { const fullDSK = FindDSKFullGFX(config) @@ -100,12 +92,11 @@ function makeStudioTimelineViz( }), // Assume DSK is off by default (config table) ...EnableDSK(config, 'FULL'), - GetSisyfosTimelineObjForCamera(context, config, 'full', SisyfosLLAyer.SisyfosGroupStudioMics), - ...muteSisyfosChannels(config.sources) + ...GetSisyfosTimelineObjForFull(config) ] } -function makeStudioTimelineCaspar(config: BlueprintConfig, context: IStudioUserContext) { +function makeStudioTimelineCaspar(config: BlueprintConfig, _context: IStudioUserContext) { const fullDSK = FindDSKFullGFX(config) return [ literal({ @@ -132,44 +123,6 @@ function makeStudioTimelineCaspar(config: BlueprintConfig, context: IStudioUserC } } }), - GetSisyfosTimelineObjForCamera(context, config, 'full', SisyfosLLAyer.SisyfosGroupStudioMics), - ...muteSisyfosChannels(config.sources) + ...GetSisyfosTimelineObjForFull(config) ] } - -function muteSisyfosChannels(sources: SourceInfo[]): TSR.TimelineObjSisyfosChannel[] { - return [ - SisyfosLLAyer.SisyfosSourceServerA, - SisyfosLLAyer.SisyfosSourceServerB, - SisyfosLLAyer.SisyfosSourceLive_1, - SisyfosLLAyer.SisyfosSourceLive_2, - SisyfosLLAyer.SisyfosSourceLive_3, - SisyfosLLAyer.SisyfosSourceLive_4, - SisyfosLLAyer.SisyfosSourceLive_5, - SisyfosLLAyer.SisyfosSourceLive_6, - SisyfosLLAyer.SisyfosSourceLive_7, - SisyfosLLAyer.SisyfosSourceLive_8, - SisyfosLLAyer.SisyfosSourceLive_9, - SisyfosLLAyer.SisyfosSourceLive_10, - SisyfosLLAyer.SisyfosSourceTLF, - ...[ - ...(sources - .filter(s => s.type === SourceLayerType.LOCAL) - .map(s => SisyfosEVSSource(s.id.replace(/^DP/i, '') as SisyfosLLAyer)) as SisyfosLLAyer[]) - ] - ].map(layer => { - return literal({ - id: '', - enable: { - start: 0 - }, - priority: 2, - layer, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 0 - } - }) - }) -} diff --git a/src/tv2_afvd_showstyle/helpers/pieces/jingle.ts b/src/tv2_afvd_showstyle/helpers/pieces/jingle.ts index bbd65df1a..706c6b3f9 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/jingle.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/jingle.ts @@ -4,19 +4,19 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectJingle, CreateJingleContentBase, CueDefinitionJingle, + generateExternalId, GetTagForJingle, GetTagForJingleNext, - literal, PartDefinition, - PieceMetaData, - t + t, + TimeFromFrames } from 'tv2-common' -import { AdlibActionType, AdlibTags, SharedOutputLayers } from 'tv2-constants' +import { AdlibActionType, AdlibTags, SharedOutputLayers, TallyTags } from 'tv2-constants' import { SourceLayer } from '../../../tv2_afvd_showstyle/layers' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../config' @@ -51,64 +51,57 @@ export function EvaluateJingle( } if (adlib) { - actions.push( - literal({ - actionId: AdlibActionType.SELECT_JINGLE, - userData: literal({ - type: AdlibActionType.SELECT_JINGLE, - clip: parsedCue.clip, - segmentExternalId: part.segmentExternalId - }), - userDataManifest: {}, - display: { - _rank: rank ?? 0, - label: t(effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip), - sourceLayerId: SourceLayer.PgmJingle, - outputLayerId: SharedOutputLayers.JINGLE, - content: { - ...createJingleContentAFVD( - config, - file, - jingle.StartAlpha, - jingle.LoadFirstFrame, - jingle.Duration, - jingle.EndAlpha - ) - }, - tags: [AdlibTags.ADLIB_FLOW_PRODUCER], - currentPieceTags: [GetTagForJingle(part.segmentExternalId, parsedCue.clip)], - nextPieceTags: [GetTagForJingleNext(part.segmentExternalId, parsedCue.clip)], - noHotKey: true - } - }) - ) - } else { - pieces.push( - literal({ - externalId: `${part.externalId}-JINGLE`, - name: effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip, - enable: { - start: 0 - }, - lifespan: PieceLifespan.WithinPart, - outputLayerId: SharedOutputLayers.JINGLE, + const userData: ActionSelectJingle = { + type: AdlibActionType.SELECT_JINGLE, + clip: parsedCue.clip, + segmentExternalId: part.segmentExternalId + } + actions.push({ + externalId: generateExternalId(context, userData), + actionId: AdlibActionType.SELECT_JINGLE, + userData, + userDataManifest: {}, + display: { + _rank: rank ?? 0, + label: t(effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip), sourceLayerId: SourceLayer.PgmJingle, - metaData: literal({ - transition: { - isJingle: !effekt, - isEffekt: !!effekt - } - }), - content: createJingleContentAFVD( - config, - file, - jingle.StartAlpha, - jingle.LoadFirstFrame, - jingle.Duration, - jingle.EndAlpha - ) - }) - ) + outputLayerId: SharedOutputLayers.JINGLE, + content: { + ...createJingleContentAFVD( + config, + file, + jingle.StartAlpha, + jingle.LoadFirstFrame, + jingle.Duration, + jingle.EndAlpha + ) + }, + tags: [AdlibTags.ADLIB_FLOW_PRODUCER], + currentPieceTags: [GetTagForJingle(part.segmentExternalId, parsedCue.clip)], + nextPieceTags: [GetTagForJingleNext(part.segmentExternalId, parsedCue.clip)] + } + }) + } else { + pieces.push({ + externalId: `${part.externalId}-JINGLE`, + name: effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip, + enable: { + start: 0 + }, + lifespan: PieceLifespan.WithinPart, + outputLayerId: SharedOutputLayers.JINGLE, + sourceLayerId: SourceLayer.PgmJingle, + prerollDuration: config.studio.CasparPrerollDuration + TimeFromFrames(Number(jingle.StartAlpha)), + tags: [!effekt ? TallyTags.JINGLE : ''], + content: createJingleContentAFVD( + config, + file, + jingle.StartAlpha, + jingle.LoadFirstFrame, + jingle.Duration, + jingle.EndAlpha + ) + }) } } @@ -120,7 +113,7 @@ export function createJingleContentAFVD( duration: number, alphaAtEnd: number ) { - const content = CreateJingleContentBase(config, file, alphaAtStart, loadFirstFrame, duration, alphaAtEnd, { + return CreateJingleContentBase(config, file, alphaAtStart, loadFirstFrame, duration, alphaAtEnd, { Caspar: { PlayerJingle: CasparLLayer.CasparPlayerJingle }, @@ -131,6 +124,4 @@ export function createJingleContentAFVD( PlayerJingle: SisyfosLLAyer.SisyfosSourceJingle } }) - - return content } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/routing.ts b/src/tv2_afvd_showstyle/helpers/pieces/routing.ts index 5bbe99712..cf116a812 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/routing.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/routing.ts @@ -5,19 +5,17 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan, - SourceLayerType, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CalculateTime, CueDefinitionRouting, FindSourceInfoStrict, literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { CalculateTime, CueDefinitionRouting, findSourceInfo, literal, TV2BlueprintConfig } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import _ = require('underscore') import { AtemLLayer } from '../../../tv2_afvd_studio/layers' import { SourceLayer } from '../../layers' -import { BlueprintConfig } from '../config' export function EvaluateCueRouting( - config: BlueprintConfig, + config: TV2BlueprintConfig, context: ISegmentUserContext, pieces: IBlueprintPiece[], _adlibPieces: IBlueprintAdLibPiece[], @@ -26,51 +24,46 @@ export function EvaluateCueRouting( parsedCue: CueDefinitionRouting ) { const time = (parsedCue.start ? CalculateTime(parsedCue.start) : 0) ?? 0 - if (parsedCue.INP1 !== undefined || parsedCue.INP !== undefined) { - const source = parsedCue.INP1 ?? parsedCue.INP - if (!source || !source.length) { - context.notifyUserWarning(`No input provided for viz engine aux`) - } else { - let sourceInfo = FindSourceInfoStrict(context, config.sources, SourceLayerType.REMOTE, source) - if (!sourceInfo) { - sourceInfo = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, source) - } + const sourceDefinition = parsedCue.INP1 ?? parsedCue.INP + if (!sourceDefinition) { + context.notifyUserWarning(`No input provided for viz engine aux`) + return + } - if (!sourceInfo) { - context.notifyUserWarning(`Could not find source ${source}`) - } else { - pieces.push( - literal({ - externalId: partId, - enable: { - start: time - }, - name: source, - outputLayerId: SharedOutputLayers.AUX, - sourceLayerId: SourceLayer.VizFullIn1, - lifespan: PieceLifespan.WithinPart, - content: literal>({ - studioLabel: '', - switcherInput: sourceInfo.port, - timelineObjects: _.compact([ - literal({ - id: '', - enable: { start: 0 }, - priority: 100, - layer: AtemLLayer.AtemAuxVizOvlIn1, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.AUX, - aux: { - input: sourceInfo.port - } - } - }) - ]) - }) - }) - ) - } - } + const sourceInfo = findSourceInfo(config.sources, sourceDefinition) + const name = sourceDefinition.name || sourceDefinition.sourceType + if (!sourceInfo) { + context.notifyUserWarning(`Could not find source ${name}`) + return } + + pieces.push({ + externalId: partId, + enable: { + start: time + }, + name, + outputLayerId: SharedOutputLayers.AUX, + sourceLayerId: SourceLayer.VizFullIn1, + lifespan: PieceLifespan.WithinPart, + content: literal>({ + studioLabel: '', + switcherInput: sourceInfo.port, + timelineObjects: _.compact([ + literal({ + id: '', + enable: { start: 0 }, + priority: 100, + layer: AtemLLayer.AtemAuxVizOvlIn1, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.AUX, + aux: { + input: sourceInfo.port + } + } + }) + ]) + }) + }) } diff --git a/src/tv2_afvd_showstyle/helpers/pieces/showLifecycle.ts b/src/tv2_afvd_showstyle/helpers/pieces/showLifecycle.ts new file mode 100644 index 000000000..691b2c59b --- /dev/null +++ b/src/tv2_afvd_showstyle/helpers/pieces/showLifecycle.ts @@ -0,0 +1,51 @@ +import { BlueprintResultPart, PieceLifespan, TSR } from '@tv2media/blueprints-integration' +import { literal, TV2BlueprintConfig } from 'tv2-common' +import { SharedOutputLayers } from 'tv2-constants' +import { GraphicLLayer } from '../../../tv2_afvd_studio/layers' +import { SourceLayer } from '../../layers' + +export function CreateShowLifecyclePieces( + config: TV2BlueprintConfig, + part: BlueprintResultPart, + initializeShowIds: string[], + cleanupShowIds: string[] +) { + if (config.studio.GraphicsType === 'VIZ') { + part.pieces.push({ + externalId: part.part.externalId, + name: 'GFX Show Init', + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: SourceLayer.GraphicsShowLifecycle, + lifespan: PieceLifespan.OutOnSegmentChange, + content: { + timelineObjects: [ + literal({ + id: '', + enable: { + while: '1' + }, + layer: GraphicLLayer.GraphicLLayerInitialize, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.INITIALIZE_SHOWS, + showIds: initializeShowIds + } + }), + literal({ + id: '', + enable: { + while: '1' + }, + layer: GraphicLLayer.GraphicLLayerCleanup, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.CLEANUP_SHOWS, + showIds: cleanupShowIds + } + }) + ] + } + }) + } +} diff --git a/src/tv2_afvd_showstyle/helpers/pieces/telefon.ts b/src/tv2_afvd_showstyle/helpers/pieces/telefon.ts index 7b6eafe75..f6e156909 100644 --- a/src/tv2_afvd_showstyle/helpers/pieces/telefon.ts +++ b/src/tv2_afvd_showstyle/helpers/pieces/telefon.ts @@ -1,16 +1,14 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, - ISegmentUserContext, - TSR -} from '@sofie-automation/blueprints-integration' + ISegmentUserContext +} from '@tv2media/blueprints-integration' import { + Adlib, CueDefinitionTelefon, - GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForTelefon, GraphicDisplayName, - literal, PartDefinition } from 'tv2-common' import { SisyfosLLAyer } from '../../../tv2_afvd_studio/layers' @@ -20,30 +18,16 @@ import { EvaluateCueGraphic } from './graphic' export function EvaluateTelefon( config: BlueprintConfig, context: ISegmentUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, partDefinition: PartDefinition, parsedCue: CueDefinitionTelefon, - adlib?: boolean, - rank?: number + adlib?: Adlib ) { if (parsedCue.graphic) { - EvaluateCueGraphic( - config, - context, - part, - pieces, - adlibPieces, - actions, - partId, - parsedCue.graphic, - !!adlib, - partDefinition, - rank - ) + EvaluateCueGraphic(config, context, pieces, adlibPieces, actions, partId, parsedCue.graphic, partDefinition, adlib) if ((!adlib && pieces.length) || (adlib && adlibPieces.length)) { if (!adlib) { @@ -51,21 +35,7 @@ export function EvaluateTelefon( const graphicPiece = pieces[graphicPieceIndex] if (graphicPiece && graphicPiece.content && graphicPiece.content.timelineObjects) { graphicPiece.content.timelineObjects.push( - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: SisyfosLLAyer.SisyfosSourceTLF, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNEL, - isPgm: 1 - } - }), - - GetSisyfosTimelineObjForCamera(context, config, 'telefon', SisyfosLLAyer.SisyfosGroupStudioMics) + ...GetSisyfosTimelineObjForTelefon(config, SisyfosLLAyer.SisyfosSourceTLF) ) graphicPiece.name = `${parsedCue.source}` pieces[graphicPieceIndex] = graphicPiece diff --git a/src/tv2_afvd_showstyle/helpers/sisyfos/__tests__/sisyfos.spec.ts b/src/tv2_afvd_showstyle/helpers/sisyfos/__tests__/sisyfos.spec.ts deleted file mode 100644 index 30d90ab45..000000000 --- a/src/tv2_afvd_showstyle/helpers/sisyfos/__tests__/sisyfos.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { GetStickyForPiece, literal, PieceMetaData } from 'tv2-common' -import { SisyfosLLAyer } from '../../../../tv2_afvd_studio/layers' - -export const STUDIO_MICS = [ - SisyfosLLAyer.SisyfosSourceHost_1_ST_A, - SisyfosLLAyer.SisyfosSourceHost_2_ST_A, - SisyfosLLAyer.SisyfosSourceGuest_1_ST_A, - SisyfosLLAyer.SisyfosSourceGuest_2_ST_A, - SisyfosLLAyer.SisyfosSourceGuest_3_ST_A, - SisyfosLLAyer.SisyfosSourceGuest_4_ST_A -] - -export const LIVE_AUDIO = [ - SisyfosLLAyer.SisyfosSourceLive_1, - SisyfosLLAyer.SisyfosSourceLive_2, - SisyfosLLAyer.SisyfosSourceLive_3, - SisyfosLLAyer.SisyfosSourceLive_4, - SisyfosLLAyer.SisyfosSourceLive_5, - SisyfosLLAyer.SisyfosSourceLive_6, - SisyfosLLAyer.SisyfosSourceLive_7, - SisyfosLLAyer.SisyfosSourceLive_8, - SisyfosLLAyer.SisyfosSourceLive_9, - SisyfosLLAyer.SisyfosSourceLive_10 -] - -export const STICKY_LAYERS = [...STUDIO_MICS, ...LIVE_AUDIO] - -describe('sisyfos', () => { - test('GetStickyForPiece', () => { - const result = GetStickyForPiece( - STUDIO_MICS.map<{ layer: SisyfosLLAyer; isPgm: 0 | 1 | 2 }>(layer => { - return { - layer, - isPgm: 1 - } - }), - STICKY_LAYERS - ) - expect(result).toEqual( - literal({ - stickySisyfosLevels: { - sisyfos_source_Host_1_st_a: { - value: 1, - followsPrevious: false - }, - sisyfos_source_Host_2_st_a: { - value: 1, - followsPrevious: false - }, - sisyfos_source_Guest_1_st_a: { - value: 1, - followsPrevious: false - }, - sisyfos_source_Guest_2_st_a: { - value: 1, - followsPrevious: false - }, - sisyfos_source_Guest_3_st_a: { - value: 1, - followsPrevious: false - }, - sisyfos_source_Guest_4_st_a: { - value: 1, - followsPrevious: false - } - } - }) - ) - }) -}) diff --git a/src/tv2_afvd_showstyle/helpers/studio.ts b/src/tv2_afvd_showstyle/helpers/studio.ts index c4e348b53..3113df726 100644 --- a/src/tv2_afvd_showstyle/helpers/studio.ts +++ b/src/tv2_afvd_showstyle/helpers/studio.ts @@ -1,4 +1,4 @@ -import { IStudioContext } from '@sofie-automation/blueprints-integration' +import { IStudioContext } from '@tv2media/blueprints-integration' /** * Gets the name of the studio this context belongs to. diff --git a/src/tv2_afvd_showstyle/helpers/time.ts b/src/tv2_afvd_showstyle/helpers/time.ts deleted file mode 100644 index fc6c8df2d..000000000 --- a/src/tv2_afvd_showstyle/helpers/time.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IBlueprintPart } from '@sofie-automation/blueprints-integration' -import { INewsStory, TimeFromINewsField } from 'tv2-common' - -export function GetTimeFromPart(story: INewsStory): Partial { - return { - expectedDuration: TimeFromINewsField(story.fields.audioTime), - prerollDuration: 0 - } -} diff --git a/src/tv2_afvd_showstyle/index.ts b/src/tv2_afvd_showstyle/index.ts index 104a220ac..e39af102f 100644 --- a/src/tv2_afvd_showstyle/index.ts +++ b/src/tv2_afvd_showstyle/index.ts @@ -1,4 +1,5 @@ -import { BlueprintManifestType, ShowStyleBlueprintManifest } from '@sofie-automation/blueprints-integration' +import { BlueprintManifestType, ShowStyleBlueprintManifest } from '@tv2media/blueprints-integration' +import { getShowStyleVariantId } from '../tv2-common/getShowStyleVariantId' import { showStyleConfigManifest } from './config-manifests' import { showStyleMigrations } from './migrations' @@ -6,7 +7,7 @@ import { GetShowStyleManifestWithMixins, ShowStyleManifestMixinINews } from 'ine import { getEndStateForPart, shouldRemoveOrphanedPartInstance } from 'tv2-common' import { onTimelineGenerateAFVD } from '../tv2_afvd_studio/onTimelineGenerate' import { executeActionAFVD } from './actions' -import { getRundown, getShowStyleVariantId } from './getRundown' +import { getRundown } from './getRundown' import { getSegment } from './getSegment' import { parseConfig } from './helpers/config' import { syncIngestUpdateToPartInstance } from './syncIngestUpdateToPartInstance' diff --git a/src/tv2_afvd_showstyle/layers.ts b/src/tv2_afvd_showstyle/layers.ts index 904163b23..2af817cd4 100644 --- a/src/tv2_afvd_showstyle/layers.ts +++ b/src/tv2_afvd_showstyle/layers.ts @@ -8,6 +8,7 @@ export enum AFVDSourceLayer { AuxStudioScreen = 'studio0_aux_studio_screen', PgmDVEBackground = 'studio0_dve_back', PgmFullBackground = 'studio0_full_back', + GraphicsShowLifecycle = 'studio0_graphic_show_lifecycle', // Wall WallGraphics = 'studio0_wall_graphics' diff --git a/src/tv2_afvd_showstyle/migrations/hotkeys.ts b/src/tv2_afvd_showstyle/migrations/hotkeys.ts new file mode 100644 index 000000000..979843c4b --- /dev/null +++ b/src/tv2_afvd_showstyle/migrations/hotkeys.ts @@ -0,0 +1,38 @@ +import { + ConfigManifestEntryTable, + MigrationContextShowStyle, + TableConfigItemValue +} from '@tv2media/blueprints-integration' +import { GlobalHotkeySources } from 'tv2-common' +import { + manifestAFVDSourcesCam, + manifestAFVDSourcesFeed, + manifestAFVDSourcesReplay, + manifestAFVDSourcesRM +} from '../../tv2_afvd_studio/config-manifests' +import { dveStylesManifest } from '../config-manifests' + +export function GetDefaultStudioSourcesForAFVD(context: MigrationContextShowStyle): GlobalHotkeySources { + const dveLayoutConfig = context.getBaseConfig('DVEStyles') as TableConfigItemValue | undefined + let dveLayouts: string[] = [] + if (dveLayoutConfig?.length) { + dveLayouts = dveLayoutConfig.map(dve => dve.DVEName).filter(name => name !== undefined) as string[] + } else { + dveLayouts = (dveStylesManifest as ConfigManifestEntryTable).defaultVal + .map(dve => dve.DVEName) + .filter(name => name !== undefined) as string[] + } + + const camera = manifestAFVDSourcesCam.defaultVal.map(source => source.SourceName) as string[] + const remote = manifestAFVDSourcesRM.defaultVal.map(source => source.SourceName) as string[] + const feed = manifestAFVDSourcesFeed.defaultVal.map(source => source.SourceName) as string[] + const replay = manifestAFVDSourcesReplay.defaultVal.map(source => source.SourceName) as string[] + + return { + camera, + remote, + feed, + local: replay, + dveLayouts + } +} diff --git a/src/tv2_afvd_showstyle/migrations/index.ts b/src/tv2_afvd_showstyle/migrations/index.ts index 7e30842de..302146dc7 100644 --- a/src/tv2_afvd_showstyle/migrations/index.ts +++ b/src/tv2_afvd_showstyle/migrations/index.ts @@ -1,22 +1,25 @@ -import { MigrationStepShowStyle } from '@sofie-automation/blueprints-integration' +import { MigrationStepShowStyle, SourceLayerType } from '@tv2media/blueprints-integration' import { AddGraphicToGFXTable, + changeGFXTemplate, + GetDefaultAdLibTriggers, GetDSKSourceLayerNames, - literal, + RemoveOldShortcuts, removeSourceLayer, - SetShortcutListMigrationStep, SetShowstyleTransitionMigrationStep, - SetSourceLayerNameMigrationStep, + SetSourceLayerName, + SetSourceLayerProperties, StripFolderFromAudioBedConfig, StripFolderFromDVEConfig, UpsertValuesIntoTransitionTable } from 'tv2-common' -import { GraphicLLayer } from 'tv2-constants' -import * as _ from 'underscore' +import { SharedGraphicLLayer } from 'tv2-constants' import { remapVizDOvl, remapVizLLayer } from '../../tv2_offtube_showstyle/migrations' import { remapTableColumnValues } from '../../tv2_offtube_showstyle/migrations/util' import { ATEMModel } from '../../types/atem' import { SourceLayer } from '../layers' +import { GetDefaultStudioSourcesForAFVD } from './hotkeys' +import sourcelayerDefaults from './sourcelayer-defaults' import { forceSourceLayerToDefaults, getOutputLayerDefaultsMigrationSteps, @@ -26,16 +29,14 @@ import { getCreateVariantMigrationSteps } from './variants-defaults' declare const VERSION: string // Injected by webpack -/** Migrations overriden later */ -// 1.3.1 -const jingle131 = SetShortcutListMigrationStep('1.3.1', SourceLayer.PgmJingle, 'NumpadDivide,NumpadSubtract,NumpadAdd') +const SHOW_STYLE_ID = 'tv2_afvd_showstyle' /** * Versions: * 0.1.0: Core 0.24.0 */ -export const showStyleMigrations: MigrationStepShowStyle[] = literal([ +export const showStyleMigrations: MigrationStepShowStyle[] = [ ...getCreateVariantMigrationSteps(), ...remapTableColumnValues('0.1.0', 'GFXTemplates', 'LayerMapping', remapVizLLayer), // Rename "viz-d-ovl" to "OVL1" @@ -45,24 +46,12 @@ export const showStyleMigrations: MigrationStepShowStyle[] = literal { - return literal({ + return { id: `${versionStr}.sourcelayer.defaults${force ? '.forced' : ''}.${defaultVal._id}`, version: versionStr, canBeRunAutomatically: true, @@ -38,7 +38,7 @@ export function getSourceLayerDefaultsMigrationSteps(versionStr: string, force?: context.insertSourceLayer(defaultVal._id, defaultVal) } } - }) + } }) ) } @@ -48,11 +48,11 @@ export function forceSourceLayerToDefaults( layer: string, overrideSteps?: string[] ): MigrationStepShowStyle { - return forceSourceLayerToDefaultsBase(SourcelayerDefaults, versionStr, layer, overrideSteps) + return forceSourceLayerToDefaultsBase(SourcelayerDefaults, versionStr, 'AFVD', layer, overrideSteps) } export function forceSettingToDefaults(versionStr: string, setting: string): MigrationStepShowStyle { - return literal({ + return { id: `${versionStr}.sourcelayer.defaults.${setting}.forced`, version: versionStr, canBeRunAutomatically: true, @@ -85,7 +85,7 @@ export function forceSettingToDefaults(versionStr: string, setting: string): Mig context.setBaseConfig(setting, defaultVal.defaultVal) } } - }) + } } export function getOutputLayerDefaultsMigrationSteps(versionStr: string): MigrationStepShowStyle[] { diff --git a/src/tv2_afvd_showstyle/migrations/variants-defaults.ts b/src/tv2_afvd_showstyle/migrations/variants-defaults.ts index 24f45aa3c..2767d6458 100644 --- a/src/tv2_afvd_showstyle/migrations/variants-defaults.ts +++ b/src/tv2_afvd_showstyle/migrations/variants-defaults.ts @@ -1,4 +1,4 @@ -import { MigrationContextShowStyle, MigrationStepShowStyle } from '@sofie-automation/blueprints-integration' +import { MigrationContextShowStyle, MigrationStepShowStyle } from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import * as _ from 'underscore' diff --git a/src/tv2_afvd_showstyle/parts/cueonly.ts b/src/tv2_afvd_showstyle/parts/cueonly.ts index a9227fb22..c378d7fb9 100644 --- a/src/tv2_afvd_showstyle/parts/cueonly.ts +++ b/src/tv2_afvd_showstyle/parts/cueonly.ts @@ -5,14 +5,13 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, ApplyFullGraphicPropertiesToPart, CueDefinition, GetJinglePartProperties, GraphicIsPilot, - literal, PartDefinition, PartTime } from 'tv2-common' @@ -21,7 +20,7 @@ import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' -export function CreatePartCueOnly( +export async function CreatePartCueOnly( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, @@ -34,11 +33,11 @@ export function CreatePartCueOnly( const partDefinitionWithID = { ...partDefinition, ...{ externalId: id } } const partTime = PartTime(config, partDefinitionWithID, totalWords, false) - let part = literal({ + let part: IBlueprintPart = { externalId: id, title, metaData: {} - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -52,17 +51,37 @@ export function CreatePartCueOnly( !partDefinition.cues.filter(c => c.type === CueType.Jingle).length ) { ApplyFullGraphicPropertiesToPart(config, part) - } else if (partDefinition.cues.filter(c => c.type === CueType.DVE).length) { - part.prerollDuration = config.studio.CasparPrerollDuration } - EvaluateCues(context, config, part, pieces, adLibPieces, actions, mediaSubscriptions, [cue], partDefinitionWithID, {}) + await EvaluateCues( + context, + config, + part, + pieces, + adLibPieces, + actions, + mediaSubscriptions, + [cue], + partDefinitionWithID, + {} + ) AddScript(partDefinitionWithID, pieces, partTime, SourceLayer.PgmScript) if (makeAdlibs) { - EvaluateCues(context, config, part, pieces, adLibPieces, actions, mediaSubscriptions, [cue], partDefinitionWithID, { - adlib: true - }) + await EvaluateCues( + context, + config, + part, + pieces, + adLibPieces, + actions, + mediaSubscriptions, + [cue], + partDefinitionWithID, + { + adlib: true + } + ) } part.hackListenToMediaObjectUpdates = mediaSubscriptions diff --git a/src/tv2_afvd_showstyle/parts/effekt.ts b/src/tv2_afvd_showstyle/parts/effekt.ts index 67b2b49d0..8cd6b8be9 100644 --- a/src/tv2_afvd_showstyle/parts/effekt.ts +++ b/src/tv2_afvd_showstyle/parts/effekt.ts @@ -1,4 +1,4 @@ -import { IBlueprintPiece, ISegmentUserContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintPiece, ISegmentUserContext } from '@tv2media/blueprints-integration' import { CreateEffektForPartBase, PartDefinition } from 'tv2-common' import { CasparLLayer, SisyfosLLAyer } from '../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../helpers/config' diff --git a/src/tv2_afvd_showstyle/parts/evs.ts b/src/tv2_afvd_showstyle/parts/evs.ts index 4a2b3459e..b2ab05004 100644 --- a/src/tv2_afvd_showstyle/parts/evs.ts +++ b/src/tv2_afvd_showstyle/parts/evs.ts @@ -7,78 +7,74 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan, - SourceLayerType, TimelineObjectCoreExt, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, CreatePartInvalid, EVSParentClass, - FindSourceInfoStrict, - GetSisyfosTimelineObjForCamera, - GetSisyfosTimelineObjForEVS, + findSourceInfo, + GetSisyfosTimelineObjForReplay, literal, PartDefinitionEVS, PartTime, + PieceMetaData, SourceInfo, - TimelineBlueprintExt, - TransitionFromString, TransitionSettings } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' -import { AtemLLayer, SisyfosLLAyer } from '../../tv2_afvd_studio/layers' +import { AtemLLayer } from '../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' import { CreateEffektForpart } from './effekt' -export function CreatePartEVS( +export async function CreatePartEVS( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinitionEVS, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) + const title = partDefinition.sourceDefinition.name - let part = literal({ + let part: IBlueprintPart = { externalId: partDefinition.externalId, - title: `EVS ${partDefinition.variant.evs} ${partDefinition.variant.isVO ? ' VO' : ''}`, + title, metaData: {}, expectedDuration: partTime > 0 ? partTime : 0 - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] const actions: IBlueprintActionManifest[] = [] const mediaSubscriptions: HackPartMediaObjectSubscription[] = [] part = { ...part, ...CreateEffektForpart(context, config, partDefinition, pieces) } - const sourceInfoDelayedPlayback = FindSourceInfoStrict( - context, - config.sources, - SourceLayerType.LOCAL, - partDefinition.rawType.replace(/ ?VO/i, '') - ) - if (sourceInfoDelayedPlayback === undefined) { + const sourceInfoReplay = findSourceInfo(config.sources, partDefinition.sourceDefinition) + if (sourceInfoReplay === undefined) { return CreatePartInvalid(partDefinition) } - const atemInput = sourceInfoDelayedPlayback.port + const atemInput = sourceInfoReplay.port - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: part.title, - enable: { start: 0 }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: SourceLayer.PgmLocal, - lifespan: PieceLifespan.WithinPart, - content: makeContentEVS(context, config, atemInput, partDefinition, sourceInfoDelayedPlayback) - }) - ) + pieces.push({ + externalId: partDefinition.externalId, + name: part.title, + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: SourceLayer.PgmLocal, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, + content: makeContentEVS(config, atemInput, partDefinition, sourceInfoReplay) + }) - EvaluateCues( + await EvaluateCues( context, config, part, @@ -107,11 +103,10 @@ export function CreatePartEVS( } function makeContentEVS( - context: ISegmentUserContext, config: BlueprintConfig, atemInput: number, partDefinition: PartDefinitionEVS, - sourceInfoDelayedPlayback: SourceInfo + sourceInfoReplay: SourceInfo ): IBlueprintPiece['content'] { return { studioLabel: '', @@ -130,41 +125,13 @@ function makeContentEVS( type: TSR.TimelineContentTypeAtem.ME, me: { input: atemInput, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) } }, - classes: [EVSParentClass('studio0', partDefinition.variant.evs)] + classes: [EVSParentClass('studio0', partDefinition.sourceDefinition.id)] }), - GetSisyfosTimelineObjForEVS(sourceInfoDelayedPlayback, partDefinition.variant.isVO), - ...(partDefinition.variant.isVO - ? [GetSisyfosTimelineObjForCamera(context, config, 'evs', SisyfosLLAyer.SisyfosGroupStudioMics)] - : [ - literal({ - id: '', - enable: { - start: 0 - }, - priority: 1, - layer: SisyfosLLAyer.SisyfosPersistedLevels, - content: { - deviceType: TSR.DeviceType.SISYFOS, - type: TSR.TimelineContentTypeSisyfos.CHANNELS, - overridePriority: 1, - channels: config.liveAudio.map(layer => { - return literal({ - mappedLayer: layer, - isPgm: 0 - }) - }) - }, - metaData: { - sisyfosPersistLevel: true - } - }) - ]) + ...GetSisyfosTimelineObjForReplay(config, sourceInfoReplay, partDefinition.sourceDefinition.vo) ]) } } diff --git a/src/tv2_afvd_showstyle/parts/grafik.ts b/src/tv2_afvd_showstyle/parts/grafik.ts index 519211a11..23b2121d1 100644 --- a/src/tv2_afvd_showstyle/parts/grafik.ts +++ b/src/tv2_afvd_showstyle/parts/grafik.ts @@ -6,32 +6,25 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { - AddScript, - ApplyFullGraphicPropertiesToPart, - GraphicIsPilot, - literal, - PartDefinition, - PartTime -} from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { AddScript, ApplyFullGraphicPropertiesToPart, GraphicIsPilot, PartDefinition, PartTime } from 'tv2-common' import { CueType } from 'tv2-constants' import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' -export function CreatePartGrafik( +export async function CreatePartGrafik( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) - const part = literal({ + const part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.type + ' - ' + partDefinition.rawType, metaData: {} - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -42,7 +35,7 @@ export function CreatePartGrafik( ApplyFullGraphicPropertiesToPart(config, part) } - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/intro.ts b/src/tv2_afvd_showstyle/parts/intro.ts index 9fbfc359d..d62a2c4a6 100644 --- a/src/tv2_afvd_showstyle/parts/intro.ts +++ b/src/tv2_afvd_showstyle/parts/intro.ts @@ -6,13 +6,12 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, CreatePartInvalid, CueDefinitionJingle, GetJinglePartProperties, - literal, PartDefinition, PartTime } from 'tv2-common' @@ -21,12 +20,12 @@ import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' -export function CreatePartIntro( +export async function CreatePartIntro( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) const jingleCue = partDefinition.cues.find(cue => { @@ -61,11 +60,11 @@ export function CreatePartIntro( return CreatePartInvalid(partDefinition) } - let part = literal({ + let part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.type + ' - ' + partDefinition.rawType, metaData: {} - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -77,7 +76,7 @@ export function CreatePartIntro( ...GetJinglePartProperties(context, config, partDefinition) } - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/kam.ts b/src/tv2_afvd_showstyle/parts/kam.ts index 67257c181..c280c73bf 100644 --- a/src/tv2_afvd_showstyle/parts/kam.ts +++ b/src/tv2_afvd_showstyle/parts/kam.ts @@ -6,12 +6,11 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan, - SourceLayerType, TimelineObjectCoreExt, TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddParentClass, AddScript, @@ -19,81 +18,80 @@ import { CreatePartInvalid, CreatePartKamBase, FindDSKJingle, - FindSourceInfoStrict, - GetCameraMetaData, - GetLayersForCamera, + findSourceInfo, GetSisyfosTimelineObjForCamera, literal, PartDefinitionKam, + PieceMetaData, TimeFromINewsField, - TransitionFromString, TransitionSettings } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' -import { AtemLLayer, SisyfosLLAyer } from '../../tv2_afvd_studio/layers' +import { AtemLLayer } from '../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' import { CreateEffektForpart } from './effekt' -export function CreatePartKam( +export async function CreatePartKam( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinitionKam, totalWords: number -): BlueprintResultPart { +): Promise { const partKamBase = CreatePartKamBase(context, config, partDefinition, totalWords) let part = partKamBase.part.part const partTime = partKamBase.duration const adLibPieces: IBlueprintAdLibPiece[] = [] - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] const actions: IBlueprintActionManifest[] = [] const mediaSubscriptions: HackPartMediaObjectSubscription[] = [] const jingleDSK = FindDSKJingle(config) if (partDefinition.rawType.match(/kam cs ?3/i)) { - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: 'CS 3 (JINGLE)', - enable: { start: 0 }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: SourceLayer.PgmJingle, - lifespan: PieceLifespan.WithinPart, - content: literal>({ - ignoreMediaObjectStatus: true, - fileName: '', - path: '', - timelineObjects: literal([ - literal({ - id: ``, - enable: { - start: 0 - }, - priority: 1, - layer: AtemLLayer.AtemMEProgram, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: jingleDSK.Fill, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } + pieces.push({ + externalId: partDefinition.externalId, + name: 'CS 3 (JINGLE)', + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: SourceLayer.PgmJingle, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, + content: literal>({ + ignoreMediaObjectStatus: true, + fileName: '', + path: '', + timelineObjects: literal([ + literal({ + id: ``, + enable: { + start: 0 + }, + priority: 1, + layer: AtemLLayer.AtemMEProgram, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: jingleDSK.Fill, + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) } - }) - ]) - }) + } + }) + ]) }) - ) + }) part.expectedDuration = TimeFromINewsField(partDefinition.fields.totalTime) * 1000 } else { - const sourceInfoCam = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, partDefinition.rawType) + const sourceInfoCam = findSourceInfo(config.sources, partDefinition.sourceDefinition) if (sourceInfoCam === undefined) { context.notifyUserWarning(`${partDefinition.rawType} does not exist in this studio`) return CreatePartInvalid(partDefinition) @@ -102,55 +100,50 @@ export function CreatePartKam( part = { ...part, ...CreateEffektForpart(context, config, partDefinition, pieces) } - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: part.title, - enable: { start: 0 }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: SourceLayer.PgmCam, - lifespan: PieceLifespan.WithinPart, - metaData: GetCameraMetaData(config, GetLayersForCamera(config, sourceInfoCam)), - content: { - studioLabel: '', - switcherInput: atemInput, - timelineObjects: literal([ - literal({ - id: ``, - enable: { - start: 0 - }, - priority: 1, - layer: AtemLLayer.AtemMEProgram, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: Number(atemInput), - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } - }, - ...(AddParentClass(config, partDefinition) - ? { classes: [CameraParentClass('studio0', partDefinition.variant.name)] } - : {}) - }), - - GetSisyfosTimelineObjForCamera( - context, - config, - partDefinition.rawType, - SisyfosLLAyer.SisyfosGroupStudioMics - ) - ]) + pieces.push({ + externalId: partDefinition.externalId, + name: part.title, + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: SourceLayer.PgmCam, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: sourceInfoCam.sisyfosLayers ?? [], + acceptPersistAudio: sourceInfoCam.acceptPersistAudio } - }) - ) + }, + content: { + studioLabel: '', + switcherInput: atemInput, + timelineObjects: literal([ + literal({ + id: ``, + enable: { + start: 0 + }, + priority: 1, + layer: AtemLLayer.AtemMEProgram, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: Number(atemInput), + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) + } + }, + ...(AddParentClass(config, partDefinition) + ? { classes: [CameraParentClass('studio0', partDefinition.sourceDefinition.id)] } + : {}) + }), + ...GetSisyfosTimelineObjForCamera(config, sourceInfoCam, partDefinition.sourceDefinition.minusMic) + ]) + } + }) } - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/live.ts b/src/tv2_afvd_showstyle/parts/live.ts index 70ca72745..6da5eb433 100644 --- a/src/tv2_afvd_showstyle/parts/live.ts +++ b/src/tv2_afvd_showstyle/parts/live.ts @@ -6,27 +6,27 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { AddScript, CueDefinitionEkstern, literal, PartDefinition, PartTime } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { AddScript, CueDefinitionEkstern, PartDefinition, PartTime } from 'tv2-common' import { CueType } from 'tv2-constants' import { BlueprintConfig } from '../../tv2_afvd_showstyle/helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' import { CreateEffektForpart } from './effekt' -export function CreatePartLive( +export async function CreatePartLive( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) - let part = literal({ + let part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.title || 'Ekstern', metaData: {}, expectedDuration: partTime > 0 ? partTime : 0 - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -35,7 +35,7 @@ export function CreatePartLive( part = { ...part, ...CreateEffektForpart(context, config, partDefinition, pieces) } - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/server.ts b/src/tv2_afvd_showstyle/parts/server.ts index 666528901..d0890b734 100644 --- a/src/tv2_afvd_showstyle/parts/server.ts +++ b/src/tv2_afvd_showstyle/parts/server.ts @@ -3,7 +3,7 @@ import { HackPartMediaObjectSubscription, IBlueprintActionManifest, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, CreatePartServerBase, PartDefinition, ServerPartProps } from 'tv2-common' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from '../../tv2_afvd_studio/layers' import { BlueprintConfig } from '../helpers/config' @@ -11,16 +11,16 @@ import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' import { CreateEffektForpart } from './effekt' -export function CreatePartServer( +export async function CreatePartServer( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, - props: ServerPartProps -): BlueprintResultPart { - const basePartProps = CreatePartServerBase(context, config, partDefinition, props, { + partProps: ServerPartProps +): Promise { + const basePartProps = await CreatePartServerBase(context, config, partDefinition, partProps, { SourceLayer: { - PgmServer: props.voLayer ? SourceLayer.PgmVoiceOver : SourceLayer.PgmServer, // TODO this actually is shared - SelectedServer: props.voLayer ? SourceLayer.SelectedVoiceOver : SourceLayer.SelectedServer + PgmServer: partProps.voLayer ? SourceLayer.PgmVoiceOver : SourceLayer.PgmServer, // TODO this actually is shared + SelectedServer: partProps.voLayer ? SourceLayer.SelectedVoiceOver : SourceLayer.SelectedServer }, AtemLLayer: { MEPgm: AtemLLayer.AtemMEProgram @@ -29,8 +29,7 @@ export function CreatePartServer( ClipPending: CasparLLayer.CasparPlayerClipPending }, Sisyfos: { - ClipPending: SisyfosLLAyer.SisyfosSourceClipPending, - StudioMicsGroup: SisyfosLLAyer.SisyfosGroupStudioMics + ClipPending: SisyfosLLAyer.SisyfosSourceClipPending }, ATEM: {} }) @@ -52,7 +51,7 @@ export function CreatePartServer( } AddScript(partDefinition, pieces, duration, SourceLayer.PgmScript) - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/teknik.ts b/src/tv2_afvd_showstyle/parts/teknik.ts index 7277f5579..f93bd2386 100644 --- a/src/tv2_afvd_showstyle/parts/teknik.ts +++ b/src/tv2_afvd_showstyle/parts/teknik.ts @@ -6,31 +6,31 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { AddScript, literal, PartDefinition, PartTime } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { AddScript, PartDefinition, PartTime } from 'tv2-common' import { BlueprintConfig } from '../helpers/config' import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' -export function CreatePartTeknik( +export async function CreatePartTeknik( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) - const part = literal({ + const part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.type + ' - ' + partDefinition.rawType, metaData: {} - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] const actions: IBlueprintActionManifest[] = [] const mediaSubscriptions: HackPartMediaObjectSubscription[] = [] - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/parts/unknown.ts b/src/tv2_afvd_showstyle/parts/unknown.ts index 50186d077..6f991fbe2 100644 --- a/src/tv2_afvd_showstyle/parts/unknown.ts +++ b/src/tv2_afvd_showstyle/parts/unknown.ts @@ -5,13 +5,12 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, ApplyFullGraphicPropertiesToPart, GetJinglePartProperties, GraphicIsPilot, - literal, PartDefinition, PartTime } from 'tv2-common' @@ -21,7 +20,7 @@ import { EvaluateCues } from '../helpers/pieces/evaluateCues' import { SourceLayer } from '../layers' import { CreateEffektForpart } from './effekt' -export function CreatePartUnknown( +export async function CreatePartUnknown( context: ISegmentUserContext, config: BlueprintConfig, partDefinition: PartDefinition, @@ -30,13 +29,13 @@ export function CreatePartUnknown( ) { const partTime = PartTime(config, partDefinition, totalWords, false) - let part = literal({ + let part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.type + ' - ' + partDefinition.rawType, metaData: {}, autoNext: false, expectedDuration: partTime - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -51,11 +50,9 @@ export function CreatePartUnknown( !partDefinition.cues.filter(c => c.type === CueType.Jingle).length ) { ApplyFullGraphicPropertiesToPart(config, part) - } else if (partDefinition.cues.filter(cue => cue.type === CueType.DVE).length) { - part.prerollDuration = config.studio.CasparPrerollDuration } - EvaluateCues( + await EvaluateCues( context, config, part, diff --git a/src/tv2_afvd_showstyle/postProcessTimelineObjects.ts b/src/tv2_afvd_showstyle/postProcessTimelineObjects.ts index b3b6405c4..14ace1ff0 100644 --- a/src/tv2_afvd_showstyle/postProcessTimelineObjects.ts +++ b/src/tv2_afvd_showstyle/postProcessTimelineObjects.ts @@ -8,11 +8,11 @@ import { TimelineObjectCoreExt, TimelineObjHoldMode, TSR -} from '@sofie-automation/blueprints-integration' -import { AtemLLayerDSK, FindDSKJingle, literal, TimelineBlueprintExt } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { AtemLLayerDSK, FindDSKJingle, TimelineBlueprintExt } from 'tv2-common' import * as _ from 'underscore' -import { BlueprintConfig } from '../tv2_afvd_studio/helpers/config' import { AtemLLayer } from '../tv2_afvd_studio/layers' +import { BlueprintConfig } from './helpers/config' import { SourceLayer } from './layers' export function postProcessPartTimelineObjects( @@ -72,7 +72,7 @@ export function postProcessPieceTimelineObjects( (tlObj.content.me.input !== -1 || tlObj.metaData?.mediaPlayerSession !== undefined) ) { // Create a lookahead-lookahead object for this me-program - const lookaheadObj = literal({ + const lookaheadObj: TSR.TimelineObjAtemAUX & TimelineBlueprintExt = { id: '', enable: { start: 0 }, priority: tlObj.holdMode === TimelineObjHoldMode.ONLY ? 5 : 0, // Must be below lookahead, except when forced by hold @@ -92,7 +92,7 @@ export function postProcessPieceTimelineObjects( context: `Lookahead-lookahead for ${tlObj.id}`, mediaPlayerSession: tlObj.metaData?.mediaPlayerSession // TODO - does this work the same? } - }) + } extraObjs.push(lookaheadObj) } @@ -120,28 +120,26 @@ export function postProcessPieceTimelineObjects( mixMinusSource = kamSources.length === 1 ? Number(kamSources[0].switcherInput) : null } if (mixMinusSource !== null && mixMinusSource !== -1) { - const mixMinusObj = literal({ + const mixMinusObj: TSR.TimelineObjAtemAUX & TimelineBlueprintExt = { ..._.omit(tlObj, 'content'), - ...literal>({ - id: '', - layer: AtemLLayer.AtemAuxVideoMixMinus, - priority: tlObj.classes?.includes('MIX_MINUS_OVERRIDE_DSK') ? 10 : tlObj.priority, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.AUX, - aux: { - input: - mixMinusSource !== undefined && mixMinusSource !== -1 - ? mixMinusSource - : config.studio.AtemSource.MixMinusDefault - } - }, - metaData: { - ...tlObj.metaData, - context: `Mix-minus for ${tlObj.id}` + id: '', + layer: AtemLLayer.AtemAuxVideoMixMinus, + priority: tlObj.classes?.includes('MIX_MINUS_OVERRIDE_DSK') ? 10 : tlObj.priority, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.AUX, + aux: { + input: + mixMinusSource !== undefined && mixMinusSource !== -1 + ? mixMinusSource + : config.studio.AtemSource.MixMinusDefault } - }) - }) + }, + metaData: { + ...tlObj.metaData, + context: `Mix-minus for ${tlObj.id}` + } + } mixMinusObj.classes = mixMinusObj.classes?.filter( c => !c.match(`studio0_parent_`) && !c.match('PLACEHOLDER_OBJECT_REMOVEME') ) @@ -163,28 +161,26 @@ export function postProcessPieceTimelineObjects( context.notifyUserWarning(`Unhandled Keyer properties for Clean keyer, it may look wrong`) } - const cleanObj = literal({ - ..._.omit(tlObj, 'content'), - ...literal>({ - id: '', - layer: AtemLLayer.AtemCleanUSKEffect, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - upstreamKeyers: [ - { - upstreamKeyerId: 0 - }, - { - upstreamKeyerId: 1, - ...newProps - } - ] - } + const cleanObj: TSR.TimelineObjAtemME & TimelineBlueprintExt = { + ..._.omit(tlObj, 'content', 'keyframes'), + id: '', + layer: AtemLLayer.AtemCleanUSKEffect, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + upstreamKeyers: [ + { + upstreamKeyerId: 0 + }, + { + upstreamKeyerId: 1, + ...newProps + } + ] } - }) - }) + } + } extraObjs.push(cleanObj) } }) diff --git a/src/tv2_afvd_showstyle/syncIngestUpdateToPartInstance.ts b/src/tv2_afvd_showstyle/syncIngestUpdateToPartInstance.ts index 60a1e9ee0..2aa947b25 100644 --- a/src/tv2_afvd_showstyle/syncIngestUpdateToPartInstance.ts +++ b/src/tv2_afvd_showstyle/syncIngestUpdateToPartInstance.ts @@ -2,7 +2,7 @@ import { BlueprintSyncIngestNewData, BlueprintSyncIngestPartInstance, ISyncIngestUpdateToPartInstanceContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { syncIngestUpdateToPartInstanceBase } from 'tv2-common' import * as _ from 'underscore' import { SourceLayer } from './layers' diff --git a/src/tv2_afvd_studio/__tests__/config-manifest.spec.ts b/src/tv2_afvd_studio/__tests__/config-manifest.spec.ts index 8f6533b0f..9130af842 100644 --- a/src/tv2_afvd_studio/__tests__/config-manifest.spec.ts +++ b/src/tv2_afvd_studio/__tests__/config-manifest.spec.ts @@ -33,8 +33,7 @@ const blankStudioConfig: StudioConfig = { SourcesCam: [], SourcesRM: [], SourcesFeed: [], - SourcesSkype: [], - SourcesDelayedPlayback: [], + SourcesReplay: [], ABMediaPlayers: [], StudioMics: [], ABPlaybackDebugLogging: false, @@ -45,7 +44,8 @@ const blankStudioConfig: StudioConfig = { SplitArtK: 0, Default: 0, MixMinusDefault: 0, - Continuity: 0 + Continuity: 0, + Dip: 0 }, AtemSettings: { MP1Baseline: { diff --git a/src/tv2_afvd_studio/__tests__/graphics.spec.ts b/src/tv2_afvd_studio/__tests__/graphics.spec.ts index 02a8c65c5..fab91a42a 100644 --- a/src/tv2_afvd_studio/__tests__/graphics.spec.ts +++ b/src/tv2_afvd_studio/__tests__/graphics.spec.ts @@ -1,4 +1,4 @@ -import { IBlueprintRundownDB, PieceLifespan, PlaylistTimingType, TSR } from '@sofie-automation/blueprints-integration' +import { IBlueprintRundownDB, PieceLifespan, PlaylistTimingType, TSR } from '@tv2media/blueprints-integration' import { CueDefinition, CueDefinitionBackgroundLoop, @@ -9,9 +9,10 @@ import { GraphicInternal, GraphicPilot, literal, - PartDefinition + PartDefinition, + RemoteType } from 'tv2-common' -import { CueType, GraphicLLayer, PartType, SharedOutputLayers } from 'tv2-constants' +import { CueType, PartType, SharedGraphicLLayer, SharedOutputLayers, SourceType } from 'tv2-constants' import { SegmentUserContext } from '../../__mocks__/context' import { defaultShowStyleConfig, defaultStudioConfig } from '../../tv2_afvd_showstyle/__tests__/configs' import { getConfig, parseConfig as parseShowStyleConfig } from '../../tv2_afvd_showstyle/helpers/config' @@ -49,7 +50,7 @@ function makeMockContext() { } describe('Graphics', () => { - it('Throws warning for unpaired target and creates invalid part', () => { + it('Throws warning for unpaired target and creates invalid part', async () => { const context = makeMockContext() const config = getConfig(context) @@ -63,7 +64,6 @@ describe('Graphics', () => { const partDefintion: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -74,7 +74,7 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefintion, 0) + const result = await CreatePartGrafik(context, config, partDefintion, 0) expect(context.getNotes().map(msg => msg.message)).toEqual([`No graphic found after GRAFIK cue`]) expect(result.pieces).toHaveLength(0) @@ -99,7 +99,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -115,7 +114,7 @@ describe('Graphics', () => { expect(context.getNotes().map(msg => msg.message)).toEqual([`Graphic found without target engine`]) }) - it('Creates FULL graphic correctly', () => { + it('Creates FULL graphic correctly', async () => { const context = makeMockContext() const config = getConfig(context) @@ -135,7 +134,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -146,23 +144,23 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefinition, 0) + const result = await CreatePartGrafik(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(2) const piece = result.pieces[0] expect(piece.sourceLayerId).toBe(SourceLayer.PgmPilot) expect(piece.outputLayerId).toBe(SharedOutputLayers.PGM) expect(piece.enable).toEqual({ start: 0 }) - expect(piece.adlibPreroll).toBe(config.studio.VizPilotGraphics.PrerollDuration) + // expect(piece.prerollDuration).toBe(config.studio.VizPilotGraphics.PrerollDuration) expect(piece.lifespan).toBe(PieceLifespan.WithinPart) const content = piece.content! const timeline = content.timelineObjects as TSR.TSRTimelineObj[] - expect(timeline).toHaveLength(20) + expect(timeline).toHaveLength(5) const vizObj = timeline.find( t => t.content.deviceType === TSR.DeviceType.VIZMSE && t.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT )! as TSR.TimelineObjVIZMSEElementPilot expect(vizObj.enable).toEqual({ start: 0 }) - expect(vizObj.layer).toEqual(GraphicLLayer.GraphicLLayerPilot) + expect(vizObj.layer).toEqual(SharedGraphicLLayer.GraphicLLayerPilot) expect(vizObj.content.channelName).toBe('FULL1') // TODO: FULL1: Enum / Type expect(vizObj.content.templateVcpId).toBe(1234567890) expect(vizObj.content.continueStep).toBe(-1) @@ -174,7 +172,7 @@ describe('Graphics', () => { expect(vizObj.classes).toEqual(['full']) }) - it('Creates OVL pilot graphic correctly', () => { + it('Creates OVL pilot graphic correctly', async () => { const context = makeMockContext() const config = getConfig(context) @@ -200,7 +198,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -211,13 +208,13 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefinition, 0) + const result = await CreatePartGrafik(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(1) const piece = result.pieces[0] expect(piece.sourceLayerId).toBe(SourceLayer.PgmPilotOverlay) expect(piece.outputLayerId).toBe(SharedOutputLayers.OVERLAY) expect(piece.enable).toEqual({ start: 2000 }) - expect(piece.adlibPreroll).toBe(config.studio.VizPilotGraphics.PrerollDuration) + expect(piece.prerollDuration).toBe(config.studio.VizPilotGraphics.PrerollDuration) expect(piece.lifespan).toBe(PieceLifespan.OutOnShowStyleEnd) const content = piece.content! const timeline = content.timelineObjects as TSR.TSRTimelineObj[] @@ -227,7 +224,7 @@ describe('Graphics', () => { t.content.deviceType === TSR.DeviceType.VIZMSE && t.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT )! as TSR.TimelineObjVIZMSEElementPilot expect(vizObj.enable).toEqual({ while: '!.full' }) - expect(vizObj.layer).toEqual(GraphicLLayer.GraphicLLayerPilotOverlay) + expect(vizObj.layer).toEqual(SharedGraphicLLayer.GraphicLLayerPilotOverlay) expect(vizObj.content.channelName).toBe('OVL1') // TODO: OVL1: Enum / Type expect(vizObj.content.templateVcpId).toBe(1234567890) expect(vizObj.content.continueStep).toBe(-1) @@ -238,7 +235,7 @@ describe('Graphics', () => { }) }) - it('Creates WALL graphic correctly', () => { + it('Creates WALL graphic correctly', async () => { const context = makeMockContext() const config = getConfig(context) @@ -258,7 +255,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -269,13 +265,13 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefinition, 0) + const result = await CreatePartGrafik(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(1) const piece = result.pieces[0] expect(piece.sourceLayerId).toBe(SourceLayer.WallGraphics) expect(piece.outputLayerId).toBe(SharedOutputLayers.SEC) expect(piece.enable).toEqual({ start: 0 }) - expect(piece.adlibPreroll).toBe(config.studio.VizPilotGraphics.PrerollDuration) + expect(piece.prerollDuration).toBe(config.studio.VizPilotGraphics.PrerollDuration) expect(piece.lifespan).toBe(PieceLifespan.OutOnShowStyleEnd) const content = piece.content! const timeline = content.timelineObjects as TSR.TSRTimelineObj[] @@ -285,7 +281,7 @@ describe('Graphics', () => { t.content.deviceType === TSR.DeviceType.VIZMSE && t.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT )! as TSR.TimelineObjVIZMSEElementPilot expect(vizObj.enable).toEqual({ while: '1' }) - expect(vizObj.layer).toEqual(GraphicLLayer.GraphicLLayerWall) + expect(vizObj.layer).toEqual(SharedGraphicLLayer.GraphicLLayerWall) expect(vizObj.content.channelName).toBe('WALL1') // TODO: OVL1: Enum / Type expect(vizObj.content.templateVcpId).toBe(1234567890) expect(vizObj.content.continueStep).toBe(-1) @@ -293,7 +289,7 @@ describe('Graphics', () => { expect(vizObj.content.outTransition).toEqual(undefined) }) - it('Creates TLF graphic correctly', () => { + it('Creates TLF graphic correctly', async () => { const context = makeMockContext() const config = getConfig(context) @@ -313,7 +309,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -324,23 +319,23 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefinition, 0) + const result = await CreatePartGrafik(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(2) const piece = result.pieces[0] expect(piece.sourceLayerId).toBe(SourceLayer.PgmGraphicsTLF) expect(piece.outputLayerId).toBe(SharedOutputLayers.PGM) expect(piece.enable).toEqual({ start: 0 }) - expect(piece.adlibPreroll).toBe(config.studio.VizPilotGraphics.PrerollDuration) + expect(piece.prerollDuration).toBe(config.studio.VizPilotGraphics.PrerollDuration) expect(piece.lifespan).toBe(PieceLifespan.WithinPart) const content = piece.content! const timeline = content.timelineObjects as TSR.TSRTimelineObj[] - expect(timeline).toHaveLength(20) + expect(timeline).toHaveLength(5) const vizObj = timeline.find( t => t.content.deviceType === TSR.DeviceType.VIZMSE && t.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_PILOT )! as TSR.TimelineObjVIZMSEElementPilot expect(vizObj.enable).toEqual({ start: 0 }) - expect(vizObj.layer).toEqual(GraphicLLayer.GraphicLLayerPilot) + expect(vizObj.layer).toEqual(SharedGraphicLLayer.GraphicLLayerPilot) expect(vizObj.content.channelName).toBe('FULL1') // TODO: FULL1: Enum / Type expect(vizObj.content.templateVcpId).toBe(1234567890) expect(vizObj.content.continueStep).toBe(-1) @@ -352,7 +347,7 @@ describe('Graphics', () => { expect(vizObj.classes).toEqual(['full']) }) - it('Routes source to engine', () => { + it('Routes source to engine', async () => { const context = makeMockContext() const config = getConfig(context) @@ -363,7 +358,7 @@ describe('Graphics', () => { routing: { type: CueType.Routing, target: 'TLF', - INP1: 'LIVE 1', + INP1: { sourceType: SourceType.REMOTE, id: '1', name: 'LIVE 1', raw: 'LIVE 1', remoteType: RemoteType.LIVE }, iNewsCommand: '' }, graphic: { @@ -378,7 +373,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Grafik, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -389,7 +383,7 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartGrafik(context, config, partDefinition, 0) + const result = await CreatePartGrafik(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(3) const auxPiece = result.pieces.find(p => p.outputLayerId === SharedOutputLayers.AUX)! expect(auxPiece.enable).toEqual({ start: 0 }) @@ -404,7 +398,7 @@ describe('Graphics', () => { expect(auxObj?.content.aux.input).toBe(1) }) - it('Creates design element', () => { + it('Creates design element', async () => { const context = makeMockContext() const config = getConfig(context) @@ -418,7 +412,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Unknown, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -429,7 +422,7 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartUnknown(context, config, partDefinition, 0) + const result = await CreatePartUnknown(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(1) const piece = result.pieces[0] expect(piece).toBeTruthy() @@ -439,7 +432,7 @@ describe('Graphics', () => { expect(piece.enable).toEqual({ start: 0 }) }) - it('Creates background loop', () => { + it('Creates background loop', async () => { const context = makeMockContext() const config = getConfig(context) @@ -454,7 +447,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Unknown, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -465,7 +457,7 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartUnknown(context, config, partDefinition, 0) + const result = await CreatePartUnknown(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(1) const piece = result.pieces[0] expect(piece).toBeTruthy() @@ -483,7 +475,7 @@ describe('Graphics', () => { expect(tlObj?.content.loop).toBe(true) }) - it('Creates overlay internal graphic', () => { + it('Creates overlay internal graphic', async () => { const context = makeMockContext() const config = getConfig(context) @@ -506,7 +498,6 @@ describe('Graphics', () => { const partDefinition: PartDefinition = literal({ type: PartType.Unknown, - variant: {}, externalId: '', segmentExternalId: SEGMENT_EXTERNAL_ID, rawType: '', @@ -517,7 +508,7 @@ describe('Graphics', () => { storyName: '' }) - const result = CreatePartUnknown(context, config, partDefinition, 0) + const result = await CreatePartUnknown(context, config, partDefinition, 0) expect(result.pieces).toHaveLength(1) const piece = result.pieces[0] expect(piece).toBeTruthy() @@ -531,7 +522,7 @@ describe('Graphics', () => { obj.content.type === TSR.TimelineContentTypeVizMSE.ELEMENT_INTERNAL ) as TSR.TimelineObjVIZMSEElementInternal | undefined expect(tlObj).toBeTruthy() - expect(tlObj?.layer).toBe(GraphicLLayer.GraphicLLayerOverlayLower) + expect(tlObj?.layer).toBe(SharedGraphicLLayer.GraphicLLayerOverlayLower) expect(tlObj?.content.templateName).toBe('bund') expect(tlObj?.content.templateData).toStrictEqual(['Some Person', 'Some Info']) expect(tlObj?.content.channelName).toBe('OVL1') diff --git a/src/tv2_afvd_studio/config-manifests.ts b/src/tv2_afvd_studio/config-manifests.ts index dc254a3eb..9998bbe39 100644 --- a/src/tv2_afvd_studio/config-manifests.ts +++ b/src/tv2_afvd_studio/config-manifests.ts @@ -4,7 +4,7 @@ import { ConfigManifestEntryType, TableConfigItemValue, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { DSKConfigManifest, literal, @@ -12,7 +12,6 @@ import { MakeConfigWithMediaFlow, TableConfigItemSourceMapping } from 'tv2-common' -import * as _ from 'underscore' import { AtemSourceIndex } from '../types/atem' import { defaultDSKConfig } from './helpers/config' import { SisyfosLLAyer } from './layers' @@ -28,7 +27,7 @@ const DEFAULT_STUDIO_MICS_LAYERS = [ SisyfosLLAyer.SisyfosSourceGuest_4_ST_A ] -export const manifestAFVDSourcesCam = MakeConfigForSources('Cam', 'Camera', false, [ +export const manifestAFVDSourcesCam = MakeConfigForSources('Cam', 'Camera', false, true, [ { _id: '', SourceName: '1', @@ -101,14 +100,15 @@ export const manifestAFVDSourcesCam = MakeConfigForSources('Cam', 'Camera', fals } ]) -export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ +export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, true, [ { _id: '', SourceName: '1', AtemSource: 1, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_1], - StudioMics: false, - KeepAudioInStudio: true + StudioMics: true, + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -116,7 +116,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 2, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_2], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudion: false }, { _id: '', @@ -124,7 +125,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 3, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_3], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -132,7 +134,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 4, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_4], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -140,7 +143,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 5, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_5], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -148,7 +152,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 6, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_6], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -156,7 +161,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 7, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_7], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -164,7 +170,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 8, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_8], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -172,7 +179,8 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 9, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_9], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false }, { _id: '', @@ -180,13 +188,14 @@ export const manifestAFVDSourcesRM = MakeConfigForSources('RM', 'Live', true, [ AtemSource: 10, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_10], StudioMics: false, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false } ]) -export const manifestAFVDSourcesFeed = MakeConfigForSources('Feed', 'Feed', true, []) +export const manifestAFVDSourcesFeed = MakeConfigForSources('Feed', 'Feed', true, false, []) -export const manifestAFVDSourcesDelayedPlayback = MakeConfigForSources('DelayedPlayback', 'EVS', false, [ +export const manifestAFVDSourcesReplay = MakeConfigForSources('Replay', 'Replay', false, false, [ { _id: '', SourceName: '1', @@ -200,79 +209,13 @@ export const manifestAFVDSourcesDelayedPlayback = MakeConfigForSources('DelayedP AtemSource: 23, SisyfosLayers: [SisyfosLLAyer.SisyfosSourceEVS_2], StudioMics: true - } -]) - -export const manifestAFVDSourcesSkype = MakeConfigForSources('Skype', 'Skype', false, [ - { - _id: '', - SourceName: '1', - AtemSource: 1, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_1], - StudioMics: false - }, - { - _id: '', - SourceName: '2', - AtemSource: 2, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_2], - StudioMics: false - }, - { - _id: '', - SourceName: '3', - AtemSource: 3, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_3], - StudioMics: false - }, - { - _id: '', - SourceName: '4', - AtemSource: 4, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_4], - StudioMics: false - }, - { - _id: '', - SourceName: '5', - AtemSource: 5, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_5], - StudioMics: false }, { _id: '', - SourceName: '6', - AtemSource: 6, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_6], - StudioMics: false - }, - { - _id: '', - SourceName: '7', - AtemSource: 7, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_7], - StudioMics: false - }, - { - _id: '', - SourceName: '8', - AtemSource: 8, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_8], - StudioMics: false - }, - { - _id: '', - SourceName: '9', - AtemSource: 9, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_9], - StudioMics: false - }, - { - _id: '', - SourceName: '10', - AtemSource: 10, - SisyfosLayers: [SisyfosLLAyer.SisyfosSourceLive_10], - StudioMics: false + SourceName: 'EPSIO', + AtemSource: 25, + SisyfosLayers: [SisyfosLLAyer.SisyfosSourceEpsio], + StudioMics: true } ]) @@ -308,7 +251,7 @@ export const manifestAFVDSourcesABMediaPlayers: ConfigManifestEntryTable = { id: 'AtemSource', name: 'ATEM input', description: 'ATEM vision mixer input for Media player', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 1 @@ -340,8 +283,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ manifestAFVDSourcesCam, manifestAFVDSourcesRM, manifestAFVDSourcesFeed, - manifestAFVDSourcesDelayedPlayback, - manifestAFVDSourcesSkype, + manifestAFVDSourcesReplay, manifestAFVDSourcesABMediaPlayers, manifestAFVDStudioMics, manifestAFVDDownstreamKeyers, @@ -357,7 +299,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.SplitArtF', name: 'ATEM Split Screen Art Fill', description: 'ATEM vision mixer input for Split Screen Art Fill', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 30 }, @@ -365,7 +307,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.SplitArtK', name: 'ATEM Split Screen Art Key', description: 'ATEM vision mixer input for Split Screen Art Key', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 32 }, @@ -373,7 +315,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.Default', name: 'ATEM Default source', description: 'ATEM vision mixer default source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: AtemSourceIndex.Col1 }, @@ -381,7 +323,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.MixMinusDefault', name: 'ATEM Mix-minus default source', description: 'ATEM vision mixer default source for mix-minus', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: AtemSourceIndex.Col1 }, @@ -389,7 +331,15 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.Continuity', name: 'ATEM continuity source', description: 'ATEM input for continuity', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, + required: true, + defaultVal: AtemSourceIndex.Col2 + }, + { + id: 'AtemSource.Dip', + name: 'ATEM Dip Source', + description: 'ATEM input for the Dip - should match the desired input in the ATEM', + type: ConfigManifestEntryType.INT, required: true, defaultVal: AtemSourceIndex.Col2 }, @@ -397,7 +347,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSettings.MP1Baseline.Clip', name: 'ATEM MP1 baseline clip number', description: 'Number of the clip to play on MP1 (counting from 1)', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 1 }, @@ -421,7 +371,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.fadeIn', name: 'Bed Fade In', description: 'Default fade in duration for audio beds', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 25 }, @@ -429,7 +379,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.volume', name: 'Bed Volume', description: 'Volume (0 - 100)', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 80 }, @@ -437,7 +387,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.fadeOut', name: 'Bed Fade Out', description: 'Default fade out duration for audio beds', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 25 }, @@ -445,7 +395,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'CasparPrerollDuration', name: 'Caspar preroll duration', description: 'ms of preroll before switching to caspar', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 200 // 5 frames }, @@ -453,7 +403,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'MaximumPartDuration', name: 'Maximum Part Duration', description: 'Maximum duration (ms) to give parts in UI', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 10000 }, @@ -461,7 +411,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'DefaultPartDuration', name: 'Default Part Duration', description: 'Duration to give parts by default', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 4000 }, @@ -469,7 +419,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'ServerPostrollDuration', name: 'Server Postroll Duration', description: 'ms of postroll at the end of Server and VO clips', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0 }, @@ -496,7 +446,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.KeepAliveDuration', name: 'Full Keep Alive Duration (HTML)', description: 'How long to keep the old part alive when going to a full', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 1000 }, @@ -504,7 +454,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.borderSoftness', name: 'Full graphic wipe softness (HTML)', description: 'Border softness of full graphic background wipe', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 7500 }, @@ -512,7 +462,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.loopOutTransitionDuration', name: 'Full graphic background loop out transition duration', description: 'Duration (ms) that the background loop behind a full takes to transition out', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 120 }, @@ -520,7 +470,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.wipeRate', name: 'Full graphic background loop wipe duration (HTML)', description: 'Frames (max 250) over which to wipe background loop behind Full', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 10 }, @@ -528,7 +478,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.CutToMediaPlayer', name: 'Pilot media Player Cut Point', description: 'ms from start of grafik before switching to background source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 500 }, @@ -536,7 +486,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.FullGraphicBackground', name: 'Full frame grafik background source', description: 'ATEM source for mos full-frame grafik background source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 36 }, @@ -544,7 +494,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.KeepAliveDuration', name: 'Pilot Keepalive Duration', description: 'ms to keep old part alive before switching to Pilot elements', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 2000 }, @@ -552,7 +502,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.OutTransitionDuration', name: 'Pilot Out Transition Duration', description: 'ms to keep pilot elements alive before transition to next part', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 1000 }, @@ -560,7 +510,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.PrerollDuration', name: 'Pilot Preroll Duration', description: 'ms of preroll before switching to Pilot elements', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 2000 }, diff --git a/src/tv2_afvd_studio/getBaseline.ts b/src/tv2_afvd_studio/getBaseline.ts index cf2021d7f..96220025b 100644 --- a/src/tv2_afvd_studio/getBaseline.ts +++ b/src/tv2_afvd_studio/getBaseline.ts @@ -4,13 +4,14 @@ import { BlueprintResultBaseline, IStudioContext, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import * as _ from 'underscore' +import { SharedGraphicLLayer } from '../tv2-constants' import { AtemSourceIndex } from '../types/atem' import { getStudioConfig } from './helpers/config' import { AtemLLayer, SisyfosLLAyer } from './layers' -import { SisyfosChannel, sisyfosChannels } from './sisyfosChannels' +import { sisyfosChannels } from './sisyfosChannels' function filterMappings( input: BlueprintMappings, @@ -47,7 +48,7 @@ export function getBaseline(context: IStudioContext): BlueprintResultBaseline { const mappedChannels: TSR.TimelineObjSisyfosChannels['content']['channels'] = [] for (const id in sisyfosMappings) { if (sisyfosMappings[id]) { - const sisyfosChannel = sisyfosChannels[id as SisyfosLLAyer] as SisyfosChannel | undefined + const sisyfosChannel = sisyfosChannels[id as SisyfosLLAyer] if (sisyfosChannel) { mappedChannels.push({ mappedLayer: id, @@ -157,6 +158,16 @@ export function getBaseline(context: IStudioContext): BlueprintResultBaseline { clipFrame: 0 } } + }), + literal({ + id: '', + enable: { while: '1' }, + layer: SharedGraphicLLayer.GraphicLLayerConcept, + content: { + deviceType: TSR.DeviceType.VIZMSE, + type: TSR.TimelineContentTypeVizMSE.CONCEPT, + concept: '' + } }) ] } diff --git a/src/tv2_afvd_studio/getShowStyleId.ts b/src/tv2_afvd_studio/getShowStyleId.ts index 7848aeb8c..1c2406d12 100644 --- a/src/tv2_afvd_studio/getShowStyleId.ts +++ b/src/tv2_afvd_studio/getShowStyleId.ts @@ -1,4 +1,4 @@ -import { IBlueprintShowStyleBase, IngestRundown, IStudioContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintShowStyleBase, IngestRundown, IStudioContext } from '@tv2media/blueprints-integration' import * as _ from 'underscore' export function getShowStyleId( diff --git a/src/tv2_afvd_studio/helpers/config.ts b/src/tv2_afvd_studio/helpers/config.ts index 4e2613fe3..2eb9c2028 100644 --- a/src/tv2_afvd_studio/helpers/config.ts +++ b/src/tv2_afvd_studio/helpers/config.ts @@ -1,26 +1,21 @@ -import { IBlueprintConfig, ICommonContext, IStudioContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintConfig, ICommonContext, IStudioContext } from '@tv2media/blueprints-integration' import { - getLiveAudioLayers, - getStickyLayers, MediaPlayerConfig, - SourceInfo, + SourceMapping, TableConfigItemDSK, TableConfigItemSourceMapping, TableConfigItemSourceMappingWithSisyfos, TV2StudioConfigBase } from 'tv2-common' import { DSKRoles } from 'tv2-constants' -import * as _ from 'underscore' import { ShowStyleConfig } from '../../tv2_afvd_showstyle/helpers/config' import { parseMediaPlayers, parseSources } from './sources' export interface BlueprintConfig { studio: StudioConfig - sources: SourceInfo[] + sources: SourceMapping showStyle: ShowStyleConfig mediaPlayers: MediaPlayerConfig // Atem Input Ids - liveAudio: string[] - stickyLayers: string[] dsk: TableConfigItemDSK[] } @@ -28,7 +23,7 @@ export interface StudioConfig extends TV2StudioConfigBase { // Injected by core SofieHostURL: string - SourcesDelayedPlayback: TableConfigItemSourceMappingWithSisyfos[] + SourcesReplay: TableConfigItemSourceMappingWithSisyfos[] ABMediaPlayers: TableConfigItemSourceMapping[] ABPlaybackDebugLogging: boolean StudioMics: string[] @@ -40,6 +35,7 @@ export interface StudioConfig extends TV2StudioConfigBase { Default: number MixMinusDefault: number Continuity: number + Dip: number } AtemSettings: { @@ -56,18 +52,11 @@ export function parseConfig(_context: ICommonContext, rawConfig: IBlueprintConfi const config: BlueprintConfig = { studio: studioConfig, showStyle: {} as any, - sources: [], - mediaPlayers: [], - liveAudio: [], - stickyLayers: [], + sources: parseSources(studioConfig), + mediaPlayers: parseMediaPlayers(studioConfig), dsk: studioConfig.AtemSource.DSK } - config.sources = parseSources(studioConfig) - config.mediaPlayers = parseMediaPlayers(studioConfig) - config.liveAudio = getLiveAudioLayers(studioConfig) - config.stickyLayers = getStickyLayers(studioConfig, config.liveAudio) - return config } diff --git a/src/tv2_afvd_studio/helpers/sources.ts b/src/tv2_afvd_studio/helpers/sources.ts index 4cd9a9ba5..dd5edeb23 100644 --- a/src/tv2_afvd_studio/helpers/sources.ts +++ b/src/tv2_afvd_studio/helpers/sources.ts @@ -1,7 +1,7 @@ import * as _ from 'underscore' -import { SourceLayerType } from '@sofie-automation/blueprints-integration' -import { ParseMappingTable, SourceInfo } from 'tv2-common' +import { SourceLayerType } from '@tv2media/blueprints-integration' +import { ParseMappingTable, SourceInfoType, SourceMapping } from 'tv2-common' import { StudioConfig } from './config' export function parseMediaPlayers(studioConfig: StudioConfig): Array<{ id: string; val: string }> { @@ -11,12 +11,11 @@ export function parseMediaPlayers(studioConfig: StudioConfig): Array<{ id: strin })) } -export function parseSources(studioConfig: StudioConfig): SourceInfo[] { - return [ - ...ParseMappingTable(studioConfig.SourcesFeed, SourceLayerType.REMOTE, 'F'), - ...ParseMappingTable(studioConfig.SourcesRM, SourceLayerType.REMOTE), - ...ParseMappingTable(studioConfig.SourcesCam, SourceLayerType.CAMERA), - ...ParseMappingTable(studioConfig.SourcesSkype, SourceLayerType.REMOTE, 'S'), - ...ParseMappingTable(studioConfig.SourcesDelayedPlayback, SourceLayerType.LOCAL, 'DP') - ] +export function parseSources(studioConfig: StudioConfig): SourceMapping { + return { + cameras: ParseMappingTable(studioConfig.SourcesCam, SourceInfoType.KAM, SourceLayerType.CAMERA), + feeds: ParseMappingTable(studioConfig.SourcesFeed, SourceInfoType.FEED, SourceLayerType.REMOTE), + lives: ParseMappingTable(studioConfig.SourcesRM, SourceInfoType.LIVE, SourceLayerType.REMOTE), + replays: ParseMappingTable(studioConfig.SourcesReplay, SourceInfoType.REPLAY, SourceLayerType.LOCAL) + } } diff --git a/src/tv2_afvd_studio/index.ts b/src/tv2_afvd_studio/index.ts index 502c00a41..2c5ad9b55 100644 --- a/src/tv2_afvd_studio/index.ts +++ b/src/tv2_afvd_studio/index.ts @@ -1,4 +1,4 @@ -import { BlueprintManifestType, StudioBlueprintManifest } from '@sofie-automation/blueprints-integration' +import { BlueprintManifestType, StudioBlueprintManifest } from '@tv2media/blueprints-integration' import { GetStudioManifestWithMixins, StudioManifestMixinINews } from 'inews-mixins' import * as _ from 'underscore' import { studioConfigManifest } from './config-manifests' diff --git a/src/tv2_afvd_studio/layers.ts b/src/tv2_afvd_studio/layers.ts index 0d1b00a31..da63cf864 100644 --- a/src/tv2_afvd_studio/layers.ts +++ b/src/tv2_afvd_studio/layers.ts @@ -1,4 +1,10 @@ -import { AbstractLLayer, GraphicLLayer, SharedATEMLLayer, SharedCasparLLayer, SharedSisyfosLLayer } from 'tv2-constants' +import { + AbstractLLayer, + SharedATEMLLayer, + SharedCasparLLayer, + SharedGraphicLLayer, + SharedSisyfosLLayer +} from 'tv2-constants' import * as _ from 'underscore' export type LLayer = VirtualAbstractLLayer | AtemLLayer | CasparLLayer | SisyfosLLAyer @@ -70,9 +76,21 @@ export const CasparLLayer = { export type CasparLLayer = AFVDCasparLLayer | SharedCasparLLayer -enum AFVDSisyfosLLAyer { +enum AFVDGraphicLLayer { + GraphicLLayerInitialize = 'graphic_initialize', + GraphicLLayerCleanup = 'graphic_cleanup' +} + +// tslint:disable-next-line: variable-name +export const GraphicLLayer = { + ...AFVDGraphicLLayer, + ...SharedGraphicLLayer +} + +export type GraphicLLayer = AFVDGraphicLLayer | SharedGraphicLLayer + +enum AFVDSisyfosLLayer { SisyfosConfig = 'sisyfos_config', - SisyfosGroupStudioMics = 'sisyfos_group_studio_mics', SisyfosPersistedLevels = 'sisyfos_persisted_levels', SisyfosSourceClipPending = 'sisyfos_source_clip_pending', SisyfosSourceJingle = 'sisyfos_source_jingle', @@ -103,13 +121,14 @@ enum AFVDSisyfosLLAyer { SisyfosSourceServerB = 'sisyfos_source_server_b', // SisyfosSourceServerC = 'sisyfos_source_server_c', SisyfosSourceEVS_1 = 'sisyfos_source_evs_1', - SisyfosSourceEVS_2 = 'sisyfos_source_evs_2' + SisyfosSourceEVS_2 = 'sisyfos_source_evs_2', + SisyfosSourceEpsio = 'sisyfos_source_epsio' } // tslint:disable-next-line: variable-name export const SisyfosLLAyer = { ...SharedSisyfosLLayer, - ...AFVDSisyfosLLAyer + ...AFVDSisyfosLLayer } -export type SisyfosLLAyer = SharedSisyfosLLayer | AFVDSisyfosLLAyer +export type SisyfosLLAyer = SharedSisyfosLLayer | AFVDSisyfosLLayer diff --git a/src/tv2_afvd_studio/migrations/devices.ts b/src/tv2_afvd_studio/migrations/devices.ts index 74dc8e7d1..ae375657d 100644 --- a/src/tv2_afvd_studio/migrations/devices.ts +++ b/src/tv2_afvd_studio/migrations/devices.ts @@ -4,8 +4,7 @@ import { MigrationStepInputFilteredResult, MigrationStepStudio, TSR -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' import * as _ from 'underscore' declare const VERSION: string // Injected by webpack @@ -218,10 +217,10 @@ const devices: DeviceEntry[] = [ } ] -export const deviceMigrations = literal([ +export const deviceMigrations: MigrationStepStudio[] = [ // create all devices ..._.map(devices, createDevice), // ensure all devices still look valid ..._.map(devices, validateDevice) -]) +] diff --git a/src/tv2_afvd_studio/migrations/index.ts b/src/tv2_afvd_studio/migrations/index.ts index 7d82250c8..421ec2d1a 100644 --- a/src/tv2_afvd_studio/migrations/index.ts +++ b/src/tv2_afvd_studio/migrations/index.ts @@ -1,23 +1,22 @@ -import { MigrationStepStudio, TSR } from '@sofie-automation/blueprints-integration' +import { MigrationStepStudio, TSR } from '@tv2media/blueprints-integration' import { AddKeepAudio, - literal, + addSourceToSourcesConfig, MoveClipSourcePath, MoveSourcesToTable, + PrefixEvsWithEvs, RemoveConfig, RenameStudioConfig, SetConfigTo, SetLayerNamesToDefaults } from 'tv2-common' -import { GraphicLLayer } from 'tv2-constants' -import * as _ from 'underscore' +import { SharedGraphicLLayer } from 'tv2-constants' import { manifestAFVDDownstreamKeyers, manifestAFVDSourcesABMediaPlayers, manifestAFVDSourcesCam, - manifestAFVDSourcesDelayedPlayback, + manifestAFVDSourcesReplay, manifestAFVDSourcesRM, - manifestAFVDSourcesSkype, manifestAFVDStudioMics } from '../config-manifests' import { CasparLLayer, SisyfosLLAyer } from '../layers' @@ -40,7 +39,7 @@ declare const VERSION: string // Injected by webpack * 0.1.0: Core 0.24.0 */ -export const studioMigrations: MigrationStepStudio[] = literal([ +export const studioMigrations: MigrationStepStudio[] = [ ensureStudioConfig( '0.1.0', 'SourcesCam', @@ -64,21 +63,11 @@ export const studioMigrations: MigrationStepStudio[] = literal({ @@ -331,6 +330,15 @@ export const MAPPINGS_SISYFOS: BlueprintMappings = { mappingType: TSR.MappingSisyfosType.CHANNEL, setLabelToLayerName: true }), + [SisyfosLLAyer.SisyfosSourceEpsio]: literal({ + device: TSR.DeviceType.SISYFOS, + deviceId: 'sisyfos0', + layerName: 'EPSIO', + channel: 29, + lookahead: LookaheadMode.NONE, + mappingType: TSR.MappingSisyfosType.CHANNEL, + setLabelToLayerName: true + }), [SisyfosLLAyer.SisyfosResync]: literal({ device: TSR.DeviceType.SISYFOS, deviceId: 'sisyfos0', @@ -536,6 +544,24 @@ export const MAPPINGS_GRAPHICS: BlueprintMappings = { deviceId: 'viz0', layerName: 'GFX Full Loop', lookahead: LookaheadMode.NONE + }), + [GraphicLLayer.GraphicLLayerConcept]: literal({ + device: TSR.DeviceType.VIZMSE, + deviceId: 'viz0', + layerName: 'Override Concept', + lookahead: LookaheadMode.NONE + }), + [GraphicLLayer.GraphicLLayerInitialize]: literal({ + device: TSR.DeviceType.VIZMSE, + deviceId: 'viz0', + layerName: 'GFX Show Initialization', + lookahead: LookaheadMode.NONE + }), + [GraphicLLayer.GraphicLLayerCleanup]: literal({ + device: TSR.DeviceType.VIZMSE, + deviceId: 'viz0', + layerName: 'GFX Show Cleanup', + lookahead: LookaheadMode.NONE }) } diff --git a/src/tv2_afvd_studio/migrations/util.ts b/src/tv2_afvd_studio/migrations/util.ts index b78f0a6ca..c3e270763 100644 --- a/src/tv2_afvd_studio/migrations/util.ts +++ b/src/tv2_afvd_studio/migrations/util.ts @@ -6,8 +6,7 @@ import { MigrationStepInputFilteredResult, MigrationStepStudio, TSR -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' import * as _ from 'underscore' import { SisyfosLLAyer } from '../layers' import MappingsDefaults from './mappings-defaults' @@ -132,9 +131,9 @@ export function removeMapping(version: string, oldMappingName: string): Migratio } export function getMappingsDefaultsMigrationSteps(versionStr: string): MigrationStepStudio[] { - const res = _.compact( + return _.compact( _.map(MappingsDefaults, (defaultVal: BlueprintMapping, id: string): MigrationStepStudio | null => { - return literal({ + return { id: `${versionStr}.mappings.defaults.${id}`, version: versionStr, canBeRunAutomatically: true, @@ -151,11 +150,9 @@ export function getMappingsDefaultsMigrationSteps(versionStr: string): Migration context.insertMapping(id, defaultVal) } } - }) + } }) ) - - return res } export function GetMappingDefaultMigrationStepForLayer( @@ -163,7 +160,7 @@ export function GetMappingDefaultMigrationStepForLayer( layer: string, force?: boolean ): MigrationStepStudio { - return literal({ + return { id: `${versionStr}.mappings.defaults.manualEnsure${layer}`, version: versionStr, canBeRunAutomatically: true, @@ -190,7 +187,7 @@ export function GetMappingDefaultMigrationStepForLayer( context.insertMapping(layer, MappingsDefaults[layer]) } } - }) + } } /** @@ -207,7 +204,7 @@ export function EnsureSisyfosMappingHasType( layer: string, mappingType: TSR.MappingSisyfosType.CHANNEL ): MigrationStepStudio { - return literal({ + return { id: `${versionStr}.mutatesisyfosmappings.${layer}`, version: versionStr, canBeRunAutomatically: true, @@ -237,7 +234,7 @@ export function EnsureSisyfosMappingHasType( context.updateMapping(layer, mapping) } - }) + } } export function GetSisyfosLayersForTableMigrationAFVD(configName: string, val: string): string[] { @@ -245,7 +242,6 @@ export function GetSisyfosLayersForTableMigrationAFVD(configName: string, val: s case 'SourcesCam': return [] case 'SourcesRM': - case 'SourcesSkype': switch (val) { case '1': return [SisyfosLLAyer.SisyfosSourceLive_1] diff --git a/src/tv2_afvd_studio/onTimelineGenerate.ts b/src/tv2_afvd_studio/onTimelineGenerate.ts index 8834d3391..0cbd50c4a 100644 --- a/src/tv2_afvd_studio/onTimelineGenerate.ts +++ b/src/tv2_afvd_studio/onTimelineGenerate.ts @@ -5,9 +5,8 @@ import { OnGenerateTimelineObj, PartEndState, TimelinePersistentState -} from '@sofie-automation/blueprints-integration' -import { onTimelineGenerate } from 'tv2-common' -import * as _ from 'underscore' +} from '@tv2media/blueprints-integration' +import { onTimelineGenerate, PieceMetaData } from 'tv2-common' import { getConfig } from '../tv2_afvd_showstyle/helpers/config' import { AtemLLayer, CasparLLayer, SisyfosLLAyer } from './layers' @@ -16,7 +15,7 @@ export function onTimelineGenerateAFVD( timeline: OnGenerateTimelineObj[], previousPersistentState: TimelinePersistentState | undefined, previousPartEndState: PartEndState | undefined, - resolvedPieces: IBlueprintResolvedPieceInstance[] + resolvedPieces: Array> ): Promise { return onTimelineGenerate( context, diff --git a/src/tv2_afvd_studio/sisyfosChannels.ts b/src/tv2_afvd_studio/sisyfosChannels.ts index b24b1818c..7dc2d5291 100644 --- a/src/tv2_afvd_studio/sisyfosChannels.ts +++ b/src/tv2_afvd_studio/sisyfosChannels.ts @@ -1,4 +1,3 @@ -import { SisyfosEVSSource } from 'tv2-common' import { SisyfosLLAyer } from './layers' export interface SisyfosChannel { @@ -86,10 +85,10 @@ export const sisyfosChannels: { [key in SisyfosLLAyer]?: SisyfosChannel } = { [SisyfosLLAyer.SisyfosSourceServerB]: { isPgm: 0 }, - [SisyfosEVSSource('1')]: { + [SisyfosLLAyer.SisyfosSourceEVS_1]: { isPgm: 0 }, - [SisyfosEVSSource('2')]: { + [SisyfosLLAyer.SisyfosSourceEVS_2]: { isPgm: 0 }, [SisyfosLLAyer.SisyfosSourceJingle]: { @@ -100,5 +99,8 @@ export const sisyfosChannels: { [key in SisyfosLLAyer]?: SisyfosChannel } = { }, [SisyfosLLAyer.SisyfosSourceTLF]: { isPgm: 0 + }, + [SisyfosLLAyer.SisyfosSourceEpsio]: { + isPgm: 0 } } diff --git a/src/tv2_offtube_showstyle/__tests__/actions.spec.ts b/src/tv2_offtube_showstyle/__tests__/actions.spec.ts index 1055c7de7..4714696ff 100644 --- a/src/tv2_offtube_showstyle/__tests__/actions.spec.ts +++ b/src/tv2_offtube_showstyle/__tests__/actions.spec.ts @@ -1,11 +1,10 @@ import { IBlueprintPartDB, IBlueprintPartInstance, - IBlueprintPieceDB, IBlueprintPieceInstance, PieceLifespan, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionCommentatorSelectDVE, ActionCutToCamera, @@ -15,9 +14,13 @@ import { ActionSelectServerClip, ActionTakeWithTransition, literal, - PartDefinitionUnknown + PartDefinitionUnknown, + PieceMetaData, + RemoteType, + SourceDefinitionKam, + SourceDefinitionRemote } from 'tv2-common' -import { AdlibActionType, CueType, NoteType, PartType, SharedSourceLayers } from 'tv2-constants' +import { AdlibActionType, CueType, NoteType, PartType, SharedSourceLayers, SourceType } from 'tv2-constants' import { ActionExecutionContext } from '../../__mocks__/context' import { defaultShowStyleConfig, defaultStudioConfig } from '../../tv2_afvd_showstyle/__tests__/configs' import { AtemLLayer } from '../../tv2_afvd_studio/layers' @@ -35,11 +38,23 @@ const CURRENT_PART_ID = 'MOCK_PART_CURRENT' const CURRENT_PART_EXTERNAL_ID = `${CURRENT_PART_ID}_EXTERNAL` const SERVER_DURATION_A = 12000 const VO_DURATION_A = 20000 -const SERVER_PREROLL = 280 -const DVE_PREROLL = 280 -const FULL_PREROLL = 280 const FULL_KEEPALIVE = 1000 +const SOURCE_DEFINITION_KAM_1: SourceDefinitionKam = { + sourceType: SourceType.KAM, + id: '1', + raw: 'KAM 1', + minusMic: false, + name: 'KAM 1' +} +const SOURCE_DEFINITION_LIVE_2: SourceDefinitionRemote = { + sourceType: SourceType.REMOTE, + remoteType: RemoteType.LIVE, + id: '1', + name: 'LIVE 1', + raw: 'Live 1' +} + const currentPartMock: IBlueprintPartInstance = { _id: CURRENT_PART_ID, segmentId: SEGMENT_ID, @@ -52,9 +67,9 @@ const currentPartMock: IBlueprintPartInstance = { rehearsal: false } -const kamPieceInstance: IBlueprintPieceInstance = { +const kamPieceInstance: IBlueprintPieceInstance = { _id: '', - piece: literal({ + piece: { _id: 'KAM 1', enable: { start: 0 @@ -83,13 +98,13 @@ const kamPieceInstance: IBlueprintPieceInstance = { }) ] } - }), + }, partInstanceId: '' } -const playingServerPieceInstance: IBlueprintPieceInstance = { +const playingServerPieceInstance: IBlueprintPieceInstance = { _id: '', - piece: literal({ + piece: { _id: 'Playing Server', enable: { start: 0 @@ -102,13 +117,13 @@ const playingServerPieceInstance: IBlueprintPieceInstance = { content: { timelineObjects: [] } - }), + }, partInstanceId: '' } -const selectedServerPieceInstance: IBlueprintPieceInstance = { +const selectedServerPieceInstance: IBlueprintPieceInstance = { _id: '', - piece: literal({ + piece: { _id: 'Selected Server', enable: { start: 0 @@ -121,7 +136,7 @@ const selectedServerPieceInstance: IBlueprintPieceInstance = { content: { timelineObjects: [] } - }), + }, partInstanceId: '' } @@ -134,7 +149,6 @@ const selectServerClipAction = literal({ partDefinition: literal({ type: PartType.Unknown, externalId: CURRENT_PART_EXTERNAL_ID, - variant: {}, rawType: '', cues: [], script: '', @@ -158,7 +172,6 @@ const selectVOClipAction = literal({ partDefinition: literal({ type: PartType.Unknown, externalId: CURRENT_PART_EXTERNAL_ID, - variant: {}, rawType: '', cues: [], script: '', @@ -179,8 +192,8 @@ const selectDVEActionMorbarn = literal({ type: CueType.DVE, template: 'morbarn', sources: { - INP1: 'Kam 1', - INP2: 'Live 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_LIVE_2 }, labels: ['Live'], iNewsCommand: 'DVE=MORBARN' @@ -195,8 +208,8 @@ const selectDVEActionBarnmor = literal({ type: CueType.DVE, template: 'barnmor', sources: { - INP1: 'Kam 1', - INP2: 'Live 2' + INP1: SOURCE_DEFINITION_KAM_1, + INP2: SOURCE_DEFINITION_LIVE_2 }, labels: ['Live'], iNewsCommand: 'DVE=BARNMOR' @@ -211,14 +224,13 @@ const commentatorSelectDVE = literal({ const selectCameraAction = literal({ type: AdlibActionType.CUT_TO_CAMERA, - name: '1', + sourceDefinition: SOURCE_DEFINITION_KAM_1, queue: true }) const selectLiveAction = literal({ type: AdlibActionType.CUT_TO_REMOTE, - name: '2', - port: 3 + sourceDefinition: SOURCE_DEFINITION_LIVE_2 }) const selectFullGrafikAction = literal({ @@ -242,48 +254,74 @@ interface ActivePiecesForSource { dataStore: IBlueprintPieceInstance | undefined } -function getServerPieces(context: ActionExecutionContext, part: 'current' | 'next'): ActivePiecesForSource { +async function getActiveServerPieces( + context: ActionExecutionContext, + part: 'current' | 'next' +): Promise { return { - activePiece: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmServer), - dataStore: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedServer) + activePiece: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmServer)), + dataStore: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedServer)) } } -function getVOPieces(context: ActionExecutionContext, part: 'current' | 'next'): ActivePiecesForSource { +async function getVOPieces(context: ActionExecutionContext, part: 'current' | 'next'): Promise { return { - activePiece: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmVoiceOver), - dataStore: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedVoiceOver) + activePiece: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmVoiceOver)), + dataStore: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedVoiceOver)) } } -function getDVEPieces(context: ActionExecutionContext, part: 'current' | 'next'): ActivePiecesForSource { +async function getDVEPieces(context: ActionExecutionContext, part: 'current' | 'next'): Promise { return { - activePiece: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmDVE), - dataStore: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedAdLibDVE) + activePiece: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmDVE)), + dataStore: await context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.SelectedAdLibDVE)) } } -function getFullGrafikPieces(context: ActionExecutionContext, part: 'current' | 'next'): ActivePiecesForSource { +async function getFullGrafikPieces( + context: ActionExecutionContext, + part: 'current' | 'next' +): Promise { return { - activePiece: context.getPieceInstances(part).find(p => p.piece.sourceLayerId === SharedSourceLayers.PgmPilot), - dataStore: context + activePiece: await context .getPieceInstances(part) - .find(p => p.piece.sourceLayerId === SharedSourceLayers.SelectedAdlibGraphicsFull) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === SharedSourceLayers.PgmPilot)), + dataStore: await context + .getPieceInstances(part) + .then(pieceInstances => + pieceInstances.find(p => p.piece.sourceLayerId === SharedSourceLayers.SelectedAdlibGraphicsFull) + ) } } -function getCameraPiece( +async function getCameraPiece( context: ActionExecutionContext, part: 'current' | 'next' -): IBlueprintPieceInstance | undefined { - return context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmCam) +): Promise { + return context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmCam)) } -function getRemotePiece( +async function getRemotePiece( context: ActionExecutionContext, part: 'current' | 'next' -): IBlueprintPieceInstance | undefined { - return context.getPieceInstances(part).find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmLive) +): Promise { + return context + .getPieceInstances(part) + .then(pieceInstances => pieceInstances.find(p => p.piece.sourceLayerId === OfftubeSourceLayer.PgmLive)) } function validateSourcePiecesExist(pieces: ActivePiecesForSource) { @@ -291,6 +329,12 @@ function validateSourcePiecesExist(pieces: ActivePiecesForSource) { expect(pieces.dataStore).toBeTruthy() } +function validateSourcePiecesExistWithPrerollDuration(pieces: ActivePiecesForSource) { + validateSourcePiecesExist(pieces) + expect(pieces.activePiece!.piece.prerollDuration) + expect(pieces.dataStore!.piece.prerollDuration) +} + function validateOnlySelectionIsPreserved(pieces: ActivePiecesForSource) { expect(pieces.activePiece).toBeFalsy() expect(pieces.dataStore).toBeTruthy() @@ -321,18 +365,13 @@ function validateNextPartExistsWithDuration(context: ActionExecutionContext, dur expect(context.nextPart?.part.expectedDuration).toEqual(duration) } -function validateNextPartExistsWithPreRoll(context: ActionExecutionContext, duration: number) { - expect(context.nextPart).toBeTruthy() - expect(context.nextPart?.part.prerollDuration).toEqual(duration) -} - -function validateNextPartExistsWithTransitionKeepAlive(context: ActionExecutionContext, duration: number) { +function validateNextPartExistsWithPreviousPartKeepaliveDuration(context: ActionExecutionContext, duration: number) { expect(context.nextPart).toBeTruthy() - expect(context.nextPart?.part.transitionKeepaliveDuration).toEqual(duration) + expect(context.nextPart?.part.inTransition?.previousPartKeepaliveDuration).toEqual(duration) } function getATEMMEObj(piece: IBlueprintPieceInstance): TSR.TimelineObjAtemME { - const atemObj = (piece.piece.content!.timelineObjects as TSR.TSRTimelineObj[]).find( + const atemObj = (piece.piece.content.timelineObjects as TSR.TSRTimelineObj[]).find( obj => obj.layer === OfftubeAtemLLayer.AtemMEClean && obj.content.deviceType === TSR.DeviceType.ATEM && @@ -357,7 +396,7 @@ function expectATEMToMixOver(piece: IBlueprintPieceInstance, frames: number) { } describe('Select Server Action', () => { - it('Inserts a new part when no next part is present', () => { + it('Inserts a new part when no next part is present', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -373,19 +412,18 @@ describe('Select Server Action', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - const pieces = getServerPieces(context, 'next') + const activePieces: ActivePiecesForSource = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(pieces) - expect(pieces.dataStore?.piece.lifespan).toEqual(PieceLifespan.OutOnSegmentEnd) + validateSourcePiecesExistWithPrerollDuration(activePieces) + expect(activePieces.dataStore?.piece.lifespan).toEqual(PieceLifespan.OutOnSegmentEnd) validateNoWarningsOrErrors(context) }) - it('Leaves current part unaffected when a clip is currently playing', () => { + it('Leaves current part unaffected when a clip is currently playing', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -401,10 +439,10 @@ describe('Select Server Action', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - const currentPieces = getServerPieces(context, 'current') - const nextPieces = getServerPieces(context, 'next') + const currentPieces = await getActiveServerPieces(context, 'current') + const nextPieces = await getActiveServerPieces(context, 'next') validateSourcePiecesExist(currentPieces) expect(currentPieces.activePiece?.piece.name).toEqual('Playing Server') @@ -417,7 +455,7 @@ describe('Select Server Action', () => { }) describe('Combination Actions', () => { - it('Server -> DVE', () => { + it('Server -> DVE', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -433,26 +471,24 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - serverPieces = getServerPieces(context, 'next') - const dvePieces = getDVEPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + const dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) validateOnlySelectionIsPreserved(serverPieces) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) }) - it('Server -> Full', () => { + it('Server -> Full', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -468,27 +504,25 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) - executeActionOfftube(context, AdlibActionType.SELECT_FULL_GRAFIK, selectFullGrafikAction) + await executeActionOfftube(context, AdlibActionType.SELECT_FULL_GRAFIK, selectFullGrafikAction) - serverPieces = getServerPieces(context, 'next') - const fullGrafikPieces = getFullGrafikPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + const fullGrafikPieces = await getFullGrafikPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, FULL_PREROLL) - validateNextPartExistsWithTransitionKeepAlive(context, FULL_KEEPALIVE) + validateNextPartExistsWithPreviousPartKeepaliveDuration(context, FULL_KEEPALIVE) validateOnlySelectionIsPreserved(serverPieces) - validateSourcePiecesExist(fullGrafikPieces) + validateSourcePiecesExistWithPrerollDuration(fullGrafikPieces) }) - it('Server -> VO', () => { + it('Server -> VO', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -504,62 +538,25 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) - serverPieces = getServerPieces(context, 'next') - const voPieces = getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + const voPieces = await getVOPieces(context, 'next') validateNextPartExistsWithDuration(context, VO_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) validateSelectionRemoved(serverPieces) - validateSourcePiecesExist(voPieces) + validateSourcePiecesExistWithPrerollDuration(voPieces) expect(voPieces.dataStore?.piece.name).toEqual('VOVOA') }) - it('Server -> DVE', () => { - const context = new ActionExecutionContext( - 'test', - mappingsDefaults, - parseStudioConfig, - parseShowStyleConfig, - RUNDOWN_ID, - SEGMENT_ID, - currentPartMock._id, - currentPartMock, - [kamPieceInstance] - ) - context.studioConfig = defaultStudioConfig as any - context.showStyleConfig = defaultShowStyleConfig as any - ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - - let serverPieces = getServerPieces(context, 'next') - - validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) - - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - - serverPieces = getServerPieces(context, 'next') - const dvePieces = getDVEPieces(context, 'next') - - validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - validateOnlySelectionIsPreserved(serverPieces) - validateSourcePiecesExist(dvePieces) - }) - - it('Server -> CAM', () => { + it('Server -> CAM', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -575,25 +572,24 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - serverPieces = getServerPieces(context, 'next') - const camPiece = getCameraPiece(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + const camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(serverPieces) validateCameraPiece(camPiece) }) - it('Server -> LIVE', () => { + it('Server -> LIVE', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -609,25 +605,24 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) - executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) - serverPieces = getServerPieces(context, 'next') - const remotePiece = getRemotePiece(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + const remotePiece = await getRemotePiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(serverPieces) validateRemotePiece(remotePiece) }) - it('DVE -> Server', () => { + it('DVE -> Server', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -643,25 +638,23 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - let dvePieces = getDVEPieces(context, 'next') - validateSourcePiecesExist(dvePieces) + let dvePieces = await getDVEPieces(context, 'next') + validateSourcePiecesExistWithPrerollDuration(dvePieces) validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - dvePieces = getDVEPieces(context, 'next') - const serverPieces = getServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + const serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) validateOnlySelectionIsPreserved(dvePieces) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) }) - it('DVE -> Full', () => { + it('DVE -> Full', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -677,26 +670,24 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - let dvePieces = getDVEPieces(context, 'next') + let dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) - executeActionOfftube(context, AdlibActionType.SELECT_FULL_GRAFIK, selectFullGrafikAction) + await executeActionOfftube(context, AdlibActionType.SELECT_FULL_GRAFIK, selectFullGrafikAction) - dvePieces = getDVEPieces(context, 'next') - const fullGrafikPieces = getFullGrafikPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + const fullGrafikPieces = await getFullGrafikPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, FULL_PREROLL) - validateNextPartExistsWithTransitionKeepAlive(context, FULL_KEEPALIVE) + validateNextPartExistsWithPreviousPartKeepaliveDuration(context, FULL_KEEPALIVE) validateOnlySelectionIsPreserved(dvePieces) - validateSourcePiecesExist(fullGrafikPieces) + validateSourcePiecesExistWithPrerollDuration(fullGrafikPieces) }) - it('DVE -> VO', () => { + it('DVE -> VO', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -712,25 +703,23 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - let dvePieces = getDVEPieces(context, 'next') - validateSourcePiecesExist(dvePieces) + let dvePieces = await getDVEPieces(context, 'next') + validateSourcePiecesExistWithPrerollDuration(dvePieces) validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) - dvePieces = getDVEPieces(context, 'next') - const voPieces = getVOPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + const voPieces = await getVOPieces(context, 'next') validateNextPartExistsWithDuration(context, VO_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) validateOnlySelectionIsPreserved(dvePieces) - validateSourcePiecesExist(voPieces) + validateSourcePiecesExistWithPrerollDuration(voPieces) }) - it('DVE -> CAM', () => { + it('DVE -> CAM', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -746,24 +735,23 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - let dvePieces = getDVEPieces(context, 'next') - validateSourcePiecesExist(dvePieces) + let dvePieces = await getDVEPieces(context, 'next') + validateSourcePiecesExistWithPrerollDuration(dvePieces) validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - dvePieces = getDVEPieces(context, 'next') - const camPiece = getCameraPiece(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + const camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(dvePieces) validateCameraPiece(camPiece) }) - it('DVE -> LIVE', () => { + it('DVE -> LIVE', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -779,24 +767,23 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - let dvePieces = getDVEPieces(context, 'next') - validateSourcePiecesExist(dvePieces) + let dvePieces = await getDVEPieces(context, 'next') + validateSourcePiecesExistWithPrerollDuration(dvePieces) validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) - dvePieces = getDVEPieces(context, 'next') - const remotePiece = getRemotePiece(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + const remotePiece = await getRemotePiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(dvePieces) validateRemotePiece(remotePiece) }) - it('Server (01234A) -> DVE (morbarn) -> VO (VOVOA) -> DVE (barnmor) -> CAM (1) -> LIVE (2) -> SERVER (01234A) -> Commentator Select DVE', () => { + it('Server (01234A) -> DVE (morbarn) -> VO (VOVOA) -> DVE (barnmor) -> CAM (1) -> LIVE (2) -> SERVER (01234A) -> Commentator Select DVE', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -813,60 +800,56 @@ describe('Combination Actions', () => { ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' // SERVER (A) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - let serverPieces = getServerPieces(context, 'next') + let serverPieces = await getActiveServerPieces(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) // DVE (A) - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - serverPieces = getServerPieces(context, 'next') - let dvePieces = getDVEPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + let dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) validateOnlySelectionIsPreserved(serverPieces) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) // VO (A) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) - let voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') + let voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, VO_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) validateSelectionRemoved(serverPieces) validateOnlySelectionIsPreserved(dvePieces) - validateSourcePiecesExist(voPieces) + validateSourcePiecesExistWithPrerollDuration(voPieces) // DVE (B) expect(dvePieces.dataStore?.piece.name).toEqual('morbarn') - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionBarnmor) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionBarnmor) - voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') + voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) validateSelectionRemoved(serverPieces) validateOnlySelectionIsPreserved(voPieces) expect(dvePieces.dataStore?.piece.name).toEqual('barnmor') // CAM (1) - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') - let camPiece = getCameraPiece(context, 'next') + voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + let camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(voPieces) @@ -875,13 +858,13 @@ describe('Combination Actions', () => { validateCameraPiece(camPiece) // LIVE (2) - executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) - voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') - camPiece = getCameraPiece(context, 'next') - let remotePiece = getRemotePiece(context, 'next') + voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + camPiece = await getCameraPiece(context, 'next') + let remotePiece = await getRemotePiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateOnlySelectionIsPreserved(voPieces) @@ -891,42 +874,40 @@ describe('Combination Actions', () => { validateRemotePiece(remotePiece) // SERVER (A) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') - camPiece = getCameraPiece(context, 'next') - remotePiece = getRemotePiece(context, 'next') + voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + camPiece = await getCameraPiece(context, 'next') + remotePiece = await getRemotePiece(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) validateSelectionRemoved(voPieces) validateOnlySelectionIsPreserved(dvePieces) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) expect(camPiece).toBeFalsy() expect(remotePiece).toBeFalsy() // Commentator Select DVE - executeActionOfftube(context, AdlibActionType.COMMENTATOR_SELECT_DVE, commentatorSelectDVE) + await executeActionOfftube(context, AdlibActionType.COMMENTATOR_SELECT_DVE, commentatorSelectDVE) - voPieces = getVOPieces(context, 'next') - serverPieces = getServerPieces(context, 'next') - dvePieces = getDVEPieces(context, 'next') - camPiece = getCameraPiece(context, 'next') - remotePiece = getRemotePiece(context, 'next') + voPieces = await getVOPieces(context, 'next') + serverPieces = await getActiveServerPieces(context, 'next') + dvePieces = await getDVEPieces(context, 'next') + camPiece = await getCameraPiece(context, 'next') + remotePiece = await getRemotePiece(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) validateSelectionRemoved(voPieces) validateOnlySelectionIsPreserved(serverPieces) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) expect(camPiece).toBeFalsy() expect(remotePiece).toBeFalsy() expect(dvePieces.activePiece?.piece.name).toEqual('barnmor') }) - it('CAM -> MIX 20 (No Take) -> LIVE (2)', () => { + it('CAM -> MIX 20 (No Take) -> LIVE (2)', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -942,26 +923,26 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - let camPiece = getCameraPiece(context, 'next') + let camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToCut(camPiece!) - executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) + await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) - camPiece = getCameraPiece(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToMixOver(camPiece!, 20) - executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_REMOTE, selectLiveAction) - const livePiece = getRemotePiece(context, 'next') - camPiece = getCameraPiece(context, 'next') + const livePiece = await getRemotePiece(context, 'next') + camPiece = await getCameraPiece(context, 'next') expect(camPiece).toBeFalsy() validateNextPartExistsWithDuration(context, 0) @@ -969,7 +950,7 @@ describe('Combination Actions', () => { expectATEMToMixOver(livePiece!, 20) }) - it('CAM -> MIX 20 (No Take) -> SERVER', () => { + it('CAM -> MIX 20 (No Take) -> SERVER', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -985,35 +966,34 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - let camPiece = getCameraPiece(context, 'next') + let camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToCut(camPiece!) - executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) + await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) - camPiece = getCameraPiece(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToMixOver(camPiece!, 20) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectServerClipAction) - const serverPieces = getServerPieces(context, 'next') - camPiece = getCameraPiece(context, 'next') + const serverPieces = await getActiveServerPieces(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, SERVER_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) expect(camPiece).toBeFalsy() expectATEMToMixOver(serverPieces.activePiece!, 20) }) - it('CAM -> MIX 20 (No Take) -> VO', () => { + it('CAM -> MIX 20 (No Take) -> VO', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -1029,35 +1009,34 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - let camPiece = getCameraPiece(context, 'next') + let camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToCut(camPiece!) - executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) + await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) - camPiece = getCameraPiece(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToMixOver(camPiece!, 20) - executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) + await executeActionOfftube(context, AdlibActionType.SELECT_SERVER_CLIP, selectVOClipAction) - const serverPieces = getVOPieces(context, 'next') - camPiece = getCameraPiece(context, 'next') + const serverPieces = await getVOPieces(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, VO_DURATION_A) - validateNextPartExistsWithPreRoll(context, SERVER_PREROLL) - validateSourcePiecesExist(serverPieces) + validateSourcePiecesExistWithPrerollDuration(serverPieces) expect(camPiece).toBeFalsy() expectATEMToMixOver(serverPieces.activePiece!, 20) }) - it('CAM -> MIX 20 (No Take) -> DVE', () => { + it('CAM -> MIX 20 (No Take) -> DVE', async () => { const context = new ActionExecutionContext( 'test', mappingsDefaults, @@ -1073,28 +1052,27 @@ describe('Combination Actions', () => { context.showStyleConfig = defaultShowStyleConfig as any ;((context.studioConfig as unknown) as OfftubeStudioConfig).GraphicsType = 'HTML' - executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) + await executeActionOfftube(context, AdlibActionType.CUT_TO_CAMERA, selectCameraAction) - let camPiece = getCameraPiece(context, 'next') + let camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToCut(camPiece!) - executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) + await executeActionOfftube(context, AdlibActionType.TAKE_WITH_TRANSITION, setMIX20AsTransition) - camPiece = getCameraPiece(context, 'next') + camPiece = await getCameraPiece(context, 'next') validateNextPartExistsWithDuration(context, 0) validateCameraPiece(camPiece) expectATEMToMixOver(camPiece!, 20) - executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) + await executeActionOfftube(context, AdlibActionType.SELECT_DVE, selectDVEActionMorbarn) - const dvePieces = getDVEPieces(context, 'next') + const dvePieces = await getDVEPieces(context, 'next') validateNextPartExistsWithDuration(context, 0) - validateNextPartExistsWithPreRoll(context, DVE_PREROLL) - validateSourcePiecesExist(dvePieces) + validateSourcePiecesExistWithPrerollDuration(dvePieces) expectATEMToMixOver(dvePieces.activePiece!, 20) }) }) diff --git a/src/tv2_offtube_showstyle/__tests__/config-manifest.spec.ts b/src/tv2_offtube_showstyle/__tests__/config-manifest.spec.ts index 28726caeb..f162b4cf0 100644 --- a/src/tv2_offtube_showstyle/__tests__/config-manifest.spec.ts +++ b/src/tv2_offtube_showstyle/__tests__/config-manifest.spec.ts @@ -12,7 +12,8 @@ const blankShowStyleConfig: OfftubeShowStyleConfig = { CasparCGLoadingClip: '', Transitions: [{ Transition: '1' }, { Transition: '2' }], ShowstyleTransition: 'CUT', - MakeAdlibsForFulls: true + MakeAdlibsForFulls: true, + SchemaConfig: [] } describe('Config Manifest', () => { diff --git a/src/tv2_offtube_showstyle/actions.ts b/src/tv2_offtube_showstyle/actions.ts index 1856fc934..5c662c342 100644 --- a/src/tv2_offtube_showstyle/actions.ts +++ b/src/tv2_offtube_showstyle/actions.ts @@ -1,4 +1,4 @@ -import { ActionUserData, IActionExecutionContext } from '@sofie-automation/blueprints-integration' +import { ActionUserData, IActionExecutionContext } from '@tv2media/blueprints-integration' import { executeAction } from 'tv2-common' import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../tv2_offtube_studio/layers' import { OFFTUBE_DVE_GENERATOR_OPTIONS } from './content/OfftubeDVEContent' @@ -17,12 +17,12 @@ const SELECTED_ADLIB_LAYERS = [ OfftubeSourceLayer.SelectedAdlibJingle ] -export function executeActionOfftube( +export async function executeActionOfftube( context: IActionExecutionContext, actionId: string, userData: ActionUserData -): void { - executeAction( +): Promise { + await executeAction( context, { getConfig, @@ -49,8 +49,7 @@ export function executeActionOfftube( Sisyfos: { ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending, Effekt: OfftubeSisyfosLLayer.SisyfosSourceJingle, - StudioMics: OfftubeSisyfosLLayer.SisyfosGroupStudioMics, - PersistedLevels: OfftubeSisyfosLLayer.SisyfosPersistedLevels + StudioMics: OfftubeSisyfosLLayer.SisyfosGroupStudioMics }, Atem: { MEProgram: OfftubeAtemLLayer.AtemMEProgram, @@ -71,11 +70,6 @@ export function executeActionOfftube( OutputLayer: { SelectedAdLib: OfftubeOutputLayers.SELECTED_ADLIB }, SELECTED_ADLIB_LAYERS }, - ServerAudioLayers: [ - OfftubeSisyfosLLayer.SisyfosSourceClipPending, - OfftubeSisyfosLLayer.SisyfosSourceServerA, - OfftubeSisyfosLLayer.SisyfosSourceServerB - ], createJingleContent: createJingleContentOfftube, pilotGraphicSettings: pilotGeneratorSettingsOfftube }, diff --git a/src/tv2_offtube_showstyle/config-manifests.ts b/src/tv2_offtube_showstyle/config-manifests.ts index 3afc7b40d..662fc68a0 100644 --- a/src/tv2_offtube_showstyle/config-manifests.ts +++ b/src/tv2_offtube_showstyle/config-manifests.ts @@ -1,6 +1,147 @@ -import { ConfigManifestEntry, ConfigManifestEntryType, TSR } from '@sofie-automation/blueprints-integration' +import { ConfigManifestEntry, ConfigManifestEntryType, TSR } from '@tv2media/blueprints-integration' import { DEFAULT_GRAPHICS } from 'tv2-common' +export const dveStylesManifest: ConfigManifestEntry = { + id: 'DVEStyles', + name: 'DVE Layouts', + description: '', + type: ConfigManifestEntryType.TABLE, + required: false, + defaultVal: [ + { + _id: '', + DVEName: 'sommerfugl', + DVEInputs: '1:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":11,"x":-800,"y":60,"size":500,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":1,"x":800,"y":60,"size":500,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "width": "963px", "text-transform": "uppercase", "overflow": "hidden", "top": "764px" }, "locator1": { "left": "960px", "padding-left": "50px", "padding-right": "120px", "text-align": "right" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px" } }', + DVEGraphicsKey: 'dve/sommerfuglK', + DVEGraphicsFrame: 'dve/sommerfugl' + }, + { + _id: '', + DVEName: 'morbarn', + DVEInputs: '3:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":false,"source":12,"x":-500,"y":140,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1000},"1":{"enabled":true,"source":2001,"x":1080,"y":-240,"size":320,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":true,"source":2,"x":-460,"y":100,"size":720,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":true,"cropTop":0,"cropBottom":119,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "1300px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "width": "624px" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "width": "1300px" } }', + DVEGraphicsKey: 'dve/morbarnK', + DVEGraphicsFrame: 'dve/morbarn' + }, + { + _id: '', + DVEName: 'barnmor', + DVEInputs: '2:INP2;1:INP1', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":13,"x":-1080,"y":-240,"size":320,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":3,"x":460,"y":100,"size":720,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":false,"source":2001,"x":-460,"y":130,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1230},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "624px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "width": "1300px" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "width": "624px" } }', + DVEGraphicsKey: 'dve/barnmorK', + DVEGraphicsFrame: 'dve/barnmor' + }, + { + _id: '', + DVEName: 'barnMorIpad', + DVEInputs: '1:INP1;2:INP2', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":11,"x":-850,"y":-250,"size":350,"cropped":true,"cropTop":240,"cropBottom":530,"cropLeft":550,"cropRight":2580},"1":{"enabled":true,"source":10,"x":507,"y":130,"size":800,"cropped":true,"cropTop":250,"cropBottom":0,"cropLeft":4380,"cropRight":4170},"2":{"enabled":false,"source":2001,"x":-460,"y":130,"size":760,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":1230},"3":{"enabled":false,"source":2001,"x":0,"y":0,"size":1000,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "text-transform": "uppercase", "top": "848px", "overflow": "hidden" }, "locator1": { "left": "733px", "padding-left": "50px", "padding-right": "50px", "text-align": "right", "width": "1014px" }, "locator2": { "left": "118px", "padding-left": "50px", "padding-right": "50px", "width": "624px" } }', + DVEGraphicsKey: 'dve/barnipadK', + DVEGraphicsFrame: 'dve/barnipad' + }, + { + _id: '', + DVEName: '3split', + DVEInputs: '1:INP1;2:INP2;3:INP3', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2,"x":-1050,"y":100,"size":700,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":8500},"1":{"enabled":true,"source":3,"x":160,"y":100,"size":700,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":6200,"cropRight":10600},"2":{"enabled":true,"source":1000,"x":1080,"y":100,"size":700,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":true,"source":2001,"x":758,"y":-425,"size":417,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: + '{ "common": { "font-family": "Alright Sans LT", "font-weight": "bold", "color": "#000000", "font-size": "30px", "background": "#FFFFFF", "height": "35px", "line-height": "35px", "width": "640px", "text-transform": "uppercase", "top": "848px" }, "locator1": { "left": "1280px", "padding-left": "50px", "padding-right": "120px", "text-align": "right", "overflow": "hidden" }, "locator2": { "left": "0px", "padding-left": "120px", "padding-right": "50px", "overflow": "hidden" } }', + DVEGraphicsKey: 'dve/3splitK', + DVEGraphicsFrame: 'dve/3split' + }, + { + _id: '', + DVEName: '3barnMor', + DVEInputs: '1:INP1;2:INP2;3:INP3;4:INP4', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2002,"x":-1055,"y":-390,"size":230,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":700},"1":{"enabled":true,"source":2,"x":358,"y":0,"size":680,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":400,"cropRight":0},"2":{"enabled":true,"source":4,"x":-1055,"y":10,"size":230,"cropped":true,"cropTop":500,"cropBottom":200,"cropLeft":0,"cropRight":700},"3":{"enabled":true,"source":1000,"x":-1055,"y":400,"size":230,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":700}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: '{}', + DVEGraphicsKey: 'dve/3barnMorK', + DVEGraphicsFrame: 'dve/3barnMor' + }, + { + _id: '', + DVEName: '2barnMor', + DVEInputs: '1:INP1;2:INP2;3:INP3', + DVEJSON: + '{"boxes":{"0":{"enabled":true,"source":2,"x":-1050,"y":-200,"size":330,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"1":{"enabled":true,"source":3,"x":540,"y":100,"size":670,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"2":{"enabled":true,"source":2,"x":-1050,"y":400,"size":330,"cropped":true,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0},"3":{"enabled":true,"source":2001,"x":758,"y":-425,"size":417,"cropped":false,"cropTop":0,"cropBottom":0,"cropLeft":0,"cropRight":0}},"index":0,"properties":{"artFillSource":30,"artCutSource":32,"artOption":1,"artPreMultiplied":false,"artClip":50,"artGain":12.5,"artInvertKey":false},"border":{"borderEnabled":false,"borderBevel":0,"borderOuterWidth":0,"borderInnerWidth":0,"borderOuterSoftness":0,"borderInnerSoftness":0,"borderBevelSoftness":0,"borderBevelPosition":0,"borderHue":0,"borderSaturation":0,"borderLuma":0,"borderLightSourceDirection":0,"borderLightSourceAltitude":10}}', + DVEGraphicsTemplateJSON: '{}', + DVEGraphicsKey: 'dve/2barnMorK', + DVEGraphicsFrame: 'dve/2barnMor' + } + ], + columns: [ + { + id: 'DVEName', + name: 'DVE name', + description: 'The name as it will appear in iNews', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 0 + }, + { + id: 'DVEInputs', + name: 'Box inputs', + description: 'I.e.: 1:INP1;2:INP3; as an example to chose which ATEM boxes to assign iNews inputs to', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '1:INP1;2:INP2;3:INP3;4:INP4', + rank: 1 + }, + { + id: 'DVEJSON', + name: 'DVE config', + description: 'DVE config pulled from ATEM', + type: ConfigManifestEntryType.JSON, + required: true, + defaultVal: '{}', + rank: 2 + }, + { + id: 'DVEGraphicsTemplateJSON', + name: 'CasparCG template config', + description: 'Position (and style) data for the boxes in the CasparCG template', + type: ConfigManifestEntryType.JSON, + required: true, + defaultVal: '{}', + rank: 4 + }, + { + id: 'DVEGraphicsKey', + name: 'CasparCG key file', + description: 'Key file for DVE', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 5 + }, + { + id: 'DVEGraphicsFrame', + name: 'CasparCG frame file', + description: 'Frames file for caspar', + type: ConfigManifestEntryType.STRING, + required: true, + defaultVal: '', + rank: 6 + } + ] +} + export const showStyleConfigManifest: ConfigManifestEntry[] = [ { id: 'MakeAdlibsForFulls', @@ -18,80 +159,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ defaultVal: 'LoadingLoop', required: true }, - { - id: 'DVEStyles', - name: 'DVE Layouts', - description: '', - type: ConfigManifestEntryType.TABLE, - required: false, - defaultVal: [ - { - _id: '', - DVEName: '', - DVEInputs: '', - DVEJSON: '{}', - DVEGraphicsTemplateJSON: '{}', - DVEGraphicsKey: '', - DVEGraphicsFrame: '' - } - ], - columns: [ - { - id: 'DVEName', - name: 'DVE name', - description: 'The name as it will appear in iNews', - type: ConfigManifestEntryType.STRING, - required: true, - defaultVal: '', - rank: 0 - }, - { - id: 'DVEInputs', - name: 'Box inputs', - description: 'I.e.: 1:INP1;2:INP3; as an example to chose which ATEM boxes to assign iNews inputs to', - type: ConfigManifestEntryType.STRING, - required: true, - defaultVal: '1:INP1;2:INP2;3:INP3;4:INP4', - rank: 1 - }, - { - id: 'DVEJSON', - name: 'DVE config', - description: 'DVE config pulled from ATEM', - type: ConfigManifestEntryType.JSON, - required: true, - defaultVal: '{}', - rank: 2 - }, - { - id: 'DVEGraphicsTemplateJSON', - name: 'CasparCG template config', - description: 'Position (and style) data for the boxes in the CasparCG template', - type: ConfigManifestEntryType.JSON, - required: true, - defaultVal: '{}', - rank: 4 - }, - { - id: 'DVEGraphicsKey', - name: 'CasparCG key file', - description: 'Key file for DVE', - type: ConfigManifestEntryType.STRING, - required: true, - defaultVal: '', - rank: 5 - }, - { - id: 'DVEGraphicsFrame', - name: 'CasparCG frame file', - description: 'Frames file for caspar', - type: ConfigManifestEntryType.STRING, - required: true, - defaultVal: '', - rank: 6 - } - ] - }, + dveStylesManifest, { /* Graphic template setup @@ -221,7 +289,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EffektNumber', name: 'Effekt Number', description: 'The Effect Number', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 0 @@ -239,7 +307,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'Duration', name: 'Effekt Duration', description: 'Duration of the effekt', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 2 @@ -248,7 +316,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'StartAlpha', name: 'Alpha at Start', description: 'Number of frames of alpha at start', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 3 @@ -257,7 +325,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EndAlpha', name: 'Alpha at End', description: 'Number of frames of alpha at end', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 4 @@ -312,7 +380,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'Duration', name: 'Effekt Duration', description: 'Duration of the effekt', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 2 @@ -321,7 +389,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'StartAlpha', name: 'Alpha at Start', description: 'Number of frames of alpha at start', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 3 @@ -330,7 +398,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'EndAlpha', name: 'Alpha at End', description: 'Number of frames of alpha at end', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 4 @@ -359,7 +427,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'DefaultTemplateDuration', name: 'Default Template Duration', description: 'Default Template Duration', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 4 }, @@ -404,7 +472,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'FadeIn', name: 'Fade In', description: 'ms duration to fade in file', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1000, rank: 2 @@ -413,7 +481,7 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ id: 'FadeOut', name: 'Fade Out', description: 'ms duration to fade out file', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1000, rank: 3 @@ -447,5 +515,51 @@ export const showStyleConfigManifest: ConfigManifestEntry[] = [ rank: 0 } ] + }, + { + id: 'SchemaConfig', + name: 'Skema', + description: 'The values for the Skema and Design combinations', + type: ConfigManifestEntryType.TABLE, + required: false, + defaultVal: [], + columns: [ + { + id: 'schemaName', + name: 'Skema', + description: 'The name of the Skema', + rank: 0, + required: true, + defaultVal: '', + type: ConfigManifestEntryType.STRING + }, + { + id: 'designIdentifier', + name: 'Design', + description: 'The identifier of the Design', + rank: 1, + required: true, + defaultVal: '', + type: ConfigManifestEntryType.STRING + }, + { + id: 'vizTemplateName', + name: 'Viz Template Name', + description: 'The name of the Viz template', + rank: 2, + required: true, + defaultVal: '', + type: ConfigManifestEntryType.STRING + }, + { + id: 'casparCgDveBgScene', + name: 'CasparCG DVE Bg Scene', + description: 'The dveBgScene', + defaultVal: '', + rank: 3, + required: true, + type: ConfigManifestEntryType.STRING + } + ] } ] diff --git a/src/tv2_offtube_showstyle/content/OfftubeDVEContent.ts b/src/tv2_offtube_showstyle/content/OfftubeDVEContent.ts index 05293f12a..8996e0054 100644 --- a/src/tv2_offtube_showstyle/content/OfftubeDVEContent.ts +++ b/src/tv2_offtube_showstyle/content/OfftubeDVEContent.ts @@ -1,23 +1,9 @@ -import { ISegmentUserContext, SplitsContent, WithTimeline } from '@sofie-automation/blueprints-integration' -import { - CueDefinitionDVE, - DVEConfigInput, - DVEOptions, - GetLayersForEkstern, - GetSisyfosTimelineObjForEkstern, - MakeContentDVEBase, - PartDefinition -} from 'tv2-common' +import { ISegmentUserContext, SplitsContent, WithTimeline } from '@tv2media/blueprints-integration' +import { CueDefinitionDVE, DVEConfigInput, DVEOptions, MakeContentDVEBase, PartDefinition } from 'tv2-common' import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' -import { OfftubeSourceLayer } from '../layers' -export const boxLayers = { - INP1: OfftubeSourceLayer.PgmDVEBox1, - INP2: OfftubeSourceLayer.PgmDVEBox2, - INP3: OfftubeSourceLayer.PgmDVEBox3, - INP4: OfftubeSourceLayer.PgmDVEBox4 -} +export const NUMBER_OF_DVE_BOXES = 4 export const boxMappings: [string, string, string, string] = [ OfftubeAtemLLayer.AtemSSrcBox1, @@ -39,21 +25,14 @@ export const OFFTUBE_DVE_GENERATOR_OPTIONS: DVEOptions = { }, SisyfosLLayer: { ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending, - StudioMics: OfftubeSisyfosLLayer.SisyfosGroupStudioMics, - PersistedLevels: OfftubeSisyfosLLayer.SisyfosPersistedLevels + StudioMics: OfftubeSisyfosLLayer.SisyfosGroupStudioMics }, CasparLLayer: { ClipPending: OfftubeCasparLLayer.CasparPlayerClipPending } }, - dveTimelineGenerators: { - GetSisyfosTimelineObjForEkstern, - GetLayersForEkstern - }, - boxLayers, boxMappings, - AUDIO_LAYERS: [], // TODO - EXCLUDED_LAYERS: [] // TODO + AUDIO_LAYERS: [] // TODO } export function OfftubeMakeContentDVE( @@ -64,7 +43,7 @@ export function OfftubeMakeContentDVE( dveConfig: DVEConfigInput | undefined, addClass?: boolean, adlib?: boolean -): { content: WithTimeline; valid: boolean; stickyLayers: string[] } { +): { content: WithTimeline; valid: boolean } { return MakeContentDVEBase( context, config, diff --git a/src/tv2_offtube_showstyle/cues/OfftubeAdlib.ts b/src/tv2_offtube_showstyle/cues/OfftubeAdlib.ts index 9007900ab..c3e76dd71 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeAdlib.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeAdlib.ts @@ -6,12 +6,13 @@ import { SplitsContent, TimelineObjectCoreExt, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectDVE, CreateAdlibServer, CueDefinitionAdLib, CueDefinitionDVE, + generateExternalId, GetDVETemplate, getUniquenessIdDVE, literal, @@ -26,7 +27,7 @@ import { OfftubeMakeContentDVE } from '../content/OfftubeDVEContent' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeOutputLayers, OfftubeSourceLayer } from '../layers' -export function OfftubeEvaluateAdLib( +export async function OfftubeEvaluateAdLib( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, _adLibPieces: IBlueprintAdLibPiece[], @@ -45,13 +46,9 @@ export function OfftubeEvaluateAdLib( return } - const sourceDuration = Math.max( - (context.hackGetMediaObjectDuration(file) || 0) * 1000 - config.studio.ServerPostrollDuration, - 0 - ) - actions.push( - CreateAdlibServer( + await CreateAdlibServer( + context, config, rank, partDefinition, @@ -67,8 +64,7 @@ export function OfftubeEvaluateAdLib( ClipPending: OfftubeCasparLLayer.CasparPlayerClipPending }, Sisyfos: { - ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending, - StudioMicsGroup: OfftubeSisyfosLLayer.SisyfosGroupStudioMics + ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending }, AtemLLayer: { MEPgm: OfftubeAtemLLayer.AtemMEClean @@ -77,7 +73,6 @@ export function OfftubeEvaluateAdLib( ServerLookaheadAux: OfftubeAtemLLayer.AtemAuxServerLookahead } }, - sourceDuration, true ) ) @@ -95,7 +90,7 @@ export function OfftubeEvaluateAdLib( return } - if (!TemplateIsValid(rawTemplate.DVEJSON as string)) { + if (!TemplateIsValid(rawTemplate.DVEJSON)) { context.notifyUserWarning(`Invalid DVE template ${parsedCue.variant}`) return } @@ -110,40 +105,28 @@ export function OfftubeEvaluateAdLib( const adlibContent = OfftubeMakeContentDVE(context, config, partDefinition, cueDVE, rawTemplate, false, true) - let sticky: { [key: string]: { value: number; followsPrevious: boolean } } = {} - - adlibContent.stickyLayers.forEach(layer => { - sticky = { - ...sticky, - [layer]: { - value: 1, - followsPrevious: false - } + const userData: ActionSelectDVE = { + type: AdlibActionType.SELECT_DVE, + config: cueDVE, + videoId: partDefinition.fields.videoId, + segmentExternalId: partDefinition.segmentExternalId + } + actions.push({ + externalId: generateExternalId(context, userData), + actionId: AdlibActionType.SELECT_DVE, + userData, + userDataManifest: {}, + display: { + sourceLayerId: OfftubeSourceLayer.PgmDVE, + outputLayerId: OfftubeOutputLayers.PGM, + uniquenessId: getUniquenessIdDVE(cueDVE), + label: t(`${partDefinition.storyName}`), + tags: [AdlibTags.ADLIB_KOMMENTATOR, AdlibTags.ADLIB_FLOW_PRODUCER], + content: literal({ + ...adlibContent.content + }) } }) - - actions.push( - literal({ - actionId: AdlibActionType.SELECT_DVE, - userData: literal({ - type: AdlibActionType.SELECT_DVE, - config: cueDVE, - videoId: partDefinition.fields.videoId, - segmentExternalId: partDefinition.segmentExternalId - }), - userDataManifest: {}, - display: { - sourceLayerId: OfftubeSourceLayer.PgmDVE, - outputLayerId: OfftubeOutputLayers.PGM, - uniquenessId: getUniquenessIdDVE(cueDVE), - label: t(`${partDefinition.storyName}`), - tags: [AdlibTags.ADLIB_KOMMENTATOR, AdlibTags.ADLIB_FLOW_PRODUCER], - content: literal({ - ...adlibContent.content - }) - } - }) - ) } } diff --git a/src/tv2_offtube_showstyle/cues/OfftubeDVE.ts b/src/tv2_offtube_showstyle/cues/OfftubeDVE.ts index 9e2b15746..0f0501234 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeDVE.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeDVE.ts @@ -5,19 +5,19 @@ import { ISegmentUserContext, PieceLifespan, SplitsContent -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectDVE, AddParentClass, CalculateTime, CueDefinitionDVE, DVEPieceMetaData, + generateExternalId, GetDVETemplate, GetTagForDVE, GetTagForDVENext, literal, PartDefinition, - PieceMetaData, t, TemplateIsValid } from 'tv2-common' @@ -76,66 +76,66 @@ export function OfftubeEvaluateDVE( let start = parsedCue.start ? CalculateTime(parsedCue.start) : 0 start = start ? start : 0 const end = parsedCue.end ? CalculateTime(parsedCue.end) : undefined - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: `${parsedCue.template}`, - enable: { - start, - ...(end ? { duration: end - start } : {}) - }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: OfftubeSourceLayer.PgmDVE, - lifespan: PieceLifespan.WithinPart, - toBeQueued: true, - content: { - ...pieceContent.content, - timelineObjects: [...pieceContent.content.timelineObjects] - }, - adlibPreroll: Number(config.studio.CasparPrerollDuration) || 0, - metaData: literal({ - mediaPlayerSessions: [partDefinition.segmentExternalId], - sources: parsedCue.sources, - config: rawTemplate, - userData: literal({ - type: AdlibActionType.SELECT_DVE, - config: parsedCue, - videoId: partDefinition.fields.videoId, - segmentExternalId: partDefinition.segmentExternalId - }) - }), - tags: [ - GetTagForDVE(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources), - GetTagForDVENext(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources), - TallyTags.DVE_IS_LIVE - ] - }) - ) - - actions.push( - literal({ - actionId: AdlibActionType.SELECT_DVE, - userData: literal({ + pieces.push({ + externalId: partDefinition.externalId, + name: `${parsedCue.template}`, + enable: { + start, + ...(end ? { duration: end - start } : {}) + }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: OfftubeSourceLayer.PgmDVE, + lifespan: PieceLifespan.WithinPart, + toBeQueued: true, + content: { + ...pieceContent.content, + timelineObjects: [...pieceContent.content.timelineObjects] + }, + prerollDuration: Number(config.studio.CasparPrerollDuration) || 0, + metaData: literal({ + mediaPlayerSessions: [partDefinition.segmentExternalId], + sources: parsedCue.sources, + config: rawTemplate, + userData: { type: AdlibActionType.SELECT_DVE, config: parsedCue, videoId: partDefinition.fields.videoId, segmentExternalId: partDefinition.segmentExternalId - }), - userDataManifest: {}, - display: { - _rank: rank, - sourceLayerId: OfftubeSourceLayer.PgmDVE, - outputLayerId: OfftubeOutputLayers.PGM, - label: t(`${partDefinition.storyName}`), - tags: [AdlibTags.ADLIB_KOMMENTATOR, ...(adlib ? [AdlibTags.ADLIB_FLOW_PRODUCER] : [])], - noHotKey: !adlib, - content: literal({ - ...pieceContent.content - }), - currentPieceTags: [GetTagForDVE(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources)], - nextPieceTags: [GetTagForDVENext(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources)] + }, + sisyfosPersistMetaData: { + sisyfosLayers: [] } - }) - ) + }), + tags: [ + GetTagForDVE(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources), + GetTagForDVENext(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources), + TallyTags.DVE_IS_LIVE + ] + }) + + const userData: ActionSelectDVE = { + type: AdlibActionType.SELECT_DVE, + config: parsedCue, + videoId: partDefinition.fields.videoId, + segmentExternalId: partDefinition.segmentExternalId + } + actions.push({ + externalId: generateExternalId(context, userData), + actionId: AdlibActionType.SELECT_DVE, + userData, + userDataManifest: {}, + display: { + _rank: rank, + sourceLayerId: OfftubeSourceLayer.PgmDVE, + outputLayerId: OfftubeOutputLayers.PGM, + label: t(`${partDefinition.storyName}`), + tags: [AdlibTags.ADLIB_KOMMENTATOR, ...(adlib ? [AdlibTags.ADLIB_FLOW_PRODUCER] : [])], + content: literal({ + ...pieceContent.content + }), + currentPieceTags: [GetTagForDVE(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources)], + nextPieceTags: [GetTagForDVENext(partDefinition.segmentExternalId, parsedCue.template, parsedCue.sources)] + } + }) } } diff --git a/src/tv2_offtube_showstyle/cues/OfftubeEkstern.ts b/src/tv2_offtube_showstyle/cues/OfftubeEkstern.ts index 53dff5eb9..1164e20a3 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeEkstern.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeEkstern.ts @@ -4,9 +4,9 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { CueDefinitionEkstern, EvaluateEksternBase, PartDefinition } from 'tv2-common' -import { OfftubeAtemLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' +} from '@tv2media/blueprints-integration' +import { CueDefinitionEkstern, EvaluateEksternBase, PartDefinition, PieceMetaData } from 'tv2-common' +import { OfftubeAtemLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeSourceLayer } from '../layers' @@ -14,8 +14,8 @@ export function OfftubeEvaluateEkstern( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, part: IBlueprintPart, - pieces: IBlueprintPiece[], - _adlibPieces: IBlueprintAdLibPiece[], + pieces: Array>, + _adlibPieces: Array>, _actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionEkstern, @@ -38,9 +38,6 @@ export function OfftubeEvaluateEkstern( }, ATEM: { MEProgram: OfftubeAtemLLayer.AtemMEClean - }, - Sisyfos: { - StudioMics: OfftubeSisyfosLLayer.SisyfosGroupStudioMics } }, adlib, diff --git a/src/tv2_offtube_showstyle/cues/OfftubeGraphicBackgroundLoop.ts b/src/tv2_offtube_showstyle/cues/OfftubeGraphicBackgroundLoop.ts index e9f663e63..2277c7248 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeGraphicBackgroundLoop.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeGraphicBackgroundLoop.ts @@ -6,14 +6,15 @@ import { PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CalculateTime, CueDefinitionBackgroundLoop, literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { CalculateTime, CueDefinitionBackgroundLoop, literal, TV2BlueprintConfig } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import _ = require('underscore') import { OfftubeCasparLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeSourceLayer } from '../layers' export function OfftubeEvaluateCueBackgroundLoop( + _config: TV2BlueprintConfig, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], _actions: IBlueprintActionManifest[], @@ -26,66 +27,62 @@ export function OfftubeEvaluateCueBackgroundLoop( const path = `dve/${fileName}` const start = (parsedCue.start ? CalculateTime(parsedCue.start) : 0) ?? 0 if (adlib) { - adlibPieces.push( - literal({ - _rank: rank || 0, - externalId: partId, - name: fileName, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: OfftubeSourceLayer.PgmDVEBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName, - path, - ignoreMediaObjectStatus: true, - timelineObjects: _.compact([ - literal({ - id: '', - enable: { start: 0 }, - priority: 100, - layer: OfftubeCasparLLayer.CasparCGDVELoop, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: path, - loop: true - } - }) - ]) - }) + adlibPieces.push({ + _rank: rank || 0, + externalId: partId, + name: fileName, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: OfftubeSourceLayer.PgmDVEBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName, + path, + ignoreMediaObjectStatus: true, + timelineObjects: _.compact([ + literal({ + id: '', + enable: { start: 0 }, + priority: 100, + layer: OfftubeCasparLLayer.CasparCGDVELoop, + content: { + deviceType: TSR.DeviceType.CASPARCG, + type: TSR.TimelineContentTypeCasparCg.MEDIA, + file: path, + loop: true + } + }) + ]) }) - ) + }) } else { - pieces.push( - literal({ - externalId: partId, - name: fileName, - enable: { - start - }, - outputLayerId: SharedOutputLayers.SEC, - sourceLayerId: OfftubeSourceLayer.PgmDVEBackground, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - fileName, - path, - ignoreMediaObjectStatus: true, - timelineObjects: _.compact([ - literal({ - id: '', - enable: { start: 0 }, - priority: 100, - layer: OfftubeCasparLLayer.CasparCGDVELoop, - content: { - deviceType: TSR.DeviceType.CASPARCG, - type: TSR.TimelineContentTypeCasparCg.MEDIA, - file: path, - loop: true - } - }) - ]) - }) + pieces.push({ + externalId: partId, + name: fileName, + enable: { + start + }, + outputLayerId: SharedOutputLayers.SEC, + sourceLayerId: OfftubeSourceLayer.PgmDVEBackground, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + fileName, + path, + ignoreMediaObjectStatus: true, + timelineObjects: _.compact([ + literal({ + id: '', + enable: { start: 0 }, + priority: 100, + layer: OfftubeCasparLLayer.CasparCGDVELoop, + content: { + deviceType: TSR.DeviceType.CASPARCG, + type: TSR.TimelineContentTypeCasparCg.MEDIA, + file: path, + loop: true + } + }) + ]) }) - ) + }) } } diff --git a/src/tv2_offtube_showstyle/cues/OfftubeGraphicDesign.ts b/src/tv2_offtube_showstyle/cues/OfftubeGraphicDesign.ts index aa3221cc4..f524c7418 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeGraphicDesign.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeGraphicDesign.ts @@ -3,7 +3,7 @@ import { IBlueprintAdLibPiece, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CueDefinitionGraphicDesign, EvaluateDesignBase } from 'tv2-common' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' diff --git a/src/tv2_offtube_showstyle/cues/OfftubeGraphics.ts b/src/tv2_offtube_showstyle/cues/OfftubeGraphics.ts index b38e7f5b1..c09058e76 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeGraphics.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeGraphics.ts @@ -1,17 +1,17 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, - IBlueprintPart, IBlueprintPiece, IShowStyleUserContext, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { + Adlib, CreateInternalGraphic, CreatePilotGraphic, CueDefinitionGraphic, FindDSKFullGFX, - GetSisyfosTimelineObjForCamera, + GetSisyfosTimelineObjForFull, GraphicInternalOrPilot, GraphicIsInternal, GraphicIsPilot, @@ -19,7 +19,7 @@ import { PartDefinition, PilotGeneratorSettings } from 'tv2-common' -import { OfftubeAtemLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' +import { OfftubeAtemLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' export const pilotGeneratorSettingsOfftube: PilotGeneratorSettings = { @@ -34,51 +34,33 @@ export const pilotGeneratorSettingsOfftube: PilotGeneratorSettings = { export function OfftubeEvaluateGrafikCaspar( config: OfftubeShowstyleBlueprintConfig, context: IShowStyleUserContext, - part: Readonly, pieces: IBlueprintPiece[], adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], partId: string, parsedCue: CueDefinitionGraphic, - adlib: boolean, partDefinition: PartDefinition, - rank?: number + adlib?: Adlib ) { if (GraphicIsPilot(parsedCue)) { - CreatePilotGraphic( + CreatePilotGraphic(pieces, adlibPieces, actions, { + engine: parsedCue.target, config, context, - part, - pieces, - adlibPieces, - actions, partId, parsedCue, - pilotGeneratorSettingsOfftube, + settings: pilotGeneratorSettingsOfftube, adlib, - rank ?? 0, - partDefinition.segmentExternalId - ) + segmentExternalId: partDefinition.segmentExternalId + }) } else if (GraphicIsInternal(parsedCue)) { - CreateInternalGraphic( - config, - context, - part, - pieces, - adlibPieces, - actions, - partId, - parsedCue, - adlib, - partDefinition, - rank - ) + CreateInternalGraphic(config, context, pieces, adlibPieces, partId, parsedCue, partDefinition, adlib) } } function createPilotTimeline( config: OfftubeShowstyleBlueprintConfig, - context: IShowStyleUserContext + _context: IShowStyleUserContext ): TSR.TSRTimelineObj[] { const fullDSK = FindDSKFullGFX(config) return [ @@ -106,6 +88,6 @@ function createPilotTimeline( } } }), - GetSisyfosTimelineObjForCamera(context, config, 'full', OfftubeSisyfosLLayer.SisyfosGroupStudioMics) + ...GetSisyfosTimelineObjForFull(config) ] } diff --git a/src/tv2_offtube_showstyle/cues/OfftubeJingle.ts b/src/tv2_offtube_showstyle/cues/OfftubeJingle.ts index faff60ba7..f82cd7ba6 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubeJingle.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubeJingle.ts @@ -4,18 +4,19 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionSelectJingle, CreateJingleContentBase, CueDefinitionJingle, + generateExternalId, GetJinglePartProperties, GetTagForJingle, GetTagForJingleNext, - literal, PartDefinition, PieceMetaData, - t + t, + TimeFromFrames } from 'tv2-common' import { AdlibActionType, AdlibTags, SharedOutputLayers, TallyTags } from 'tv2-constants' import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' @@ -25,7 +26,7 @@ import { OfftubeOutputLayers, OfftubeSourceLayer } from '../layers' export function OfftubeEvaluateJingle( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, - pieces: IBlueprintPiece[], + pieces: Array>, _adlibPieces: IBlueprintAdLibPiece[], actions: IBlueprintActionManifest[], parsedCue: CueDefinitionJingle, @@ -58,68 +59,66 @@ export function OfftubeEvaluateJingle( return } - actions.push( - literal({ - actionId: AdlibActionType.SELECT_JINGLE, - userData: literal({ - type: AdlibActionType.SELECT_JINGLE, - clip: parsedCue.clip, - segmentExternalId: part.segmentExternalId - }), - userDataManifest: {}, - display: { - label: t(effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip), - sourceLayerId: OfftubeSourceLayer.PgmJingle, - outputLayerId: OfftubeOutputLayers.JINGLE, - content: { - ...createJingleContentOfftube( - config, - file, - jingle.StartAlpha, - jingle.LoadFirstFrame, - jingle.Duration, - jingle.EndAlpha - ) - }, - tags: [AdlibTags.OFFTUBE_100pc_SERVER, AdlibTags.ADLIB_KOMMENTATOR], - currentPieceTags: [GetTagForJingle(part.segmentExternalId, parsedCue.clip)], - nextPieceTags: [GetTagForJingleNext(part.segmentExternalId, parsedCue.clip)], - noHotKey: true - } - }) - ) - - pieces.push( - literal({ - externalId: `${part.externalId}-JINGLE`, - name: effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip, - enable: { - start: 0 - }, - lifespan: PieceLifespan.WithinPart, - outputLayerId: SharedOutputLayers.JINGLE, + const userData: ActionSelectJingle = { + type: AdlibActionType.SELECT_JINGLE, + clip: parsedCue.clip, + segmentExternalId: part.segmentExternalId + } + actions.push({ + externalId: generateExternalId(context, userData), + actionId: AdlibActionType.SELECT_JINGLE, + userData, + userDataManifest: {}, + display: { + label: t(effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip), sourceLayerId: OfftubeSourceLayer.PgmJingle, - metaData: literal({ - transition: { - isJingle: !effekt, - isEffekt: !!effekt - } - }), - content: createJingleContentOfftube( - config, - file, - jingle.StartAlpha, - jingle.LoadFirstFrame, - jingle.Duration, - jingle.EndAlpha - ), - tags: [ - GetTagForJingle(part.segmentExternalId, parsedCue.clip), - GetTagForJingleNext(part.segmentExternalId, parsedCue.clip), - TallyTags.JINGLE_IS_LIVE - ] - }) - ) + outputLayerId: OfftubeOutputLayers.JINGLE, + content: { + ...createJingleContentOfftube( + config, + file, + jingle.StartAlpha, + jingle.LoadFirstFrame, + jingle.Duration, + jingle.EndAlpha + ) + }, + tags: [AdlibTags.OFFTUBE_100pc_SERVER, AdlibTags.ADLIB_KOMMENTATOR], + currentPieceTags: [GetTagForJingle(part.segmentExternalId, parsedCue.clip)], + nextPieceTags: [GetTagForJingleNext(part.segmentExternalId, parsedCue.clip)] + } + }) + + pieces.push({ + externalId: `${part.externalId}-JINGLE`, + name: effekt ? `EFFEKT ${parsedCue.clip}` : parsedCue.clip, + enable: { + start: 0 + }, + lifespan: PieceLifespan.WithinPart, + outputLayerId: SharedOutputLayers.JINGLE, + sourceLayerId: OfftubeSourceLayer.PgmJingle, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: [] + } + }, + prerollDuration: config.studio.CasparPrerollDuration + TimeFromFrames(Number(jingle.StartAlpha)), + content: createJingleContentOfftube( + config, + file, + jingle.StartAlpha, + jingle.LoadFirstFrame, + jingle.Duration, + jingle.EndAlpha + ), + tags: [ + GetTagForJingle(part.segmentExternalId, parsedCue.clip), + GetTagForJingleNext(part.segmentExternalId, parsedCue.clip), + TallyTags.JINGLE_IS_LIVE, + !effekt ? TallyTags.JINGLE : '' + ] + }) } export function createJingleContentOfftube( @@ -133,7 +132,7 @@ export function createJingleContentOfftube( return CreateJingleContentBase(config, file, alphaAtStart, loadFirstFrame, duration, alphaAtEnd, { Caspar: { PlayerJingle: OfftubeCasparLLayer.CasparPlayerJingle, - PlayerJingleLookahead: OfftubeCasparLLayer.CasparPlayerJingleLookahead + PlayerJinglePreload: OfftubeCasparLLayer.CasparPlayerJinglePreload }, ATEM: { USKJinglePreview: OfftubeAtemLLayer.AtemMENextJingle diff --git a/src/tv2_offtube_showstyle/cues/OfftubePgmClean.ts b/src/tv2_offtube_showstyle/cues/OfftubePgmClean.ts index bbe605101..b54b086d4 100644 --- a/src/tv2_offtube_showstyle/cues/OfftubePgmClean.ts +++ b/src/tv2_offtube_showstyle/cues/OfftubePgmClean.ts @@ -3,13 +3,12 @@ import { IBlueprintPiece, IShowStyleUserContext, PieceLifespan, - SourceLayerType, TimelineObjectCoreExt, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' -import { CueDefinitionPgmClean, FindSourceInfoStrict, literal, SourceInfo, SourceInfoType } from 'tv2-common' -import { SharedOutputLayers } from 'tv2-constants' +} from '@tv2media/blueprints-integration' +import { CueDefinitionPgmClean, findSourceInfo, literal, SourceInfo } from 'tv2-common' +import { SharedOutputLayers, SourceType } from 'tv2-constants' import { OfftubeAtemLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeSourceLayer } from '../layers' @@ -22,58 +21,44 @@ export function OfftubeEvaluatePgmClean( parsedCue: CueDefinitionPgmClean ) { let sourceInfo: SourceInfo | undefined - if (parsedCue.source.match(/PGM/i)) { + if (parsedCue.sourceDefinition.sourceType === SourceType.PGM) { return } - let sourceType: SourceInfoType | undefined - if (parsedCue.source.match(/live|feed/i)) { - sourceType = SourceLayerType.REMOTE - } else if (parsedCue.source.match(/[k|c]am/i)) { - sourceType = SourceLayerType.CAMERA - } else if (parsedCue.source.match(/evs/i)) { - sourceType = SourceLayerType.LOCAL - } - - if (!sourceType) { - context.notifyUserWarning(`Invalid source for clean output: ${parsedCue.source}`) - return - } + sourceInfo = findSourceInfo(config.sources, parsedCue.sourceDefinition) - sourceInfo = FindSourceInfoStrict(context, config.sources, sourceType, parsedCue.source) + const name = parsedCue.sourceDefinition.name || parsedCue.sourceDefinition.sourceType if (!sourceInfo) { - context.notifyUserWarning(`Invalid source for clean output: ${parsedCue.source}`) + context.notifyUserWarning(`Invalid source for clean output: ${name}`) return } - pieces.push( - literal({ - externalId: partId, - name: parsedCue.source, - enable: { - start: 0 - }, - outputLayerId: SharedOutputLayers.AUX, - sourceLayerId: OfftubeSourceLayer.AuxPgmClean, - lifespan: PieceLifespan.OutOnShowStyleEnd, - content: literal>({ - timelineObjects: literal([ - literal({ - id: '', - enable: { while: '1' }, - priority: 0, - layer: OfftubeAtemLLayer.AtemAuxClean, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.AUX, - aux: { - input: sourceInfo.port - } + pieces.push({ + externalId: partId, + name, + enable: { + start: 0 + }, + outputLayerId: SharedOutputLayers.AUX, + sourceLayerId: OfftubeSourceLayer.AuxPgmClean, + lifespan: PieceLifespan.OutOnShowStyleEnd, + content: literal>({ + timelineObjects: literal([ + literal({ + id: '', + enable: { while: '1' }, + priority: 0, + layer: OfftubeAtemLLayer.AtemAuxClean, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.AUX, + aux: { + input: sourceInfo.port } - }) - ]) - }) + } + }) + ]) }) - ) + }) } diff --git a/src/tv2_offtube_showstyle/getRundown.ts b/src/tv2_offtube_showstyle/getRundown.ts index 932cec8ba..209a92cba 100644 --- a/src/tv2_offtube_showstyle/getRundown.ts +++ b/src/tv2_offtube_showstyle/getRundown.ts @@ -4,16 +4,13 @@ import { IBlueprintActionManifest, IBlueprintAdLibPiece, IBlueprintRundown, - IBlueprintShowStyleVariant, IngestRundown, IShowStyleUserContext, - IStudioContext, IStudioUserContext, PieceLifespan, PlaylistTimingType, - SourceLayerType, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { ActionClearGraphics, ActionCommentatorSelectDVE, @@ -31,21 +28,28 @@ import { CreateDSKBaselineAdlibs, CreateGraphicBaseline, CreateLYDBaseline, + generateExternalId, GetTagForKam, GetTagForLive, GetTransitionAdLibActions, literal, + SourceDefinitionKam, + SourceDefinitionRemote, SourceInfo, + SourceInfoToSourceDefinition, + SourceInfoType, t, TimeFromINewsField } from 'tv2-common' import { AdlibActionType, + AdlibTagCutToBox, AdlibTags, CONSTANTS, SharedOutputLayers, SharedSisyfosLLayer, SharedSourceLayers, + SourceType, TallyTags } from 'tv2-constants' import * as _ from 'underscore' @@ -56,23 +60,10 @@ import { import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../tv2_offtube_studio/layers' import { SisyfosChannel, sisyfosChannels } from '../tv2_offtube_studio/sisyfosChannels' import { AtemSourceIndex } from '../types/atem' -import { boxLayers } from './content/OfftubeDVEContent' +import { NUMBER_OF_DVE_BOXES } from './content/OfftubeDVEContent' import { OfftubeOutputLayers, OfftubeSourceLayer } from './layers' import { postProcessPieceTimelineObjects } from './postProcessTimelineObjects' -export function getShowStyleVariantId( - _context: IStudioContext, - showStyleVariants: IBlueprintShowStyleVariant[], - _ingestRundown: IngestRundown -): string | null { - const variant = _.first(showStyleVariants) - - if (variant) { - return variant._id - } - return null -} - export function getRundown(context: IShowStyleUserContext, ingestRundown: IngestRundown): BlueprintResultRundown { const config = getShowStyleConfig(context) @@ -129,7 +120,7 @@ function getGlobalAdLibPiecesOfftube( sourceLayerId: SharedSourceLayers.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_MICS_UP], expectedDuration: 0, content: { timelineObjects: [ @@ -159,7 +150,7 @@ function getGlobalAdLibPiecesOfftube( sourceLayerId: SharedSourceLayers.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_MICS_DOWN], expectedDuration: 0, content: { timelineObjects: [ @@ -189,10 +180,10 @@ function getGlobalAdLibPiecesOfftube( sourceLayerId: SharedSourceLayers.PgmSisyfosAdlibs, outputLayerId: SharedOutputLayers.SEC, lifespan: PieceLifespan.WithinPart, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIBS_RESYNC_SISYFOS], expectedDuration: 1000, content: { - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: '', enable: { start: 0 }, @@ -216,6 +207,7 @@ function getGlobalAdLibPiecesOfftube( outputLayerId: 'musik', expectedDuration: 1000, lifespan: PieceLifespan.WithinPart, + tags: [AdlibTags.ADLIB_STOP_AUDIO_BED], content: { timelineObjects: [ literal({ @@ -244,146 +236,123 @@ function getGlobalAdlibActionsOfftube( _context: IStudioUserContext, config: OfftubeShowstyleBlueprintConfig ): IBlueprintActionManifest[] { - const res: IBlueprintActionManifest[] = [] + const blueprintActions: IBlueprintActionManifest[] = [] let globalRank = 2000 function makeCutCameraActions(info: SourceInfo, queue: boolean, rank: number) { - res.push( - literal({ - actionId: AdlibActionType.CUT_TO_CAMERA, - userData: literal({ - type: AdlibActionType.CUT_TO_CAMERA, - queue, - name: info.id - }), + const sourceDefinition = SourceInfoToSourceDefinition(info) as SourceDefinitionKam + const userData: ActionCutToCamera = { + type: AdlibActionType.CUT_TO_CAMERA, + queue, + sourceDefinition + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_TO_CAMERA, + userData, + userDataManifest: {}, + display: { + _rank: rank, + label: t(sourceDefinition.name), + sourceLayerId: OfftubeSourceLayer.PgmCam, + outputLayerId: SharedOutputLayers.PGM, + content: {}, + tags: queue ? [AdlibTags.OFFTUBE_SET_CAM_NEXT, AdlibTags.ADLIB_QUEUE_NEXT] : [AdlibTags.ADLIB_CUT_DIRECT], + currentPieceTags: [GetTagForKam(sourceDefinition)], + nextPieceTags: [GetTagForKam(sourceDefinition)] + } + }) + } + + function makeRemoteAction(sourceInfo: SourceInfo, rank: number) { + const sourceDefinition = SourceInfoToSourceDefinition(sourceInfo) as SourceDefinitionRemote + const userData: ActionCutToRemote = { + type: AdlibActionType.CUT_TO_REMOTE, + sourceDefinition + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_TO_REMOTE, + userData, + userDataManifest: {}, + display: { + _rank: rank, + label: t(`${sourceDefinition.name}`), + sourceLayerId: OfftubeSourceLayer.PgmLive, + outputLayerId: OfftubeOutputLayers.PGM, + content: {}, + tags: [AdlibTags.OFFTUBE_SET_REMOTE_NEXT, AdlibTags.ADLIB_QUEUE_NEXT], + currentPieceTags: [GetTagForLive(sourceDefinition)], + nextPieceTags: [GetTagForLive(sourceDefinition)] + } + }) + } + + function makeAdlibBoxesActions( + info: SourceInfo, + type: SourceInfoType.KAM | SourceInfoType.LIVE | SourceInfoType.FEED, + rank: number + ) { + for (let box = 0; box < NUMBER_OF_DVE_BOXES; box++) { + const sourceDefinition = SourceInfoToSourceDefinition(info) + const layer = type === SourceInfoType.KAM ? OfftubeSourceLayer.PgmCam : OfftubeSourceLayer.PgmLive + const userData: ActionCutSourceToBox = { + type: AdlibActionType.CUT_SOURCE_TO_BOX, + name: sourceDefinition.name, + box, + sourceDefinition + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_SOURCE_TO_BOX, + userData, userDataManifest: {}, display: { - _rank: rank, - label: t(`KAM ${info.id}`), - sourceLayerId: OfftubeSourceLayer.PgmCam, - outputLayerId: SharedOutputLayers.PGM, + _rank: rank + 0.1 * box, + label: t(`${sourceDefinition.name} inp ${box + 1}`), + sourceLayerId: layer, + outputLayerId: OfftubeOutputLayers.PGM, content: {}, - tags: queue ? [AdlibTags.OFFTUBE_SET_CAM_NEXT] : [], - currentPieceTags: [GetTagForKam(info.id)], - nextPieceTags: [GetTagForKam(info.id)] + tags: [AdlibTagCutToBox(box)] } }) - ) + } } - function makeRemoteAction(name: string, type: 'Live' | 'Feed', port: number, rank: number) { - res.push( - literal({ - actionId: AdlibActionType.CUT_TO_REMOTE, - userData: literal({ - type: AdlibActionType.CUT_TO_REMOTE, - name, - port - }), + function makeServerAdlibBoxesActions(rank: number) { + for (let box = 0; box < NUMBER_OF_DVE_BOXES; box++) { + const userData: ActionCutSourceToBox = { + type: AdlibActionType.CUT_SOURCE_TO_BOX, + name: `SERVER`, + box, + sourceDefinition: { sourceType: SourceType.SERVER } + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.CUT_SOURCE_TO_BOX, + userData, userDataManifest: {}, display: { - _rank: rank, - label: t(`${type} ${name}`), - sourceLayerId: OfftubeSourceLayer.PgmLive, - outputLayerId: OfftubeOutputLayers.PGM, + _rank: rank + 0.1 * box, + label: t(`Server inp ${box + 1}`), + sourceLayerId: OfftubeSourceLayer.PgmServer, + outputLayerId: SharedOutputLayers.SEC, content: {}, - tags: [AdlibTags.OFFTUBE_SET_REMOTE_NEXT], - currentPieceTags: [GetTagForLive(name)], - nextPieceTags: [GetTagForLive(name)] + tags: [AdlibTagCutToBox(box)] } }) - ) - } - - function makeAdlibBoxesActions(info: SourceInfo, type: 'Kamera' | 'Live', rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - const feed = type === 'Live' && info.id.match(/^F(.+).*$/) - const name = feed ? `Feed ${feed[1]}` : `${type} ${info.id}` - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name, - port: info.port, - sourceType: info.type, - box - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`Cut ${name} to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: OfftubeOutputLayers.PGM, - content: {}, - tags: [] - } - }) - ) - }) - } - - function makeAdlibBoxesActionsDirectPlayback(info: SourceInfo, vo: boolean, rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name: `EVS ${info.id.replace(/dp/i, '')}${vo ? ' VO' : ''}`, - port: info.port, - sourceType: info.type, - box, - vo - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`EVS ${info.id.replace(/dp/i, '')}${vo ? ' VO' : ''} to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: SharedOutputLayers.SEC, - content: {}, - tags: [] - } - }) - ) - }) - } - - function makeServerAdlibBoxesActions(rank: number) { - Object.values(boxLayers).forEach((layer, box) => { - res.push( - literal({ - actionId: AdlibActionType.CUT_SOURCE_TO_BOX, - userData: literal({ - type: AdlibActionType.CUT_SOURCE_TO_BOX, - name: `SERVER`, - port: -1, - sourceType: SourceLayerType.VT, - box, - server: true - }), - userDataManifest: {}, - display: { - _rank: rank + 0.1 * box, - label: t(`Server to box ${box + 1}`), - sourceLayerId: layer, - outputLayerId: SharedOutputLayers.SEC, - content: {}, - tags: [] - } - }) - ) - }) + } } - res.push( - literal({ + function makeCommentatorSelectServerAction(): IBlueprintActionManifest { + const userData: ActionCommentatorSelectServer = { + type: AdlibActionType.COMMENTATOR_SELECT_SERVER + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.COMMENTATOR_SELECT_SERVER, - userData: literal({ - type: AdlibActionType.COMMENTATOR_SELECT_SERVER - }), + userData, userDataManifest: {}, display: { _rank: globalRank++, @@ -395,15 +364,19 @@ function getGlobalAdlibActionsOfftube( currentPieceTags: [TallyTags.SERVER_IS_LIVE], nextPieceTags: [TallyTags.SERVER_IS_LIVE] } - }) - ) + } + } - res.push( - literal({ + blueprintActions.push(makeCommentatorSelectServerAction()) + + function makeCommentatorSelectDveAction(): IBlueprintActionManifest { + const userData: ActionCommentatorSelectDVE = { + type: AdlibActionType.COMMENTATOR_SELECT_DVE + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.COMMENTATOR_SELECT_DVE, - userData: literal({ - type: AdlibActionType.COMMENTATOR_SELECT_DVE - }), + userData, userDataManifest: {}, display: { _rank: globalRank++, @@ -415,15 +388,19 @@ function getGlobalAdlibActionsOfftube( currentPieceTags: [TallyTags.DVE_IS_LIVE], nextPieceTags: [TallyTags.DVE_IS_LIVE] } - }) - ) + } + } + + blueprintActions.push(makeCommentatorSelectDveAction()) - res.push( - literal({ + function makeCommentatorSelectFullAction(): IBlueprintActionManifest { + const userData: ActionCommentatorSelectFull = { + type: AdlibActionType.COMMENTATOR_SELECT_FULL + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.COMMENTATOR_SELECT_FULL, - userData: literal({ - type: AdlibActionType.COMMENTATOR_SELECT_FULL - }), + userData, userDataManifest: {}, display: { _rank: globalRank++, @@ -435,17 +412,21 @@ function getGlobalAdlibActionsOfftube( currentPieceTags: [TallyTags.FULL_IS_LIVE], nextPieceTags: [TallyTags.FULL_IS_LIVE] } - }) - ) + } + } + + blueprintActions.push(makeCommentatorSelectFullAction()) - res.push( - literal({ + function makeClearGraphicsAltudAction(): IBlueprintActionManifest { + const userData: ActionClearGraphics = { + type: AdlibActionType.CLEAR_GRAPHICS, + sendCommands: false, + label: 'GFX Altud' + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.CLEAR_GRAPHICS, - userData: literal({ - type: AdlibActionType.CLEAR_GRAPHICS, - sendCommands: false, - label: 'GFX Altud' - }), + userData, userDataManifest: {}, display: { _rank: 400, @@ -453,117 +434,131 @@ function getGlobalAdlibActionsOfftube( sourceLayerId: SharedSourceLayers.PgmAdlibGraphicCmd, outputLayerId: SharedOutputLayers.SEC, content: {}, - tags: [AdlibTags.ADLIB_STATIC_BUTTON], + tags: [AdlibTags.ADLIB_STATIC_BUTTON, AdlibTags.ADLIB_GFX_ALTUD], currentPieceTags: [TallyTags.GFX_ALTUD], nextPieceTags: [TallyTags.GFX_ALTUD] } - }) - ) + } + } - res.push(...GetTransitionAdLibActions(config, 800)) + blueprintActions.push(makeClearGraphicsAltudAction()) - res.push( - literal({ + blueprintActions.push(...GetTransitionAdLibActions(config, 800)) + + function makeRecallLastDveAction(): IBlueprintActionManifest { + const userData: ActionRecallLastDVE = { + type: AdlibActionType.RECALL_LAST_DVE + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.RECALL_LAST_DVE, - userData: literal({ - type: AdlibActionType.RECALL_LAST_DVE - }), + userData, userDataManifest: {}, display: { _rank: 1, label: t('Last DVE'), sourceLayerId: OfftubeSourceLayer.PgmDVEAdLib, - outputLayerId: 'pgm' + outputLayerId: 'pgm', + tags: [AdlibTags.ADLIB_RECALL_LAST_DVE] } - }) - ) + } + } + + blueprintActions.push(makeRecallLastDveAction()) _.each(config.showStyle.DVEStyles, (dveConfig, i) => { - res.push( - literal({ - actionId: AdlibActionType.SELECT_DVE_LAYOUT, - userData: literal({ - type: AdlibActionType.SELECT_DVE_LAYOUT, - config: dveConfig - }), - userDataManifest: {}, - display: { - _rank: 200 + i, - label: t(dveConfig.DVEName), - sourceLayerId: OfftubeSourceLayer.PgmDVEAdLib, - outputLayerId: SharedOutputLayers.PGM - } - }) - ) + const userData: ActionSelectDVELayout = { + type: AdlibActionType.SELECT_DVE_LAYOUT, + config: dveConfig + } + blueprintActions.push({ + externalId: generateExternalId(_context, userData), + actionId: AdlibActionType.SELECT_DVE_LAYOUT, + userData, + userDataManifest: {}, + display: { + _rank: 200 + i, + label: t(dveConfig.DVEName), + sourceLayerId: OfftubeSourceLayer.PgmDVEAdLib, + outputLayerId: SharedOutputLayers.PGM, + tags: [AdlibTags.ADLIB_SELECT_DVE_LAYOUT, dveConfig.DVEName] + } + }) }) - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + config.sources.cameras .slice(0, 5) // the first x cameras to create INP1/2/3 cam-adlibs from .forEach(o => { makeCutCameraActions(o, false, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + config.sources.cameras .slice(0, 5) // the first x cameras to create preview cam-adlibs from .forEach(o => { makeCutCameraActions(o, true, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.CAMERA) + config.sources.cameras .slice(0, 5) // the first x cameras to create preview cam-adlibs from .forEach(o => { - makeAdlibBoxesActions(o, 'Kamera', globalRank++) + makeAdlibBoxesActions(o, SourceInfoType.KAM, globalRank++) }) - res.push( - literal({ + function makeRecallLastLiveAction(): IBlueprintActionManifest { + const userData: ActionRecallLastLive = { + type: AdlibActionType.RECALL_LAST_LIVE + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.RECALL_LAST_LIVE, - userData: literal({ - type: AdlibActionType.RECALL_LAST_LIVE - }), + userData, userDataManifest: {}, display: { _rank: 1, label: t('Last Live'), sourceLayerId: OfftubeSourceLayer.PgmLive, - outputLayerId: SharedOutputLayers.PGM + outputLayerId: SharedOutputLayers.PGM, + tags: [AdlibTags.ADLIB_RECALL_LAST_LIVE] } + } + } + + blueprintActions.push(makeRecallLastLiveAction()) + + config.sources.feeds + .slice(0, 10) // the first x sources to create feed-adlibs from + .forEach(o => { + makeRemoteAction(o, globalRank++) }) - ) - config.sources - .filter(u => u.type === SourceLayerType.REMOTE) - .slice(0, 10) // the first x cameras to create live-adlibs from + config.sources.lives + .slice(0, 10) // the first x sources to create live-adlibs from .forEach(o => { - makeRemoteAction(o.id, o.id.match(/^F/) ? 'Feed' : 'Live', o.port, globalRank++) + makeRemoteAction(o, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.REMOTE) - .slice(0, 10) // the first x remote to create INP1/2/3 live-adlibs from + config.sources.feeds + .slice(0, 10) // the first x remote to create INP1/2/3 feed-adlibs from .forEach(o => { - makeAdlibBoxesActions(o, 'Live', globalRank++) + makeAdlibBoxesActions(o, SourceInfoType.FEED, globalRank++) }) - config.sources - .filter(u => u.type === SourceLayerType.LOCAL) + config.sources.lives .slice(0, 10) // the first x remote to create INP1/2/3 live-adlibs from .forEach(o => { - makeAdlibBoxesActionsDirectPlayback(o, false, globalRank++) - makeAdlibBoxesActionsDirectPlayback(o, true, globalRank++) + makeAdlibBoxesActions(o, SourceInfoType.LIVE, globalRank++) }) makeServerAdlibBoxesActions(globalRank++) - res.push( - literal({ + function makeCommentatorSelectJingleAction(): IBlueprintActionManifest { + const userData: ActionCommentatorSelectJingle = { + type: AdlibActionType.COMMENTATOR_SELECT_JINGLE + } + return { + externalId: generateExternalId(_context, userData), actionId: AdlibActionType.COMMENTATOR_SELECT_JINGLE, - userData: literal({ - type: AdlibActionType.COMMENTATOR_SELECT_JINGLE - }), + userData, userDataManifest: {}, display: { _rank: globalRank++, @@ -575,10 +570,12 @@ function getGlobalAdlibActionsOfftube( currentPieceTags: [TallyTags.JINGLE_IS_LIVE], nextPieceTags: [TallyTags.JINGLE_IS_LIVE] } - }) - ) + } + } + + blueprintActions.push(makeCommentatorSelectJingleAction()) - return res + return blueprintActions } function getBaseline(config: OfftubeShowstyleBlueprintConfig): BlueprintResultBaseline { diff --git a/src/tv2_offtube_showstyle/getSegment.ts b/src/tv2_offtube_showstyle/getSegment.ts index efc766528..eedba6e0c 100644 --- a/src/tv2_offtube_showstyle/getSegment.ts +++ b/src/tv2_offtube_showstyle/getSegment.ts @@ -2,13 +2,12 @@ import { BlueprintResultPart, BlueprintResultSegment, CameraContent, - IBlueprintPiece, IngestSegment, ISegmentUserContext, PieceLifespan, TSR, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { getSegmentBase, literal } from 'tv2-common' import { SharedOutputLayers } from 'tv2-constants' import * as _ from 'underscore' @@ -22,10 +21,13 @@ import { OfftubeCreatePartServer } from './parts/OfftubeServer' import { CreatePartUnknown } from './parts/OfftubeUnknown' import { postProcessPartTimelineObjects } from './postProcessTimelineObjects' -export function getSegment(context: ISegmentUserContext, ingestSegment: IngestSegment): BlueprintResultSegment { +export async function getSegment( + context: ISegmentUserContext, + ingestSegment: IngestSegment +): Promise { const config = getConfig(context) - const result: BlueprintResultSegment = getSegmentBase(context, ingestSegment, { + const result: BlueprintResultSegment = await getSegmentBase(context, ingestSegment, { getConfig, CreatePartContinuity, CreatePartUnknown, @@ -50,15 +52,18 @@ export function getSegment(context: ISegmentUserContext, ingestSegment: IngestSe } } -function CreatePartContinuity(config: OfftubeShowstyleBlueprintConfig, ingestSegment: IngestSegment) { - return literal({ +function CreatePartContinuity( + config: OfftubeShowstyleBlueprintConfig, + ingestSegment: IngestSegment +): BlueprintResultPart { + return { part: { externalId: `${ingestSegment.externalId}-CONTINUITY`, title: 'CONTINUITY', untimed: true }, pieces: [ - literal({ + { externalId: `${ingestSegment.externalId}-CONTINUITY`, enable: { start: 0 @@ -70,7 +75,7 @@ function CreatePartContinuity(config: OfftubeShowstyleBlueprintConfig, ingestSeg content: literal>({ studioLabel: '', switcherInput: config.studio.AtemSource.Continuity, - timelineObjects: _.compact([ + timelineObjects: _.compact([ literal({ id: '', enable: { @@ -89,8 +94,9 @@ function CreatePartContinuity(config: OfftubeShowstyleBlueprintConfig, ingestSeg }) ]) }) - }) + } ], - adLibPieces: [] - }) + adLibPieces: [], + actions: [] + } } diff --git a/src/tv2_offtube_showstyle/helpers/EvaluateCues.ts b/src/tv2_offtube_showstyle/helpers/EvaluateCues.ts index de6afa96a..1744b59d3 100644 --- a/src/tv2_offtube_showstyle/helpers/EvaluateCues.ts +++ b/src/tv2_offtube_showstyle/helpers/EvaluateCues.ts @@ -5,7 +5,7 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { CueDefinition, EvaluateCuesBase, EvaluateCuesOptions, EvaluateLYD, PartDefinition } from 'tv2-common' import { OfftubeEvaluateAdLib } from '../cues/OfftubeAdlib' import { OfftubeEvaluateDVE } from '../cues/OfftubeDVE' @@ -17,7 +17,7 @@ import { OfftubeEvaluateJingle } from '../cues/OfftubeJingle' import { OfftubeEvaluatePgmClean } from '../cues/OfftubePgmClean' import { OfftubeShowstyleBlueprintConfig } from './config' -export function OfftubeEvaluateCues( +export async function OfftubeEvaluateCues( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, part: IBlueprintPart, @@ -29,7 +29,7 @@ export function OfftubeEvaluateCues( partDefinition: PartDefinition, options: EvaluateCuesOptions ) { - EvaluateCuesBase( + await EvaluateCuesBase( { EvaluateCueDVE: OfftubeEvaluateDVE, EvaluateCueJingle: OfftubeEvaluateJingle, diff --git a/src/tv2_offtube_showstyle/helpers/config.ts b/src/tv2_offtube_showstyle/helpers/config.ts index 32e3e4068..3ad8906ad 100644 --- a/src/tv2_offtube_showstyle/helpers/config.ts +++ b/src/tv2_offtube_showstyle/helpers/config.ts @@ -4,8 +4,8 @@ import { IShowStyleContext, IStudioContext, TableConfigItemValue -} from '@sofie-automation/blueprints-integration' -import { TV2ShowstyleBlueprintConfigBase } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { TableConfigGraphicsSetup, TV2ShowstyleBlueprintConfigBase } from 'tv2-common' import * as _ from 'underscore' import { OfftubeStudioBlueprintConfig } from '../../tv2_offtube_studio/helpers/config' @@ -22,6 +22,7 @@ export interface TableConfigItemGFXTemplates { export interface OfftubeShowstyleBlueprintConfig extends OfftubeStudioBlueprintConfig { showStyle: OfftubeShowStyleConfig + selectedGraphicsSetup: TableConfigGraphicsSetup } export interface DVEConfigInput { @@ -37,8 +38,27 @@ export interface OfftubeShowStyleConfig extends TV2ShowstyleBlueprintConfigBase WipesConfig: TableConfigItemValue } -export function parseConfig(_context: ICommonContext, config: IBlueprintConfig): any { - return { showStyle: config } +function findGraphicsSetup( + _context: ICommonContext, + _config: TV2ShowstyleBlueprintConfigBase +): TableConfigGraphicsSetup { + // just for type compatibility, not really supported in offtube + return { + Name: '', + VcpConcept: '', + OvlShowId: '', + FullShowId: '', + DveLayoutFolder: '' + } +} + +export function parseConfig(context: ICommonContext, rawConfig: IBlueprintConfig): any { + const showstyleConfig = (rawConfig as unknown) as OfftubeShowStyleConfig + const selectedGraphicsSetup = findGraphicsSetup(context, showstyleConfig) + return { + showStyle: showstyleConfig, + selectedGraphicsSetup + } } export function getConfig(context: IShowStyleContext): OfftubeShowstyleBlueprintConfig { diff --git a/src/tv2_offtube_showstyle/index.ts b/src/tv2_offtube_showstyle/index.ts index 185f1ec6e..e6aba71e8 100644 --- a/src/tv2_offtube_showstyle/index.ts +++ b/src/tv2_offtube_showstyle/index.ts @@ -1,4 +1,5 @@ -import { BlueprintManifestType, ShowStyleBlueprintManifest } from '@sofie-automation/blueprints-integration' +import { BlueprintManifestType, ShowStyleBlueprintManifest } from '@tv2media/blueprints-integration' +import { getShowStyleVariantId } from '../tv2-common/getShowStyleVariantId' import { showStyleConfigManifest } from './config-manifests' import { showStyleMigrations } from './migrations' @@ -6,7 +7,7 @@ import { GetShowStyleManifestWithMixins, ShowStyleManifestMixinINews } from 'ine import { getEndStateForPart } from 'tv2-common' import { onTimelineGenerateOfftube } from '../tv2_offtube_showstyle/onTimelineGenerate' import { executeActionOfftube } from './actions' -import { getRundown, getShowStyleVariantId } from './getRundown' +import { getRundown } from './getRundown' import { getSegment } from './getSegment' import { parseConfig } from './helpers/config' import { syncIngestUpdateToPartInstance } from './syncIngestUpdateToPartInstances' diff --git a/src/tv2_offtube_showstyle/migrations/hotkeys.ts b/src/tv2_offtube_showstyle/migrations/hotkeys.ts new file mode 100644 index 000000000..52a07d7fe --- /dev/null +++ b/src/tv2_offtube_showstyle/migrations/hotkeys.ts @@ -0,0 +1,37 @@ +import { + ConfigManifestEntryTable, + MigrationContextShowStyle, + TableConfigItemValue +} from '@tv2media/blueprints-integration' +import { GlobalHotkeySources } from 'tv2-common' +import { + manifestOfftubeSourcesCam, + manifestOfftubeSourcesFeed, + manifestOfftubeSourcesRM +} from '../../tv2_offtube_studio/config-manifests' +import { dveStylesManifest } from '../config-manifests' + +export function GetDefaultStudioSourcesForOfftube(context: MigrationContextShowStyle): GlobalHotkeySources { + const dveLayoutConfig = context.getBaseConfig('DVEStyles') as TableConfigItemValue | undefined + let dveLayouts: string[] = [] + if (dveLayoutConfig?.length) { + dveLayouts = dveLayoutConfig.map(dve => dve.DVEName).filter(name => name !== undefined) as string[] + } else { + dveLayouts = (dveStylesManifest as ConfigManifestEntryTable).defaultVal + .map(dve => dve.DVEName) + .filter(name => name !== undefined) as string[] + } + + const camera = manifestOfftubeSourcesCam.defaultVal.map(source => source.SourceName) as string[] + const remote = manifestOfftubeSourcesRM.defaultVal.map(source => source.SourceName) as string[] + const feed = manifestOfftubeSourcesFeed.defaultVal.map(source => `F${source.SourceName}`) + const local: string[] = [] + + return { + camera, + remote, + feed, + local, + dveLayouts + } +} diff --git a/src/tv2_offtube_showstyle/migrations/index.ts b/src/tv2_offtube_showstyle/migrations/index.ts index 81bd25e4f..9ca3d320d 100644 --- a/src/tv2_offtube_showstyle/migrations/index.ts +++ b/src/tv2_offtube_showstyle/migrations/index.ts @@ -1,21 +1,24 @@ -import { MigrationStepShowStyle } from '@sofie-automation/blueprints-integration' +import { MigrationStepShowStyle, SourceLayerType } from '@tv2media/blueprints-integration' import { AddGraphicToGFXTable, + changeGFXTemplate, + GetDefaultAdLibTriggers, GetDSKSourceLayerNames, - literal, + RemoveOldShortcuts, removeSourceLayer, renameSourceLayer, - SetShortcutListMigrationStep, SetShowstyleTransitionMigrationStep, + SetSourceLayerName, + SetSourceLayerProperties, StripFolderFromAudioBedConfig, StripFolderFromDVEConfig, UpsertValuesIntoTransitionTable } from 'tv2-common' -import { GraphicLLayer, SharedSourceLayers } from 'tv2-constants' -import * as _ from 'underscore' -import { SetSourceLayerNameMigrationStep } from '../../tv2-common/migrations/shortcuts' +import { SharedGraphicLLayer, SharedSourceLayers } from 'tv2-constants' import { ATEMModel } from '../../types/atem' import { OfftubeSourceLayer } from '../layers' +import { GetDefaultStudioSourcesForOfftube } from './hotkeys' +import sourcelayerDefaults from './sourcelayer-defaults' import { forceSourceLayerToDefaults, getOutputLayerDefaultsMigrationSteps, @@ -44,35 +47,29 @@ enum VizLLayer { } export const remapVizLLayer: Map = new Map([ - [VizLLayer.VizLLayerOverlay, GraphicLLayer.GraphicLLayerOverlay], - [VizLLayer.VizLLayerOverlayIdent, GraphicLLayer.GraphicLLayerOverlayIdent], - [VizLLayer.VizLLayerOverlayTopt, GraphicLLayer.GraphicLLayerOverlayIdent], - [VizLLayer.VizLLayerOverlayLower, GraphicLLayer.GraphicLLayerOverlayLower], - [VizLLayer.VizLLayerOverlayHeadline, GraphicLLayer.GraphicLLayerOverlayHeadline], - [VizLLayer.VizLLayerOverlayTema, GraphicLLayer.GraphicLLayerOverlayTema], - [VizLLayer.VizLLayerPilot, GraphicLLayer.GraphicLLayerPilot], - [VizLLayer.VizLLayerPilotOverlay, GraphicLLayer.GraphicLLayerPilotOverlay], - [VizLLayer.VizLLayerDesign, GraphicLLayer.GraphicLLayerDesign], - [VizLLayer.VizLLayerAdLibs, GraphicLLayer.GraphicLLayerAdLibs], - [VizLLayer.VizLLayerWall, GraphicLLayer.GraphicLLayerWall] + [VizLLayer.VizLLayerOverlay, SharedGraphicLLayer.GraphicLLayerOverlay], + [VizLLayer.VizLLayerOverlayIdent, SharedGraphicLLayer.GraphicLLayerOverlayIdent], + [VizLLayer.VizLLayerOverlayTopt, SharedGraphicLLayer.GraphicLLayerOverlayIdent], + [VizLLayer.VizLLayerOverlayLower, SharedGraphicLLayer.GraphicLLayerOverlayLower], + [VizLLayer.VizLLayerOverlayHeadline, SharedGraphicLLayer.GraphicLLayerOverlayHeadline], + [VizLLayer.VizLLayerOverlayTema, SharedGraphicLLayer.GraphicLLayerOverlayTema], + [VizLLayer.VizLLayerPilot, SharedGraphicLLayer.GraphicLLayerPilot], + [VizLLayer.VizLLayerPilotOverlay, SharedGraphicLLayer.GraphicLLayerPilotOverlay], + [VizLLayer.VizLLayerDesign, SharedGraphicLLayer.GraphicLLayerDesign], + [VizLLayer.VizLLayerAdLibs, SharedGraphicLLayer.GraphicLLayerAdLibs], + [VizLLayer.VizLLayerWall, SharedGraphicLLayer.GraphicLLayerWall] ]) export const remapVizDOvl: Map = new Map([['viz-d-ovl', 'OVL1']]) -/** Migrations overriden later */ -// 1.3.1 -const jingle131 = SetShortcutListMigrationStep( - '1.3.1', - OfftubeSourceLayer.PgmJingle, - 'NumpadDivide,NumpadSubtract,NumpadAdd' -) +const SHOW_STYLE_ID = 'tv2_offtube_showstyle' /** * Versions: * 0.1.0: Core 0.24.0 */ -export const showStyleMigrations: MigrationStepShowStyle[] = literal([ +export const showStyleMigrations: MigrationStepShowStyle[] = [ // Fill in any layers that did not exist before // Note: These should only be run as the very final step of all migrations. otherwise they will add items too early, and confuse old migrations ...getCreateVariantMigrationSteps(), @@ -81,20 +78,12 @@ export const showStyleMigrations: MigrationStepShowStyle[] = literal { - return literal({ + return { id: `${versionStr}.sourcelayer.defaults${force ? '.forced' : ''}.${defaultVal._id}`, version: versionStr, canBeRunAutomatically: true, @@ -39,13 +39,13 @@ export function getSourceLayerDefaultsMigrationSteps(versionStr: string, force?: context.insertSourceLayer(defaultVal._id, defaultVal) } } - }) + } }) ) } export function forceSettingToDefaults(versionStr: string, setting: string): MigrationStepShowStyle { - return literal({ + return { id: `${versionStr}.sourcelayer.defaults.${setting}.forced`, version: versionStr, canBeRunAutomatically: true, @@ -78,13 +78,13 @@ export function forceSettingToDefaults(versionStr: string, setting: string): Mig context.setBaseConfig(setting, defaultVal.defaultVal) } } - }) + } } export function getOutputLayerDefaultsMigrationSteps(versionStr: string): MigrationStepShowStyle[] { return _.compact( _.map(OutputlayerDefaults, (defaultVal: IOutputLayer): MigrationStepShowStyle | null => { - return literal({ + return { id: `${versionStr}.outputlayer.defaults.${defaultVal._id}`, version: versionStr, canBeRunAutomatically: true, @@ -99,7 +99,7 @@ export function getOutputLayerDefaultsMigrationSteps(versionStr: string): Migrat context.insertOutputLayer(defaultVal._id, defaultVal) } } - }) + } }) ) } @@ -112,7 +112,7 @@ function remapTableColumnValuesInner( ): { changed: number; table: TableConfigItemValue } { let changed = 0 - table.map(row => { + table.forEach(row => { const val = row[columnId] if (val) { @@ -123,8 +123,6 @@ function remapTableColumnValuesInner( changed++ } } - - return row }) return { changed, table } @@ -135,7 +133,7 @@ export function forceSourceLayerToDefaults( layer: string, overrideSteps?: string[] ): MigrationStepShowStyle { - return forceSourceLayerToDefaultsBase(SourcelayerDefaults, versionStr, layer, overrideSteps) + return forceSourceLayerToDefaultsBase(SourcelayerDefaults, versionStr, 'Offtube', layer, overrideSteps) } export function remapTableColumnValues( @@ -153,12 +151,8 @@ export function remapTableColumnValues( validate: (context: MigrationContextShowStyle) => { const table = context.getBaseConfig(tableId) as TableConfigItemValue | undefined - if (!table) { - return `Table "${tableId}" does not exist` - } - - if (!table.length) { - // No values, nothing to remap + if (!table || !table.length) { + // No table or no values, nothing to remap return false } diff --git a/src/tv2_offtube_showstyle/migrations/variants-defaults.ts b/src/tv2_offtube_showstyle/migrations/variants-defaults.ts index 24f45aa3c..2767d6458 100644 --- a/src/tv2_offtube_showstyle/migrations/variants-defaults.ts +++ b/src/tv2_offtube_showstyle/migrations/variants-defaults.ts @@ -1,4 +1,4 @@ -import { MigrationContextShowStyle, MigrationStepShowStyle } from '@sofie-automation/blueprints-integration' +import { MigrationContextShowStyle, MigrationStepShowStyle } from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import * as _ from 'underscore' diff --git a/src/tv2_offtube_showstyle/onTimelineGenerate.ts b/src/tv2_offtube_showstyle/onTimelineGenerate.ts index 341980170..805cbe46f 100644 --- a/src/tv2_offtube_showstyle/onTimelineGenerate.ts +++ b/src/tv2_offtube_showstyle/onTimelineGenerate.ts @@ -6,9 +6,15 @@ import { PartEndState, TimelinePersistentState, TSR -} from '@sofie-automation/blueprints-integration' -import { disablePilotWipeAfterJingle, onTimelineGenerate, PartEndStateExt, TimelineBlueprintExt } from 'tv2-common' -import { GraphicLLayer, TallyTags } from 'tv2-constants' +} from '@tv2media/blueprints-integration' +import { + disablePilotWipeAfterJingle, + onTimelineGenerate, + PartEndStateExt, + PieceMetaData, + TimelineBlueprintExt +} from 'tv2-common' +import { SharedGraphicLLayer, TallyTags } from 'tv2-constants' import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../tv2_offtube_studio/layers' import { getConfig } from './helpers/config' @@ -17,7 +23,7 @@ export function onTimelineGenerateOfftube( timeline: OnGenerateTimelineObj[], previousPersistentState: TimelinePersistentState | undefined, previousPartEndState: PartEndState | undefined, - resolvedPieces: IBlueprintResolvedPieceInstance[] + resolvedPieces: Array> ): Promise { const previousPartEndState2 = previousPartEndState as PartEndStateExt | undefined disablePilotWipeAfterJingle(timeline, previousPartEndState2, resolvedPieces) @@ -54,7 +60,7 @@ export function disableFirstPilotGFXAnimation( const isFull = resolvedPieces.find(p => p.piece.tags?.includes(TallyTags.FULL_IS_LIVE)) for (const obj of timeline) { if ( - obj.layer === GraphicLLayer.GraphicLLayerPilot && + obj.layer === SharedGraphicLLayer.GraphicLLayerPilot && obj.content.deviceType === TSR.DeviceType.CASPARCG && (obj.isLookahead || (isFull && !previousPartEndState?.fullFileName) || diff --git a/src/tv2_offtube_showstyle/parts/OfftubeDVE.ts b/src/tv2_offtube_showstyle/parts/OfftubeDVE.ts index b9c6f57c5..e4c365924 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeDVE.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeDVE.ts @@ -6,37 +6,32 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { AddScript, literal, PartDefinitionDVE, PartTime } from 'tv2-common' -import { CueType } from 'tv2-constants' +} from '@tv2media/blueprints-integration' +import { AddScript, PartDefinitionDVE, PartTime } from 'tv2-common' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeEvaluateCues } from '../helpers/EvaluateCues' import { OfftubeSourceLayer } from '../layers' -export function OfftubeCreatePartDVE( +export async function OfftubeCreatePartDVE( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, partDefinition: PartDefinitionDVE, totalWords: number -): BlueprintResultPart { +): Promise { const partTime = PartTime(config, partDefinition, totalWords, false) - const part = literal({ + const part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.title || `DVE`, autoNext: false, expectedDuration: partTime - }) + } const pieces: IBlueprintPiece[] = [] const adLibPieces: IBlueprintAdLibPiece[] = [] const actions: IBlueprintActionManifest[] = [] const mediaSubscriptions: HackPartMediaObjectSubscription[] = [] - if (partDefinition.cues.filter(cue => cue.type === CueType.DVE).length) { - part.prerollDuration = config.studio.CasparPrerollDuration - } - - OfftubeEvaluateCues( + await OfftubeEvaluateCues( context, config, part, diff --git a/src/tv2_offtube_showstyle/parts/OfftubeEffekt.ts b/src/tv2_offtube_showstyle/parts/OfftubeEffekt.ts index 55aff6753..b86c22f31 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeEffekt.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeEffekt.ts @@ -1,4 +1,4 @@ -import { IBlueprintPiece, IShowStyleUserContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintPiece, IShowStyleUserContext } from '@tv2media/blueprints-integration' import { CreateEffektForPartBase, PartDefinition } from 'tv2-common' import { SharedSourceLayers } from 'tv2-constants' import { OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' diff --git a/src/tv2_offtube_showstyle/parts/OfftubeGrafik.ts b/src/tv2_offtube_showstyle/parts/OfftubeGrafik.ts index 72eb7ce41..e04113b16 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeGrafik.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeGrafik.ts @@ -5,13 +5,13 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' -import { AddScript, ApplyFullGraphicPropertiesToPart, literal, PartDefinition, PartTime } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { AddScript, ApplyFullGraphicPropertiesToPart, PartDefinition, PartTime } from 'tv2-common' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeEvaluateCues } from '../helpers/EvaluateCues' import { OfftubeSourceLayer } from '../layers' -export function OfftubeCreatePartGrafik( +export async function OfftubeCreatePartGrafik( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, partDefinition: PartDefinition, @@ -20,13 +20,13 @@ export function OfftubeCreatePartGrafik( ) { const partTime = PartTime(config, partDefinition, totalWords) - const part = literal({ + const part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.title || partDefinition.type + ' - ' + partDefinition.rawType, metaData: {}, autoNext: false, expectedDuration: partTime - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -35,7 +35,7 @@ export function OfftubeCreatePartGrafik( ApplyFullGraphicPropertiesToPart(config, part) - OfftubeEvaluateCues( + await OfftubeEvaluateCues( context, config, part, diff --git a/src/tv2_offtube_showstyle/parts/OfftubeKam.ts b/src/tv2_offtube_showstyle/parts/OfftubeKam.ts index 65adbd758..055679741 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeKam.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeKam.ts @@ -6,12 +6,11 @@ import { IBlueprintPiece, ISegmentUserContext, PieceLifespan, - SourceLayerType, TimelineObjectCoreExt, TSR, VTContent, WithTimeline -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddParentClass, AddScript, @@ -19,81 +18,75 @@ import { CreatePartInvalid, CreatePartKamBase, FindDSKJingle, - FindSourceInfoStrict, - GetCameraMetaData, - GetLayersForCamera, + findSourceInfo, GetSisyfosTimelineObjForCamera, GetTagForKam, literal, PartDefinitionKam, - TransitionFromString, + PieceMetaData, TransitionSettings } from 'tv2-common' import { SharedOutputLayers, TallyTags } from 'tv2-constants' -import { OfftubeAtemLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' +import { OfftubeAtemLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeEvaluateCues } from '../helpers/EvaluateCues' import { OfftubeSourceLayer } from '../layers' import { CreateEffektForpart } from './OfftubeEffekt' -export function OfftubeCreatePartKam( +export async function OfftubeCreatePartKam( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, partDefinition: PartDefinitionKam, totalWords: number -): BlueprintResultPart { +): Promise { const partKamBase = CreatePartKamBase(context, config, partDefinition, totalWords) let part = partKamBase.part.part const partTime = partKamBase.duration const adLibPieces: IBlueprintAdLibPiece[] = [] - const pieces: IBlueprintPiece[] = [] + const pieces: Array> = [] const actions: IBlueprintActionManifest[] = [] const mediaSubscriptions: HackPartMediaObjectSubscription[] = [] const jingleDSK = FindDSKJingle(config) - if (partDefinition.rawType.match(/kam cs ?3/i)) { - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: 'CS 3 (JINGLE)', - enable: { start: 0 }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: OfftubeSourceLayer.PgmJingle, - lifespan: PieceLifespan.WithinPart, - tags: [GetTagForKam('JINGLE'), TallyTags.JINGLE_IS_LIVE], - content: literal>({ - ignoreMediaObjectStatus: true, - fileName: '', - path: '', - timelineObjects: literal([ - literal({ - id: ``, - enable: { - start: 0 - }, - priority: 1, - layer: OfftubeAtemLLayer.AtemMEClean, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: jingleDSK.Fill, - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } + if (/cs ?3/i.test(partDefinition.sourceDefinition.id)) { + pieces.push({ + externalId: partDefinition.externalId, + name: 'CS 3 (JINGLE)', + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: OfftubeSourceLayer.PgmJingle, + lifespan: PieceLifespan.WithinPart, + tags: [GetTagForKam(partDefinition.sourceDefinition), TallyTags.JINGLE_IS_LIVE], + content: literal>({ + ignoreMediaObjectStatus: true, + fileName: '', + path: '', + timelineObjects: literal([ + literal({ + id: ``, + enable: { + start: 0 + }, + priority: 1, + layer: OfftubeAtemLLayer.AtemMEClean, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: jingleDSK.Fill, + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) } - }) - ]) - }) + } + }) + ]) }) - ) + }) } else { - const sourceInfoCam = FindSourceInfoStrict(context, config.sources, SourceLayerType.CAMERA, partDefinition.rawType) + const sourceInfoCam = findSourceInfo(config.sources, partDefinition.sourceDefinition) if (sourceInfoCam === undefined) { return CreatePartInvalid(partDefinition) } @@ -101,56 +94,52 @@ export function OfftubeCreatePartKam( part = { ...part, ...CreateEffektForpart(context, config, partDefinition, pieces) } - pieces.push( - literal({ - externalId: partDefinition.externalId, - name: part.title, - enable: { start: 0 }, - outputLayerId: SharedOutputLayers.PGM, - sourceLayerId: OfftubeSourceLayer.PgmCam, - lifespan: PieceLifespan.WithinPart, - metaData: GetCameraMetaData(config, GetLayersForCamera(config, sourceInfoCam)), - tags: [GetTagForKam(sourceInfoCam.id)], - content: { - studioLabel: '', - switcherInput: atemInput, - timelineObjects: literal([ - literal({ - id: ``, - enable: { - start: 0 - }, - priority: 1, - layer: OfftubeAtemLLayer.AtemMEClean, - content: { - deviceType: TSR.DeviceType.ATEM, - type: TSR.TimelineContentTypeAtem.ME, - me: { - input: Number(atemInput), - transition: partDefinition.transition - ? TransitionFromString(partDefinition.transition.style) - : TSR.AtemTransitionStyle.CUT, - transitionSettings: TransitionSettings(partDefinition) - } - }, - ...(AddParentClass(config, partDefinition) - ? { classes: [CameraParentClass('studio0', partDefinition.variant.name)] } - : {}) - }), - - GetSisyfosTimelineObjForCamera( - context, - config, - partDefinition.rawType, - OfftubeSisyfosLLayer.SisyfosGroupStudioMics - ) - ]) + pieces.push({ + externalId: partDefinition.externalId, + name: part.title, + enable: { start: 0 }, + outputLayerId: SharedOutputLayers.PGM, + sourceLayerId: OfftubeSourceLayer.PgmCam, + lifespan: PieceLifespan.WithinPart, + metaData: { + sisyfosPersistMetaData: { + sisyfosLayers: sourceInfoCam.sisyfosLayers ?? [], + acceptPersistAudio: sourceInfoCam.acceptPersistAudio } - }) - ) + }, + tags: [GetTagForKam(partDefinition.sourceDefinition)], + content: { + studioLabel: '', + switcherInput: atemInput, + timelineObjects: literal([ + literal({ + id: ``, + enable: { + start: 0 + }, + priority: 1, + layer: OfftubeAtemLLayer.AtemMEClean, + content: { + deviceType: TSR.DeviceType.ATEM, + type: TSR.TimelineContentTypeAtem.ME, + me: { + input: Number(atemInput), + transition: partDefinition.transition ? partDefinition.transition.style : TSR.AtemTransitionStyle.CUT, + transitionSettings: TransitionSettings(config, partDefinition) + } + }, + ...(AddParentClass(config, partDefinition) + ? { classes: [CameraParentClass('studio0', partDefinition.sourceDefinition.id)] } + : {}) + }), + + ...GetSisyfosTimelineObjForCamera(config, sourceInfoCam, partDefinition.sourceDefinition.minusMic) + ]) + } + }) } - OfftubeEvaluateCues( + await OfftubeEvaluateCues( context, config, part, @@ -174,6 +163,7 @@ export function OfftubeCreatePartKam( return { part, adLibPieces, - pieces + pieces, + actions } } diff --git a/src/tv2_offtube_showstyle/parts/OfftubeServer.ts b/src/tv2_offtube_showstyle/parts/OfftubeServer.ts index 778b54014..4a72ec850 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeServer.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeServer.ts @@ -3,7 +3,7 @@ import { HackPartMediaObjectSubscription, IBlueprintActionManifest, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, CreateAdlibServer, CreatePartServerBase, PartDefinition, ServerPartProps } from 'tv2-common' import { OfftubeAtemLLayer, OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../../tv2_offtube_studio/layers' import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' @@ -11,16 +11,16 @@ import { OfftubeEvaluateCues } from '../helpers/EvaluateCues' import { OfftubeSourceLayer } from '../layers' import { CreateEffektForpart } from './OfftubeEffekt' -export function OfftubeCreatePartServer( +export async function OfftubeCreatePartServer( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, partDefinition: PartDefinition, - props: ServerPartProps -): BlueprintResultPart { - const basePartProps = CreatePartServerBase(context, config, partDefinition, props, { + partProps: ServerPartProps +): Promise { + const basePartProps = await CreatePartServerBase(context, config, partDefinition, partProps, { SourceLayer: { - PgmServer: props.voLayer ? OfftubeSourceLayer.PgmVoiceOver : OfftubeSourceLayer.PgmServer, // TODO this actually is shared - SelectedServer: props.voLayer ? OfftubeSourceLayer.SelectedVoiceOver : OfftubeSourceLayer.SelectedServer + PgmServer: partProps.voLayer ? OfftubeSourceLayer.PgmVoiceOver : OfftubeSourceLayer.PgmServer, // TODO this actually is shared + SelectedServer: partProps.voLayer ? OfftubeSourceLayer.SelectedVoiceOver : OfftubeSourceLayer.SelectedServer }, AtemLLayer: { MEPgm: OfftubeAtemLLayer.AtemMEClean, @@ -30,8 +30,7 @@ export function OfftubeCreatePartServer( ClipPending: OfftubeCasparLLayer.CasparPlayerClipPending }, Sisyfos: { - ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending, - StudioMicsGroup: OfftubeSisyfosLLayer.SisyfosGroupStudioMics + ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending }, ATEM: { ServerLookaheadAux: OfftubeAtemLLayer.AtemAuxServerLookahead @@ -52,30 +51,25 @@ export function OfftubeCreatePartServer( part = { ...part, ...CreateEffektForpart(context, config, partDefinition, pieces) } - const sourceDuration = Math.max( - (context.hackGetMediaObjectDuration(file) || 0) * 1000 - config.studio.ServerPostrollDuration, - 0 - ) - actions.push( - CreateAdlibServer( + await CreateAdlibServer( + context, config, 0, partDefinition, file, - props.voLayer, - props.voLevels, + partProps.voLayer, + partProps.voLevels, { SourceLayer: { - PgmServer: props.voLayer ? OfftubeSourceLayer.PgmVoiceOver : OfftubeSourceLayer.PgmServer, // TODO this actually is shared - SelectedServer: props.voLayer ? OfftubeSourceLayer.SelectedVoiceOver : OfftubeSourceLayer.SelectedServer + PgmServer: partProps.voLayer ? OfftubeSourceLayer.PgmVoiceOver : OfftubeSourceLayer.PgmServer, // TODO this actually is shared + SelectedServer: partProps.voLayer ? OfftubeSourceLayer.SelectedVoiceOver : OfftubeSourceLayer.SelectedServer }, Caspar: { ClipPending: OfftubeCasparLLayer.CasparPlayerClipPending }, Sisyfos: { - ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending, - StudioMicsGroup: OfftubeSisyfosLLayer.SisyfosGroupStudioMics + ClipPending: OfftubeSisyfosLLayer.SisyfosSourceClipPending }, AtemLLayer: { MEPgm: OfftubeAtemLLayer.AtemMEClean, @@ -85,12 +79,11 @@ export function OfftubeCreatePartServer( ServerLookaheadAux: OfftubeAtemLLayer.AtemAuxServerLookahead } }, - sourceDuration, false ) ) - OfftubeEvaluateCues( + await OfftubeEvaluateCues( context, config, part, diff --git a/src/tv2_offtube_showstyle/parts/OfftubeUnknown.ts b/src/tv2_offtube_showstyle/parts/OfftubeUnknown.ts index e377d3e83..ececf2cbf 100644 --- a/src/tv2_offtube_showstyle/parts/OfftubeUnknown.ts +++ b/src/tv2_offtube_showstyle/parts/OfftubeUnknown.ts @@ -5,13 +5,12 @@ import { IBlueprintPart, IBlueprintPiece, ISegmentUserContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddScript, ApplyFullGraphicPropertiesToPart, GetJinglePartProperties, GraphicIsPilot, - literal, PartDefinition, PartTime } from 'tv2-common' @@ -20,7 +19,7 @@ import { OfftubeShowstyleBlueprintConfig } from '../helpers/config' import { OfftubeEvaluateCues } from '../helpers/EvaluateCues' import { OfftubeSourceLayer } from '../layers' -export function CreatePartUnknown( +export async function CreatePartUnknown( context: ISegmentUserContext, config: OfftubeShowstyleBlueprintConfig, partDefinition: PartDefinition, @@ -29,13 +28,13 @@ export function CreatePartUnknown( ) { const partTime = PartTime(config, partDefinition, totalWords) - let part = literal({ + let part: IBlueprintPart = { externalId: partDefinition.externalId, title: partDefinition.title || partDefinition.type + ' - ' + partDefinition.rawType, metaData: {}, autoNext: false, expectedDuration: partTime - }) + } const adLibPieces: IBlueprintAdLibPiece[] = [] const pieces: IBlueprintPiece[] = [] @@ -49,11 +48,9 @@ export function CreatePartUnknown( !partDefinition.cues.filter(c => c.type === CueType.Jingle).length ) { ApplyFullGraphicPropertiesToPart(config, part) - } else if (partDefinition.cues.filter(cue => cue.type === CueType.DVE).length) { - part.prerollDuration = config.studio.CasparPrerollDuration } - OfftubeEvaluateCues( + await OfftubeEvaluateCues( context, config, part, diff --git a/src/tv2_offtube_showstyle/postProcessTimelineObjects.ts b/src/tv2_offtube_showstyle/postProcessTimelineObjects.ts index 04e4437fd..44e44292f 100644 --- a/src/tv2_offtube_showstyle/postProcessTimelineObjects.ts +++ b/src/tv2_offtube_showstyle/postProcessTimelineObjects.ts @@ -6,8 +6,8 @@ import { TimelineObjectCoreExt, TimelineObjHoldMode, TSR -} from '@sofie-automation/blueprints-integration' -import { literal, TimelineBlueprintExt, TV2BlueprintConfig } from 'tv2-common' +} from '@tv2media/blueprints-integration' +import { TimelineBlueprintExt, TV2BlueprintConfig } from 'tv2-common' import { ControlClasses } from 'tv2-constants' import _ = require('underscore') import { OfftubeAbstractLLayer, OfftubeAtemLLayer } from '../tv2_offtube_studio/layers' @@ -60,7 +60,7 @@ export function postProcessPieceTimelineObjects( ) { if (tlObj.classes?.includes(ControlClasses.AbstractLookahead)) { // Create a lookahead-lookahead object for this me-program - const lookaheadObj = literal({ + const lookaheadObj: TSR.TimelineObjAbstractAny & TimelineBlueprintExt = { id: '', enable: { start: 0 }, priority: tlObj.holdMode === TimelineObjHoldMode.ONLY ? 5 : 0, // Must be below lookahead, except when forced by hold @@ -74,11 +74,11 @@ export function postProcessPieceTimelineObjects( mediaPlayerSession: tlObj.metaData?.mediaPlayerSession }, classes: ['ab_on_preview'] - }) + } extraObjs.push(lookaheadObj) } else { // Create a lookahead-lookahead object for this me-program - const lookaheadObj = literal({ + const lookaheadObj: TSR.TimelineObjAtemME & TimelineBlueprintExt = { id: '', enable: { start: 0 }, priority: tlObj.holdMode === TimelineObjHoldMode.ONLY ? 5 : 0, // Must be below lookahead, except when forced by hold @@ -97,7 +97,7 @@ export function postProcessPieceTimelineObjects( mediaPlayerSession: tlObj.metaData?.mediaPlayerSession }, classes: ['ab_on_preview'] - }) + } extraObjs.push(lookaheadObj) } } diff --git a/src/tv2_offtube_showstyle/syncIngestUpdateToPartInstances.ts b/src/tv2_offtube_showstyle/syncIngestUpdateToPartInstances.ts index 5c15b7874..48a42652a 100644 --- a/src/tv2_offtube_showstyle/syncIngestUpdateToPartInstances.ts +++ b/src/tv2_offtube_showstyle/syncIngestUpdateToPartInstances.ts @@ -2,7 +2,7 @@ import { BlueprintSyncIngestNewData, BlueprintSyncIngestPartInstance, ISyncIngestUpdateToPartInstanceContext -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { syncIngestUpdateToPartInstanceBase } from 'tv2-common' import { OfftubeSourceLayer } from './layers' diff --git a/src/tv2_offtube_studio/__tests__/config-manifest.spec.ts b/src/tv2_offtube_studio/__tests__/config-manifest.spec.ts index 8e2336a2d..d3a4f9825 100644 --- a/src/tv2_offtube_studio/__tests__/config-manifest.spec.ts +++ b/src/tv2_offtube_studio/__tests__/config-manifest.spec.ts @@ -24,7 +24,6 @@ const blankStudioConfig: OfftubeStudioConfig = { SourcesCam: [], SourcesRM: [], SourcesFeed: [], - SourcesSkype: [], ABMediaPlayers: [], StudioMics: [], ABPlaybackDebugLogging: false, @@ -36,7 +35,8 @@ const blankStudioConfig: OfftubeStudioConfig = { Default: 0, Continuity: 0, SplitBackground: 0, - Loop: 0 + Loop: 0, + Dip: 0 }, AtemSettings: {}, AudioBedSettings: { diff --git a/src/tv2_offtube_studio/config-manifests.ts b/src/tv2_offtube_studio/config-manifests.ts index 1e8c007dd..4d70a632c 100644 --- a/src/tv2_offtube_studio/config-manifests.ts +++ b/src/tv2_offtube_studio/config-manifests.ts @@ -4,7 +4,7 @@ import { ConfigManifestEntryType, TableConfigItemValue, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { DSKConfigManifest, literal, @@ -12,7 +12,6 @@ import { MakeConfigWithMediaFlow, TableConfigItemSourceMapping } from 'tv2-common' -import * as _ from 'underscore' import { AtemSourceIndex } from '../types/atem' import { defaultDSKConfig } from './helpers/config' import { OfftubeSisyfosLLayer } from './layers' @@ -25,7 +24,7 @@ const DEFAULT_STUDIO_MICS_LAYERS = [ OfftubeSisyfosLLayer.SisyfosSourceHost_3_ST_A ] -export const manifestOfftubeSourcesCam = MakeConfigForSources('Cam', 'Cameras', false, [ +export const manifestOfftubeSourcesCam = MakeConfigForSources('Cam', 'Cameras', false, true, [ { _id: '', SourceName: '1', @@ -35,25 +34,26 @@ export const manifestOfftubeSourcesCam = MakeConfigForSources('Cam', 'Cameras', } ]) -export const manifestOfftubeSourcesRM = MakeConfigForSources('RM', 'Live', true, [ +export const manifestOfftubeSourcesRM = MakeConfigForSources('RM', 'Live', true, true, [ { _id: '', SourceName: '1', AtemSource: 3, SisyfosLayers: [OfftubeSisyfosLLayer.SisyfosSourceLive_3], StudioMics: true, - KeepAudioInStudio: true + WantsToPersistAudio: true, + AcceptPersistAudio: false } ]) -export const manifestOfftubeSourcesFeed = MakeConfigForSources('Feed', 'Feed', true, [ +export const manifestOfftubeSourcesFeed = MakeConfigForSources('Feed', 'Feed', true, true, [ { _id: '', SourceName: '1', AtemSource: 1, SisyfosLayers: [OfftubeSisyfosLLayer.SisyfosSourceLive_1_Stereo, OfftubeSisyfosLLayer.SisyfosSourceLive_1_Surround], StudioMics: true, - KeepAudioInStudio: true + WantsToPersistAudio: false }, { _id: '', @@ -61,12 +61,10 @@ export const manifestOfftubeSourcesFeed = MakeConfigForSources('Feed', 'Feed', t AtemSource: 2, SisyfosLayers: [OfftubeSisyfosLLayer.SisyfosSourceLive_2_Stereo], StudioMics: true, - KeepAudioInStudio: true + WantsToPersistAudio: false } ]) -export const manifestOfftubeSourcesSkype = MakeConfigForSources('Skype', 'Skype', false, []) - export const manifestOfftubeSourcesABMediaPlayers: ConfigManifestEntryTable = { id: 'ABMediaPlayers', name: 'Media Players inputs', @@ -99,7 +97,7 @@ export const manifestOfftubeSourcesABMediaPlayers: ConfigManifestEntryTable = { id: 'AtemSource', name: 'ATEM input', description: 'ATEM vision mixer input for Media player', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0, rank: 1 @@ -131,7 +129,6 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ manifestOfftubeSourcesCam, manifestOfftubeSourcesRM, manifestOfftubeSourcesFeed, - manifestOfftubeSourcesSkype, manifestOfftubeSourcesABMediaPlayers, manifestOfftubeStudioMics, manifestOfftubeDownstreamKeyers, @@ -147,7 +144,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.SplitArtF', name: 'ATEM Split Screen Art Fill', description: 'ATEM vision mixer input for Split Screen Art Fill', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 10 }, @@ -155,7 +152,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.SplitArtK', name: 'ATEM Split Screen Art Key', description: 'ATEM vision mixer input for Split Screen Art Key', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 9 }, @@ -163,7 +160,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.SplitBackground', name: 'ATEM split screen background loop source', description: 'ATEM source for mos full-frame grafik background source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 11 }, @@ -171,7 +168,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.Loop', name: 'Studio screen loop graphics source', description: 'ATEM source for loop for studio screen', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 12 }, @@ -179,7 +176,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.Default', name: 'ATEM Default source', description: 'ATEM vision mixer default source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: AtemSourceIndex.Col1 }, @@ -187,7 +184,15 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AtemSource.Continuity', name: 'ATEM continuity source', description: 'ATEM input for continuity', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, + required: true, + defaultVal: AtemSourceIndex.Col2 + }, + { + id: 'AtemSource.Dip', + name: 'ATEM Dip Source', + description: 'ATEM input for the Dip - should match the desired input in the ATEM', + type: ConfigManifestEntryType.INT, required: true, defaultVal: AtemSourceIndex.Col2 }, @@ -195,7 +200,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.fadeIn', name: 'Bed Fade In', description: 'Default fade in duration for audio beds', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 25 }, @@ -203,7 +208,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.volume', name: 'Bed Volume', description: 'Volume (0 - 100)', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 80 }, @@ -211,7 +216,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'AudioBedSettings.fadeOut', name: 'Bed Fade Out', description: 'Default fade out duration for audio beds', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 25 }, @@ -219,7 +224,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'CasparPrerollDuration', name: 'Caspar preroll duration', description: 'ms of preroll before switching to caspar', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 200 // 5 frames }, @@ -227,7 +232,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'MaximumPartDuration', name: 'Maximum Part Duration', description: 'Maximum duration (ms) to give parts in UI', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 10000 }, @@ -235,7 +240,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'DefaultPartDuration', name: 'Default Part Duration', description: 'Duration to give parts by default', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 4000 }, @@ -243,7 +248,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'IdleSource', name: 'Idle Source', description: 'Source to display when studio is off-air', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 1 }, @@ -263,7 +268,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'ServerPostrollDuration', name: 'Server Postroll Duration', description: 'ms of postroll at the end of Server and VO clips', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: true, defaultVal: 0 }, @@ -290,7 +295,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.KeepAliveDuration', name: 'Full Keep Alive Duration (HTML)', description: 'How long to keep the old part alive when going to a full', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 1000 }, @@ -298,7 +303,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.borderSoftness', name: 'Full graphic wipe softness (HTML)', description: 'Border softness of full graphic background wipe', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 7500 }, @@ -306,7 +311,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.loopOutTransitionDuration', name: 'Full graphic background loop out transition duration', description: 'Duration (ms) that the background loop behind a full takes to transition out', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 120 }, @@ -314,7 +319,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'HTMLGraphics.TransitionSettings.wipeRate', name: 'Full graphic background loop wipe duration (HTML)', description: 'Frames (max 250) over which to wipe background loop behind Full', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 10 }, @@ -322,7 +327,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.CutToMediaPlayer', name: 'Pilot media Player Cut Point', description: 'ms from start of grafik before switching to background source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 500 }, @@ -330,7 +335,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.KeepAliveDuration', name: 'Pilot Keepalive Duration', description: 'ms to keep old part alive before switching to Pilot elements', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 2000 }, @@ -338,7 +343,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.OutTransitionDuration', name: 'Pilot Out Transition Duration', description: 'ms to keep pilot elements alive before transition to next part', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 1000 }, @@ -346,7 +351,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.PrerollDuration', name: 'Pilot Preroll Duration', description: 'ms of preroll before switching to Pilot elements', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 2000 }, @@ -354,7 +359,7 @@ export const studioConfigManifest: ConfigManifestEntry[] = [ id: 'VizPilotGraphics.FullGraphicBackground', name: 'Full frame grafik background source', description: 'ATEM source for mos full-frame grafik background source', - type: ConfigManifestEntryType.NUMBER, + type: ConfigManifestEntryType.INT, required: false, defaultVal: 0 }, diff --git a/src/tv2_offtube_studio/getBaseline.ts b/src/tv2_offtube_studio/getBaseline.ts index 95de6e565..7e3ce879d 100644 --- a/src/tv2_offtube_studio/getBaseline.ts +++ b/src/tv2_offtube_studio/getBaseline.ts @@ -4,13 +4,13 @@ import { BlueprintResultBaseline, IStudioContext, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { literal } from 'tv2-common' import * as _ from 'underscore' import { AtemSourceIndex } from '../types/atem' import { OfftubeStudioBlueprintConfig } from './helpers/config' import { OfftubeAtemLLayer, OfftubeSisyfosLLayer } from './layers' -import { SisyfosChannel, sisyfosChannels } from './sisyfosChannels' +import { sisyfosChannels } from './sisyfosChannels' function filterMappings( input: BlueprintMappings, @@ -30,14 +30,14 @@ function filterMappings( export function getBaseline(context: IStudioContext): BlueprintResultBaseline { const mappings = context.getStudioMappings() - const config = (context.getStudioConfig() as unknown) as OfftubeStudioBlueprintConfig + const config = context.getStudioConfig() as OfftubeStudioBlueprintConfig const sisyfosMappings = filterMappings(mappings, (_id, v) => v.device === TSR.DeviceType.SISYFOS) const mappedChannels: TSR.TimelineObjSisyfosChannels['content']['channels'] = [] for (const id in sisyfosMappings) { if (sisyfosMappings[id]) { - const sisyfosChannel = sisyfosChannels[id as OfftubeSisyfosLLayer] as SisyfosChannel | undefined + const sisyfosChannel = sisyfosChannels[id as OfftubeSisyfosLLayer] if (sisyfosChannel) { mappedChannels.push({ mappedLayer: id, diff --git a/src/tv2_offtube_studio/getShowStyleId.ts b/src/tv2_offtube_studio/getShowStyleId.ts index 7848aeb8c..1c2406d12 100644 --- a/src/tv2_offtube_studio/getShowStyleId.ts +++ b/src/tv2_offtube_studio/getShowStyleId.ts @@ -1,4 +1,4 @@ -import { IBlueprintShowStyleBase, IngestRundown, IStudioContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintShowStyleBase, IngestRundown, IStudioContext } from '@tv2media/blueprints-integration' import * as _ from 'underscore' export function getShowStyleId( diff --git a/src/tv2_offtube_studio/helpers/config.ts b/src/tv2_offtube_studio/helpers/config.ts index 27623e342..35c497d43 100644 --- a/src/tv2_offtube_studio/helpers/config.ts +++ b/src/tv2_offtube_studio/helpers/config.ts @@ -1,9 +1,7 @@ -import { IBlueprintConfig, ICommonContext } from '@sofie-automation/blueprints-integration' +import { IBlueprintConfig, ICommonContext } from '@tv2media/blueprints-integration' import { - getLiveAudioLayers, - getStickyLayers, MediaPlayerConfig, - SourceInfo, + SourceMapping, TableConfigItemDSK, TableConfigItemSourceMapping, TV2StudioConfigBase @@ -14,10 +12,8 @@ import { parseMediaPlayers, parseSources } from './sources' export interface OfftubeStudioBlueprintConfig { studio: OfftubeStudioConfig - sources: SourceInfo[] + sources: SourceMapping mediaPlayers: MediaPlayerConfig // Atem Input Ids - liveAudio: string[] - stickyLayers: string[] dsk: TableConfigItemDSK[] } @@ -36,6 +32,7 @@ export interface OfftubeStudioConfig extends TV2StudioConfigBase { Default: number Continuity: number + Dip: number } AtemSettings: {} @@ -56,17 +53,10 @@ export function parseConfig(_context: ICommonContext, rawConfig: IBlueprintConfi const config: OfftubeStudioBlueprintConfig = { studio: rawConfig as any, // showStyle: {} as any, - sources: [], - mediaPlayers: [], - liveAudio: [], - stickyLayers: [], + sources: parseSources(studioConfig), + mediaPlayers: parseMediaPlayers(studioConfig), dsk: studioConfig.AtemSource.DSK } - config.sources = parseSources(studioConfig) - config.mediaPlayers = parseMediaPlayers(studioConfig) - config.liveAudio = getLiveAudioLayers(studioConfig) - config.stickyLayers = getStickyLayers(studioConfig, config.liveAudio) - return config } diff --git a/src/tv2_offtube_studio/helpers/sources.ts b/src/tv2_offtube_studio/helpers/sources.ts index 2a1263efc..b19c28bd2 100644 --- a/src/tv2_offtube_studio/helpers/sources.ts +++ b/src/tv2_offtube_studio/helpers/sources.ts @@ -1,17 +1,18 @@ import * as _ from 'underscore' -import { SourceLayerType } from '@sofie-automation/blueprints-integration' -import { ParseMappingTable, SourceInfo } from 'tv2-common' +import { SourceLayerType } from '@tv2media/blueprints-integration' +import { ParseMappingTable, SourceInfoType, SourceMapping } from 'tv2-common' import { OfftubeStudioConfig } from './config' export function parseMediaPlayers(studioConfig: OfftubeStudioConfig): Array<{ id: string; val: string }> { return studioConfig.ABMediaPlayers.map(player => ({ id: player.SourceName, val: player.AtemSource.toString() })) } -export function parseSources(studioConfig: OfftubeStudioConfig): SourceInfo[] { - return [ - ...ParseMappingTable(studioConfig.SourcesFeed, SourceLayerType.REMOTE, 'F'), - ...ParseMappingTable(studioConfig.SourcesRM, SourceLayerType.REMOTE), - ...ParseMappingTable(studioConfig.SourcesCam, SourceLayerType.CAMERA) - ] +export function parseSources(studioConfig: OfftubeStudioConfig): SourceMapping { + return { + cameras: ParseMappingTable(studioConfig.SourcesCam, SourceInfoType.KAM, SourceLayerType.CAMERA), + lives: ParseMappingTable(studioConfig.SourcesRM, SourceInfoType.LIVE, SourceLayerType.REMOTE), + feeds: ParseMappingTable(studioConfig.SourcesFeed, SourceInfoType.FEED, SourceLayerType.REMOTE), + replays: [] + } } diff --git a/src/tv2_offtube_studio/index.ts b/src/tv2_offtube_studio/index.ts index 502c00a41..2c5ad9b55 100644 --- a/src/tv2_offtube_studio/index.ts +++ b/src/tv2_offtube_studio/index.ts @@ -1,4 +1,4 @@ -import { BlueprintManifestType, StudioBlueprintManifest } from '@sofie-automation/blueprints-integration' +import { BlueprintManifestType, StudioBlueprintManifest } from '@tv2media/blueprints-integration' import { GetStudioManifestWithMixins, StudioManifestMixinINews } from 'inews-mixins' import * as _ from 'underscore' import { studioConfigManifest } from './config-manifests' diff --git a/src/tv2_offtube_studio/layers.ts b/src/tv2_offtube_studio/layers.ts index d9008b611..96797bb71 100644 --- a/src/tv2_offtube_studio/layers.ts +++ b/src/tv2_offtube_studio/layers.ts @@ -1,4 +1,10 @@ -import { AbstractLLayer, GraphicLLayer, SharedATEMLLayer, SharedCasparLLayer, SharedSisyfosLLayer } from 'tv2-constants' +import { + AbstractLLayer, + SharedATEMLLayer, + SharedCasparLLayer, + SharedGraphicLLayer, + SharedSisyfosLLayer +} from 'tv2-constants' import * as _ from 'underscore' /** Get all the Real LLayers (map to devices). Note: Does not include some which are dynamically generated */ @@ -14,7 +20,7 @@ export function RealLLayers(): string[] { // @ts-ignore .concat(_.values(AbstractLLayer)) // @ts-ignore - .concat(_.values(GraphicLLayer)) + .concat(_.values(SharedGraphicLLayer)) ) } @@ -25,7 +31,6 @@ export enum OfftubeAbstractLLayer { enum SisyfosLLayer { SisyfosConfig = 'sisyfos_config', - SisyfosGroupStudioMics = 'sisyfos_group_studio_mics', SisyfosGroupServer = 'sisyfos_group_server', SisyfosPersistedLevels = 'sisyfos_persisted_levels', SisyfosSourceClipPending = 'sisyfos_source_clip_pending', @@ -70,7 +75,8 @@ export const OfftubeAtemLLayer = { export type OfftubeAtemLLayer = AtemLLayer | SharedATEMLLayer enum CasparLLayer { - CasparPlayerJingleLookahead = 'casparcg_player_jingle_looakhead', + /** Maps to the same Caspar layer as CasparPlayerJingle but its lookahead preloads the first frame */ + CasparPlayerJinglePreload = 'casparcg_player_jingle_preload', CasparGraphicsFullLoop = 'casparcg_graphics_full_loop', CasparCGDVELoop = 'casparcg_dve_loop', CasparCGDVEKeyedLoop = 'casparcg_dve_keyed_loop', @@ -93,3 +99,9 @@ export const OfftubeSisyfosLLayer = { } export type OfftubeSisyfosLLayer = SharedSisyfosLLayer | SisyfosLLayer + +// tslint:disable-next-line: variable-name +export const OfftubeGraphicLLayer = { + ...SharedGraphicLLayer +} +export type OfftubeGraphicLLayer = SharedGraphicLLayer diff --git a/src/tv2_offtube_studio/migrations/devices.ts b/src/tv2_offtube_studio/migrations/devices.ts index 74dc8e7d1..ae375657d 100644 --- a/src/tv2_offtube_studio/migrations/devices.ts +++ b/src/tv2_offtube_studio/migrations/devices.ts @@ -4,8 +4,7 @@ import { MigrationStepInputFilteredResult, MigrationStepStudio, TSR -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' import * as _ from 'underscore' declare const VERSION: string // Injected by webpack @@ -218,10 +217,10 @@ const devices: DeviceEntry[] = [ } ] -export const deviceMigrations = literal([ +export const deviceMigrations: MigrationStepStudio[] = [ // create all devices ..._.map(devices, createDevice), // ensure all devices still look valid ..._.map(devices, validateDevice) -]) +] diff --git a/src/tv2_offtube_studio/migrations/index.ts b/src/tv2_offtube_studio/migrations/index.ts index a1d8f622b..9c55ff58f 100644 --- a/src/tv2_offtube_studio/migrations/index.ts +++ b/src/tv2_offtube_studio/migrations/index.ts @@ -3,10 +3,9 @@ import { MigrationStepStudio, TableConfigItemValue, TSR -} from '@sofie-automation/blueprints-integration' +} from '@tv2media/blueprints-integration' import { AddKeepAudio, - literal, MoveClipSourcePath, MoveSourcesToTable, RemoveConfig, @@ -14,14 +13,13 @@ import { SetConfigTo, SetLayerNamesToDefaults } from 'tv2-common' -import { GraphicLLayer } from 'tv2-constants' +import { SharedGraphicLLayer } from 'tv2-constants' import * as _ from 'underscore' import { EnsureSisyfosMappingHasType } from '../../tv2_afvd_studio/migrations/util' import { manifestOfftubeDownstreamKeyers, manifestOfftubeSourcesABMediaPlayers, manifestOfftubeSourcesCam, - manifestOfftubeSourcesRM, manifestOfftubeStudioMics } from '../config-manifests' import { OfftubeCasparLLayer, OfftubeSisyfosLLayer } from '../layers' @@ -42,7 +40,7 @@ function renameAudioSources(versionStr: string, renaming: Map): const steps: MigrationStepStudio[] = [] for (const layer in renaming) { if (layer in renaming) { - const res = literal({ + const res: MigrationStepStudio = { id: `${versionStr}.studioConfig.renameAudioSources.${layer}`, version: versionStr, canBeRunAutomatically: true, @@ -65,7 +63,7 @@ function renameAudioSources(versionStr: string, renaming: Map): } } } - }) + } steps.push(res) } @@ -75,7 +73,7 @@ function renameAudioSources(versionStr: string, renaming: Map): } function ensureMappingDeleted(versionStr: string, mapping: string): MigrationStepStudio { - const res = literal({ + return { id: `${versionStr}.studioConfig.ensureMappingDeleted.${mapping}`, version: versionStr, canBeRunAutomatically: true, @@ -93,9 +91,7 @@ function ensureMappingDeleted(versionStr: string, mapping: string): MigrationSte context.removeMapping(mapping) } } - }) - - return res + } } function remapTableColumnValuesInner( @@ -106,7 +102,7 @@ function remapTableColumnValuesInner( ): { changed: number; table: TableConfigItemValue } { let changed = 0 - table.map(row => { + table.forEach(row => { const val = row[columnId] if (val) { @@ -128,8 +124,6 @@ function remapTableColumnValuesInner( } } } - - return row }) return { changed, table } @@ -143,7 +137,7 @@ function remapTableColumnValues( remapping: Map ): MigrationStepStudio[] { return [ - literal({ + { id: `${versionStr}.remapTableColumnValue.${tableId}.${columnId}`, version: versionStr, canBeRunAutomatically: true, @@ -180,7 +174,7 @@ function remapTableColumnValues( context.setConfig(tableId, ret.table) } - }) + } ] } @@ -191,7 +185,7 @@ const audioSourceRenaming: Map = new Map([ ['sisyfos_source_world_feed_surround', OfftubeSisyfosLLayer.SisyfosSourceLive_3] ]) -export const studioMigrations: MigrationStepStudio[] = literal([ +export const studioMigrations: MigrationStepStudio[] = [ ensureStudioConfig( '0.1.0', 'SourcesCam', @@ -205,11 +199,29 @@ export const studioMigrations: MigrationStepStudio[] = literal({ @@ -264,12 +269,12 @@ const MAPPINGS_CASPAR: BlueprintMappings = { lookahead: LookaheadMode.PRELOAD, channel: 3, layer: 110, - previewWhenNotOnAir: true + previewWhenNotOnAir: false }), - [OfftubeCasparLLayer.CasparPlayerJingleLookahead]: literal({ + [OfftubeCasparLLayer.CasparPlayerJinglePreload]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', - layerName: 'Jingle Lookahead', + layerName: 'Jingle (Preloading First Frame)', lookahead: LookaheadMode.PRELOAD, lookaheadMaxSearchDistance: 1, channel: 3, @@ -293,7 +298,7 @@ const MAPPINGS_CASPAR: BlueprintMappings = { layer: 100, previewWhenNotOnAir: true }), - [GraphicLLayer.GraphicLLayerLocators]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerLocators]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Locators', @@ -344,13 +349,13 @@ const MAPPINGS_CASPAR: BlueprintMappings = { } const MAPPINGS_GRAPHICS: BlueprintMappings = { - [GraphicLLayer.GraphicLLayerAdLibs]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerAdLibs]: literal({ device: TSR.DeviceType.ABSTRACT, deviceId: 'abstract0', layerName: 'GFX AdLibs', lookahead: LookaheadMode.NONE }), - [GraphicLLayer.GraphicLLayerDesign]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerDesign]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Design', @@ -359,7 +364,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerOverlay]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlay]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Overlay', @@ -368,12 +373,12 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerOverlayHeadline]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlayHeadline]: literal({ device: TSR.DeviceType.ABSTRACT, deviceId: 'abstract0', lookahead: LookaheadMode.NONE }), - [GraphicLLayer.GraphicLLayerOverlayIdent]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlayIdent]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Ident', @@ -382,7 +387,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerOverlayLower]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlayLower]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Bund', @@ -391,7 +396,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerOverlayTema]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlayTema]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Tema', @@ -400,7 +405,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerOverlayTopt]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerOverlayTopt]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Topt', @@ -409,7 +414,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { channel: 3, layer: 111 }), - [GraphicLLayer.GraphicLLayerPilot]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerPilot]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Pilot (Full)', @@ -419,7 +424,7 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { previewWhenNotOnAir: true }), /** TODO: Revisit these */ - [GraphicLLayer.GraphicLLayerPilotOverlay]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerPilotOverlay]: literal({ device: TSR.DeviceType.CASPARCG, deviceId: 'caspar01', layerName: 'GFX Pilot (Overlay)', @@ -430,18 +435,24 @@ const MAPPINGS_GRAPHICS: BlueprintMappings = { }), // Full loop and DVE loop are the same channel in Q2. // No mapping to caspar to avoid conflicts. - [GraphicLLayer.GraphicLLayerFullLoop]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerFullLoop]: literal({ device: TSR.DeviceType.ABSTRACT, deviceId: 'abstract0', layerName: 'GFX Full Loop', lookahead: LookaheadMode.NONE }), // No Screen for now - [GraphicLLayer.GraphicLLayerWall]: literal({ + [OfftubeGraphicLLayer.GraphicLLayerWall]: literal({ device: TSR.DeviceType.ABSTRACT, deviceId: 'abstract0', layerName: 'GFX Wall', lookahead: LookaheadMode.NONE + }), + [OfftubeGraphicLLayer.GraphicLLayerConcept]: literal({ + device: TSR.DeviceType.ABSTRACT, + deviceId: 'abstract0', + layerName: 'Override Concept', + lookahead: LookaheadMode.NONE }) } diff --git a/src/tv2_offtube_studio/migrations/util.ts b/src/tv2_offtube_studio/migrations/util.ts index 27932bf3c..5abc96813 100644 --- a/src/tv2_offtube_studio/migrations/util.ts +++ b/src/tv2_offtube_studio/migrations/util.ts @@ -5,8 +5,7 @@ import { MigrationStepInput, MigrationStepInputFilteredResult, MigrationStepStudio -} from '@sofie-automation/blueprints-integration' -import { literal } from 'tv2-common' +} from '@tv2media/blueprints-integration' import * as _ from 'underscore' import { OfftubeSisyfosLLayer } from '../layers' import MappingsDefaults from './mappings-defaults' @@ -131,9 +130,9 @@ export function removeMapping(version: string, oldMappingName: string): Migratio } export function getMappingsDefaultsMigrationSteps(versionStr: string): MigrationStepStudio[] { - const res = _.compact( + return _.compact( _.map(MappingsDefaults, (defaultVal: BlueprintMapping, id: string): MigrationStepStudio | null => { - return literal({ + return { id: `${versionStr}.mappings.defaults.${id}`, version: versionStr, canBeRunAutomatically: true, @@ -150,11 +149,9 @@ export function getMappingsDefaultsMigrationSteps(versionStr: string): Migration context.insertMapping(id, defaultVal) } } - }) + } }) ) - - return res } export function GetMappingDefaultMigrationStepForLayer( @@ -162,7 +159,7 @@ export function GetMappingDefaultMigrationStepForLayer( layer: string, force?: boolean ): MigrationStepStudio { - return literal({ + return { id: `${versionStr}.mappings.defaults.manualEnsure${layer}`, version: versionStr, canBeRunAutomatically: true, @@ -189,7 +186,7 @@ export function GetMappingDefaultMigrationStepForLayer( context.insertMapping(layer, MappingsDefaults[layer]) } } - }) + } } export function GetSisyfosLayersForTableMigrationOfftube(configName: string, val: string): string[] { diff --git a/src/tv2_system/index.ts b/src/tv2_system/index.ts index e23bbb70f..9072d563f 100644 --- a/src/tv2_system/index.ts +++ b/src/tv2_system/index.ts @@ -1,5 +1,6 @@ -import { BlueprintManifestType, SystemBlueprintManifest } from '@sofie-automation/blueprints-integration' +import { BlueprintManifestType, SystemBlueprintManifest } from '@tv2media/blueprints-integration' import * as _ from 'underscore' +import { systemMigrations } from './migrations' declare const VERSION: string // Injected by webpack declare const VERSION_TSR: string // Injected by webpack @@ -10,7 +11,8 @@ const manifest: SystemBlueprintManifest = { blueprintVersion: VERSION, integrationVersion: VERSION_INTEGRATION, - TSRVersion: VERSION_TSR + TSRVersion: VERSION_TSR, + coreMigrations: systemMigrations } export default manifest diff --git a/src/tv2_system/migrations/hotkeys.ts b/src/tv2_system/migrations/hotkeys.ts new file mode 100644 index 000000000..7f0ce7b08 --- /dev/null +++ b/src/tv2_system/migrations/hotkeys.ts @@ -0,0 +1,440 @@ +import { + ClientActions, + IBlueprintTriggeredActions, + MigrationContextSystem, + MigrationStepSystem, + PlayoutActions, + TriggerType +} from '@tv2media/blueprints-integration' + +export function RemoveDefaultCoreShortcuts(versionStr: string): MigrationStepSystem { + const defaultTriggerIds = DEFAULT_CORE_TRIGGERS.map(trigger => trigger._id) + + return { + id: `${versionStr}.disableCoreDefaultTriggers`, + version: versionStr, + canBeRunAutomatically: true, + validate: (context: MigrationContextSystem) => { + for (const coreTrigger of DEFAULT_CORE_TRIGGERS) { + const defaultTrigger = context.getTriggeredAction(coreTrigger._id) + if (defaultTrigger && defaultTrigger.triggers.length) { + return true + } + } + + return false + }, + migrate: (context: MigrationContextSystem) => { + for (const trigger of defaultTriggerIds) { + const defaultTrigger = context.getTriggeredAction(trigger) + if (defaultTrigger) { + defaultTrigger.triggers = [] + context.setTriggeredAction(defaultTrigger) + } + } + } + } +} + +// copy-pasted from core migrations +const t = (text: string) => text +let j = 0 +const DEFAULT_CORE_TRIGGERS: IBlueprintTriggeredActions[] = [ + { + _id: 'toggleShelf', + actions: [ + { + action: ClientActions.shelf, + filterChain: [ + { + object: 'view' + } + ], + state: 'toggle' + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Tab', + up: true + } + ], + _rank: ++j * 1000, + name: t('Toggle Shelf') + }, + { + _id: 'activateRundownPlaylist', + actions: [ + { + action: PlayoutActions.activateRundownPlaylist, + rehearsal: false, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Backquote', + up: true + } + ], + _rank: ++j * 1000, + name: t('Activate (On-Air)') + }, + { + _id: 'activateRundownPlaylist_rehearsal', + actions: [ + { + action: PlayoutActions.activateRundownPlaylist, + rehearsal: true, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Control+Backquote', + up: true + } + ], + _rank: ++j * 1000, + name: t('Activate (Rehearsal)') + }, + { + _id: 'deactivateRundownPlaylist', + actions: [ + { + action: PlayoutActions.deactivateRundownPlaylist, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Control+Shift+Backquote', + up: true + } + ], + _rank: ++j * 1000, + name: t('Deactivate') + }, + { + _id: 'take', + actions: [ + { + action: PlayoutActions.take, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'NumpadEnter', + up: true + }, + { + type: TriggerType.hotkey, + keys: 'F12', + up: true + } + ], + _rank: ++j * 1000, + name: t('Take') + }, + { + _id: 'hold', + actions: [ + { + action: PlayoutActions.hold, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'KeyH', + up: true + } + ], + _rank: ++j * 1000, + name: t('Hold') + }, + { + _id: 'hold_undo', + actions: [ + { + action: PlayoutActions.hold, + undo: true, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Shift+KeyH', + up: true + } + ], + _rank: ++j * 1000, + name: t('Undo Hold') + }, + { + _id: 'reset_rundown_playlist', + actions: [ + { + action: PlayoutActions.resetRundownPlaylist, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Control+Shift+F12', + up: true + }, + { + type: TriggerType.hotkey, + keys: 'Control+Shift+AnyEnter', + up: true + } + ], + _rank: ++j * 1000, + name: t('Reset Rundown') + }, + { + _id: 'disable_next_piece', + actions: [ + { + action: PlayoutActions.disableNextPiece, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'KeyG', + up: true + } + ], + _rank: ++j * 1000, + name: t('Disable the next element') + }, + { + _id: 'disable_next_piece_undo', + actions: [ + { + action: PlayoutActions.disableNextPiece, + filterChain: [ + { + object: 'view' + } + ], + undo: true + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Shift+KeyG', + up: true + } + ], + _rank: ++j * 1000, + name: t('Undo Disable the next element') + }, + { + _id: 'create_snapshot_for_debug', + actions: [ + { + action: PlayoutActions.createSnapshotForDebug, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Backspace', + up: true + } + ], + _rank: ++j * 1000, + name: t('Store Snapshot') + }, + { + _id: 'move_next_part', + actions: [ + { + action: PlayoutActions.moveNext, + filterChain: [ + { + object: 'view' + } + ], + parts: 1, + segments: 0 + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'F9', + up: true + } + ], + _rank: ++j * 1000, + name: t('Move Next forwards') + }, + { + _id: 'move_next_segment', + actions: [ + { + action: PlayoutActions.moveNext, + filterChain: [ + { + object: 'view' + } + ], + parts: 0, + segments: 1 + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'F10', + up: true + } + ], + _rank: ++j * 1000, + name: t('Move Next to the following segment') + }, + { + _id: 'move_previous_part', + actions: [ + { + action: PlayoutActions.moveNext, + filterChain: [ + { + object: 'view' + } + ], + parts: -1, + segments: 0 + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Shift+F9', + up: true + } + ], + _rank: ++j * 1000, + name: t('Move Next backwards') + }, + { + _id: 'move_previous_segment', + actions: [ + { + action: PlayoutActions.moveNext, + filterChain: [ + { + object: 'view' + } + ], + parts: 0, + segments: -1 + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Shift+F10', + up: true + } + ], + _rank: ++j * 1000, + name: t('Move Next to the previous segment') + }, + { + _id: 'go_to_onAir_line', + actions: [ + { + action: ClientActions.goToOnAirLine, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Control+Home', + up: true + } + ], + _rank: ++j * 1000, + name: t('Go to On Air line') + }, + { + _id: 'rewind_segments', + actions: [ + { + action: ClientActions.rewindSegments, + filterChain: [ + { + object: 'view' + } + ] + } + ], + triggers: [ + { + type: TriggerType.hotkey, + keys: 'Shift+Home', + up: true + } + ], + _rank: ++j * 1000, + name: t('Rewind segments to start') + } +] diff --git a/src/tv2_system/migrations/index.ts b/src/tv2_system/migrations/index.ts new file mode 100644 index 000000000..5d86532c1 --- /dev/null +++ b/src/tv2_system/migrations/index.ts @@ -0,0 +1,6 @@ +import { MigrationStepSystem } from '@tv2media/blueprints-integration' +import { RemoveDefaultCoreShortcuts } from './hotkeys' + +declare const VERSION: string // Injected by webpack + +export const systemMigrations: MigrationStepSystem[] = [RemoveDefaultCoreShortcuts(VERSION)] diff --git a/yarn.lock b/yarn.lock index 56f281d77..573b38d9e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,135 +2,289 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" - integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== - dependencies: - "@babel/highlight" "^7.8.3" - -"@babel/core@^7.1.0": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.8.7.tgz#b69017d221ccdeb203145ae9da269d72cf102f3b" - integrity sha512-rBlqF3Yko9cynC5CCFy6+K/w2N+Sq/ff2BPy+Krp7rHlABIr5epbA7OxVeKoMHB39LZOp1UY5SuLjy6uWi35yA== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.7" - "@babel/helpers" "^7.8.4" - "@babel/parser" "^7.8.7" - "@babel/template" "^7.8.6" - "@babel/traverse" "^7.8.6" - "@babel/types" "^7.8.7" +"@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + +"@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== + +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.9.tgz#6bae81a06d95f4d0dec5bb9d74bbc1f58babdcfe" + integrity sha512-5ug+SfZCpDAkVp9SFIZAzlW18rlzsOcJGaetCjkySnrXXDUw9AR8cDUm1iByTmdWM6yxX6/zycaV76w3YTF2gw== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.9" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.9" + "@babel/parser" "^7.17.9" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.9" + "@babel/types" "^7.17.0" convert-source-map "^1.7.0" debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.0" - lodash "^4.17.13" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.1" + semver "^6.3.0" -"@babel/generator@^7.4.0", "@babel/generator@^7.8.6", "@babel/generator@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.8.7.tgz#870b3cf7984f5297998152af625c4f3e341400f7" - integrity sha512-DQwjiKJqH4C3qGiyQCAExJHoZssn49JTMJgZ8SANGgVFdkupcUhLOdkAeoC6kmHZCPfoDG5M0b6cFlSN5wW7Ew== +"@babel/generator@^7.17.9", "@babel/generator@^7.7.2": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc" + integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ== dependencies: - "@babel/types" "^7.8.7" + "@babel/types" "^7.17.0" jsesc "^2.5.1" - lodash "^4.17.13" source-map "^0.5.0" -"@babel/helper-function-name@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" - integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== +"@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + +"@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-function-name@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" + integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== + dependencies: + "@babel/template" "^7.16.7" + "@babel/types" "^7.17.0" + +"@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + +"@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== + dependencies: + "@babel/types" "^7.17.0" + +"@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + +"@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + +"@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + +"@babel/helpers@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.9.tgz#b2af120821bfbe44f9907b1826e168e819375a1a" + integrity sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.9" + "@babel/types" "^7.17.0" + +"@babel/highlight@^7.16.7": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.17.9.tgz#61b2ee7f32ea0454612def4fccdae0de232b73e3" + integrity sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7", "@babel/parser@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" + integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: - "@babel/helper-get-function-arity" "^7.8.3" - "@babel/template" "^7.8.3" - "@babel/types" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helper-get-function-arity@^7.8.3": +"@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" - integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== dependencies: - "@babel/types" "^7.8.3" + "@babel/helper-plugin-utils" "^7.12.13" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.8.3.tgz#9ea293be19babc0f52ff8ca88b34c3611b208670" - integrity sha512-j+fq49Xds2smCUNYmEHF9kGNkhbet6yVIBp4e6oeQpH1RUs/Ir06xUKzDjDkGcaaokPiTNs2JBWHjaE4csUkZQ== +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/helper-split-export-declaration@^7.8.3": +"@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" - integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: - "@babel/types" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/helpers@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" - integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== dependencies: - "@babel/template" "^7.8.3" - "@babel/traverse" "^7.8.4" - "@babel/types" "^7.8.3" + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/highlight@^7.8.3": +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" - integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" + "@babel/helper-plugin-utils" "^7.8.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.4.3", "@babel/parser@^7.8.6", "@babel/parser@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.8.7.tgz#7b8facf95d25fef9534aad51c4ffecde1a61e26a" - integrity sha512-9JWls8WilDXFGxs0phaXAZgpxTZhSk/yOYH2hTHC0X1yC7Z78IJfvR1vJ+rmJKq3I35td2XzXzN6ZLYlna+r/A== +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-object-rest-spread@^7.0.0": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/template@^7.4.0", "@babel/template@^7.8.3", "@babel/template@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.8.6.tgz#86b22af15f828dfb086474f964dcc3e39c43ce2b" - integrity sha512-zbMsPMy/v0PWFZEhQJ66bqjhH+z0JgMoBWuikXybgG3Gkd/3t5oQ1Rw2WQhnSrsOmsKXnZOx15tkC4qON/+JPg== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.3", "@babel/traverse@^7.8.4", "@babel/traverse@^7.8.6": - version "7.8.6" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.8.6.tgz#acfe0c64e1cd991b3e32eae813a6eb564954b5ff" - integrity sha512-2B8l0db/DPi8iinITKuo7cbPznLCEk0kCxDoB9/N6gGNg/gxOXiR/IcymAFPiBwk5w6TtQ27w4wpElgp9btR9A== - dependencies: - "@babel/code-frame" "^7.8.3" - "@babel/generator" "^7.8.6" - "@babel/helper-function-name" "^7.8.3" - "@babel/helper-split-export-declaration" "^7.8.3" - "@babel/parser" "^7.8.6" - "@babel/types" "^7.8.6" +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + +"@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + +"@babel/traverse@^7.17.3", "@babel/traverse@^7.17.9", "@babel/traverse@^7.7.2": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" + integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.9" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.9" + "@babel/types" "^7.17.0" debug "^4.1.0" globals "^11.1.0" - lodash "^4.17.13" -"@babel/types@^7.0.0", "@babel/types@^7.3.0", "@babel/types@^7.4.0", "@babel/types@^7.8.3", "@babel/types@^7.8.6", "@babel/types@^7.8.7": - version "7.8.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.8.7.tgz#1fc9729e1acbb2337d5b6977a63979b4819f5d1d" - integrity sha512-k2TreEHxFA4CjGkL+GYjRyx35W0Mr7DP5+9q6WMkyKXB+904bYmG40syjMFV0oLlhhFCwWl0vA0DyzTDkwAiJw== +"@babel/types@^7.0.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== dependencies: - esutils "^2.0.2" - lodash "^4.17.13" + "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -139,7 +293,28 @@ exec-sh "^0.3.2" minimist "^1.2.0" -"@jest/console@^24.7.1", "@jest/console@^24.9.0": +"@hutson/parse-repository-url@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" + integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== @@ -148,49 +323,61 @@ chalk "^2.0.1" slash "^2.0.0" -"@jest/core@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" - integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== - dependencies: - "@jest/console" "^24.7.1" - "@jest/reporters" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" +"@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + +"@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" exit "^0.1.2" - graceful-fs "^4.1.15" - jest-changed-files "^24.9.0" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-resolve-dependencies "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - jest-watcher "^24.9.0" - micromatch "^3.1.10" - p-each-series "^1.0.0" - realpath-native "^1.1.0" - rimraf "^2.5.4" - slash "^2.0.0" - strip-ansi "^5.0.0" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" -"@jest/environment@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" - integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== dependencies: - "@jest/fake-timers" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" "@jest/fake-timers@^24.9.0": version "24.9.0" @@ -201,34 +388,59 @@ jest-message-util "^24.9.0" jest-mock "^24.9.0" -"@jest/reporters@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" - integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + +"@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" exit "^0.1.2" glob "^7.1.2" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.2.6" - jest-haste-map "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - node-notifier "^5.4.2" - slash "^2.0.0" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" source-map "^0.6.0" - string-length "^2.0.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" -"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": +"@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== @@ -237,6 +449,15 @@ graceful-fs "^4.1.15" source-map "^0.6.0" +"@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + "@jest/test-result@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" @@ -246,37 +467,46 @@ "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" -"@jest/test-sequencer@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" - integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== +"@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== dependencies: - "@jest/test-result" "^24.9.0" - jest-haste-map "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" -"@jest/transform@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" - integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== +"@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + +"@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^24.9.0" - babel-plugin-istanbul "^5.1.0" - chalk "^2.0.1" + "@jest/types" "^27.5.1" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.1.15" - jest-haste-map "^24.9.0" - jest-regex-util "^24.9.0" - jest-util "^24.9.0" - micromatch "^3.1.10" - pirates "^4.0.1" - realpath-native "^1.1.0" - slash "^2.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" source-map "^0.6.1" - write-file-atomic "2.4.1" + write-file-atomic "^3.0.0" "@jest/types@^24.9.0": version "24.9.0" @@ -287,20 +517,68 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@sofie-automation/blueprints-integration@npm:@tv2media/blueprints-integration@1.37.0-rc19": - version "1.37.0-rc19" - resolved "https://registry.yarnpkg.com/@tv2media/blueprints-integration/-/blueprints-integration-1.37.0-rc19.tgz#b0899f1e017747dec24ab5f9188830345fe477eb" - integrity sha512-ctKx/MHkHku4vINjw1mSqmEGHRBHl0nncGamPXgilLZhoSQDhAM0HOBTqZbznC22DATKK29Gh264VFTOKj6QJg== +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + +"@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + +"@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + +"@jridgewell/trace-mapping@^0.3.0": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@sinonjs/commons@^1.7.0": + version "1.8.3" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" + integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== dependencies: - moment "2.29.1" - timeline-state-resolver-types "npm:@tv2media/timeline-state-resolver-types@1.0.0-release37" - tslib "^2.1.0" - underscore "1.13.1" + "@sinonjs/commons" "^1.7.0" -"@types/babel__core@^7.1.0": - version "7.1.6" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.6.tgz#16ff42a5ae203c9af1c6e190ed1f30f83207b610" - integrity sha512-tTnhWszAqvXnhW7m5jQU9PomXSiKXk2sFxpahXvI20SZKu9ylPi8WtIxueZ6ehDWikPT0jeFujMj3X4ZHuf3Tg== +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@tv2media/blueprints-integration@1.42.7": + version "1.42.7" + resolved "https://registry.yarnpkg.com/@tv2media/blueprints-integration/-/blueprints-integration-1.42.7.tgz#b88bc4becb27d0b5e828562286bd01cbbb1ee422" + integrity sha512-GAalonu3u6v4bjkM+v0IFDBdKksfMsch7GpsR7Yef7HMpFhEqQvl2rXqd9j3NyQhJKKmywG9Oh081HsvHCfOKg== + dependencies: + moment "2.29.3" + timeline-state-resolver-types "npm:@tv2media/timeline-state-resolver-types@2.1.3" + tslib "^2.3.1" + type-fest "^2.11.1" + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": + version "7.1.19" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.19.tgz#7b497495b7d1b4812bdb9d02804d0576f43ee460" + integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" @@ -309,31 +587,38 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.1" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" - integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" - integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.9.tgz#be82fab304b141c3eee81a4ce3b034d0eba1590a" - integrity sha512-jEFQ8L1tuvPjOI8lnpaf73oCJe+aoxL6ygqSy6c8LcW98zaC+4mzWuQIRCEvKeCOu+lbqdXcg4Uqmm1S8AP1tw== +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.17.0.tgz#7a9b80f712fe2052bc20da153ff1e552404d8e4b" + integrity sha512-r8aveDbd+rzGP+ykSdF3oPuTVRWRfbBiHl0rVDM2yNEmSMXfkObQLV46b4RnCv3Lra51OlfnZhkkFaDl2MIRaA== dependencies: "@babel/types" "^7.3.0" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" - integrity sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg== +"@types/graceful-fs@^4.1.2": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.5.tgz#21ffba0d98da4350db64891f92a9e5db3cdb4e15" + integrity sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== "@types/istanbul-lib-report@*": version "3.0.0" @@ -343,19 +628,27 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz#7a8cbf6a406f36c8add871625b278eaf0b0d255a" - integrity sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA== + version "1.1.2" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" -"@types/jest@^24.0.0": - version "24.9.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.1.tgz#02baf9573c78f1b9974a5f36778b366aa77bd534" - integrity sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q== +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^27.4.1": + version "27.4.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d" + integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw== dependencies: - jest-diff "^24.3.0" + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" "@types/json5@^0.0.29": version "0.0.29" @@ -363,39 +656,61 @@ integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= "@types/minimist@^1.2.0": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.1.tgz#283f669ff76d7b8260df8ab7a4262cc83d988256" - integrity sha512-fZQQafSREFyuZcdWFAExYjBiCL7AUCdgsk80iO0q4yihYYdcIiH28CcuPTGFgLOCC8RlW49GSQxdHwZP+I7CNg== + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + +"@types/node@*": + version "17.0.25" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.25.tgz#527051f3c2f77aa52e5dc74e45a3da5fb2301448" + integrity sha512-wANk6fBrUwdpY4isjWrKTufkrXdu1D2YHCot2fD/DfWxF5sMrVSA+KN7ydckvaTCh0HiqX9IVl0L5/ZoXg5M7w== "@types/node@^12.12.2": - version "12.12.29" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.29.tgz#46275f028b4e463b9ac5fefc1d08bc66cc193f25" - integrity sha512-yo8Qz0ygADGFptISDj3pOC9wXfln/5pQaN/ysDIzOaAWXt73cNHmtEC8zSO2Y+kse/txmwIAJzkYZ5fooaS5DQ== + version "12.20.48" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.48.tgz#55f70bd432b6515828c0298689776861b90ca4fa" + integrity sha512-4kxzqkrpwYtn6okJUcb2lfUu9ilnb3yhUOH6qX3nug8D2DupZ2drIkff2yJzYcNJVl3begnlcaBJ7tqiTTzjnQ== "@types/normalize-package-data@^2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" - integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + +"@types/prettier@^2.1.5": + version "2.6.0" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.6.0.tgz#efcbd41937f9ae7434c714ab698604822d890759" + integrity sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw== "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + "@types/underscore@^1.8.9": - version "1.9.4" - resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.9.4.tgz#22d1a3e6b494608e430221ec085fa0b7ccee7f33" - integrity sha512-CjHWEMECc2/UxOZh0kpiz3lEyX2Px3rQS9HzD20lxMvx571ivOBQKeLnqEjxUY0BMgp6WJWo/pQLRBwMW5v4WQ== + version "1.11.4" + resolved "https://registry.yarnpkg.com/@types/underscore/-/underscore-1.11.4.tgz#62e393f8bc4bd8a06154d110c7d042a93751def3" + integrity sha512-uO4CD2ELOjw8tasUrAhvnn2W4A0ZECOvMjCivJr4gA9pGgjv+qxKWY9GLTMVEK8ej85BxQOocUyE7hImmSQYcg== "@types/yargs-parser@*": - version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" - integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== "@types/yargs@^13.0.0": - version "13.0.8" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.8.tgz#a38c22def2f1c2068f8971acb3ea734eb3c64a99" - integrity sha512-XAvHLwG7UQ+8M4caKIH0ZozIOYay5fQkAgyIXegXT9jPtdIGdhga+sUEdAr1CiG46aB+c64xQEYyEzlwWVTNzA== + version "13.0.12" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" + integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== dependencies: "@types/yargs-parser" "*" @@ -562,44 +877,56 @@ JSONStream@^1.0.4: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" - integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== - -acorn-globals@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== - dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" +abab@^2.0.3, abab@^2.0.5: + version "2.0.6" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" + integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -acorn@^5.5.3: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" -acorn@^6.0.1: - version "6.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" - integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn@^6.4.1: version "6.4.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== +acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.2.4: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -620,40 +947,22 @@ ajv@^6.1.0, ajv@^6.10.2: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^6.5.5: - version "6.12.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.0.tgz#06d60b96d87b8454a5adaba86e7854da629db4b7" - integrity sha512-D6gFiFA0RRLyUbvijN74DWAjXSFxWKaWP7mldxkVhyhAV3+SWA9HEJPHQ2c9soIeTFJqcSdFDGFgdqs1iUU2Hw== +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" + type-fest "^0.21.3" -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - -ansi-regex@^4.0.0, ansi-regex@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" - integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== +ansi-regex@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" + integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== -ansi-regex@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" - integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" @@ -662,13 +971,18 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + anymatch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" @@ -677,10 +991,10 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" - integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -690,11 +1004,6 @@ aproba@^1.1.1: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -archy@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" - integrity sha1-+cjBN1fMHde8N5rHeyxipcKGjEA= - arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" @@ -722,12 +1031,7 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" - integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= - -array-find-index@^1.0.1: +array-find-index@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= @@ -762,18 +1066,6 @@ asn1.js@^5.2.0: minimalistic-assert "^1.0.0" safer-buffer "^2.1.0" -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - assert@^1.1.1: version "1.5.0" resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" @@ -787,21 +1079,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -812,16 +1094,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e" - integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug== - axios@^0.19.0: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" @@ -829,48 +1101,71 @@ axios@^0.19.0: dependencies: follow-redirects "1.5.10" -babel-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" - integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== - dependencies: - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/babel__core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.9.0" - chalk "^2.4.2" - slash "^2.0.0" - -babel-plugin-istanbul@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" - integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== +babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - find-up "^3.0.0" - istanbul-lib-instrument "^3.3.0" - test-exclude "^5.2.3" - -babel-plugin-jest-hoist@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" - integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== - dependencies: + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" -babel-preset-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" - integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== - dependencies: - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.9.0" +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.0.2: version "1.5.1" @@ -890,13 +1185,6 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -925,14 +1213,14 @@ bluebird@^3.5.5: integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: - version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" - integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== bn.js@^5.0.0, bn.js@^5.1.1: - version "5.1.3" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.1.3.tgz#beca005408f642ebebea80b042b4d18d2ac0ee6b" - integrity sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ== + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== brace-expansion@^1.1.7: version "1.1.11" @@ -958,7 +1246,7 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1, braces@~3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1043,6 +1331,17 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +browserslist@^4.17.5: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== + dependencies: + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -1057,10 +1356,10 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" - integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-xor@^1.0.3: version "1.0.3" @@ -1122,19 +1421,19 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" +call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - camelcase-keys@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" @@ -1144,21 +1443,21 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^2.0.0, camelcase@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001317: + version "1.0.30001332" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz#39476d3aa8d83ea76359c70302eafdd4a1d727dd" + integrity sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -1166,12 +1465,7 @@ capture-exit@^2.0.0: dependencies: rsvp "^4.8.4" -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -1180,6 +1474,19 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + chokidar@^2.1.8: version "2.1.8" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" @@ -1200,19 +1507,19 @@ chokidar@^2.1.8: fsevents "^1.2.7" chokidar@^3.4.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" - integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: - anymatch "~3.1.1" + anymatch "~3.1.2" braces "~3.0.2" - glob-parent "~5.1.0" + glob-parent "~5.1.2" is-binary-path "~2.1.0" is-glob "~4.0.1" normalize-path "~3.0.0" - readdirp "~3.5.0" + readdirp "~3.6.0" optionalDependencies: - fsevents "~2.3.1" + fsevents "~2.3.2" chownr@^1.1.1: version "1.1.4" @@ -1220,17 +1527,20 @@ chownr@^1.1.1: integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chrome-trace-event@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" - integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== - dependencies: - tslib "^1.9.0" + version "1.0.3" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" + integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -1239,6 +1549,11 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: inherits "^2.0.1" safe-buffer "^5.0.1" +cjs-module-lexer@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" + integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -1249,15 +1564,6 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -cliui@^3.0.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" - integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -1281,10 +1587,10 @@ co@^4.6.0: resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= +collect-v8-coverage@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== collection-visit@^1.0.0: version "1.0.0" @@ -1318,20 +1624,13 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" -commander@2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= - dependencies: - graceful-readlink ">= 1.0.0" - commander@^2.12.1, commander@^2.20.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -1350,11 +1649,6 @@ compare-func@^2.0.0: array-ify "^1.0.0" dot-prop "^5.1.0" -compare-versions@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.0.0.tgz#92da44cf19ea53fff6c6e8d4e88221d4e155d672" - integrity sha1-ktpEzxnqU//2xujU6IIh1OFV1nI= - component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1396,9 +1690,9 @@ constants-browserify@^1.0.0: integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= conventional-changelog-angular@^5.0.12: - version "5.0.12" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.12.tgz#c979b8b921cbfe26402eb3da5bbfda02d865a2b9" - integrity sha512-5GLsbnkR/7A89RyHLvvoExbiGbd9xKdKqDTrArnPbOqBqG/2wIosu0fHwpeIRI8Tl94MhVNBXcLJZl92ZQ5USw== + version "5.0.13" + resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" + integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== dependencies: compare-func "^2.0.0" q "^1.5.1" @@ -1422,7 +1716,7 @@ conventional-changelog-config-spec@2.1.0: resolved "https://registry.yarnpkg.com/conventional-changelog-config-spec/-/conventional-changelog-config-spec-2.1.0.tgz#874a635287ef8b581fd8558532bf655d4fb59f2d" integrity sha512-IpVePh16EbbB02V+UA+HQnnPIohgXvJRxHcS5+Uwk4AT5LjzCZJm5sp/yqs5C6KZJ1jMsV4paEV13BN1pvDuxQ== -conventional-changelog-conventionalcommits@4.5.0, conventional-changelog-conventionalcommits@^4.5.0: +conventional-changelog-conventionalcommits@4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.5.0.tgz#a02e0b06d11d342fdc0f00c91d78265ed0bc0a62" integrity sha512-buge9xDvjjOxJlyxUnar/+6i/aVEVGA7EEh4OafBCXPlLUQPGbRUBhBUveWRxzvR8TEjhKEP4BdepnpG2FSZXw== @@ -1431,16 +1725,25 @@ conventional-changelog-conventionalcommits@4.5.0, conventional-changelog-convent lodash "^4.17.15" q "^1.5.1" +conventional-changelog-conventionalcommits@^4.5.0: + version "4.6.3" + resolved "https://registry.yarnpkg.com/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-4.6.3.tgz#0765490f56424b46f6cb4db9135902d6e5a36dc2" + integrity sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g== + dependencies: + compare-func "^2.0.0" + lodash "^4.17.15" + q "^1.5.1" + conventional-changelog-core@^4.2.1: - version "4.2.2" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.2.tgz#f0897df6d53b5d63dec36b9442bd45354f8b3ce5" - integrity sha512-7pDpRUiobQDNkwHyJG7k9f6maPo9tfPzkSWbRq97GGiZqisElhnvUZSvyQH20ogfOjntB5aadvv6NNcKL1sReg== + version "4.2.4" + resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" + integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== dependencies: add-stream "^1.0.0" - conventional-changelog-writer "^4.0.18" + conventional-changelog-writer "^5.0.0" conventional-commits-parser "^3.2.0" dateformat "^3.0.0" - get-pkg-repo "^1.0.0" + get-pkg-repo "^4.0.0" git-raw-commits "^2.0.8" git-remote-origin-url "^2.0.0" git-semver-tags "^4.1.1" @@ -1449,7 +1752,6 @@ conventional-changelog-core@^4.2.1: q "^1.5.1" read-pkg "^3.0.0" read-pkg-up "^3.0.0" - shelljs "^0.8.3" through2 "^4.0.0" conventional-changelog-ember@^2.0.9: @@ -1493,15 +1795,14 @@ conventional-changelog-preset-loader@^2.3.4: resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== -conventional-changelog-writer@^4.0.18: - version "4.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" - integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== +conventional-changelog-writer@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.1.tgz#e0757072f045fe03d91da6343c843029e702f359" + integrity sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ== dependencies: - compare-func "^2.0.0" conventional-commits-filter "^2.0.7" dateformat "^3.0.0" - handlebars "^4.7.6" + handlebars "^4.7.7" json-stringify-safe "^5.0.1" lodash "^4.17.15" meow "^8.0.0" @@ -1535,9 +1836,9 @@ conventional-commits-filter@^2.0.7: modify-values "^1.0.0" conventional-commits-parser@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.1.tgz#ba44f0b3b6588da2ee9fd8da508ebff50d116ce2" - integrity sha512-OG9kQtmMZBJD/32NEw5IhN5+HnBqVjy03eC+I71I0oQRFA5rOgA4OtPOYG7mz1GkCfCNxn3gKIX8EiHJYuf1cA== + version "3.2.4" + resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.4.tgz#a7d3b77758a202a9b2293d2112a8d8052c740972" + integrity sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q== dependencies: JSONStream "^1.0.4" is-text-path "^1.0.1" @@ -1545,7 +1846,6 @@ conventional-commits-parser@^3.2.0: meow "^8.0.0" split2 "^3.0.0" through2 "^4.0.0" - trim-off-newlines "^1.0.0" conventional-recommended-bump@6.1.0: version "6.1.0" @@ -1561,10 +1861,10 @@ conventional-recommended-bump@6.1.0: meow "^8.0.0" q "^1.5.1" -convert-source-map@^1.4.0, convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== +convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== dependencies: safe-buffer "~5.1.1" @@ -1585,10 +1885,10 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -core-util-is@1.0.2, core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== create-ecdh@^4.0.0: version "4.0.4" @@ -1632,6 +1932,15 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5: shebang-command "^1.2.0" which "^1.2.9" +cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + crypto-browserify@^3.11.0: version "3.12.0" resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" @@ -1649,24 +1958,22 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": +cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + +cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== - dependencies: - cssom "0.3.x" - -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: - array-find-index "^1.0.1" + cssom "~0.3.6" cyclist@^1.0.1: version "1.0.1" @@ -1678,29 +1985,29 @@ dargs@^7.0.0: resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -data-urls@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" dateformat@^3.0.0: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@=3.1.0: - version "3.1.0" +debug@4, debug@^4.1.0, debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@=3.1.0: + version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== dependencies: @@ -1713,10 +2020,10 @@ debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.1.0, debug@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" - integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" @@ -1733,27 +2040,43 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= +dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + deep-is@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" - integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== +deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + +define-properties@^1.1.3: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.4.tgz#0b14d7bd7fbeb2f3572c3a7eda80ea5d57fb05b1" + integrity sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA== dependencies: - object-keys "^1.0.12" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" define-property@^0.2.5: version "0.2.5" @@ -1796,32 +2119,27 @@ detect-file@^1.0.0: integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= detect-indent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.0.0.tgz#0abd0f549f69fc6659a254fe96786186b6f528fd" - integrity sha512-oSyFlqaTHCItVRGK5RmrmjB+CmaMOW7IaNA/kdxqhoa6d17j/5ce9O9eWXmV/KEdRwqpQA+Vqe8a8Bsybu4YnA== - -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + version "6.1.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== -detect-newline@^3.1.0: +detect-newline@^3.0.0, detect-newline@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= + version "1.0.4" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" + integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== dependencies: asap "^2.0.0" wrappy "1" -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== +diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== diff@^4.0.1: version "4.0.2" @@ -1842,12 +2160,12 @@ domain-browser@^1.1.1: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== -domexception@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" - integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== dependencies: - webidl-conversions "^4.0.2" + webidl-conversions "^5.0.0" dot-prop@^5.1.0: version "5.3.0" @@ -1874,13 +2192,10 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" +electron-to-chromium@^1.4.84: + version "1.4.116" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.116.tgz#cf0b106d462a78e43ef33cc269caf2ad70e3c7a8" + integrity sha512-sy2ol5DTH0sy8xvAglyHFxsNFXFsOBfa6rGmrtjiSdQOp53ossspduOzU+5Lx23H7GxEjjvtSF36XqkajV6Z5A== elliptic@^6.5.3: version "6.5.4" @@ -1895,6 +2210,11 @@ elliptic@^6.5.3: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" +emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1917,16 +2237,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -enhanced-resolve@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" - integrity sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA== - dependencies: - graceful-fs "^4.1.2" - memory-fs "^0.5.0" - tapable "^1.0.0" - -enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: +enhanced-resolve@^4.0.0, enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== @@ -1935,43 +2246,53 @@ enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" -errno@^0.1.3: - version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" - integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== +enhanced-resolve@^5.7.0: + version "5.9.3" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz#44a342c012cbc473254af5cc6ae20ebd0aae5d88" + integrity sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow== dependencies: - prr "~1.0.1" + graceful-fs "^4.2.4" + tapable "^2.2.0" -errno@~0.1.7: +errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== dependencies: prr "~1.0.1" -error-ex@^1.2.0, error-ex@^1.3.1: +error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: is-arrayish "^0.2.1" -es-abstract@^1.17.0-next.1, es-abstract@^1.17.2: - version "1.17.4" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184" - integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ== +es-abstract@^1.19.1: + version "1.19.5" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.5.tgz#a2cb01eb87f724e815b278b0dd0d00f36ca9a7f1" + integrity sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA== dependencies: + call-bind "^1.0.2" es-to-primitive "^1.2.1" function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" has "^1.0.3" - has-symbols "^1.0.1" - is-callable "^1.1.5" - is-regex "^1.0.5" - object-inspect "^1.7.0" + has-symbols "^1.0.3" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-weakref "^1.0.2" + object-inspect "^1.12.0" object-keys "^1.1.1" - object.assign "^4.1.0" - string.prototype.trimleft "^2.1.1" - string.prototype.trimright "^2.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" es-to-primitive@^1.2.1: version "1.2.1" @@ -1992,13 +2313,18 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -escodegen@^1.9.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.1.tgz#ba01d0c8278b5e95a9a45350142026659027a457" - integrity sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ== +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== dependencies: esprima "^4.0.1" - estraverse "^4.2.0" + estraverse "^5.2.0" esutils "^2.0.2" optionator "^0.8.1" optionalDependencies: @@ -2032,15 +2358,15 @@ esrecurse@^4.1.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estraverse@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880" - integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ== + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== esutils@^2.0.2: version "2.0.3" @@ -2048,9 +2374,9 @@ esutils@^2.0.2: integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== events@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" - integrity sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg== + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" @@ -2061,9 +2387,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: safe-buffer "^5.1.1" exec-sh@^0.3.2: - version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" - integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== execa@^1.0.0: version "1.0.0" @@ -2078,6 +2404,21 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -2103,17 +2444,15 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" - integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== dependencies: - "@jest/types" "^24.9.0" - ansi-styles "^3.2.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.9.0" + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" extend-shallow@^2.0.1: version "2.0.1" @@ -2130,11 +2469,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - extglob@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" @@ -2149,20 +2483,10 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - fast-deep-equal@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4" - integrity sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA== + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== fast-diff@^1.1.1: version "1.2.0" @@ -2229,14 +2553,6 @@ find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - find-up@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" @@ -2251,7 +2567,7 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" -find-up@^4.1.0: +find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== @@ -2292,23 +2608,25 @@ follow-redirects@1.5.10: dependencies: debug "=3.1.0" +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== dependencies: asynckit "^0.4.0" - combined-stream "^1.0.6" + combined-stream "^1.0.8" mime-types "^2.1.12" fragment-cache@^0.2.1: @@ -2349,48 +2667,56 @@ fs.realpath@^1.0.0: integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: - version "1.2.11" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3" - integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw== + version "1.2.13" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" + integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== dependencies: bindings "^1.5.0" nan "^2.12.1" -fsevents@~2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.1.tgz#b209ab14c61012636c8863507edf7fb68cc54e9f" - integrity sha512-YR47Eg4hChJGAB1O3yEAOkGO+rlzutoICGqGo9EZ4lKWokzZRSyIW1QmTzqjtw8MJdj9srP869CuWw/hyzSiBw== +fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -gensync@^1.0.0-beta.1: - version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" - integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-pkg-repo@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d" - integrity sha1-xztInAbYDMVTbCyFP54FIyBWly0= +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== dependencies: - hosted-git-info "^2.1.4" - meow "^3.3.0" - normalize-package-data "^2.3.0" - parse-github-repo-url "^1.3.0" - through2 "^2.0.0" + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-pkg-repo@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" + integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== + dependencies: + "@hutson/parse-repository-url" "^3.0.0" + hosted-git-info "^4.0.0" + through2 "^2.0.0" + yargs "^16.2.0" get-stream@^4.0.0: version "4.1.0" @@ -2399,22 +2725,28 @@ get-stream@^4.0.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - git-raw-commits@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" - integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== + version "2.0.11" + resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.11.tgz#bc3576638071d18655e1cc60d7f524920008d723" + integrity sha512-VnctFhw+xfj8Va1xtfEqCUD2XDrbAPSJx+hSrE5K7fGdjZruW7XV+QOrN7LF/RJyvspRiD2I0asWsxFp0ya26A== dependencies: dargs "^7.0.0" lodash "^4.17.15" @@ -2431,9 +2763,9 @@ git-remote-origin-url@^2.0.0: pify "^2.3.0" git-revision-webpack-plugin@^3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/git-revision-webpack-plugin/-/git-revision-webpack-plugin-3.0.4.tgz#ed1eaad094d6956d3299381050a5a50f662550bd" - integrity sha512-ym4Zkl32HtTRZVVgl1KoE+sWtgeFyDjN3vaBQfn8cCv1btAX7rdDY9tgpv4Zi+yxq150pp+pUkGH9L1lRpZOUg== + version "3.0.6" + resolved "https://registry.yarnpkg.com/git-revision-webpack-plugin/-/git-revision-webpack-plugin-3.0.6.tgz#5dd6c6829fae05b405059dea6195b23875d69d4d" + integrity sha512-vW/9dBahGbpKPcccy3xKkHgdWoH/cAPPc3lQw+3edl7b4j29JfNGVrja0a1d8ZoRe4nTN8GCPrF9aBErDnzx5Q== git-semver-tags@^4.0.0, git-semver-tags@^4.1.1: version "4.1.1" @@ -2450,14 +2782,6 @@ gitconfiglocal@^1.0.0: dependencies: ini "^1.3.2" -"glob-all@3.1.0 ": - version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-all/-/glob-all-3.1.0.tgz#8913ddfb5ee1ac7812656241b03d5217c64b02ab" - integrity sha1-iRPd+17hrHgSZWJBsD1SF8ZLAqs= - dependencies: - glob "^7.0.5" - yargs "~1.2.6" - glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -2466,17 +2790,17 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@~5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2526,22 +2850,12 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= - -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== -handlebars@^4.7.6: +handlebars@^4.7.7: version "4.7.7" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== @@ -2553,33 +2867,44 @@ handlebars@^4.7.6: optionalDependencies: uglify-js "^3.1.4" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== +has-bigints@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= -has-symbols@^1.0.0, has-symbols@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" - integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" + integrity sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ== + dependencies: + get-intrinsic "^1.1.1" + +has-symbols@^1.0.1, has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" has-value@^0.3.1: version "0.3.1" @@ -2652,44 +2977,57 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" -hosted-git-info@^2.1.4, hosted-git-info@^2.1.5: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -hosted-git-info@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.1.tgz#710ef5452ea429a844abc33c981056e7371edab7" - integrity sha512-eT7NrxAsppPRQEBSwKSosReE+v8OzABwEScQYk5d4uxaEPlzxTIku7LINXtBGalthkLhJnq5lBI89PfK43zAKg== +hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== dependencies: lru-cache "^6.0.0" -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== dependencies: - whatwg-encoding "^1.0.1" + whatwg-encoding "^1.0.5" html-escaper@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.0.tgz#71e87f931de3fe09e56661ab9a29aadec707b491" - integrity sha512-a4u9BeERWGu/S8JiWEAQcdrg9v4QArtP9keViQjGMdff20fBdd8waotXaNmODqBe6uZ3Nafi7K/ho4gCQHV3Ig== + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" + "@tootallnate/once" "1" + agent-base "6" + debug "4" https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" + integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== + dependencies: + agent-base "6" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -2715,18 +3053,19 @@ import-local@^2.0.0: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -2765,7 +3104,16 @@ ini@^1.3.2, ini@^1.3.4, ini@^1.3.5: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -interpret@^1.0.0, interpret@^1.4.0: +internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + +interpret@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== @@ -2777,11 +3125,6 @@ invariant@^2.2.4: dependencies: loose-envify "^1.0.0" -invert-kv@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" - integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY= - is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -2801,6 +3144,13 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -2815,15 +3165,23 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4, is-callable@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab" - integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q== +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== is-ci@^2.0.0: version "2.0.0" @@ -2832,10 +3190,10 @@ is-ci@^2.0.0: dependencies: ci-info "^2.0.0" -is-core-module@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a" - integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ== +is-core-module@^2.5.0, is-core-module@^2.8.1: + version "2.9.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" + integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A== dependencies: has "^1.0.3" @@ -2854,9 +3212,11 @@ is-data-descriptor@^1.0.0: kind-of "^6.0.0" is-date-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" - integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" is-descriptor@^0.1.0: version "0.1.6" @@ -2893,18 +3253,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= - dependencies: - number-is-nan "^1.0.0" - is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -2928,12 +3276,24 @@ is-glob@^3.1.0: is-extglob "^2.1.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -2963,24 +3323,49 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" -is-regex@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae" - integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== dependencies: - has "^1.0.3" + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= -is-symbol@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" - integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== dependencies: - has-symbols "^1.0.1" + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" is-text-path@^1.0.1: version "1.0.1" @@ -2989,15 +3374,17 @@ is-text-path@^1.0.1: dependencies: text-extensions "^1.0.0" -is-typedarray@~1.0.0: +is-typedarray@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" is-windows@^1.0.1, is-windows@^1.0.2: version "1.0.2" @@ -3031,169 +3418,194 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz#31d18bdd127f825dd02ea7bfdfd906f8ab840e9f" + integrity sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" -istanbul-lib-report@^2.0.4: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== +istanbul-lib-report@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" + istanbul-lib-coverage "^3.0.0" + make-dir "^3.0.0" + supports-color "^7.1.0" -istanbul-lib-source-maps@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" + istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== +istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== dependencies: html-escaper "^2.0.0" - -jest-changed-files@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== - dependencies: - "@jest/types" "^24.9.0" - execa "^1.0.0" - throat "^4.0.0" - -jest-cli@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" - integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== - dependencies: - "@jest/core" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + +jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + +jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" exit "^0.1.2" - import-local "^2.0.0" - is-ci "^2.0.0" - jest-config "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^13.3.0" - -jest-config@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" - integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.9.0" - "@jest/types" "^24.9.0" - babel-jest "^24.9.0" - chalk "^2.0.1" + yargs "^16.2.0" + +jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" glob "^7.1.1" - jest-environment-jsdom "^24.9.0" - jest-environment-node "^24.9.0" - jest-get-type "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - micromatch "^3.1.10" - pretty-format "^24.9.0" - realpath-native "^1.1.0" - -jest-diff@^24.3.0, jest-diff@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" jest-docblock@^21.0.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" integrity sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw== -jest-docblock@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" - integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== - dependencies: - detect-newline "^2.1.0" - -jest-each@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" - integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== - dependencies: - "@jest/types" "^24.9.0" - chalk "^2.0.1" - jest-get-type "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - -jest-environment-jsdom@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" - integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jsdom "^11.5.1" - -jest-environment-node@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" - integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - -jest-haste-map@^24.5.0, jest-haste-map@^24.9.0: +jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + +jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + +jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + +jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + +jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + +jest-haste-map@^24.5.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== @@ -3212,45 +3624,66 @@ jest-haste-map@^24.5.0, jest-haste-map@^24.9.0: optionalDependencies: fsevents "^1.2.7" -jest-jasmine2@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" - integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== +jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + +jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" co "^4.6.0" - expect "^24.9.0" + expect "^27.5.1" is-generator-fn "^2.0.0" - jest-each "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - throat "^4.0.0" - -jest-leak-detector@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" - integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== - dependencies: - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-matcher-utils@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" - integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + +jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + +jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" jest-message-util@^24.9.0: version "24.9.0" @@ -3266,6 +3699,21 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" @@ -3273,26 +3721,34 @@ jest-mock@^24.9.0: dependencies: "@jest/types" "^24.9.0" -jest-pnp-resolver@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" - integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" -jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" - integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== +jest-pnp-resolver@^1.2.1, jest-pnp-resolver@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== -jest-resolve-dependencies@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" - integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== +jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + +jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== dependencies: - "@jest/types" "^24.9.0" - jest-regex-util "^24.3.0" - jest-snapshot "^24.9.0" + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" -jest-resolve@^24.5.0, jest-resolve@^24.9.0: +jest-resolve@^24.5.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== @@ -3303,83 +3759,117 @@ jest-resolve@^24.5.0, jest-resolve@^24.9.0: jest-pnp-resolver "^1.2.1" realpath-native "^1.1.0" -jest-runner@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" - integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-docblock "^24.3.0" - jest-haste-map "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-leak-detector "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" +jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + +jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" source-map-support "^0.5.6" - throat "^4.0.0" - -jest-runtime@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" - integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - chalk "^2.0.1" - exit "^0.1.2" + throat "^6.0.1" + +jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + execa "^5.0.0" glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - realpath-native "^1.1.0" - slash "^2.0.0" - strip-bom "^3.0.0" - yargs "^13.3.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" jest-serializer@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== -jest-snapshot@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" - integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== +jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + +jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" "@babel/types" "^7.0.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - expect "^24.9.0" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - mkdirp "^0.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" natural-compare "^1.4.0" - pretty-format "^24.9.0" - semver "^6.2.0" + pretty-format "^27.5.1" + semver "^7.3.2" jest-util@^24.9.0: version "24.9.0" @@ -3399,32 +3889,44 @@ jest-util@^24.9.0: slash "^2.0.0" source-map "^0.6.0" -jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" +jest-util@^27.0.0, jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" leven "^3.1.0" - pretty-format "^24.9.0" - -jest-watcher@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" - integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== - dependencies: - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - jest-util "^24.9.0" - string-length "^2.0.0" - -jest-worker@^24.6.0, jest-worker@^24.9.0: + pretty-format "^27.5.1" + +jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + +jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -3432,13 +3934,23 @@ jest-worker@^24.6.0, jest-worker@^24.9.0: merge-stream "^2.0.0" supports-color "^6.1.0" -jest@^24.0.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" - integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== +jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== dependencies: - import-local "^2.0.0" - jest-cli "^24.9.0" + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== + dependencies: + "@jest/core" "^27.5.1" + import-local "^3.0.2" + jest-cli "^27.5.1" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -3446,48 +3958,44 @@ jest@^24.0.0: integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" esprima "^4.0.0" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -jsdom@^11.5.1: - version "11.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" - integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== - dependencies: - abab "^2.0.0" - acorn "^5.5.3" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - cssom ">= 0.3.2 < 0.4.0" - cssstyle "^1.0.0" - data-urls "^1.0.0" - domexception "^1.0.1" - escodegen "^1.9.1" - html-encoding-sniffer "^1.0.2" - left-pad "^1.3.0" - nwsapi "^2.0.7" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.87.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.4" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.1" - ws "^5.2.0" +jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" xml-name-validator "^3.0.0" jsesc@^2.5.1: @@ -3510,22 +4018,15 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@2.x, json5@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.1.tgz#81b6cb04e9ba496f1c7005d07b4368a2638f90b6" - integrity sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ== - dependencies: - minimist "^1.2.0" +json5@2.x, json5@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" + integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== json5@^1.0.1: version "1.0.1" @@ -3539,16 +4040,6 @@ jsonparse@^1.2.0: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -3578,18 +4069,6 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== -lcid@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" - integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU= - dependencies: - invert-kv "^1.0.0" - -left-pad@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - leven@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" @@ -3603,21 +4082,26 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lines-and-columns@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" - integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= - -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= +license-checker@^25.0.1: + version "25.0.1" + resolved "https://registry.yarnpkg.com/license-checker/-/license-checker-25.0.1.tgz#4d14504478a5240a857bb3c21cd0491a00d761fa" + integrity sha512-mET5AIwl7MR2IAKYYoVBBpV0OnkKQ1xGj2IMMeEFIs42QAkEVjRtFZGWmQ28WeU7MP779iAgOaOy93Mn44mn6g== dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" + chalk "^2.4.1" + debug "^3.1.0" + mkdirp "^0.5.1" + nopt "^4.0.1" + read-installed "~4.0.3" + semver "^5.5.0" + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + spdx-satisfies "^4.0.0" + treeify "^1.1.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== load-json-file@^4.0.0: version "4.0.0" @@ -3683,15 +4167,10 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash@^4.17.13, lodash@^4.17.15: - version "4.17.15" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" - integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.15, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== loose-envify@^1.0.0: version "1.4.0" @@ -3700,14 +4179,6 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -3722,7 +4193,7 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -3730,32 +4201,39 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@1.x, make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: +map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= map-obj@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.0.tgz#0e8bc823e2aaca8a0942567d12ed14f389eec153" - integrity sha512-NAq0fCmZYGz9UFEQyndp7sisrow4GroyGeKluyKC/chuITZsPyOyC1UJZPJlVFImhXdROIP5xqouRLThT3BbpQ== + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== map-visit@^1.0.0: version "1.0.0" @@ -3789,22 +4267,6 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - meow@^8.0.0: version "8.1.2" resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" @@ -3846,13 +4308,13 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== +micromatch@^4.0.0, micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.0.5" + braces "^3.0.2" + picomatch "^2.3.1" miller-rabin@^4.0.0: version "4.0.1" @@ -3862,17 +4324,22 @@ miller-rabin@^4.0.0: bn.js "^4.0.0" brorand "^1.0.1" -mime-db@1.43.0: - version "1.43.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58" - integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ== +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@~2.1.19: - version "2.1.26" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06" - integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ== +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: - mime-db "1.43.0" + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== min-indent@^1.0.0: version "1.0.1" @@ -3890,9 +4357,9 @@ minimalistic-crypto-utils@^1.0.1: integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" @@ -3905,25 +4372,10 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -minimist@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" - integrity sha1-md9lelJXTCHJBXSX33QnkLK0wN4= - -minimist@^1.1.1, minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - -minimist@^1.1.3, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mississippi@^3.0.0: version "3.0.0" @@ -3949,34 +4401,22 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.x, mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= +mkdirp@^0.5.1, mkdirp@^0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: - minimist "0.0.8" - -mkdirp@^0.5.3: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" + minimist "^1.2.6" modify-values@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== -moment@2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== - -moment@^2.22.2: - version "2.24.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" - integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== +moment@2.29.3, moment@^2.29.2: + version "2.29.4" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" + integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== move-concurrently@^1.0.1: version "1.0.1" @@ -3995,15 +4435,20 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@^2.1.1: +ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + nan@^2.12.1: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== nanomatch@^1.2.9: version "1.2.13" @@ -4037,17 +4482,6 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nlf@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/nlf/-/nlf-1.4.3.tgz#3e8370a0bd0d1758b97d49d69d79bdcd0d1d113d" - integrity sha1-PoNwoL0NF1i5fUnWnXm9zQ0dET0= - dependencies: - archy "1.0.0" - commander "2.9.0" - compare-versions "3.0.0" - glob-all "3.1.0 " - read-installed "4.0.3" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -4082,35 +4516,20 @@ node-libs-browser@^2.2.1: util "^0.11.0" vm-browserify "^1.0.1" -node-license-validator@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/node-license-validator/-/node-license-validator-1.3.0.tgz#c49d3399ccb6087605a4464e9716d8242a36f454" - integrity sha1-xJ0zmcy2CHYFpEZOlxbYJCo29FQ= - dependencies: - nlf "^1.4.2" - npm-package-arg "^4.2.0" - semver "^4.3.6" - spdx-expression-validate "^1.0.1" - spdx-satisfies "^0.1.3" - yargs "^3.32.0" - -node-modules-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" - integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= +node-releases@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.3.tgz#225ee7488e4a5e636da8da52854844f9d716ca96" + integrity sha512-maHFz6OLqYxz+VQyCAtA3PTX4UP/53pa05fyDNc9CwjvJ0yEh6+xBwKsgCxMNhS8taUKBFYxfuiaD9U/55iFaw== -node-notifier@^5.4.2: - version "5.4.3" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" - integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== +nopt@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" + integrity sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg== dependencies: - growly "^1.3.0" - is-wsl "^1.1.0" - semver "^5.5.0" - shellwords "^0.1.1" - which "^1.3.0" + abbrev "1" + osenv "^0.1.4" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: +normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -4121,12 +4540,12 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- validate-npm-package-license "^3.0.1" normalize-package-data@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.2.tgz#cae5c410ae2434f9a6c1baa65d5bc3b9366c8699" - integrity sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== dependencies: hosted-git-info "^4.0.1" - resolve "^1.20.0" + is-core-module "^2.5.0" semver "^7.3.4" validate-npm-package-license "^3.0.1" @@ -4147,14 +4566,6 @@ npm-normalize-package-bin@^1.0.0: resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -npm-package-arg@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-4.2.1.tgz#593303fdea85f7c422775f17f9eb7670f680e3ec" - integrity sha1-WTMD/eqF98Qid18X+et2cPaA4+w= - dependencies: - hosted-git-info "^2.1.5" - semver "^5.1.0" - npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -4162,27 +4573,24 @@ npm-run-path@^2.0.0: dependencies: path-key "^2.0.0" +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + null-check@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/null-check/-/null-check-1.0.0.tgz#977dffd7176012b9ec30d2a39db5cf72a0439edd" integrity sha1-l33/1xdgErnsMNKjnbXPcqBDnt0= -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= - -nwsapi@^2.0.7: +nwsapi@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -object-assign@^4.0.1, object-assign@^4.1.1: +object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -4196,12 +4604,12 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" - integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== +object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: +object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -4213,23 +4621,24 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== +object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" -object.getownpropertydescriptors@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz#369bf1f9592d8ab89d712dced5cb81c7c5352649" - integrity sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg== +object.getownpropertydescriptors@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.3.tgz#b223cf38e17fefb97a63c10c91df72ccb386df9e" + integrity sha512-VdDoCwvJI4QdC6ndjpqFmoL3/+HxffFBbcJzKi5hwLLqqx3mdbedRpfZDdK0SrOSauj8X4GzBvnDZl4vTN7dOw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - es-abstract "^1.17.0-next.1" + es-abstract "^1.19.1" object.pick@^1.3.0: version "1.3.0" @@ -4245,6 +4654,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.8.1: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -4262,19 +4678,23 @@ os-browserify@^0.3.0: resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= -os-locale@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" - integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk= - dependencies: - lcid "^1.0.0" +os-homedir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= +os-tmpdir@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= + +osenv@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: - p-reduce "^1.0.0" + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" p-finally@^1.0.0: version "1.0.0" @@ -4288,14 +4708,7 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.2.tgz#61279b67721f5287aa1c13a9a7fbbc48c9291b1e" - integrity sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ== - dependencies: - p-try "^2.0.0" - -p-limit@^2.2.0: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -4337,11 +4750,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -4377,18 +4785,6 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-github-repo-url@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" - integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - parse-json@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" @@ -4397,7 +4793,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -4412,10 +4808,10 @@ parse-passwd@^1.0.0: resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY= -parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== pascalcase@^0.1.1: version "0.1.1" @@ -4432,13 +4828,6 @@ path-dirname@^1.0.0: resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -4459,19 +4848,15 @@ path-key@^2.0.0, path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-type@^3.0.0: version "3.0.0" @@ -4481,9 +4866,9 @@ path-type@^3.0.0: pify "^3.0.0" pbkdf2@^3.0.3: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.1.tgz#cb8724b0fada984596856d1a6ebafd3584654b94" - integrity sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -4491,22 +4876,17 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -picomatch@^2.0.4, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.5: - version "2.2.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" - integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== -pify@^2.0.0, pify@^2.3.0: +pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= @@ -4521,24 +4901,10 @@ pify@^4.0.1: resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - -pirates@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" - integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== - dependencies: - node-modules-regexp "^1.0.0" +pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== pkg-dir@^3.0.0: version "3.0.0" @@ -4547,10 +4913,12 @@ pkg-dir@^3.0.0: dependencies: find-up "^3.0.0" -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" posix-character-classes@^0.1.0: version "0.1.1" @@ -4567,15 +4935,14 @@ prettier@^1.18.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb" integrity sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew== -pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== +pretty-format@^27.0.0, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" process-nextick-args@~2.0.0: version "2.0.1" @@ -4593,22 +4960,22 @@ promise-inflight@^1.0.1: integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= prompts@^2.0.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.1.tgz#b63a9ce2809f106fa9ae1277c275b167af46ea05" - integrity sha512-qIP2lQyCwYbdzcqHIUi2HAxiWixhoM9OdLCWf8txXsapC/X9YdsCoeyRIXE/GP+Q0J37Q7+XN/MFqbUa7IzXNA== + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" - sisteransi "^1.0.4" + sisteransi "^1.0.5" prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= -psl@^1.1.28: - version "1.7.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c" - integrity sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ== +psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== public-encrypt@^4.0.0: version "4.0.3" @@ -4667,11 +5034,6 @@ q@^1.5.1: resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - querystring-es3@^0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -4702,12 +5064,12 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -react-is@^16.8.4: - version "16.13.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.0.tgz#0f37c3613c34fe6b37cd7f763a0d6293ab15c527" - integrity sha512-GFMtL0vHkiBv9HluwNZTggSn/sCyEt9n02aM0dSAjGGyqyNlAyftYm4phPxdvCigG15JreC5biwxCgTAJZ7yAA== +react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -read-installed@4.0.3: +read-installed@~4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/read-installed/-/read-installed-4.0.3.tgz#ff9b8b67f187d1e4c29b9feb31f6b223acd19067" integrity sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc= @@ -4722,24 +5084,14 @@ read-installed@4.0.3: graceful-fs "^4.1.2" read-package-json@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.1.tgz#16aa66c59e7d4dad6288f179dd9295fd59bb98f1" - integrity sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A== + version "2.1.2" + resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" + integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== dependencies: glob "^7.1.1" - json-parse-better-errors "^1.0.1" + json-parse-even-better-errors "^2.3.0" normalize-package-data "^2.0.0" npm-normalize-package-bin "^1.0.0" - optionalDependencies: - graceful-fs "^4.1.2" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" read-pkg-up@^3.0.0: version "3.0.0" @@ -4749,14 +5101,6 @@ read-pkg-up@^3.0.0: find-up "^2.0.0" read-pkg "^3.0.0" -read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -4766,15 +5110,6 @@ read-pkg-up@^7.0.1: read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -4835,10 +5170,10 @@ readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" -readdirp@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" - integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" @@ -4849,21 +5184,6 @@ realpath-native@^1.1.0: dependencies: util.promisify "^1.0.0" -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= - dependencies: - resolve "^1.1.6" - -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - redent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" @@ -4886,64 +5206,15 @@ remove-trailing-separator@^1.0.1: integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - -request-promise-core@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" - integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== - dependencies: - lodash "^4.17.15" - -request-promise-native@^1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" - integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== - dependencies: - request-promise-core "1.1.3" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.87.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -4961,6 +5232,13 @@ resolve-cwd@^2.0.0: dependencies: resolve-from "^3.0.0" +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + resolve-dir@^1.0.0, resolve-dir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43" @@ -4974,30 +5252,34 @@ resolve-from@^3.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" integrity sha1-six699nWiBvItuZTM17rywoYh0g= +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= +resolve.exports@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" + integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.x, resolve@^1.10.0, resolve@^1.3.2: - version "1.15.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" - integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== - dependencies: - path-parse "^1.0.6" - -resolve@^1.1.6, resolve@^1.20.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== +resolve@^1.10.0, resolve@^1.20.0, resolve@^1.3.2: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" ret@~0.1.10: version "0.1.15" @@ -5011,6 +5293,13 @@ rimraf@^2.5.4, rimraf@^2.6.3: dependencies: glob "^7.1.3" +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -5031,12 +5320,7 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -safe-buffer@^5.1.1, safe-buffer@^5.2.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5053,7 +5337,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5073,10 +5357,12 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" schema-utils@^1.0.0: version "1.0.0" @@ -5087,28 +5373,23 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.3.0, semver@^5.4.1, semver@^5.5, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^4.3.6: - version "4.3.6" - resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.6.tgz#300bc6e0e86374f7ba61068b5b1ecd57fc6532da" - integrity sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto= +semver@7.x, semver@^7.1.1, semver@^7.3.2, semver@^7.3.4: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.2.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.1.1, semver@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97" - integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw== - dependencies: - lru-cache "^6.0.0" - serialize-javascript@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" @@ -5151,40 +5432,52 @@ shebang-command@^1.2.0: dependencies: shebang-regex "^1.0.0" +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + shebang-regex@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= -shelljs@^0.8.3: - version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" - integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" -signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -sisteransi@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.4.tgz#386713f1ef688c7c0304dc4c0632898941cad2e3" - integrity sha512-/ekMoM4NJ59ivGSfKapeG+FWtrmWvA1p6FBZwXrqojw90vJu8lBmrTxCMuBCydKtkaUe2zt4PlxeTKpjwMbyig== +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + slide@~1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" @@ -5236,26 +5529,18 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.6: - version "0.5.16" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" - integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map-support@~0.5.12: - version "0.5.19" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61" - integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw== +source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" source-map-url@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" - integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" @@ -5267,64 +5552,59 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spdx-compare@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/spdx-compare/-/spdx-compare-0.1.2.tgz#b06af3ea34af7437d91a9f449eaf2d2e93c3c8fb" - integrity sha1-sGrz6jSvdDfZGp9Enq8tLpPDyPs= +source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + +spdx-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/spdx-compare/-/spdx-compare-1.0.0.tgz#2c55f117362078d7409e6d7b08ce70a857cd3ed7" + integrity sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A== dependencies: - spdx-expression-parse "^1.0.0" - spdx-ranges "^1.0.0" + array-find-index "^1.0.2" + spdx-expression-parse "^3.0.0" + spdx-ranges "^2.0.0" spdx-correct@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" - integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" spdx-license-ids "^3.0.0" spdx-exceptions@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" - integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== - -spdx-expression-parse@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" - integrity sha1-m98vIOH0DtRH++JzJmGR/O1RYmw= + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" - integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" -spdx-expression-validate@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/spdx-expression-validate/-/spdx-expression-validate-1.0.2.tgz#5a4e4d7616ed1c9b88150366b4217f767c27e9e3" - integrity sha1-Wk5NdhbtHJuIFQNmtCF/dnwn6eM= - dependencies: - spdx-expression-parse "^1.0.0" - spdx-license-ids@^3.0.0: - version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" - integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + version "3.0.11" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== -spdx-ranges@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/spdx-ranges/-/spdx-ranges-1.0.1.tgz#0f4eec7b8ea48ed202e374bb8942e8d18dc0113e" - integrity sha1-D07se46kjtIC43S7iULo0Y3AET4= +spdx-ranges@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/spdx-ranges/-/spdx-ranges-2.1.1.tgz#87573927ba51e92b3f4550ab60bfc83dd07bac20" + integrity sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA== -spdx-satisfies@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/spdx-satisfies/-/spdx-satisfies-0.1.3.tgz#67a1f274e6115d4aae28afe474db76164be10bdc" - integrity sha1-Z6HydOYRXUquKK/kdNt2FkvhC9w= +spdx-satisfies@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/spdx-satisfies/-/spdx-satisfies-4.0.1.tgz#9a09a68d80f5f1a31cfaebb384b0c6009e4969fe" + integrity sha512-WVzZ/cXAzoNmjCWiEluEA3BjHp5tiUmmhn9MK+X0tBbR9sOqtC6UQwmgCNrAIZvNlMuBUYAaHYfb2oqlF9SwKA== dependencies: - spdx-compare "^0.1.2" - spdx-expression-parse "^1.0.0" + spdx-compare "^1.0.0" + spdx-expression-parse "^3.0.0" + spdx-ranges "^2.0.0" split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" @@ -5352,32 +5632,26 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - ssri@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8" - integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA== + version "6.0.2" + resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" + integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== dependencies: figgy-pudding "^3.5.1" stack-utils@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" - integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + version "1.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" + integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== + dependencies: + escape-string-regexp "^2.0.0" + +stack-utils@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" + integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== + dependencies: + escape-string-regexp "^2.0.0" standard-version@9.1.1: version "9.1.1" @@ -5408,11 +5682,6 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= - stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -5445,22 +5714,13 @@ stream-shift@^1.0.0: resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d" integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ== -string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= - dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" - -string-width@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" @@ -5472,29 +5732,29 @@ string-width@^3.0.0, string-width@^3.1.0: strip-ansi "^5.1.0" string-width@^4.1.0, string-width@^4.2.0: - version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" - integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.0" + strip-ansi "^6.0.1" -string.prototype.trimleft@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74" - integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag== +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - function-bind "^1.1.1" -string.prototype.trimright@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9" - integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g== +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: + call-bind "^1.0.2" define-properties "^1.1.3" - function-bind "^1.1.1" string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" @@ -5515,20 +5775,6 @@ stringify-package@^1.0.1: resolved "https://registry.yarnpkg.com/stringify-package/-/stringify-package-1.0.1.tgz#e5aa3643e7f74d0f28628b72f3dad5cecfc3ba85" integrity sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg== -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -5536,36 +5782,32 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" -strip-ansi@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" - integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== - dependencies: - ansi-regex "^5.0.0" - -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: - is-utf8 "^0.2.0" + ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + strip-eof@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-indent@^3.0.0: version "3.0.0" @@ -5574,6 +5816,11 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + supports-color@^5.3.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -5588,7 +5835,34 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -symbol-tree@^3.2.2: +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== @@ -5598,6 +5872,19 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + +terminal-link@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== + dependencies: + ansi-escapes "^4.2.1" + supports-hyperlinks "^2.0.0" + terser-webpack-plugin@^1.4.3: version "1.4.5" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz#a217aefaea330e734ffacb6120ec1fa312d6040b" @@ -5622,25 +5909,24 @@ terser@^4.1.2: source-map "~0.6.1" source-map-support "~0.5.12" -test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: - glob "^7.1.3" + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" text-extensions@^1.0.0: version "1.9.0" resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== -throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= +throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== through2@^2.0.0: version "2.0.5" @@ -5662,12 +5948,12 @@ through@2, "through@>=2.2.7 <3": resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= -"timeline-state-resolver-types@npm:@tv2media/timeline-state-resolver-types@1.0.0-release37": - version "1.0.0-release37" - resolved "https://registry.yarnpkg.com/@tv2media/timeline-state-resolver-types/-/timeline-state-resolver-types-1.0.0-release37.tgz#3271b202cd0c4e03ae418c76019276238eede7db" - integrity sha512-HdCWUQ0EJ7LwlaH9eRtURwzXknIvo3U8kInzus9Vx0M0HoUixYgfV5Z80w/PVSYdUk0L95kW2oLZB4ECB1M7Pg== +"timeline-state-resolver-types@npm:@tv2media/timeline-state-resolver-types@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@tv2media/timeline-state-resolver-types/-/timeline-state-resolver-types-2.1.3.tgz#b79f4a5449428c517398bc908e93c13477ff04a8" + integrity sha512-wHW2S/Q/i2Dn7QPjY8nCdfjGG/a8BCvMfuI/vMm9WTqfzRnBgh9S8gd4TmOFUEaAiEZNGRy/wR6Y0ZquLYQ0mQ== dependencies: - tslib "^2.1.0" + tslib "^2.3.1" timers-browserify@^2.0.4: version "2.0.12" @@ -5676,10 +5962,10 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-arraybuffer@^1.0.0: version "1.0.1" @@ -5723,56 +6009,50 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" -tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== dependencies: - psl "^1.1.28" + psl "^1.1.33" punycode "^2.1.1" + universalify "^0.1.2" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== dependencies: - punycode "^2.1.0" + punycode "^2.1.1" -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= +treeify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/treeify/-/treeify-1.1.0.tgz#4e31c6a463accd0943879f30667c4fdaff411bb8" + integrity sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A== trim-newlines@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30" - integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA== - -trim-off-newlines@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz#9f9ba9d9efa8764c387698bcbfeb2c848f11adb3" - integrity sha1-n5up2e+odkw4dpi8v+sshI8RrbM= + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== -ts-jest@^24.0.0: - version "24.3.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.3.0.tgz#b97814e3eab359ea840a1ac112deae68aa440869" - integrity sha512-Hb94C/+QRIgjVZlJyiWwouYUF+siNJHJHknyspaOcZ+OQAIdFG/UrdQVXw/0B8Z3No34xkUXZJpOTy9alOWdVQ== +ts-jest@^27.1.3: + version "27.1.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.4.tgz#84d42cf0f4e7157a52e7c64b1492c46330943e00" + integrity sha512-qjkZlVPWVctAezwsOD1OPzbZ+k7zA5z3oxII4dGdZo5ggX/PL7kvwTM0pXTr10fAtbiVpJaL3bWd502zAhpgSQ== dependencies: bs-logger "0.x" - buffer-from "1.x" fast-json-stable-stringify "2.x" + jest-util "^27.0.0" json5 "2.x" lodash.memoize "4.x" make-error "1.x" - mkdirp "0.x" - resolve "1.x" - semver "^5.5" - yargs-parser "10.x" + semver "7.x" + yargs-parser "20.x" ts-loader@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.1.tgz#67939d5772e8a8c6bdaf6277ca023a4812da02ef" - integrity sha512-Dd9FekWuABGgjE1g0TlQJ+4dFUfYGbYcs52/HQObE0ZmUNjQlmLAS7xXsSzy23AMaMwipsx5sNHvoEpT2CZq1g== + version "6.2.2" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-6.2.2.tgz#dffa3879b01a1a1e0a4b85e2b8421dc0dfff1c58" + integrity sha512-HDo5kXZCBml3EUPcc7RlZOV/JGlLHwppTLEHb3SHnr5V7NXD4klMEkrhJe5wgRbaWsSXi+Y1SIBN/K9B6zWGWQ== dependencies: chalk "^2.3.0" enhanced-resolve "^4.0.0" @@ -5781,41 +6061,41 @@ ts-loader@^6.2.1: semver "^6.0.0" ts-node@^8.0.3: - version "8.6.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35" - integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg== + version "8.10.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== dependencies: arg "^4.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.6" + source-map-support "^0.5.17" yn "3.1.1" tsconfig-paths-webpack-plugin@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.2.0.tgz#6e70bd42915ad0efb64d3385163f0c1270f3e04d" - integrity sha512-S/gOOPOkV8rIL4LurZ1vUdYCVgo15iX9ZMJ6wx6w2OgcpT/G4wMyHB6WM+xheSqGMrWKuxFul+aXpCju3wmj/g== + version "3.5.2" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-3.5.2.tgz#01aafff59130c04a8c4ebc96a3045c43c376449a" + integrity sha512-EhnfjHbzm5IYI9YPNVIxx1moxMI4bpHD2e0zTXeDNQcwjjRaGepP7IhTHJkyDBG0CAOoxRfe7jCG630Ou+C6Pw== dependencies: - chalk "^2.3.0" - enhanced-resolve "^4.0.0" - tsconfig-paths "^3.4.0" + chalk "^4.1.0" + enhanced-resolve "^5.7.0" + tsconfig-paths "^3.9.0" -tsconfig-paths@^3.4.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" - integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== +tsconfig-paths@^3.9.0: + version "3.14.1" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a" + integrity sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.1" - minimist "^1.2.0" + minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: - version "1.11.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" - integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== +tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: +tslib@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -5826,9 +6106,9 @@ tslint-config-prettier@^1.18.0: integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== tslint-plugin-prettier@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tslint-plugin-prettier/-/tslint-plugin-prettier-2.1.0.tgz#e2522d273cb9672d93d0e68f2514fe3c19698c3a" - integrity sha512-nMCpU+QSpXtydcWXeZF+3ljIbG/K8SHVZwB7K/MtuoQQFXxXN6watqTSBpVXCInuPFvmjiWkhxeMoUW4N0zgSg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz#73fe71bf9f03842ac48c104122ca9b1de012ecf4" + integrity sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA== dependencies: eslint-plugin-prettier "^2.2.0" lines-and-columns "^1.1.6" @@ -5865,18 +6145,6 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -5884,11 +6152,21 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + type-fest@^0.18.0: version "0.18.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + type-fest@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" @@ -5899,25 +6177,47 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +type-fest@^2.11.1: + version "2.12.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.12.2.tgz#80a53614e6b9b475eb9077472fb7498dc7aa51d0" + integrity sha512-qt6ylCGpLjZ7AaODxbpyBZSs9fCI9SkL3Z9q2oxMBQhs/uyY+VD8jHA8ULCGmWQJlBgqvO3EJeAngOHD8zQCrQ== + +typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.3.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^4.1: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== uglify-js@^3.1.4: - version "3.13.2" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.13.2.tgz#fe10319861bccc8682bfe2e8151fbdd8aa921c44" - integrity sha512-SbMu4D2Vo95LMC/MetNaso1194M1htEA+JrqE9Hk+G2DhI+itfS9TRu9ZKeCahLDNa/J3n4MqUJ/fOHMzQpRWw== + version "3.15.4" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.4.tgz#fa95c257e88f85614915b906204b9623d4fa340d" + integrity sha512-vMOPGDuvXecPs34V74qDKk4iJ/SN4vL3Ow/23ixafENYvtrNvtbcgUeugTcUGRGsOF/5fU8/NYSL5Hyb3l1OJA== -underscore@1.13.1, underscore@^1.12.1: - version "1.13.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" - integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== +unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + +underscore@^1.12.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.2.tgz#276cea1e8b9722a8dbed0100a407dda572125881" + integrity sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g== union-value@^1.0.0: version "1.0.1" @@ -5943,6 +6243,11 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + unset-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" @@ -5957,9 +6262,9 @@ upath@^1.1.1: integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== dependencies: punycode "^2.1.0" @@ -5992,14 +6297,15 @@ util-extend@^1.0.1: integrity sha1-p8IW0mdUUWljeztu3GypEZ4v+T8= util.promisify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee" - integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA== + version "1.1.1" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.1.tgz#77832f57ced2c9478174149cae9b96e9918cd54b" + integrity sha512-/s3UsZUrIfa6xDhr7zZhnE9SLQ5RIXyYfiVnMMyMDzOc8WhWN4Nbh36H842OyurKbCDAesZOJaVyvmSl6fhGQw== dependencies: + call-bind "^1.0.0" define-properties "^1.1.3" - es-abstract "^1.17.2" + for-each "^0.3.3" has-symbols "^1.0.1" - object.getownpropertydescriptors "^2.1.0" + object.getownpropertydescriptors "^2.1.1" util@0.10.3: version "0.10.3" @@ -6015,15 +6321,19 @@ util@^0.11.0: dependencies: inherits "2.0.3" -uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - v8-compile-cache@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132" - integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q== + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + +v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -6033,33 +6343,31 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vm-browserify@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -w3c-hr-time@^1.0.1: +w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: browser-process-hrtime "^1.0.0" +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" watchpack-chokidar2@^2.0.1: version "2.0.1" @@ -6079,10 +6387,15 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== webpack-cli@^3.1.2: version "3.3.12" @@ -6138,52 +6451,56 @@ webpack@^4.27.1: watchpack "^1.7.4" webpack-sources "^1.4.1" -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: +whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" -whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: +whatwg-mimetype@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" - integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -window-size@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.4.tgz#f8e1aa1ee5a53ec5bf151ffa09742a6ad7697876" - integrity sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY= +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" word-wrap@~1.2.3: version "1.2.3" @@ -6202,14 +6519,6 @@ worker-farm@^1.7.0: dependencies: errno "~0.1.7" -wrap-ansi@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" - integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= - dependencies: - string-width "^1.0.1" - strip-ansi "^3.0.1" - wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -6233,46 +6542,45 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" - integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== +write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: - graceful-fs "^4.1.11" imurmurhash "^0.1.4" + is-typedarray "^1.0.0" signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" -ws@^5.2.0: - version "5.2.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" - integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== - dependencies: - async-limiter "~1.0.0" +ws@^7.4.6: + version "7.5.7" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" + integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -y18n@^3.2.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" - integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= - y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== y18n@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" - integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== yallist@^3.0.2: version "3.1.1" @@ -6284,20 +6592,10 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@10.x: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - -yargs-parser@^13.1.1: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" +yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs-parser@^13.1.2: version "13.1.2" @@ -6307,27 +6605,6 @@ yargs-parser@^13.1.2: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^20.2.2, yargs-parser@^20.2.3: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== - -yargs@^13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" - integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.1" - yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" @@ -6344,7 +6621,7 @@ yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^16.0.0: +yargs@^16.0.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -6357,26 +6634,6 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^3.32.0: - version "3.32.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.32.0.tgz#03088e9ebf9e756b69751611d2a5ef591482c995" - integrity sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU= - dependencies: - camelcase "^2.0.1" - cliui "^3.0.3" - decamelize "^1.1.1" - os-locale "^1.4.0" - string-width "^1.0.1" - window-size "^0.1.4" - y18n "^3.2.0" - -yargs@~1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.2.6.tgz#9c7b4a82fd5d595b2bf17ab6dcc43135432fe34b" - integrity sha1-nHtKgv1dWVsr8Xq23MQxNUMv40s= - dependencies: - minimist "^0.1.0" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"