├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── run_canary.yaml │ ├── run_prod.yaml │ ├── run_tests.yaml │ ├── trigger_canary.yaml │ └── update_dependencies.yaml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── api-extractor.json ├── assets └── style.css ├── demo ├── player-ott.html ├── player-ovp.html └── style.css ├── docs ├── Kaltura-Player-V7-V2-differences.md ├── adding-vtt-thumbnails.md ├── ads.md ├── advertisement-layout-management.md ├── api.md ├── change-media.md ├── coding-guidlines.md ├── configuration.md ├── debugging.md ├── embed-types.md ├── errors.md ├── events.md ├── getting-started-using-player-studio.md ├── guides.md ├── images │ ├── ad-events-timeline.jpg │ ├── ads-controller.jpg │ ├── chrome-local-storage.png │ ├── clear-button-local-storage.png │ ├── configuration-strength.jpg │ ├── console-logs-example.png │ ├── content-share-and-embed.png │ ├── content-tab.png │ ├── dash-instream-thumbnail.png │ ├── kaltura-logo.svg │ ├── kmc.png │ ├── playback-start-end-timeline.jpg │ ├── player-save.png │ ├── player-state-machine.jpg │ ├── playlist-countdown.png │ ├── save-value-flow-local-storage.png │ ├── setup-flow-local-storage.jpg │ ├── share-and-embed-dynamic-copy.png │ ├── studio.png │ ├── translation-tree.png │ └── tv-platform-add.png ├── instream-dash-thumbnails.md ├── keyboard-shortcuts.md ├── localization.md ├── managing-tracks.md ├── media-capabilities.md ├── migration-from-v2-player.md ├── player-setup.md ├── player-states.md ├── playing-your-video.md ├── playlist.md ├── request-response-manipulation.md ├── service-provider.md ├── supportedPlatforms.md ├── ui.md ├── user-preferences.md └── writing-a-plugin.md ├── flow-typed ├── interfaces │ ├── ads-controller-provider.js │ ├── ads-controller.js │ ├── ads-plugin-controller.js │ ├── cue-point.js │ ├── middleware-provider.js │ ├── plugin.js │ └── preset-components-provider.js ├── modules │ ├── babel-polyfill.js │ ├── intersection-observer.js │ ├── js-logger.js │ ├── playkit-js-providers.js │ ├── playkit-js-ui.js │ └── playkit-js.js └── types │ ├── advertising.js │ ├── kaltura-player-event-types.js │ ├── kaltura-player-options.js │ ├── kaltura-player-ui-options.js │ ├── kaltura-player-visibility-config.js │ ├── kaltura-players.js │ ├── log-level.js │ ├── media-capabilities.js │ ├── media-config.js │ ├── playlist.js │ ├── plugins.js │ ├── prebid-config.js │ ├── thumbnail-config.js │ ├── ui-component-options.js │ └── ui-component.js ├── karma.conf.js ├── package.json ├── samples ├── ovp │ ├── all-plugins.html │ ├── auto-pause.html │ ├── auto-play-in-view.html │ ├── cast.html │ ├── change-media-clear.html │ ├── change-media-drm.html │ ├── custom-poster.html │ ├── custom-preview-thumbnail.html │ ├── dash-in-stream-thumbnails.html │ ├── floating.html │ ├── live-stats.html │ ├── playlist-by-config.html │ ├── playlist-by-entry-list.html │ ├── playlist-by-id.html │ ├── prebid.html │ ├── set-media.html │ ├── standalone-ima.html │ └── ui-conf.html └── style.css ├── src ├── common │ ├── ads │ │ ├── ad-break.ts │ │ ├── ad-layout-middleware.ts │ │ ├── ad.ts │ │ ├── index.ts │ │ └── prebid-manager.ts │ ├── cast │ │ ├── base-remote-player.ts │ │ ├── cast-event-type.ts │ │ ├── custom-message.ts │ │ ├── index.ts │ │ ├── player-snapshot.ts │ │ ├── remote-control.ts │ │ ├── remote-payload.ts │ │ ├── remote-player-manager.ts │ │ ├── remote-player-type.ts │ │ ├── remote-player-ui.ts │ │ ├── remote-player.ts │ │ ├── remote-session.ts │ │ └── text-style-convertor.ts │ ├── controllers │ │ ├── ads-controller.ts │ │ ├── controller-provider.ts │ │ └── index.ts │ ├── cuepoint │ │ └── cuepoint-manager.ts │ ├── playlist │ │ ├── index.ts │ │ ├── playlist-event-type.ts │ │ ├── playlist-item.ts │ │ ├── playlist-manager.ts │ │ └── playlist.ts │ ├── plugins │ │ ├── base-plugin.ts │ │ ├── index.ts │ │ ├── plugin-manager.ts │ │ ├── plugin-readiness-middleware.ts │ │ ├── plugins-config-store.ts │ │ └── plugins-config.ts │ ├── service-provider.ts │ ├── storage │ │ ├── base-storage-manager.ts │ │ ├── local-storage-manager.ts │ │ ├── session-storage-manager.ts │ │ └── storage-wrapper.ts │ ├── thumbnail-manager.ts │ ├── ui-wrapper.ts │ └── utils │ │ ├── error-helper.ts │ │ ├── evaluate.ts │ │ ├── external-stream-redirect-helper.ts │ │ ├── kaltura-params.ts │ │ ├── media-capabilities.ts │ │ ├── session-id-cache.ts │ │ ├── session-id-generator.ts │ │ ├── setup-helpers.ts │ │ ├── validation-error.ts │ │ └── viewability-manager.ts ├── exported.scss ├── index.ts ├── kaltura-player.ts ├── ott │ ├── player-defaults.ts │ ├── plugins │ │ └── plugins-config-store.ts │ └── poster.ts ├── ovp │ ├── player-defaults.ts │ ├── plugins │ │ └── plugins-config-store.ts │ └── poster.ts ├── proxy.ts ├── setup.ts └── types │ ├── ads │ ├── ad-break-options.ts │ ├── ad-break-types.ts │ ├── ad-options.ts │ ├── ad-tag-types.ts │ ├── ads-controller-provider.ts │ ├── ads-controller.ts │ ├── ads-plugin-controller.ts │ ├── advertising.ts │ ├── index.ts │ └── prebid-config.ts │ ├── advertising-config.ts │ ├── cue-point.ts │ ├── events │ ├── event-types.ts │ └── index.ts │ ├── exteranl-thumbnails-object.ts │ ├── global │ └── globals.d.ts │ ├── image-player-options.ts │ ├── index.ts │ ├── kaltura-player-options.ts │ ├── log-level.ts │ ├── media-capabilities.ts │ ├── media-config.ts │ ├── media-source-options.ts │ ├── network-config.ts │ ├── playback-config.ts │ ├── playlist-object.ts │ ├── playlist │ ├── KPPlaylistObject.ts │ ├── index.ts │ ├── playlis-countdown-options.ts │ ├── playlist-config-object.ts │ ├── playlist-item-config.ts │ └── playlist-options.ts │ ├── plugins │ ├── index.ts │ ├── plugin-class-type.ts │ └── plugins-config.ts │ ├── prebid-config.ts │ ├── sources-config.ts │ ├── thumbnail-config.ts │ ├── ui-config.ts │ ├── utils │ ├── class-constructor.ts │ └── index.ts │ └── visibility-config.ts ├── tests ├── .eslintrc ├── assets │ ├── audios.mp4 │ └── mov_bbb.mp4 ├── e2e │ ├── common │ │ ├── ads │ │ │ └── ads-controller.spec.ts │ │ ├── cuepoints │ │ │ └── cuepoint-manager.spec.js │ │ ├── playlist │ │ │ └── playlist-manager.spec.ts │ │ ├── plugin │ │ │ ├── base-plugin.spec.ts │ │ │ ├── plugin-manager.spec.ts │ │ │ ├── plugins-config.spec.ts │ │ │ └── test-plugins │ │ │ │ ├── async-reject-plugin.ts │ │ │ │ ├── async-resolve-plugin.ts │ │ │ │ ├── colors-plugin.ts │ │ │ │ └── numbers-plugin.ts │ │ ├── service-provider.spec.ts │ │ ├── storage │ │ │ ├── storage-manager.spec.ts │ │ │ └── storage-wrapper.spec.js │ │ ├── thumbnail-manager.spec.ts │ │ └── utils │ │ │ ├── evaluate.spec.js │ │ │ ├── kaltura-params.spec.ts │ │ │ ├── setup-helpers.spec.js │ │ │ └── viewability-manager.spec.ts │ ├── configs │ │ ├── plugins.json │ │ └── sources.json │ ├── kaltura-player.spec.ts │ ├── mock-data │ │ ├── images.js │ │ ├── media.js │ │ └── playlist.js │ ├── ott │ │ ├── player-defaults.spec.js │ │ └── poster.spec.js │ ├── ovp │ │ ├── player-defaults.spec.js │ │ └── poster.spec.js │ └── setup.spec.js ├── index.js └── utils │ └── test-utils.ts ├── ts-typed ├── base-middleware.d.ts ├── base-plugin.d.ts ├── cue-point-manager.d.ts ├── engine-decorator.d.ts ├── event-manager.d.ts ├── fake-event-target.d.ts ├── kaltura-player.d.ts ├── logger.d.ts ├── player-config.d.ts ├── player.d.ts ├── playlist.d.ts └── provider-loader.d.ts ├── tsconfig-lib.json ├── tsconfig.json ├── webpack.config.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_size = 2 7 | end_of_line = lf 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | types/ 3 | demo/ 4 | ts-typed/ 5 | webpack.config.js 6 | tsconfig.json 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "extends": ["plugin:prettier/recommended", "prettier", "plugin:@typescript-eslint/recommended"], 5 | "plugins": ["prettier", "@typescript-eslint"], 6 | "rules": { 7 | "max-len": [ 8 | "error", 9 | { 10 | "code": 150, 11 | "ignoreComments": true, 12 | "ignoreStrings": true, 13 | "ignoreUrls": true, 14 | "ignoreTemplateLiterals": true, 15 | "ignoreRegExpLiterals": true 16 | } 17 | ], 18 | "eol-last": "off", 19 | "prettier/prettier": "error", 20 | "@typescript-eslint/explicit-function-return-type": "warn", 21 | "@typescript-eslint/no-non-null-assertion": "off", 22 | "@typescript-eslint/no-unused-vars": "error", 23 | "@typescript-eslint/no-explicit-any": "off", 24 | "@typescript-eslint/explicit-member-accessibility": [ 25 | "error", 26 | { 27 | "accessibility": "explicit", 28 | "overrides": { 29 | "accessors": "explicit", 30 | "constructors": "no-public", 31 | "methods": "explicit", 32 | "properties": "explicit", 33 | "parameterProperties": "explicit" 34 | } 35 | } 36 | ], 37 | "block-scoped-var": "error", 38 | "arrow-parens": "error", 39 | "eqeqeq": "error", 40 | "no-var": "error", 41 | "no-console": "error", 42 | "prefer-const": "error", 43 | "prefer-arrow-callback": "error", 44 | "no-trailing-spaces": "error", 45 | "quotes": ["warn", "single", { "avoidEscape": true }] 46 | }, 47 | "overrides": [ 48 | { 49 | "files": ["**/*.json"], 50 | "rules": { 51 | "max-len": ["error", { "code": 60 }] 52 | } 53 | } 54 | ], 55 | "settings": {}, 56 | "env": { 57 | "browser": true, 58 | "es6": true 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ##### Prerequisites 4 | 5 | - [ ] Have you checked for duplicate [issues](https://github.com/kaltura/kaltura-player-js/issues): **\_\_** 6 | - [ ] Which Plugin [version](https://github.com/kaltura/kaltura-player-js/releases) are you using: **\_\_** 7 | - [ ] Can you reproduce the issue with our latest release version: **\_\_** 8 | - [ ] Can you reproduce the issue with the latest code from master: **\_\_** 9 | - [ ] What browser and OS names and versions are you using: **\_\_** 10 | - [ ] If applicable, add test code or test page to reproduce: 11 | 12 | ``` 13 | Paste test code here 14 | ``` 15 | 16 | ##### Expected behavior 17 | 18 | What you expected to happen 19 | 20 | ##### Actual behavior 21 | 22 | What actually happened 23 | 24 | ##### Console output 25 | 26 | ``` 27 | Paste the contents of the browser console here. 28 | ``` 29 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description of the Changes 2 | 3 | Please add a detailed description of the change, whether it's an enhancement or a bugfix. 4 | If the PR is related to an open issue please link to it. 5 | 6 | **Issue:** 7 | 8 | **Fix:** 9 | 10 | #### Resolves FEC-[Please add the ticket reference here] 11 | -------------------------------------------------------------------------------- /.github/workflows/run_canary.yaml: -------------------------------------------------------------------------------- 1 | ## Canary CI/CD 2 | name: Canary 3 | run-name: Canary 4 | 5 | on: 6 | push: 7 | branches: 8 | - master 9 | - patch-version 10 | paths-ignore: 11 | - '.github/workflows/**' 12 | 13 | workflow_dispatch: 14 | inputs: 15 | branch: 16 | description: 'branch name' 17 | required: false 18 | default: 'master' 19 | 20 | jobs: 21 | canary: 22 | uses: kaltura/playkit-js-common/.github/workflows/canary_player.yaml@master 23 | secrets: inherit 24 | with: 25 | node-version: "20.x" 26 | player-type: "ovp tv" 27 | schema-type: "playerV3Versions" 28 | tests-yarn-run-to-execute: 'build lint type-check test' 29 | yarn-upgrade-list: "" 30 | -------------------------------------------------------------------------------- /.github/workflows/run_prod.yaml: -------------------------------------------------------------------------------- 1 | ## Prod CI 2 | name: Prod 3 | run-name: Prod 4 | 5 | on: 6 | workflow_dispatch: 7 | 8 | jobs: 9 | prod: 10 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_cicd.yaml@master 11 | secrets: 12 | PLAYER_CENTRAL_ACCOUNT_ID: ${{ secrets.PLAYER_CENTRAL_ACCOUNT_ID }} 13 | PLAYER_SERVICES_ACCOUNT_ID: ${{ secrets.PLAYER_SERVICES_ACCOUNT_ID }} 14 | PLAYER_S3_BUCKET_DEPLOYMENT: ${{ secrets.PLAYER_S3_BUCKET_DEPLOYMENT }} 15 | PLAYER_S3_BUCKET_APPS: ${{ secrets.PLAYER_S3_BUCKET_APPS }} 16 | PLAYER_NPM_TOKEN: ${{ secrets.PLAYER_NPM_TOKEN }} 17 | PLAYER_LAMBDA_NAME: ${{ secrets.PLAYER_LAMBDA_NAME }} 18 | PLAYER_MSTEAMS_WEBHOOK: ${{ secrets.PLAYER_MSTEAMS_WEBHOOK }} 19 | PLAYER_GITHUB_BOT_TOKEN: ${{ secrets.PLAYER_GITHUB_BOT_TOKEN }} 20 | with: 21 | node-version: "20.x" 22 | type: "player" 23 | env: "prod" 24 | player-type: "ovp tv" 25 | schema-type: "playerV3Versions" 26 | tests-yarn-run-to-execute: 'build lint type-check test' 27 | yarn-upgrade-list: "" 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/run_tests.yaml: -------------------------------------------------------------------------------- 1 | ## CI - Player And Plugin Tests 2 | name: Player And Plugin Tests 3 | run-name: Player And Plugin Tests 4 | 5 | on: 6 | pull_request: 7 | branches: 8 | - "*" 9 | 10 | jobs: 11 | build: 12 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master 13 | with: 14 | node-version: '20.x' 15 | yarn-run-to-execute: 'build' 16 | test: 17 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master 18 | with: 19 | node-version: '20.x' 20 | yarn-run-to-execute: 'test' 21 | type-check: 22 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master 23 | with: 24 | node-version: '20.x' 25 | yarn-run-to-execute: 'type-check' 26 | build-types: 27 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master 28 | with: 29 | node-version: '20.x' 30 | yarn-run-to-execute: 'build:types' 31 | lint: 32 | uses: kaltura/ovp-pipelines-pub/.github/workflows/player_tests.yaml@master 33 | with: 34 | node-version: '20.x' 35 | yarn-run-to-execute: 'lint' 36 | notification: 37 | if: always() 38 | uses: kaltura/ovp-pipelines-pub/.github/workflows/notification.yaml@master 39 | needs: [build, test, type-check, lint] 40 | secrets: 41 | PLAYER_MSTEAMS_WEBHOOK: ${{ secrets.PLAYER_MSTEAMS_WEBHOOK }} 42 | with: 43 | failure-status: ${{ contains(needs.*.result, 'failure') }} 44 | cancelled-status: ${{ contains(needs.*.result, 'cancelled') }} 45 | is-test: 'true' 46 | -------------------------------------------------------------------------------- /.github/workflows/trigger_canary.yaml: -------------------------------------------------------------------------------- 1 | ## Trigger Canary Release 2 | name: Manual Trigger Canary Release 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | repo_name: 8 | default: master 9 | required: true 10 | 11 | jobs: 12 | trigger_canary: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v3 19 | with: 20 | token: ${{ secrets.PLAYER_GITHUB_BOT_TOKEN }} 21 | - name: Setup Git 22 | run: | 23 | git config --global user.email ${{ secrets.PLAYER_BOT_EMAIL }} 24 | git config --global user.name ${{ secrets.PLAYER_BOT_USER }} 25 | - name: Commit and Push 26 | run: | 27 | set +e 28 | git commit --no-verify --allow-empty -m "chore: trigger build" 29 | set -e 30 | git push origin HEAD:master 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | lib/ 3 | demo/ 4 | node_modules 5 | *.log 6 | types/ 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | lib/ 3 | docs/ 4 | .github/ 5 | flow-typed/ 6 | samples/ 7 | coverage/ 8 | CHANGELOG.md 9 | yarn.lock 10 | yarn-error.log 11 | LICENSE 12 | README.md 13 | ts-typed/ 14 | webpack.config.js 15 | tsconfig.json 16 | 17 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 150, 3 | "tabWidth": 2, 4 | "singleQuote": true, 5 | "trailingComma": "none", 6 | "arrowParens": "always" 7 | } 8 | -------------------------------------------------------------------------------- /api-extractor.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", 3 | "mainEntryPointFilePath": "/lib/index.d.ts", 4 | "bundledPackages": [], 5 | "compiler": {}, 6 | "apiReport": { 7 | "enabled": false, 8 | "reportFolder": "/api-extractor/report", 9 | "reportTempFolder": "/api-extractor/report-temp" 10 | }, 11 | "docModel": { 12 | "enabled": false, 13 | "apiJsonFilePath": "/api-extractor/.api.json" 14 | }, 15 | "dtsRollup": { 16 | "enabled": true, 17 | "untrimmedFilePath": "/dist/.d.ts" 18 | }, 19 | "tsdocMetadata": {}, 20 | "messages": { 21 | "compilerMessageReporting": { 22 | "default": { 23 | "logLevel": "warning" 24 | } 25 | }, 26 | "extractorMessageReporting": { 27 | "default": { 28 | "logLevel": "none" 29 | } 30 | }, 31 | "tsdocMessageReporting": { 32 | "default": { 33 | "logLevel": "none" 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /assets/style.css: -------------------------------------------------------------------------------- 1 | .kaltura-player-container { 2 | width: 100%; 3 | height: 100%; 4 | position: relative; 5 | background-color: #000; 6 | outline: none; 7 | -webkit-touch-callout: none; 8 | -webkit-user-select: none; 9 | -moz-user-select: none; 10 | -ms-user-select: none; 11 | user-select: none; 12 | -webkit-tap-highlight-color: transparent; 13 | } 14 | -------------------------------------------------------------------------------- /demo/player-ott.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /demo/player-ovp.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Player 9 | 10 | 11 | 12 | 13 |
14 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /demo/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #212121; 3 | } 4 | 5 | #player-placeholder { 6 | margin: 100px auto; 7 | max-width: 640px; 8 | aspect-ratio: 10 / 5.62; 9 | } 10 | -------------------------------------------------------------------------------- /docs/Kaltura-Player-V7-V2-differences.md: -------------------------------------------------------------------------------- 1 | ## Player V7 - V2 Differences 2 | 3 | Kaltura V7 Player is the current version of the Kaltura Player, intended to replace the V2 Player functionality, while providing improvements in several areas. 4 | The main differences between the two version will be described below. 5 | 6 | ### 1. Motivation 7 | * Shorter startup time 8 | * Modular player bundle, containing the minimum code required for playback 9 | * Performance improvements over V2 10 | * Allowing easy development of plugins for additional functionality 11 | * More options for UI customization 12 | * Exposing playback and license adapters 13 | * New plugins such as Ad Waterfalling, Smartswitch and Broadpeak 14 | 15 | ### 2. Embed types 16 | There are several options to embed V2 and V7 players in an HTML page, all of which are available through the Kaltura Management Console (KMC). However, regardless of the selected embed type, the V2 player always runs inside an iframe, while the V7 player would be scoped in an iframe only when using the iframe embed. 17 | 18 | ### 3. Player Configuration 19 | The V7 player allows setting configuration options in KMC and overriding them through either the application or the local storage. 20 | 21 | Unlike the V2 player, the V7 player uses a json object for configuration, with all of the configuration settings located under this object, unlike in V2. The player can be configured at startup using setup() method, or during runtime using the configure() method. 22 | 23 | ### 4. Player API 24 | While the V2 player provided several classes exposing different API functions, the V7 player exposes all of its API using the KalturaPlayer class and the player instance created by invoking KalturaPlayer.setup. 25 | 26 | ### 5. Playback Engines 27 | The V7 player supports most of the media formats supported by the V2 player, except for all image files(PNG,JPEG,JPG ...), HDS, MSS, Multicast and P2P streaming. The V7 player also adds support for offline playback. 28 | 29 | ### 6. Platform support 30 | V7 Player supports playback on Smart TV devices, including support for native HTML5 video playback on supported platforms 31 | 32 | ### 7. UI 33 | The V7 player supports most of the UI functionality of the V2 player, and includes multiple graphic enhancements, giving it an updated and user-friendly user experience. 34 | The V7 player comes working out-of-the-box, and unlike the V2 player does not require enabling plugins for ui controls such as quality and volume selection. 35 | Users can extend the ui by creating their own plugins, use css to style the player elements, or even disable the player’s default player ui controls if they want to. 36 | 37 | ### 8. Analytics 38 | The V7 player supports most of the analytics platforms supported by the V2 player. 39 | The V7 player supports the latest Google Analytics version and Google Tag Manager. 40 | 41 | ### 9. Advertising 42 | In addition to VAST and VPAID ads supported in V2, the V7 player also supports VMAP ads and IMA DAI ads. 43 | 44 | ### 10. Plugins 45 | Almost all of the plugin functionality of the V2 player is expected to be migrated into the V7 player. In addition, the V7 player supports additional plugins such as the ADs-ondemand, ADs-Waterfalling, IMADAI, Broadpeak, GoogleTagManager and more. 46 | 47 | -------------------------------------------------------------------------------- /docs/adding-vtt-thumbnails.md: -------------------------------------------------------------------------------- 1 | # Adding preview thumbnails using VTT files 2 | 3 | Kaltura player supports the loading of preview thumbnails using VTT files, 4 | 5 | #### A configuration for the VTT file is provided as a part of the mediaOptions or mediaConfig objects parameters As seen in the examples, we include: 6 | 7 | - vttUrl: URL to the WebVTT file that refers to the thumbnails. 8 | 9 | NOTE: The urls specified in the WebVTT file are relative to the vtt file address. 10 | 11 | ### Example 1 - provided as a part of the mediaOptions 12 | 13 | ```js 14 | var kalturaPlayer = KalturaPlayer.setup(playerConfig); 15 | kalturaPlayer.loadMedia( 16 | {entryId: '0_wifqaipd'}, 17 | { 18 | thumbnails: { 19 | vttUrl: 'https://somedomain/media/thumbnails/thumbnails.vtt' 20 | } 21 | } 22 | ); 23 | ``` 24 | 25 | ### Example 2 - provided as a part of the mediaConfig 26 | 27 | ```js 28 | var kalturaPlayer = KalturaPlayer.setup(playerConfig); 29 | kalturaPlayer.setMedia({ 30 | plugins: {...}, 31 | sources: { 32 | options: {}, 33 | thumbnails : { 34 | vttUrl: 'https://somedomain/media/thumbnails/thumbnails.vtt', 35 | } 36 | } 37 | }); 38 | ``` 39 | 40 | ### The supported formats 41 | 42 | #### Sprite Image file 43 | 44 | ```js 45 | 00:05.000 --> 00:10.000 46 | /assets/preview2.jpg 47 | ``` 48 | 49 | The Player will render the thumbnails in the tooltip using their original dimensions. Thumbnails of 100-150 pixels wide tend to work well. Smaller thumbnails are hard to decipher and larger thumbnails are too much of a distraction to the main content. 50 | 51 | #### Single Image files 52 | 53 | ```js 54 | 00:00:00.000 --> 00:00:10.000 55 | /preview/sprite.png#xywh=0,0,128,72 56 | ``` 57 | 58 | NOTE: The Player only supports pixel-based fragments, not percentage-based ones. 59 | 60 | 61 | # Adding preview thumbnails using images file 62 | 63 | Kaltura player supports the loading of preview thumbnails using image file. 64 | 65 | ### A configuration for the images file and more is provided as a part of the player ui objects config: 66 | 67 | #### Example: 68 | ```js 69 | ui: { 70 | components: { 71 | seekbar: { 72 | thumbsSprite: "https://images_url", 73 | 74 | } 75 | } 76 | } 77 | ``` 78 | 79 | ### Referance: 80 | 81 | [Seekbar config](https://github.com/kaltura/playkit-js-ui/blob/master/docs/configuration.md#configcomponentsseekbar) 82 | 83 | -------------------------------------------------------------------------------- /docs/embed-types.md: -------------------------------------------------------------------------------- 1 | # Embed Code Types 2 | 3 | When using embed codes, you can select from one of three options: Auto Embed, Dynamic Embed and Iframe Embed. You may want to use different embed code types in different situations, according to the explanations below. 4 | 5 | ## Dynamic Embed 6 | 7 | Dynamic embed is recommended for cases where you want to control runtime configuration dynamically and/or have more control over the embed call.
8 | 9 | Basic dynamic embed codes look like this: 10 | 11 | ```html 12 |
13 | 14 | 31 | ``` 32 | 33 | ## Auto Embed 34 | 35 | Auto embed is the recommended embed code for the Kaltura Player. It uses precise code and is good for getting a player or widget onto the page quickly and easily without any runtime customizations.
36 | 37 | Auto embed is optimized for packing a lots of resources into the initial request, allowing the player to be rendered quickly.
38 | 39 | It is possible to control the configuration passed to the player by adding query strings params. The parameter name should be `config[CONFIG_SECTION_NAME]`. The `CONFIG_SECTION_NAME` possible options are playback, provider and plugins. 40 | The value of the configuration passed should be in JSON Format and the JSON keys should be quoted Strings. Make sure to pass only URL valid characters, so URL encode it before - 41 | The configuration will be decoded properly to the original characters. 42 |
Here's how to use the auto embed code: 43 | 44 | ```html 45 |
46 | 50 | ``` 51 | 52 | ## IFrame Embed 53 | 54 | The iframe embed is good for sites that don't allow third-party JavaScript to be embedded in their pages. This makes the iFrame embed a better fit for sites that have stringent page security requirements.
55 | 56 | It is possible to control the configuration passed to the player by adding query strings params (This is same as the Auto Embed configuration - Look there for more details) 57 | 58 | Note that if you use the iframe only embed mode, the page won't be able to access the player API: 59 | 60 | ```html 61 | 71 | ``` 72 | -------------------------------------------------------------------------------- /docs/errors.md: -------------------------------------------------------------------------------- 1 | # Controlling Errors 2 | 3 | Errors are used to notify a user when a critical issue has occurred or to log recoverable issues. An error object consists of three mandatory parameters: 4 | 5 | - Error Severity 6 | - Error Category 7 | - Error Code 8 | - Error Custom Data - An optional object with additional information about the issue. 9 | 10 | > There are two severities to an error: **critical** and **recoverable**. 11 | > 12 | > - A critical error is triggered in an error event and is shown to the user as error overlay in the player itself. 13 | > - A recoverable error is not shown to an end user, but appears in the console. 14 | 15 | ## Error Lists 16 | 17 | You'll find the full lists of errors here: 18 | 19 | - [Error Severity List](https://github.com/kaltura/playkit-js/blob/master/src/error/severity.ts) 20 | - [Error Category List](https://github.com/kaltura/playkit-js/blob/master/src/error/category.ts) 21 | - [Error Code List](https://github.com/kaltura/playkit-js/blob/master/src/error/code.ts) 22 | 23 | ## Listening to an Error Event 24 | 25 | You can listen to errors the player emits by listening to an '`error`' event as follows: 26 | 27 | ```javascript 28 | player.addEventListener(player.Event.ERROR, event => { 29 | const error = e.payload; 30 | console.log('The error severity is: ' + error.severity); 31 | console.log('The error category is: ' + error.category); 32 | console.log('The error code is: ' + error.code); 33 | console.log('The error data is', error.data); 34 | }); 35 | ``` 36 | 37 | ## Creating an Error 38 | 39 | If you wish to change / emit an error event, you'll need to create an error object in the following manner: 40 | 41 | ```javascript 42 | const myError = new Error(Error.Severity.CRITICAL, Error.Category.NETWORK, Error.Code.HTTP_ERROR, {url: 'www.some-bad-url.com'}); 43 | ``` 44 | 45 | Next, you'll need to dispatch an `Error` event: 46 | 47 | ```js 48 | player.dispatchEvent(new FakeEvent(player.Event.Error, myError)); 49 | ``` 50 | 51 | > You'll find additional information about dispatching events [here](./events.md). 52 | 53 | ## Using Debug Mode to See Explicit Error Messages 54 | 55 | Use the debug mode in the player to view explicit error messages in the console. 56 | 57 | > You'll find additional information about debugging and troubleshooting the player [here](./debugging.md). 58 | 59 | ## Error Message Example 60 | 61 | Here's an example of an error message that can be observed in the console: 62 | 63 | [Error] Category:1 | Code:1002 | 'Http Error' 64 | -------------------------------------------------------------------------------- /docs/guides.md: -------------------------------------------------------------------------------- 1 | # Guides 2 | 3 | - Getting Started 4 | - [Supported Platforms](./supportedPlatforms.md) 5 | - [Create a Player Using the TV Platform Player Studio](./getting-started-using-player-studio.md) 6 | - [Player Setup](./player-setup.md) 7 | - [Playing Your Video](./playing-your-video.md) 8 | - [Change Media](./change-media.md) 9 | - [Playlist](./playlist.md) 10 | - [Embed Code Types](./embed-types.md) 11 | - [Player Events](./events.md) 12 | - [Monitoring Player States](./player-states.md) 13 | - [Managing Tracks on the Player](managing-tracks.md) 14 | - [Ads](./ads.md) 15 | - [Advertisement layout management](./advertisement-layout-management.md) 16 | - [Request/Response Manipulation](./request-response-manipulation.md) 17 | - [User Preferences](./user-preferences.md) 18 | - [Controlling Errors](errors.md) 19 | - [Debugging & Troubleshooting](./debugging.md) 20 | - [Writing a Plugin](./writing-a-plugin.md) 21 | - [Customizing the Player UI](./ui.md) 22 | - [Keyboard Shortcuts](./keyboard-shortcuts.md) 23 | - [Localization](./localization.md) 24 | - [Coding Guidelines](./coding-guidlines.md) 25 | - [Service Provider](./service-provider.md) 26 | - [VTT thumbnails](./adding-vtt-thumbnails.md) 27 | - [Media Capabilities](./media-capabilities.md) 28 | -------------------------------------------------------------------------------- /docs/images/ad-events-timeline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/ad-events-timeline.jpg -------------------------------------------------------------------------------- /docs/images/ads-controller.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/ads-controller.jpg -------------------------------------------------------------------------------- /docs/images/chrome-local-storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/chrome-local-storage.png -------------------------------------------------------------------------------- /docs/images/clear-button-local-storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/clear-button-local-storage.png -------------------------------------------------------------------------------- /docs/images/configuration-strength.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/configuration-strength.jpg -------------------------------------------------------------------------------- /docs/images/console-logs-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/console-logs-example.png -------------------------------------------------------------------------------- /docs/images/content-share-and-embed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/content-share-and-embed.png -------------------------------------------------------------------------------- /docs/images/content-tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/content-tab.png -------------------------------------------------------------------------------- /docs/images/dash-instream-thumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/dash-instream-thumbnail.png -------------------------------------------------------------------------------- /docs/images/kmc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/kmc.png -------------------------------------------------------------------------------- /docs/images/playback-start-end-timeline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/playback-start-end-timeline.jpg -------------------------------------------------------------------------------- /docs/images/player-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/player-save.png -------------------------------------------------------------------------------- /docs/images/player-state-machine.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/player-state-machine.jpg -------------------------------------------------------------------------------- /docs/images/playlist-countdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/playlist-countdown.png -------------------------------------------------------------------------------- /docs/images/save-value-flow-local-storage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/save-value-flow-local-storage.png -------------------------------------------------------------------------------- /docs/images/setup-flow-local-storage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/setup-flow-local-storage.jpg -------------------------------------------------------------------------------- /docs/images/share-and-embed-dynamic-copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/share-and-embed-dynamic-copy.png -------------------------------------------------------------------------------- /docs/images/studio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/studio.png -------------------------------------------------------------------------------- /docs/images/translation-tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/translation-tree.png -------------------------------------------------------------------------------- /docs/images/tv-platform-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/docs/images/tv-platform-add.png -------------------------------------------------------------------------------- /docs/keyboard-shortcuts.md: -------------------------------------------------------------------------------- 1 | # Keyboard Shortcuts 2 | 3 | You can use the following keyboard shortcuts to control the player: 4 | 5 | > Note that these shortcuts will work only if the player is the focused element in the page. 6 | 7 | | Feature | Action | Keyboard | 8 | | --------------------------------- | ----------------------- | ------------ | 9 | | Playback | Play/Pause/Replay | Spacebar | 10 | | | Increase volume by 5% | UP | 11 | | | Decrease volume by 5% | DOWN | 12 | | | Mute/Unmute | m | 13 | | | Switch to full screen | f | 14 | | | Exit full screen | ESC | 15 | | | Seek 5 seconds forward | RIGHT | 16 | | | Seek 5 seconds back | LEFT | 17 | | | Jump to video start | Home | 18 | | | Jump to video end | End | 19 | | Speed Selector | Increase playback speed | \> (SHIFT+.) | 20 | | | Decrease playback speed | < (SHIFT+,) | 21 | | Captions | Show/Hide captions | c | 22 | | Multi Audio (Not implemented yet) | Next audio stream | [ | 23 | | | Previous audio stream | ] | 24 | | 360 Video (Not implemented yet) | Navigate Up | w | 25 | | | Navigate Down | s | 26 | | | Navigate Right | d | 27 | | | Navigate Left | a | 28 | | Live (Not implemented yet) | Jump back to live | l | 29 | -------------------------------------------------------------------------------- /docs/localization.md: -------------------------------------------------------------------------------- 1 | # Localization 2 | 3 | This article explains how to upload translation dictionaries to Kaltura platform, 4 | and how to control the language that actually will be served to the player. 5 | 6 | > This feature uses the `ui.translations` config, for more details see [Adding translations and choosing locale language](https://github.com/kaltura/playkit-js-ui/blob/master/docs/translations.md). 7 | 8 | ## Uploading translation dictionaries via Kaltura platform 9 | 10 | Plugin which served by Kaltura platform (via the bundle builder) can upload its translation dictionaries also by Kaltura platform. 11 | To get this ability, The plugin needs to add the translation json file/s (`*.i18n.json`) under a `translations` folder in the location of the plugin source code and source map. 12 | For example: Plugin called _playkit-ui-plugin_, which contains, in the dist folder, 2 files - `playkit-ui-plugin.js` and `playkit-ui-plugin.js.map`, 13 | Will add a `translations` folder with the translation file/s: 14 | ![](images/translation-tree.png) 15 | Each json file contains the translation dictionary under the language code key. 16 | For example `en.i18n.json` looks like: 17 | 18 | ```json 19 | { 20 | "en": { 21 | "buttons": { 22 | "btn1": "Button1", 23 | "btn2": "Button2" 24 | } 25 | } 26 | } 27 | ``` 28 | 29 | `fr.i18n.json` looks like: 30 | 31 | ```json 32 | { 33 | "fr": { 34 | "buttons": { 35 | "btn1": "Bouton1", 36 | "btn2": "Bouton2" 37 | } 38 | } 39 | } 40 | ``` 41 | 42 | Actually, the plugin could supply only one json contains multi language dictionaries. For example `langs.i18n.json` looks like: 43 | 44 | ```json 45 | { 46 | "en": { 47 | "buttons": { 48 | "btn1": "Button1", 49 | "btn2": "Button2" 50 | } 51 | }, 52 | "fr": { 53 | "buttons": { 54 | "btn1": "Bouton1", 55 | "btn2": "Bouton2" 56 | } 57 | } 58 | } 59 | ``` 60 | 61 | ## Control the served languages 62 | 63 | By default only English dictionary injected to the player (by [`ui.translations`](https://github.com/kaltura/playkit-js-ui/blob/master/docs/configuration.md#configtranslations) config). 64 | There are 2 ways to change this behavior: 65 | 66 | 1. By the Studio. 67 | 2. By a Url parameter called `langs` on the embed player Url. For example: 68 | _https://qa-apache-php7.dev.kaltura.com/p/1091/sp/109100/embedPlaykitJs/uiconf_id/15215933/partner_id/1091/langs/de,fr_. 69 | -------------------------------------------------------------------------------- /docs/media-capabilities.md: -------------------------------------------------------------------------------- 1 | # Media Capabilities API 2 | 3 | It is possible to get the media capabilities and to decide which action to take accordingly. 4 | 5 | This API will give you the following information: 6 | 7 | - Whether the browser is supporting HEVC 8 | - Whether the browser is supporting DRM 9 | - Which DRM schemas, if any, are supported by the browser (widevine, fairplay, playready) 10 | - Whether the playback of the media will be power efficient 11 | 12 | It is optional to pass an object parameter to the API, which will contain the HEVC configuration to test. 13 | See below a list of the optional properties: 14 | 15 | - `width` (number) - Optional width of the video. default is `1920`. 16 | - `height` (number) - Optional height of the video. default is `1080`. 17 | - `bitrate` (number) - Optional number of bits used to encode a second of video. default is `1200000`. 18 | - `framerate` (number) - Optional number of frames used in one second. default is `30`. 19 | 20 | The Media Capabilities API is returning the following object structure: 21 | 22 | - `isHEVCSupported` (number) - Specifies the HEVC supported type by the browser 23 | - `isPowerEfficient` (number) - Specifies power efficiency supported type 24 | - `isDRMSupported` (number) - Specifies the DRM supported type by the browser 25 | - `supportedDRMs` (Array) - List of supported DRMs (optional values: widevine, playready, fairplay) 26 | 27 | Note - the optional numbers for the flags are: 28 | 29 | - 1 - SUPPORTED 30 | - 0 - NOT_SUPPORTED 31 | - -1 - MAYBE_SUPPORTED in case there was a problem with getting the information 32 | 33 | ### Example - how to use Media Capabilities API and its response 34 | 35 | ```js 36 | // after calling KalturaPlayer.setup()..... 37 | kalturaPlayer.getMediaCapabilities({width: 1280, height: 720}).then(mediaCapabilities => { 38 | // print the media capabilities result to the console 39 | console.log('media capabilities result --> ', {mediaCapabilities}); 40 | // load drm media or clear media, based on the API response 41 | kalturaPlayer.loadMedia({entryId: mediaCapabilities.isDRMSupported === 1 ? DRM_ENTRY_ID : CLEAR_ENTRY_ID}); 42 | }); 43 | ``` 44 | 45 | Note: the API should be invoked after calling KalturaPlayer.setup() API 46 | 47 | ### You want to pass HEVC configuration to the API, but you don't know which values to choose 48 | 49 | See below a list of online resources to help you choose the values you need: 50 | 51 | - optional values for [width and height][1] 52 | - optional values for [bitrate][2] 53 | - optional values for [framerate][3] 54 | 55 | [1]: https://support.google.com/youtube/answer/6375112 56 | [2]: https://support.google.com/youtube/answer/1722171?hl=en#zippy=%2Cbitrate 57 | [3]: https://support.google.com/youtube/answer/1722171?hl=en#zippy=%2Cframe-rate 58 | -------------------------------------------------------------------------------- /docs/migration-from-v2-player.md: -------------------------------------------------------------------------------- 1 | # How to migrate your Player Embed Code from v2 to v7 ? 2 | 3 | ### Step 1 - Create new v7 player 4 | 5 | Create new a new v7 player using the **TV Platform Studio** in your [KMC](https://kmc.kaltura.com/index.php/kmcng/login), 6 | see [here](./getting-started-using-player-studio.md#creating-a-new-kaltura-player-a-namecreatea) step-by-step guid. 7 | 8 | ### Step 2 - Migrate your settings 9 | 10 | Set your preferences and plugins as before 11 | 12 | ### Step 3 - Get the new embed code 13 | 14 | Open your [KMC](https://kmc.kaltura.com/index.php/kmcng/login) Dashboard and follow these steps: 15 | 16 | 1. Go to **CONTENT > ENTRIES >** 17 | 2. Go to your desired **Entry Id**. 18 | 3. Click The three dots **Icon** on the left, and select the **Share & Embed** option. 19 | 20 | Now you will see the Embed Code on the right, And a **Dropdown** contains a list of player names on the tap, 21 | The players are sorted by the update date, 22 | And on the left of each of them you will see an **icon** indicating what player it is V2 or V7 23 | . 24 | 25 | 4. Select the just newly created V7 Player from the list. 26 | 27 | Now the Embed Code on the right would be replaced by V7 player Embed Code. 28 | 29 | 5. Select your preferred **[Embed Type](https://developer.kaltura.com/player/web/embed-types-web)** or stick with the default Embed Type 30 | 31 | That's all, now you can copy the Embed Code and embed it on you webpage as before 32 | 33 | **Congratulations!!** 34 | 35 | You entered the V7 Players Club! 36 | 37 | **NOTE:** Configuring and setting the V7 Player doesn't override the v2 player's settings, it is totally different Player. 38 | -------------------------------------------------------------------------------- /docs/player-setup.md: -------------------------------------------------------------------------------- 1 | # Player Setup 2 | 3 | Player setup requires the following steps to create a player instance: 4 | 5 | ### Step 1 - Load the Library 6 | 7 | ```html 8 | 9 | ``` 10 | 11 | ### Step 2 - Create the Player Container 12 | 13 | ```html 14 |
15 | ``` 16 | 17 | ### Step 3 - Define Your Configuration 18 | 19 | ```js 20 | var config = { 21 | targetId: "player-container", 22 | provider: { // provider configuration 23 | ... 24 | partnerId: 'YOUR_PARTNER_ID', 25 | uiConfId: 'YOUR_UICONF_ID' 26 | ... 27 | }, 28 | playback: { ... }, // playback configuration 29 | plugins: { ... }, // plugins configuration 30 | ui: { ... } // ui configuration 31 | }; 32 | ``` 33 | 34 | The following sections are examples of common (and important) configurations for the player setup. 35 | 36 | #### Example: Using a Kaltura Session (KS) 37 | 38 | If you need to use a KS for your media requests, configure it inside your provider configuration: 39 | 40 | ```js 41 | var config = { 42 | ... 43 | provider: { 44 | ... 45 | partnerId: 'YOUR_PARTNER_ID', 46 | ks: 'YOUR_KS' 47 | ... 48 | } 49 | ... 50 | }; 51 | ``` 52 | 53 | See this [article](https://developer.kaltura.com/api-docs/VPaaS-API-Getting-Started/how-to-create-kaltura-session.html) to learn more about how to create a KS. 54 | 55 | #### Example: Using Server Configuration 56 | 57 | If you want to use a server configuration, you'll need to provide the `uiConfId` in your provider configuration: 58 | 59 | ```js 60 | var config = { 61 | ... 62 | provider: { 63 | ... 64 | partnerId: 'YOUR_PARTNER_ID', 65 | uiConfId: 'YOUR_UI_CONF_ID' 66 | ... 67 | } 68 | ... 69 | }; 70 | ``` 71 | 72 | #### Example: Using an Environment 73 | 74 | If you want to refer to a specific backend URL, you can specify it in your provider configuration: 75 | 76 | ```js 77 | var config = { 78 | ... 79 | provider: { 80 | ... 81 | partnerId: 'YOUR_PARTNER_ID', 82 | env: { 83 | serviceUrl: 'YOUR_SERVICE_URL' 84 | } 85 | ... 86 | } 87 | ... 88 | }; 89 | ``` 90 | 91 | > For full configuration details see [this](./configuration.md) document. 92 | 93 | ### Step 4 - Set Up the Player 94 | 95 | To get your player instance, use the `setup` factory method and pass it your player configuration: 96 | 97 | ```js 98 | var player = KalturaPlayer.setup(config); 99 | ``` 100 | 101 | ## Next Step 102 | 103 | You're now ready to start playing your video; see [Playing Your Video](./playing-your-video.md) for details. 104 | -------------------------------------------------------------------------------- /docs/service-provider.md: -------------------------------------------------------------------------------- 1 | # Service Provider 2 | 3 | Service provider enables cross service registration and accessing. 4 | 5 | For example - Plugin A gives service to Plugin B - 6 | Without the Service Provider, Plugin A is inaccessible to Plugin B and vise versa. 7 | 8 | We exposed three new API methods in Kaltura Player - 9 | 10 | - registerService 11 | - hasService 12 | - getService 13 | 14 | ## How to register as a service 15 | In this example plugin A will register `doSomethingInstance` as a service called 'pluginAService' 16 | ```js 17 | player.registerService('pluginAService', doSomethingInstance); 18 | ``` 19 | 20 | ## How to use a registered service 21 | In this example plugin B will use some method `doSomething` from `doSomethingInstance` in plugin A 22 | ```js 23 | if (player.hasService('pluginAService')){ 24 | player.getService('pluginAService').doSomething() 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/supportedPlatforms.md: -------------------------------------------------------------------------------- 1 | 2 | ## Kaltura Player Browsers Support 3 | 4 | 5 | * Kaltura Player playback and features are tested on the stable and latest versions of the browsers below. 6 | 7 | 8 |
9 | 10 | ### Desktop Web HLS 11 | 12 | [compatability](https://github.com/video-dev/hls.js/#compatibility) 13 | 14 | 15 | 16 | |Browser - Last 3 major versions |Windows |Mac |Linux |Android |iOS >= 13 |DRM|Other| 17 | |:---------:|:--------:|:-------:|:-------:|:-------:|:--------:|:------:|:---:| 18 | |Chrome |**Y**|**Y**|**Y**|**Y**|**Native**|**AES-128**|-| 19 | |Firefox |**Y**|**Y**|**Y**|**Y**|**Native**|**AES-128**|-| 20 | |Edge |**Y**|-|-|-|-|**AES-128**|-| 21 | |Safari |-|**Y**|-|-|**iPadOS 13
Native**|**AES-128**
**FAIRPLAY** |-| 22 | |Apple TV |-|**Y**|-|-|**Native**|**AES-128**
**FAIRPLAY** |-| 23 | |Chromecast|-|-|-|-|-|**AES-128**|**Y**| 24 | |Tizen TV 4+ Chromium |-|-|-|-|-|-|**Y**| 25 | |WebOS 4+ Chromium |-|-|-|-|-|-|**Y**| 26 | 27 |

28 | ### Desktop Web DASH 29 | [compatability](https://github.com/shaka-project/shaka-player#platform-and-browser-support-matrix) 30 | 31 | 32 | |Browser - Last 3 major versions |Windows |Mac |Linux |Android |iOS >= 13 |DRM|Other| 33 | |:---------:|:--------:|:-------:|:-------:|:-------:|:--------:|:------:|:---:| 34 | |Chrome |**Y**|**Y**|**Y**|**Y**|**Native**|**WIDEVINE**|-| 35 | |Firefox |**Y**|**Y**|**Y**|-|**Native**|**WIDEVINE**|-| 36 | |Edge |**Y**|-|-|-|-| **WIDEVINE**
**PLAYREADY**|-| 37 | |Chromecast|-|-|-|-|-|**WIDEVINE**|**Y**| 38 | |Tizen TV 4+ Chromium |-|-|-|-|-| **WIDEVINE**|**Y**| 39 | |WebOS 4+ Chromium |-|-|-|-|-| **WIDEVINE**|**Y**| 40 | 41 |

42 | ### Mobile Web HLS 43 | 44 | |Browser - Last 3 major versions |Android |iOS / iPadOS|DRM|Other| 45 | |:---------:|:--------:|:-------:|:-------:|:---:| 46 | |Chrome |**Y**|**Y**|**AES-128**| -| 47 | |Safari |**Y**|**Y**|**AES-128**
**FAIRPLAY** |-| 48 | |Firefox |**Y**|**Y**|**AES-128**|-| 49 | 50 |

51 | ### Mobile Web DASH 52 | 53 | |Browser - Last 3 major versions |Android |iOS / iPadOS|DRM|Other| 54 | |:---------:|:--------:|:-------:|:------:|:---:| 55 | |Chrome |**Y** |**N** |**WIDEVINE** |-| 56 | |Safari |**N** |**N** |-|-| 57 | |Firefox |**Y** |**N** |**WIDEVINE** |-| 58 | 59 | -------------------------------------------------------------------------------- /docs/ui.md: -------------------------------------------------------------------------------- 1 | ## UI 2 | 3 | The UI configuration supports the following params: 4 | 5 | - As defined in type [UIOptionsObject](https://github.com/kaltura/playkit-js-ui/blob/master/docs/configuration.md) 6 | - css - Applying an external style sheet URL is possible as described in [External CSS](#External-CSS) 7 | 8 | See also the [UI guides](https://github.com/kaltura/playkit-js-ui/blob/master/docs/guides.md). 9 | 10 | ## 11 | 12 | ### External CSS 13 | 14 | An external style sheet URL can be given in the configuration as follows: 15 | 16 | ```js 17 | { 18 | ui: { 19 | css: 'https://myDomain.com/path/to/css'; // place a valid css file URL String 20 | } 21 | } 22 | ``` 23 | 24 | The main use case of this parameter is for [Auto Embed](./embed-types.md#auto-embed) and [IFrame Embed](./embed-types.md#iframe-embed) 25 | 26 | Read also about [customizing the Player CSS](https://github.com/kaltura/playkit-js-ui/blob/master/docs/css-classes-override.md). 27 | 28 | ## 29 | -------------------------------------------------------------------------------- /flow-typed/interfaces/ads-controller-provider.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare interface IAdsControllerProvider { 4 | getAdsController(): IAdsPluginController; 5 | } 6 | -------------------------------------------------------------------------------- /flow-typed/interfaces/ads-controller.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | import {Ad} from '../../src/common/ads'; 4 | import {AdBreak} from '../../src/common/ads'; 5 | 6 | declare interface IAdsController { 7 | +allAdsCompleted: boolean; 8 | isAdBreak(): boolean; 9 | getAdBreaksLayout(): Array; 10 | getAdBreak(): ?AdBreak; 11 | getAd(): ?Ad; 12 | skipAd(): void; 13 | playAdNow(adPod: KPAdPod): void; 14 | } 15 | -------------------------------------------------------------------------------- /flow-typed/interfaces/ads-plugin-controller.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | 3 | declare interface IAdsPluginController { 4 | skipAd(): void; 5 | playAdNow?: (adPod: KPAdPod) => void; 6 | onPlaybackEnded(): Promise; 7 | +active: boolean; 8 | +done: boolean; 9 | +name: string; 10 | } 11 | -------------------------------------------------------------------------------- /flow-typed/interfaces/cue-point.js: -------------------------------------------------------------------------------- 1 | declare interface CuePoint { 2 | id: string; 3 | startTime: number; 4 | endTime: number; 5 | metadata: any; 6 | } 7 | -------------------------------------------------------------------------------- /flow-typed/interfaces/middleware-provider.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {BaseMiddleware} from '@playkit-js/playkit-js'; 3 | 4 | declare interface IMiddlewareProvider { 5 | getMiddlewareImpl(): BaseMiddleware; 6 | } 7 | -------------------------------------------------------------------------------- /flow-typed/interfaces/plugin.js: -------------------------------------------------------------------------------- 1 | //@flow 2 | declare interface IPlugin { 3 | getConfig(attr?: string): any; 4 | updateConfig(update: Object): void; 5 | loadMedia(): void; 6 | destroy(): void; 7 | reset(): void; 8 | } 9 | -------------------------------------------------------------------------------- /flow-typed/interfaces/preset-components-provider.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare interface IUIComponentsProvider { 4 | getUIComponents(): Array; 5 | } 6 | -------------------------------------------------------------------------------- /flow-typed/modules/babel-polyfill.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module '@babel/polyfill' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/modules/intersection-observer.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module 'intersection-observer' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/modules/js-logger.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module 'js-logger' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/modules/playkit-js-providers.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module '@playkit-js/playkit-js-providers' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/modules/playkit-js-ui.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module '@playkit-js/playkit-js-ui' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/modules/playkit-js.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare module '@playkit-js/playkit-js' { 3 | declare module.exports: any; 4 | } 5 | -------------------------------------------------------------------------------- /flow-typed/types/advertising.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /** 4 | * @typedef {Object} KPAdObject 5 | * @property {Array} url - List of urls, each one specifies the ad tag url that is requested from the ad server. The player will request the first url, if failed, it will request the second url and so on (aka waterfalling). 6 | * @property {Array} response - List of XMLs, each one specifies a VAST 2.0 document to be used as the ads response instead of making a request via an ad tag url. The player will use the first XML, if failed, it will use the second and so on (aka waterfalling). 7 | * @property {boolean} bumper - Specifies whether this is a bumper. 8 | * @property {KPAdPrebidConfig} prebid - Specifies whether this is a prebid ad and add the relevant config for prebid request. 9 | */ 10 | type _KPAdObject = { 11 | url?: Array, 12 | response?: Array, 13 | bumper?: boolean, 14 | prebid?: KPAdPrebidConfig 15 | }; 16 | declare type KPAdObject = _KPAdObject; 17 | 18 | /** 19 | * @typedef {Array} KPAdPod 20 | */ 21 | type _KPAdPod = Array; 22 | declare type KPAdPod = _KPAdPod; 23 | 24 | /** 25 | * @typedef {Object} KPAdBreakObject 26 | * @property {number} position - The position, in seconds, to show the ad break. 27 | * @property {number} percentage - Alternative parameter to `position`. The position, in percentage of the media length, to show the ad break (optional). 28 | * @property {number} every - Alternative parameter to `position`. Play ad break every X seconds (optional). 29 | * @property {KPAdPod} ads - An array of ads to play (Ad pod). 30 | */ 31 | type _KPAdBreakObject = { 32 | position: number, 33 | percentage?: number, 34 | every?: number, 35 | ads: KPAdPod 36 | }; 37 | declare type KPAdBreakObject = _KPAdBreakObject; 38 | 39 | /** 40 | * @typedef {Object} KPAdvertisingConfigObject 41 | * @property {KPPrebidConfig} prebid - The prebid config. 42 | * @property {Array} adBreaks - The ad breaks scheme. 43 | * @property {number} [playAdsAfterTime] - Only play ad breaks scheduled after this time (in seconds). This setting is strictly after - e.g. setting playAdsAfterTime to 15 will cause the player to ignore an ad break scheduled to play at 15s. 44 | * @property {boolean} [showAdBreakCuePoint] - Whether to show the ad breaks cue points. 45 | * @property {Object} [adBreakCuePointStyle] - Style options for the ad breaks cue points - See the options {@link https://github.com/kaltura/playkit-js-timeline/blob/main/docs/types.md#cuepointoptionsobject|Here}. 46 | */ 47 | type _KPAdvertisingConfigObject = { 48 | prebid?: KPPrebidConfig, 49 | adBreaks: Array, 50 | playAdsAfterTime?: number, 51 | showAdBreakCuePoint?: boolean, 52 | adBreakCuePointStyle?: Object 53 | }; 54 | declare type KPAdvertisingConfigObject = _KPAdvertisingConfigObject; 55 | -------------------------------------------------------------------------------- /flow-typed/types/kaltura-player-event-types.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare type KPEventTypes = { 3 | Core: PKEventTypes, 4 | UI: {[event: string]: string}, 5 | Cast: {[event: string]: string}, 6 | Playlist: {[event: string]: string} 7 | }; 8 | -------------------------------------------------------------------------------- /flow-typed/types/kaltura-player-options.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {KPPlaylistObject} from './playlist'; 3 | 4 | declare type KPOptionsObject = { 5 | targetId: string, 6 | log?: KPLogConfigObject, 7 | disableUserCache?: boolean, 8 | text?: PKTextConfigObject, 9 | playback?: PKPlaybackConfigObject, 10 | sources?: PKSourcesConfigObject, 11 | plugins: KPPluginsConfigObject, 12 | advertising: KPAdvertisingConfigObject, 13 | session?: PKSessionConfigObject, 14 | provider: ProviderOptionsObject, 15 | playlist?: KPPlaylistObject, 16 | dimensions?: PKDimensionsConfig, 17 | ui: KPUIOptionsObject, 18 | cast?: {[key: string]: any}, 19 | productVersion?: string, 20 | viewability: KPViewabilityConfigObject 21 | }; 22 | 23 | declare type PartialKPOptionsObject = { 24 | targetId: string, 25 | log?: KPLogConfigObject, 26 | disableUserCache?: boolean, 27 | text?: PKTextConfigObject, 28 | playback?: PKPlaybackConfigObject, 29 | sources?: PKSourcesConfigObject, 30 | plugins: KPPluginsConfigObject, 31 | advertising: KPAdvertisingConfigObject, 32 | session?: PKSessionConfigObject, 33 | provider: ProviderOptionsObject, 34 | playlist?: KPPlaylistObject, 35 | dimensions?: PKDimensionsConfig, 36 | ui?: KPUIOptionsObject, 37 | cast?: {[key: string]: any}, 38 | viewability?: KPViewabilityConfigObject 39 | }; 40 | 41 | declare type LegacyPartialKPOptionsObject = { 42 | targetId: string, 43 | logLevel?: string, 44 | disableUserCache?: boolean, 45 | player?: PKPlayerOptionsObject, 46 | provider: ProviderOptionsObject, 47 | ui?: KPUIOptionsObject 48 | }; 49 | -------------------------------------------------------------------------------- /flow-typed/types/kaltura-player-ui-options.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare type KPUIOptionsObject = { 3 | disable?: boolean, 4 | css?: string, 5 | customPreset?: Array<{template: Function, condition: Function}> 6 | } & UIOptionsObject; 7 | -------------------------------------------------------------------------------- /flow-typed/types/kaltura-player-visibility-config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare type KPViewabilityConfigObject = { 3 | observedThresholds: Array, 4 | playerThreshold: number 5 | }; 6 | -------------------------------------------------------------------------------- /flow-typed/types/kaltura-players.js: -------------------------------------------------------------------------------- 1 | import {KalturaPlayer} from '../../src/kaltura-player'; 2 | 3 | /** 4 | * @type {Object.} 5 | * @name KalturaPlayers 6 | * @description a map of player instances by player ids 7 | */ 8 | type _KalturaPlayers = {[id: string]: KalturaPlayer}; 9 | declare type KalturaPlayers = _KalturaPlayers; 10 | -------------------------------------------------------------------------------- /flow-typed/types/log-level.js: -------------------------------------------------------------------------------- 1 | declare type KPLogConfigObject = PKLogConfigObject & { 2 | playerVersion: ?boolean 3 | }; 4 | -------------------------------------------------------------------------------- /flow-typed/types/media-capabilities.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | /** 4 | * @typedef {Object} HEVCConfigObject 5 | * @property {number} width - Optional width of the video 6 | * @property {number} height - Optional height of the video 7 | * @property {number} bitrate - Optional number of bits used to encode a second of video 8 | * @property {number} framerate - Optional number of frames used in one second 9 | */ 10 | declare type HEVCConfigObject = { 11 | width?: number, 12 | height?: number, 13 | bitrate?: number, 14 | framerate?: number 15 | }; 16 | 17 | /** 18 | * @typedef {Object} HEVCSupportedObject 19 | * @property {number} isHEVCSupported - Specifies HEVC supported option by the browser 20 | * @property {number} isPowerEfficient - Specifies power efficiency supported option 21 | */ 22 | declare type HEVCSupportedObject = { 23 | isHEVCSupported: number, 24 | isPowerEfficient: number 25 | }; 26 | 27 | /** 28 | * @typedef {Object} DRMSupportedObject 29 | * @property {number} isDRMSupported - Specifies DRM supported option by the browser 30 | * @property {Array} supportedDRMs - List of supported DRMs (optional values: widevine, playready, fairplay) 31 | */ 32 | declare type DRMSupportedObject = { 33 | isDRMSupported: number, 34 | supportedDRMs: Array 35 | }; 36 | 37 | /** 38 | * @typedef {Object} MediaCapabilitiesObject 39 | */ 40 | declare type MediaCapabilitiesObject = HEVCSupportedObject & DRMSupportedObject; 41 | 42 | /** 43 | * @typedef {Object.} SupportedOptionsType 44 | */ 45 | declare type SupportedOptionsType = {[supportedOption: string]: number}; 46 | -------------------------------------------------------------------------------- /flow-typed/types/media-config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | 4 | /** 5 | * @typedef {Object} KPMediaConfig 6 | * @property {ProviderMediaConfigSourcesObject} sources 7 | * @property {ProviderMediaConfigSessionObject} session 8 | * @property {{[plugin: string]: Object}} plugins 9 | */ 10 | declare type KPMediaConfig = { 11 | sources: ProviderMediaConfigSourcesObject, 12 | session?: ProviderMediaConfigSessionObject, 13 | plugins?: {[plugin: string]: Object} 14 | } & PKPlaybackConfigObject; 15 | -------------------------------------------------------------------------------- /flow-typed/types/playlist.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | import {PlaylistItem} from '../../src/common/playlist/playlist-item'; 3 | 4 | /** 5 | * @typedef {Object} KPPlaylistOptions 6 | * @property {boolean} [autoContinue=true] - Determines whether to continue to the next item automatically. 7 | * @property {boolean} [loop=false] - Determines whether to play the playlist in a loop. When selected, the playlist will play automatically even if autoContinue is set to false. 8 | */ 9 | type _KPPlaylistOptions = { 10 | autoContinue: boolean, 11 | loop: boolean, 12 | imageDuration: number 13 | }; 14 | declare type KPPlaylistOptions = _KPPlaylistOptions; 15 | 16 | /** 17 | * @typedef {Object} KPPlaylistCountdownOptions 18 | * @property {number} [timeToShow] - Shows when the countdown is scheduled to appear (by default, this is towards the end). 19 | * @property {number} [duration=10] - Shows for how long the countdown will appear. 20 | * @property {boolean} [showing=true] - Determines whether to show the countdown. 21 | */ 22 | type _KPPlaylistCountdownOptions = { 23 | timeToShow?: number, 24 | duration: number, 25 | showing: boolean 26 | }; 27 | declare type KPPlaylistCountdownOptions = _KPPlaylistCountdownOptions; 28 | 29 | /** 30 | * @typedef {Object} KPPlaylistConfigObject 31 | * @property {KPPlaylistOptions} options - Sets the playlist options. 32 | * @property {KPPlaylistCountdownOptions} countdown - Configures the playlist countdown. 33 | * @property {Array} items - Lists the available playlist items. 34 | */ 35 | type _KPPlaylistConfigObject = { 36 | options: KPPlaylistOptions, 37 | countdown: KPPlaylistCountdownOptions, 38 | items: Array 39 | }; 40 | declare type KPPlaylistConfigObject = _KPPlaylistConfigObject; 41 | 42 | /** 43 | * @typedef {Object} KPPlaylistObject 44 | * @property {string} id - This is playlist's ID. 45 | * @property {ProviderPlaylistMetadataObject} metadata - This is the playlist metadata. 46 | * @property {KPPlaylistOptions} options - These are the playlist options. 47 | * @property {KPPlaylistCountdownOptions} countdown - This is the playlist countdown configuration. 48 | * @property {Array} items - These are the playlist items. 49 | */ 50 | type _KPPlaylistObject = { 51 | id: string, 52 | metadata: ProviderPlaylistMetadataObject, 53 | poster?: string, 54 | options: KPPlaylistOptions, 55 | countdown: KPPlaylistCountdownOptions, 56 | items: Array 57 | }; 58 | declare type KPPlaylistObject = _KPPlaylistObject; 59 | 60 | /** 61 | * @typedef {Object} KPPlaylistItemConfigObject 62 | * @property {KPPlaylistCountdownOptions} [countdown] - Countdown options 63 | */ 64 | type _KPPlaylistItemConfigObject = { 65 | countdown?: KPPlaylistCountdownOptions 66 | }; 67 | declare type KPPlaylistItemConfigObject = _KPPlaylistItemConfigObject; 68 | -------------------------------------------------------------------------------- /flow-typed/types/plugins.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | /** 3 | * @typedef {Object} KPPluginsConfigObject 4 | */ 5 | type _KPPluginsConfigObject = { 6 | [plugin: string]: Object 7 | }; 8 | declare type KPPluginsConfigObject = _KPPluginsConfigObject; 9 | -------------------------------------------------------------------------------- /flow-typed/types/prebid-config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | 3 | declare type KPAdPrebidConfig = { 4 | adUnit: Object, 5 | params?: Object, 6 | options?: Object, 7 | timeout: number 8 | }; 9 | 10 | declare type KPPrebidConfig = KPAdPrebidConfig & { 11 | libUrl: string 12 | }; 13 | -------------------------------------------------------------------------------- /flow-typed/types/thumbnail-config.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare type KPThumbnailConfig = { 3 | thumbsSprite: string, 4 | thumbsWidth: number, 5 | thumbsSlices: number 6 | }; 7 | -------------------------------------------------------------------------------- /flow-typed/types/ui-component-options.js: -------------------------------------------------------------------------------- 1 | declare type KPUIComponentOptions = { 2 | label: string, 3 | presets: Array, 4 | area: string, 5 | beforeComponent?: string, 6 | afterComponent?: string, 7 | replaceComponent?: string 8 | }; 9 | -------------------------------------------------------------------------------- /flow-typed/types/ui-component.js: -------------------------------------------------------------------------------- 1 | // @flow 2 | declare type KPUIAddComponent = KPUIComponentOptions & { 3 | get: Function, 4 | props?: {} 5 | }; 6 | 7 | declare type KPUIRemoveComponent = { 8 | removeComponent: string, 9 | presets: Array, 10 | area: string 11 | }; 12 | 13 | declare type KPUIComponent = KPUIAddComponent & KPUIRemoveComponent; 14 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | const webpackConfig = require('./webpack.config')({ playerType: 'ovp' }, { mode: 'development' }); 2 | delete webpackConfig.entry; 3 | delete webpackConfig.externals; 4 | delete webpackConfig.output; 5 | delete webpackConfig.devServer; 6 | webpackConfig.devtool = 'inline-source-map'; 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | frameworks: ['webpack', 'mocha'], 11 | browserDisconnectTimeout: 60000, 12 | browserNoActivityTimeout: 60000, 13 | files: [ 14 | { 15 | pattern: 'tests/index.js', 16 | watched: false 17 | }, 18 | { 19 | pattern: 'tests/assets/**/*', 20 | included: false 21 | } 22 | ], 23 | exclude: [], 24 | preprocessors: { 25 | 'tests/index.js': ['webpack', 'sourcemap'] 26 | }, 27 | reporters: ['mocha'], 28 | mochaReporter: { 29 | showDiff: true 30 | }, 31 | 32 | coverageIstanbulReporter: { 33 | reports: ['lcov', 'text-summary'], 34 | fixWebpackSourcePaths: true 35 | }, 36 | webpack: webpackConfig, 37 | port: 9876, 38 | colors: true, 39 | logLevel: config.LOG_INFO, 40 | autoWatch: false, 41 | customLaunchers: { 42 | ChromeHeadlessWithFlags: { 43 | base: 'ChromeHeadless', 44 | flags: ['--no-sandbox', '--autoplay-policy=no-user-gesture-required', '--mute-audio'] 45 | } 46 | }, 47 | browsers: ['ChromeHeadlessWithFlags'], 48 | singleRun: true, 49 | concurrency: Infinity, 50 | client: { 51 | mocha: { 52 | reporter: 'html', 53 | timeout: 50000 54 | } 55 | } 56 | }); 57 | }; 58 | -------------------------------------------------------------------------------- /samples/ovp/all-plugins.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /samples/ovp/auto-pause.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /samples/ovp/auto-play-in-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /samples/ovp/cast.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /samples/ovp/change-media-clear.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /samples/ovp/change-media-drm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /samples/ovp/custom-poster.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 |
13 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /samples/ovp/custom-preview-thumbnail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 |
13 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /samples/ovp/floating.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 |
13 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /samples/ovp/live-stats.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 24 | 25 | 26 |
27 |

Live Stats

28 |
29 |
30 |
Current time:
31 |
End:
32 |
End:
33 |
Distance from live edge:
34 |
Live edge?
35 |
Total time in range:
36 |
Segment duration:
37 |
38 | 39 |
40 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /samples/ovp/playlist-by-config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /samples/ovp/playlist-by-entry-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /samples/ovp/playlist-by-id.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /samples/ovp/prebid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 | 12 |
13 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /samples/ovp/standalone-ima.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /samples/ovp/ui-conf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Title 7 | 8 | 9 | 10 | 11 |
12 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /samples/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #212121; 3 | padding: 0; 4 | margin: 0; 5 | height: 300vh; 6 | } 7 | 8 | #player-placeholder { 9 | position: absolute; 10 | margin: auto; 11 | top: 0; 12 | right: 0; 13 | bottom: 0; 14 | left: 0; 15 | width: 640px; 16 | height: 360px; 17 | } 18 | 19 | #player-placeholder.out-of-view { 20 | margin-top: 0px; 21 | margin-bottom: 0px; 22 | top: 95vh; 23 | } 24 | -------------------------------------------------------------------------------- /src/common/ads/ad-break.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @class AdBreak 3 | * @param {PKAdBreakOptions} options - Ad break data options. 4 | */ 5 | import { PKAdBreakOptions } from '../../types'; 6 | 7 | class AdBreak { 8 | private readonly _type: string | undefined; 9 | private readonly _position: number | undefined; 10 | private readonly _numAds: number | undefined; 11 | 12 | constructor(options: PKAdBreakOptions) { 13 | this._type = options.type; 14 | this._position = options.position; 15 | this._numAds = options.numAds; 16 | } 17 | 18 | /** 19 | * @instance 20 | * @memberof AdBreak 21 | * @return {string} - Ad break type - pre/mid/post. 22 | */ 23 | public get type(): string | undefined { 24 | return this._type; 25 | } 26 | 27 | /** 28 | * @instance 29 | * @memberof AdBreak 30 | * @return {string} - Ad break position on the playback timeline. 31 | */ 32 | public get position(): number | undefined { 33 | return this._position; 34 | } 35 | 36 | /** 37 | * @instance 38 | * @memberof AdBreak 39 | * @return {string} - The number of ads inside the ad break. 40 | */ 41 | public get numAds(): number | undefined { 42 | return this._numAds; 43 | } 44 | 45 | public toJSON(): any { 46 | return { 47 | type: this.type, 48 | position: this.position, 49 | numAds: this.numAds 50 | }; 51 | } 52 | } 53 | 54 | export { AdBreak }; 55 | -------------------------------------------------------------------------------- /src/common/ads/ad-layout-middleware.ts: -------------------------------------------------------------------------------- 1 | import { BaseMiddleware } from '@playkit-js/playkit-js'; 2 | import { AdsController } from '../controllers'; 3 | 4 | /** 5 | * Middleware implementation for ima plugin. 6 | * @class AdLayoutMiddleware 7 | * @param {Ima} context - The ima plugin context. 8 | * @private 9 | */ 10 | class AdLayoutMiddleware extends BaseMiddleware { 11 | /** 12 | * The id of the ima middleware. 13 | * @type {string} 14 | * @public 15 | * @memberof AdLayoutMiddleware 16 | */ 17 | public id: string = 'AdLayoutMiddleware'; 18 | /** 19 | * The plugin context. 20 | * @member 21 | * @private 22 | * @memberof AdLayoutMiddleware 23 | */ 24 | public _context: AdsController; 25 | 26 | constructor(context: AdsController) { 27 | super(); 28 | this._context = context; 29 | } 30 | 31 | /** 32 | * Load middleware handler. 33 | * @param {Function} next - The load play handler in the middleware chain. 34 | * @returns {void} 35 | * @memberof AdLayoutMiddleware 36 | */ 37 | public load(next: () => void): void { 38 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 39 | // @ts-ignore 40 | this._context.prerollReady.then(() => this.callNext(next)); 41 | } 42 | 43 | /** 44 | * Play middleware handler. 45 | * @param {Function} next - The next play handler in the middleware chain. 46 | * @returns {void} 47 | * @memberof AdLayoutMiddleware 48 | */ 49 | public play(next: () => void): void { 50 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 51 | // @ts-ignore 52 | this._context.prerollReady.then(() => this.callNext(next)); 53 | } 54 | } 55 | 56 | export { AdLayoutMiddleware }; 57 | -------------------------------------------------------------------------------- /src/common/ads/index.ts: -------------------------------------------------------------------------------- 1 | export { AdBreak } from './ad-break'; 2 | export { Ad } from './ad'; 3 | -------------------------------------------------------------------------------- /src/common/cast/cast-event-type.ts: -------------------------------------------------------------------------------- 1 | const namespace = 'kaltura-player'; 2 | 3 | /** 4 | * @const {Object} CastEventType 5 | * 6 | * @example 7 | * // Events lifecycle 8 | * 1. CAST_AVAILABLE 9 | * 2. CAST_SESSION_STARTING 10 | * 3. CAST_SESSION_STARTED || CAST_SESSION_START_FAILED -> X 11 | * 4. CAST_SESSION_ENDING 12 | * 5. CAST_SESSION_ENDED 13 | * @example 14 | * // How to use 15 | * player.addEventListener(KalturaPlayer.cast.CastEventType.CAST_SESSION_STARTED, e => { 16 | * console.log(e.session); 17 | * }; 18 | */ 19 | const CastEventType = { 20 | /** 21 | * Fires when cast session start failed. 22 | * @event CAST_SESSION_START_FAILED 23 | * @memberof CastEventType 24 | */ 25 | CAST_SESSION_START_FAILED: `${namespace}-castsessionstartfailed`, 26 | /** 27 | * Fires when cast session starting. 28 | * @event CAST_SESSION_STARTING 29 | * @memberof CastEventType 30 | */ 31 | CAST_SESSION_STARTING: `${namespace}-castsessionstarting`, 32 | /** 33 | * Fires when cast session started. 34 | * @event CAST_SESSION_STARTED 35 | * @memberof CastEventType 36 | */ 37 | CAST_SESSION_STARTED: `${namespace}-castsessionstarted`, 38 | /** 39 | * Fires when cast session ending. 40 | * @event CAST_SESSION_ENDING 41 | * @memberof CastEventType 42 | */ 43 | CAST_SESSION_ENDING: `${namespace}-castsessionending`, 44 | /** 45 | * Fires when cast session ended. 46 | * @event CAST_SESSION_ENDED 47 | * @memberof CastEventType 48 | */ 49 | CAST_SESSION_ENDED: `${namespace}-castsessionended`, 50 | /** 51 | * Fires when cast is available. 52 | * @event CAST_AVAILABLE 53 | * @memberof CastEventType 54 | */ 55 | CAST_AVAILABLE: `${namespace}-castavailable` 56 | } as const; 57 | 58 | export { CastEventType }; 59 | -------------------------------------------------------------------------------- /src/common/cast/custom-message.ts: -------------------------------------------------------------------------------- 1 | const CustomMessageType: { [type: string]: string } = { 2 | ACTION: 'action', 3 | EVENT: 'event' 4 | }; 5 | 6 | const CustomActionType: { [action: string]: string } = { 7 | SKIP_AD: 'skipAd' 8 | }; 9 | 10 | class CustomMessage { 11 | public type: string; 12 | 13 | constructor(type: string) { 14 | this.type = type; 15 | } 16 | } 17 | 18 | class CustomEventMessage extends CustomMessage { 19 | public event: string; 20 | public payload: any; 21 | 22 | constructor(event: string, payload: any) { 23 | super(CustomMessageType.EVENT); 24 | this.event = event; 25 | this.payload = payload; 26 | } 27 | } 28 | 29 | class CustomActionMessage extends CustomMessage { 30 | public action: string; 31 | public args: any; 32 | 33 | constructor(action: string, args: any) { 34 | super(CustomMessageType.ACTION); 35 | this.action = action; 36 | this.args = args; 37 | } 38 | } 39 | 40 | export { CustomMessageType, CustomActionType, CustomMessage, CustomEventMessage, CustomActionMessage }; 41 | -------------------------------------------------------------------------------- /src/common/cast/index.ts: -------------------------------------------------------------------------------- 1 | import { RemotePlayerManager } from './remote-player-manager'; 2 | import { PlayerSnapshot } from './player-snapshot'; 3 | import { RemoteControl } from './remote-control'; 4 | import { CastEventType } from './cast-event-type'; 5 | import { RemoteSession } from './remote-session'; 6 | import { BaseRemotePlayer } from './base-remote-player'; 7 | import { RemoteAvailablePayload, RemoteConnectedPayload, RemoteDisconnectedPayload } from './remote-payload'; 8 | import { RemotePlayerUI } from './remote-player-ui'; 9 | import { RemotePlayerType } from './remote-player-type'; 10 | import { TextStyleConverter } from './text-style-convertor'; 11 | import { CustomActionMessage, CustomActionType, CustomEventMessage, CustomMessage, CustomMessageType } from './custom-message'; 12 | 13 | const cast = { 14 | registerRemotePlayer: RemotePlayerManager.register, 15 | PlayerSnapshot, 16 | RemoteControl, 17 | RemoteSession, 18 | BaseRemotePlayer, 19 | RemoteConnectedPayload, 20 | RemoteDisconnectedPayload, 21 | RemoteAvailablePayload, 22 | RemotePlayerUI, 23 | CastEventType, 24 | RemotePlayerType, 25 | TextStyleConverter, 26 | CustomEventMessage, 27 | CustomActionMessage, 28 | CustomMessageType, 29 | CustomActionType, 30 | CustomMessage 31 | }; 32 | 33 | export { cast }; 34 | -------------------------------------------------------------------------------- /src/common/cast/player-snapshot.ts: -------------------------------------------------------------------------------- 1 | import { KalturaPlayer } from '../../kaltura-player'; 2 | import { TextStyle, TrackType, Utils } from '@playkit-js/playkit-js'; 3 | import { KPMediaConfig } from '../../types'; 4 | import { ProviderMediaInfoObject } from '@playkit-js/playkit-js-providers/types'; 5 | 6 | /** 7 | * @class PlayerSnapshot 8 | * @param {KalturaPlayer} player - The Kaltura player. 9 | * 10 | */ 11 | class PlayerSnapshot { 12 | public mediaInfo: ProviderMediaInfoObject; 13 | public mediaConfig: KPMediaConfig; 14 | /** 15 | * @type {TextStyle} 16 | * @instance 17 | * @memberof PlayerSnapshot 18 | */ 19 | public textStyle: TextStyle; 20 | /** 21 | * @type {Object} 22 | * @instance 23 | * @memberof PlayerSnapshot 24 | */ 25 | public advertising: any; 26 | /** 27 | * @type {Object} 28 | * @instance 29 | * @memberof PlayerSnapshot 30 | */ 31 | public config: any; 32 | 33 | constructor(player: KalturaPlayer) { 34 | this.textStyle = player.textStyle; 35 | this.mediaInfo = player.getMediaInfo(); 36 | this.mediaConfig = player.getMediaConfig(); 37 | this.advertising = player.config.plugins && player.config.plugins.ima; 38 | this.config = Utils.Object.mergeDeep({}, player.config, { 39 | sources: { 40 | startTime: getStartTime(player) 41 | }, 42 | playback: { 43 | autoplay: player.currentTime === 0 ? true : !player.paused, 44 | audioLanguage: getLanguage(TrackType.AUDIO, player), 45 | textLanguage: getLanguage(TrackType.TEXT, player) 46 | } 47 | }); 48 | } 49 | } 50 | 51 | /** 52 | * Gets the time to start from with respect to live media. 53 | * @private 54 | * @param {KalturaPlayer} player - The player. 55 | * @returns {number} - The time to start from (0 in live indicates the live edge). 56 | */ 57 | function getStartTime(player: KalturaPlayer): number { 58 | if (player.isLive()) { 59 | if (player.isDvr()) { 60 | const isOnLiveEdge = 61 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 62 | // @ts-ignore 63 | player.duration - player.currentTime < player.config.cast.dvrThreshold; 64 | if (isOnLiveEdge || !player.currentTime) { 65 | return -1; 66 | } 67 | return player.currentTime; 68 | } else { 69 | return -1; 70 | } 71 | } else if (!player.isCasting() && !player.currentTime && player.config.sources.startTime! > -1) { 72 | return player.config.sources.startTime!; 73 | } 74 | return player.currentTime!; 75 | } 76 | 77 | /** 78 | * Gets the audio/text language. 79 | * If the player has started to play it will return the current played audio/text. 80 | * Otherwise, it will return the configured audio/text. 81 | * @private 82 | * @param {string} type - The language type. 83 | * @param {KalturaPlayer} player - The player. 84 | * @returns {?string} - The audio language or undefined. 85 | */ 86 | function getLanguage(type: string, player: KalturaPlayer): string | null { 87 | const activeTracks = player.getActiveTracks(); 88 | if (activeTracks[type]) { 89 | return activeTracks[type].language; 90 | } 91 | try { 92 | return player.config.playback[`${type}Language`]; 93 | } catch (e) { 94 | return null; 95 | } 96 | } 97 | 98 | export { PlayerSnapshot }; 99 | -------------------------------------------------------------------------------- /src/common/cast/remote-player-manager.ts: -------------------------------------------------------------------------------- 1 | import { getLogger } from '@playkit-js/playkit-js'; 2 | import { RemoteControl } from './remote-control'; 3 | import { BaseRemotePlayer } from './base-remote-player'; 4 | import { KalturaPlayer } from '../../kaltura-player'; 5 | import { ClassConstructor } from '../../types'; 6 | 7 | class RemotePlayerManager { 8 | private static _registry: Map> = new Map(); 9 | private static _logger: any = getLogger('RemotePlayerManager'); 10 | 11 | private _remotePlayers: Map = new Map(); 12 | 13 | public static register(type: string, remotePlayer: BaseRemotePlayer): void { 14 | if (typeof remotePlayer === 'function') { 15 | if (!RemotePlayerManager._registry.has(type)) { 16 | RemotePlayerManager._logger.debug(`Register remote player of type ${type}`); 17 | RemotePlayerManager._registry.set(type, remotePlayer); 18 | } else { 19 | RemotePlayerManager._logger.debug(`Remote player of type ${type} is already registered`); 20 | } 21 | } else { 22 | RemotePlayerManager._logger.debug('remote player must be instance of BaseRemotePlayer'); 23 | } 24 | } 25 | 26 | public load(castConfig: any, player: KalturaPlayer): void { 27 | const registry = RemotePlayerManager._registry; 28 | registry.forEach((RemotePlayer: ClassConstructor, type: string) => { 29 | RemotePlayerManager._logger.debug(`Load remote player of type ${type}`); 30 | const remotePlayer: BaseRemotePlayer = new RemotePlayer(castConfig, new RemoteControl(player), player.config.targetId); 31 | this._remotePlayers.set(type, remotePlayer); 32 | }); 33 | } 34 | 35 | public startCasting(type?: string): Promise { 36 | RemotePlayerManager._logger.debug('Start casting'); 37 | const remotePlayer = this._getRemotePlayer(type); 38 | if (remotePlayer) { 39 | return remotePlayer.startCasting(); 40 | } 41 | return Promise.reject(); 42 | } 43 | 44 | public isCastAvailable(type?: string): boolean { 45 | const remotePlayer = this._getRemotePlayer(type); 46 | if (remotePlayer) { 47 | RemotePlayerManager._logger.debug(`isCastAvailable: ${remotePlayer.isCastAvailable()}`); 48 | return remotePlayer.isCastAvailable(); 49 | } 50 | return false; 51 | } 52 | 53 | public destroy(): void { 54 | const remotePlayers = this._remotePlayers; 55 | Array.from(remotePlayers.values()).forEach((remotePlayer) => remotePlayer.destroy()); 56 | } 57 | 58 | public setIsCastInitiator(type: string, isCastInitiator: boolean): void { 59 | const remotePlayer = this._getRemotePlayer(type); 60 | if (remotePlayer) { 61 | remotePlayer.isCastInitiator = isCastInitiator; 62 | } 63 | } 64 | 65 | private _getRemotePlayer(type?: string): BaseRemotePlayer | undefined { 66 | const remotePlayers = this._remotePlayers; 67 | if (type && remotePlayers.get(type)) { 68 | return remotePlayers.get(type); 69 | } else if (remotePlayers.size > 0) { 70 | return Array.from(remotePlayers.values())[0]; 71 | } 72 | } 73 | } 74 | 75 | export { RemotePlayerManager }; 76 | -------------------------------------------------------------------------------- /src/common/cast/remote-player-type.ts: -------------------------------------------------------------------------------- 1 | const RemotePlayerType: { [type: string]: string } = { 2 | CHROMECAST: 'chromecast' 3 | }; 4 | 5 | export { RemotePlayerType }; 6 | -------------------------------------------------------------------------------- /src/common/cast/remote-player-ui.ts: -------------------------------------------------------------------------------- 1 | import { Presets, UIPreset } from '@playkit-js/playkit-js-ui'; 2 | 3 | /** 4 | * @class RemotePlayerUI 5 | */ 6 | class RemotePlayerUI { 7 | private _uis: Array = [ 8 | { 9 | template: (props): any => this.idleUI(props), 10 | condition: (state): boolean => state.engine.isIdle 11 | }, 12 | { 13 | template: (props): any => this.errorUI(props), 14 | condition: (state): boolean => state.engine.hasError 15 | }, 16 | { 17 | template: (props): any => this.adsUI(props), 18 | condition: (state): boolean => state.engine.adBreak 19 | }, 20 | { 21 | template: (props): any => this.liveUI(props), 22 | condition: (state): boolean => state.engine.isLive 23 | }, 24 | { template: (props): any => this.playbackUI(props) } 25 | ]; 26 | 27 | /** 28 | * Playback UI of the remote player. 29 | * @param {Object} props - UI creation parameters. 30 | * @returns {React$Element} - Component. 31 | * @instance 32 | * @memberof RemotePlayerUI 33 | */ 34 | public playbackUI(props: any): any { 35 | return Presets.playbackUI(props); 36 | } 37 | 38 | /** 39 | * Idle UI of the remote player. 40 | * @param {Object} props - UI creation parameters. 41 | * @returns {React$Element} - Component. 42 | * @instance 43 | * @memberof RemotePlayerUI 44 | */ 45 | public idleUI(props: any): any { 46 | return Presets.idleUI(props); 47 | } 48 | 49 | /** 50 | * Idle UI of the remote player. 51 | * @param {Object} props - UI creation parameters. 52 | * @returns {React$Element} - Component. 53 | * @instance 54 | * @memberof RemotePlayerUI 55 | */ 56 | public adsUI(props: any): any { 57 | return Presets.adsUI(props); 58 | } 59 | 60 | /** 61 | * Live UI of the remote player. 62 | * @param {Object} props - UI creation parameters. 63 | * @returns {React$Element} - Component. 64 | * @instance 65 | * @memberof RemotePlayerUI 66 | */ 67 | public liveUI(props: any): any { 68 | return Presets.liveUI(props); 69 | } 70 | 71 | /** 72 | * Error UI of the remote player. 73 | * @param {Object} props - UI creation parameters. 74 | * @returns {React$Element} - Component. 75 | * @instance 76 | * @memberof RemotePlayerUI 77 | */ 78 | public errorUI(props: any): any { 79 | return Presets.errorUI(props); 80 | } 81 | 82 | /** 83 | * UI presets. 84 | * @type {Array} 85 | * @instance 86 | * @memberof RemotePlayerUI 87 | */ 88 | public get uis(): UIPreset[] { 89 | return this._uis; 90 | } 91 | } 92 | 93 | export { RemotePlayerUI }; 94 | -------------------------------------------------------------------------------- /src/common/cast/remote-session.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @class RemoteSession 3 | * @param {string} id - Session ID. 4 | * @param {string} friendlyName - Receiver friendly name. 5 | * @param {boolean} [resuming] - Whether the session is resuming. 6 | */ 7 | class RemoteSession { 8 | private readonly _id: string; 9 | private readonly _friendlyName: string; 10 | private readonly _resuming: boolean | undefined; 11 | 12 | constructor(id: string, friendlyName: string, resuming?: boolean) { 13 | this._id = id; 14 | this._friendlyName = friendlyName; 15 | this._resuming = resuming; 16 | } 17 | 18 | /** 19 | * Receiver friendly name. 20 | * @type {string} 21 | * @instance 22 | * @memberof RemoteSession 23 | */ 24 | public get deviceFriendlyName(): string { 25 | return this._friendlyName; 26 | } 27 | 28 | /** 29 | * Session ID. 30 | * @type {string} 31 | * @instance 32 | * @memberof RemoteSession 33 | */ 34 | public get id(): string { 35 | return this._id; 36 | } 37 | 38 | /** 39 | * Whether the session is resuming. 40 | * @type {?boolean} 41 | * @instance 42 | * @memberof RemoteSession 43 | */ 44 | public get resuming(): boolean | undefined { 45 | return this._resuming; 46 | } 47 | } 48 | 49 | export { RemoteSession }; 50 | -------------------------------------------------------------------------------- /src/common/cast/text-style-convertor.ts: -------------------------------------------------------------------------------- 1 | import { TextStyle } from '@playkit-js/playkit-js'; 2 | 3 | declare global { 4 | interface Window { 5 | chrome?: { 6 | cast?: any; 7 | }; 8 | } 9 | } 10 | 11 | class TextStyleConverter { 12 | public static toCastTextStyle(playerTextStyle: TextStyle): any { 13 | if (window.chrome && window.chrome.cast) { 14 | const textTrackStyle = new window.chrome.cast.media.TextTrackStyle(); 15 | textTrackStyle.fontFamily = playerTextStyle.fontFamily; 16 | textTrackStyle.backgroundColor = TextStyleConverter.rgbToHex(playerTextStyle.backgroundColor); 17 | textTrackStyle.foregroundColor = TextStyleConverter.rgbToHex(playerTextStyle.fontColor); 18 | textTrackStyle.fontScale = Number.parseFloat(playerTextStyle.fontSize) / 100; 19 | return textTrackStyle; 20 | } 21 | return {}; 22 | } 23 | 24 | public static toPlayerTextStyle(castTextStyle: any): TextStyle { 25 | const textStyle = new TextStyle(); 26 | textStyle.fontFamily = castTextStyle.fontFamily; 27 | textStyle.fontSize = castTextStyle.fontScale * 100 + '%'; 28 | textStyle.fontColor = TextStyleConverter.hexToRGB(castTextStyle.foregroundColor); 29 | textStyle.backgroundColor = TextStyleConverter.hexToRGB(castTextStyle.backgroundColor); 30 | return textStyle; 31 | } 32 | 33 | public static rgbToHex(rgb: Array): string { 34 | let hex = 35 | '#' + 36 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 37 | // @ts-ignore 38 | ('0' + parseInt(rgb[0], 10).toString(16)).slice(-2) + 39 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 40 | // @ts-ignore 41 | ('0' + parseInt(rgb[1], 10).toString(16)).slice(-2) + 42 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 43 | // @ts-ignore 44 | ('0' + parseInt(rgb[2], 10).toString(16)).slice(-2); 45 | if (rgb[3]) { 46 | let digit = rgb[3]; 47 | digit = Math.round(digit * 100) / 100; 48 | const alpha = Math.round(digit * 255); 49 | hex += (alpha + 0x10000).toString(16).substr(-2).toUpperCase(); 50 | } else { 51 | hex += 'FF'; 52 | } 53 | return hex.toUpperCase(); 54 | } 55 | 56 | public static hexToRGB(hex: string): [number, number, number] { 57 | const rgb: [number, number, number] = [] as unknown as [number, number, number]; 58 | hex = hex.slice(1); 59 | const channels = hex.match(/.{1,2}/g); 60 | for (let i = 0; i < 3; i++) { 61 | const channel = channels && channels[i]; 62 | if (channel) { 63 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 64 | // @ts-ignore 65 | rgb.push(parseInt(channel, 16)); 66 | } 67 | } 68 | return rgb; 69 | } 70 | } 71 | 72 | export { TextStyleConverter }; 73 | -------------------------------------------------------------------------------- /src/common/controllers/controller-provider.ts: -------------------------------------------------------------------------------- 1 | import { PluginManager } from '../plugins'; 2 | import { IAdsPluginController, IAdsControllerProvider } from '../../types'; 3 | 4 | /** 5 | * Controller provider 6 | * @classdesc 7 | */ 8 | class ControllerProvider { 9 | private _pluginManager: PluginManager; 10 | 11 | /** 12 | * @constructor 13 | * @param {PluginManager} pluginManager - the plugin manager 14 | */ 15 | constructor(pluginManager: PluginManager) { 16 | this._pluginManager = pluginManager; 17 | } 18 | 19 | /** 20 | * Get the ads controller of the all ads plugins. 21 | * @returns {Array} - the ads controllers. 22 | */ 23 | public getAdsControllers(): Array { 24 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 25 | // @ts-ignore 26 | const adPlugins: Array = Object.values(this._pluginManager.getAll()).filter( 27 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 28 | // @ts-ignore 29 | (plugin) => typeof plugin.getAdsController === 'function' 30 | ); 31 | return adPlugins.map((plugin) => plugin.getAdsController()); 32 | } 33 | } 34 | 35 | export { ControllerProvider }; 36 | -------------------------------------------------------------------------------- /src/common/controllers/index.ts: -------------------------------------------------------------------------------- 1 | export { AdsController } from './ads-controller'; 2 | export { ControllerProvider } from './controller-provider'; 3 | -------------------------------------------------------------------------------- /src/common/playlist/index.ts: -------------------------------------------------------------------------------- 1 | import { PlaylistEventType } from './playlist-event-type'; 2 | 3 | const playlist = { 4 | PlaylistEventType 5 | }; 6 | 7 | export { playlist }; 8 | -------------------------------------------------------------------------------- /src/common/playlist/playlist-event-type.ts: -------------------------------------------------------------------------------- 1 | const namespace = 'kaltura-player'; 2 | 3 | /** 4 | * @const {Object} PlaylistEventType 5 | * 6 | * @example 7 | * // Events lifecycle 8 | * 1. PLAYLIST_LOADED 9 | * 2. PLAYLIST_ITEM_CHANGED (multiple) 10 | * 3. PLAYLIST_ENDED 11 | * @example 12 | * // How to use 13 | * player.addEventListener(KalturaPlayer.playlist.PlaylistEventType.PLAYLIST_LOADED, e => { 14 | * console.log(e.payload.playlist.metadata.name); 15 | * }; 16 | */ 17 | const PlaylistEventType = { 18 | /** 19 | * Fires when the playlist has been loaded. 20 | * @event PLAYLIST_LOADED 21 | * @memberof PlaylistEventType 22 | */ 23 | PLAYLIST_LOADED: `${namespace}-playlistloaded`, 24 | /** 25 | * Fires when a playlist item start to changed. 26 | * @event PLAYLIST_ITEM_CHANGED 27 | * @memberof PlaylistEventType 28 | */ 29 | PLAYLIST_ITEM_CHANGED: `${namespace}-playlistitemchanged`, 30 | /** 31 | * Fires when the playlist has finished. 32 | * @event PLAYLIST_ENDED 33 | * @memberof PlaylistEventType 34 | */ 35 | PLAYLIST_ENDED: `${namespace}-playlistended` 36 | } as const; 37 | 38 | export { PlaylistEventType }; 39 | -------------------------------------------------------------------------------- /src/common/playlist/playlist-item.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@playkit-js/playkit-js'; 2 | import { PluginsConfig, SourcesConfig, KPPlaylistItemConfigObject } from '../../types'; 3 | const formats = ['hls', 'dash', 'progressive', 'image', 'document']; 4 | /** 5 | * @class PlaylistItem 6 | * @param {PKSourcesConfigObject} [sources] - The item sources 7 | * @param {KPPlaylistItemConfigObject} [config] - The item config 8 | */ 9 | class PlaylistItem { 10 | private _sources: SourcesConfig; 11 | private _config: KPPlaylistItemConfigObject; 12 | private _plugins!: PluginsConfig; 13 | private _index: number; 14 | 15 | constructor(sources: SourcesConfig, config: KPPlaylistItemConfigObject, index: number) { 16 | this._sources = sources; 17 | this._config = config; 18 | this._index = index; 19 | } 20 | 21 | /** 22 | * Update the playlist item sources 23 | * @param {PKSourcesConfigObject} sourcesObject - The sources 24 | * @returns {void} 25 | * @instance 26 | * @memberof PlaylistItem 27 | */ 28 | public updateSources(sourcesObject: SourcesConfig): void { 29 | this._sources = Utils.Object.mergeDeep({}, sourcesObject); 30 | } 31 | 32 | /** 33 | * Update the playlist item plugins (e.g. bumper from BE) 34 | * @param {KPPluginsConfigObject} pluginsObject - The plugins 35 | * @returns {void} 36 | * @instance 37 | * @memberof PlaylistItem 38 | */ 39 | public updatePlugins(pluginsObject: PluginsConfig): void { 40 | this._plugins = Utils.Object.copyDeep(pluginsObject); 41 | } 42 | 43 | /** 44 | * Playlist item sources 45 | * @type {?PKSourcesConfigObject} 46 | * @instance 47 | * @memberof PlaylistItem 48 | */ 49 | public get sources(): SourcesConfig { 50 | formats.forEach((format: string) => { 51 | if (this._sources && this._sources[format] && this._sources[format].length === 0) { 52 | delete this._sources[format]; 53 | } 54 | }); 55 | return this._sources; 56 | } 57 | 58 | /** 59 | * Playlist item config 60 | * @type {?KPPlaylistItemConfigObject} 61 | * @instance 62 | * @memberof PlaylistItem 63 | */ 64 | public get config(): KPPlaylistItemConfigObject { 65 | return this._config; 66 | } 67 | 68 | /** 69 | * Playlist item plugins 70 | * @type {KPPluginsConfigObject} 71 | * @instance 72 | * @memberof PlaylistItem 73 | */ 74 | public get plugins(): PluginsConfig { 75 | return this._plugins || {}; 76 | } 77 | 78 | /** 79 | * Playlist item index 80 | * @type {number} 81 | * @instance 82 | * @memberof PlaylistItem 83 | */ 84 | public get index(): number { 85 | return this._index; 86 | } 87 | 88 | /** 89 | * @returns {boolean} = Whether the playlist item has sources to play 90 | * @instance 91 | * @memberof PlaylistItem 92 | */ 93 | public isPlayable(): boolean { 94 | return !!formats.find((format) => { 95 | return this._sources && this._sources[format] && this._sources[format].length; 96 | }); 97 | } 98 | } 99 | 100 | export { PlaylistItem }; 101 | -------------------------------------------------------------------------------- /src/common/playlist/playlist.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@playkit-js/playkit-js'; 2 | import { ProviderPlaylistMetadataObject } from '@playkit-js/playkit-js-providers/types'; 3 | import { PlaylistItem } from './playlist-item'; 4 | import { KPPlaylistObject, SourcesConfig, PluginsConfig, MediaSourceOptionsObject } from '../../types'; 5 | 6 | class Playlist { 7 | private _id: string; 8 | private _metadata: ProviderPlaylistMetadataObject; 9 | private _poster: string | undefined; 10 | private _items: Array; 11 | public _activeItemIndex: number; 12 | 13 | constructor() { 14 | this._id = ''; 15 | this._metadata = { name: '', description: '' }; 16 | this._poster = ''; 17 | this._items = []; 18 | this._activeItemIndex = -1; 19 | } 20 | 21 | public configure(config: KPPlaylistObject, sourcesOptions: MediaSourceOptionsObject): void { 22 | this._id = config.id ? config.id : this._id; 23 | this._poster = config.poster ? config.poster : this._poster; 24 | this._metadata = config.metadata ? config.metadata : this._metadata; 25 | if (config.items) { 26 | this._items = []; 27 | config.items.forEach((item, index) => { 28 | if (item.sources) { 29 | const configSourcesOptions = Utils.Object.mergeDeep({}, sourcesOptions); 30 | const itemSourcesOptions = item.sources.options || {}; 31 | item.sources.options = Utils.Object.mergeDeep(configSourcesOptions, itemSourcesOptions); 32 | } 33 | this._items.push(new PlaylistItem(item.sources, item.config, index)); 34 | }); 35 | } 36 | } 37 | 38 | public updateItemSources(index: number, sourcesObject: SourcesConfig): void { 39 | this._items[index].updateSources(sourcesObject); 40 | } 41 | 42 | public updateItemPlugins(index: number, pluginsObject: PluginsConfig): void { 43 | this._items[index].updatePlugins(pluginsObject); 44 | } 45 | 46 | public get id(): string { 47 | return this._id; 48 | } 49 | 50 | public get items(): Array { 51 | return this._items; 52 | } 53 | 54 | public get metadata(): ProviderPlaylistMetadataObject { 55 | return this._metadata; 56 | } 57 | 58 | public get poster(): string | undefined { 59 | return this._poster; 60 | } 61 | 62 | public get current(): PlaylistItem | undefined { 63 | return this._items[this._activeItemIndex] || null; 64 | } 65 | 66 | public getNext(loop: boolean): PlaylistItem | undefined { 67 | const nextIndex = loop ? (this._activeItemIndex + 1) % this._items.length : this._activeItemIndex + 1; 68 | return this._items[nextIndex] || null; 69 | } 70 | 71 | public get prev(): PlaylistItem | undefined { 72 | return this._items[this._activeItemIndex - 1] || null; 73 | } 74 | 75 | public set activeItemIndex(index: number) { 76 | this._activeItemIndex = index; 77 | } 78 | } 79 | 80 | export { Playlist }; 81 | -------------------------------------------------------------------------------- /src/common/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export { BasePlugin } from './base-plugin'; 2 | export * from './plugin-manager'; 3 | export * from './plugins-config'; 4 | export * from './plugins-config-store'; 5 | -------------------------------------------------------------------------------- /src/common/plugins/plugin-readiness-middleware.ts: -------------------------------------------------------------------------------- 1 | import { BaseMiddleware, getLogger } from '@playkit-js/playkit-js'; 2 | import { BasePlugin } from './base-plugin'; 3 | class PluginReadinessMiddleware extends BaseMiddleware { 4 | private readonly _plugins: Array; 5 | public id: string = 'PluginReadinessMiddleware'; 6 | private static _logger = getLogger('PluginReadinessMiddleware'); 7 | 8 | constructor(plugins: Array) { 9 | super(); 10 | this._plugins = plugins; 11 | PluginReadinessMiddleware._logger.debug('plugins readiness', this._plugins); 12 | } 13 | 14 | /** 15 | * Load middleware handler. 16 | * @param {Function} next - The load handler in the middleware chain. 17 | * @returns {void} 18 | * @memberof PluginReadinessMiddleware 19 | */ 20 | public load(next: () => any): void { 21 | this._checkNextSettle(0, next); 22 | } 23 | private _checkNextSettle(index: number, next: () => any): void { 24 | if (index < this._plugins.length) { 25 | this._checkSettle(index, next); 26 | } else { 27 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 28 | // @ts-ignore 29 | this.callNext(next); 30 | } 31 | } 32 | 33 | private _checkSettle(index: number, next: () => any): void { 34 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 35 | // @ts-ignore 36 | const readyPromise = this._plugins[index].ready 37 | ? // eslint-disable-next-line @typescript-eslint/ban-ts-comment 38 | // @ts-ignore 39 | this._plugins[index].ready 40 | : Promise.resolve(); 41 | readyPromise 42 | .then(() => { 43 | PluginReadinessMiddleware._logger.debug(`plugin ${this._plugins[index].name} ready promise resolved`); 44 | this._checkNextSettle(index + 1, next); 45 | }) 46 | .catch(() => { 47 | PluginReadinessMiddleware._logger.debug(`plugin ${this._plugins[index].name} ready promise rejected`); 48 | this._checkNextSettle(index + 1, next); 49 | }); 50 | } 51 | /** 52 | * Play middleware handler. 53 | * @param {Function} next - The play handler in the middleware chain. 54 | * @returns {void} 55 | * @memberof PluginReadinessMiddleware 56 | */ 57 | public play(next: () => any): void { 58 | this._checkNextSettle(0, next); 59 | } 60 | } 61 | export { PluginReadinessMiddleware }; 62 | -------------------------------------------------------------------------------- /src/common/service-provider.ts: -------------------------------------------------------------------------------- 1 | import { getLogger, EventManager } from '@playkit-js/playkit-js'; 2 | import { KalturaPlayer } from '../kaltura-player'; 3 | 4 | /** 5 | * @class ServiceProvider 6 | */ 7 | class ServiceProvider { 8 | private static _logger: any; 9 | private _servicesRegistry: Map = new Map(); 10 | private _eventManager: EventManager; 11 | 12 | /** 13 | * @constructor 14 | * @param {KalturaPlayer} player - The player. 15 | */ 16 | constructor(player: KalturaPlayer) { 17 | ServiceProvider._logger = getLogger('ServiceProvider'); 18 | this._eventManager = new EventManager(); 19 | this._eventManager.listen(player, player.Event.Core.PLAYER_RESET, () => this.reset()); 20 | } 21 | 22 | /** 23 | * @param {string} name - the service name 24 | * @param {Object} service - the service object 25 | * @returns {void} 26 | */ 27 | public register(name: string, service: any): void { 28 | if (this._servicesRegistry.has(name)) { 29 | ServiceProvider._logger.debug(`${name} service already exists`); 30 | } else { 31 | this._servicesRegistry.set(name, service); 32 | ServiceProvider._logger.debug(`${name} service registered`); 33 | } 34 | } 35 | 36 | /** 37 | * 38 | * @param {string} name - the service name 39 | * @returns {Object} - the service object 40 | */ 41 | public get(name: string): any | void { 42 | return this._servicesRegistry.get(name); 43 | } 44 | 45 | /** 46 | * 47 | * @param {string} name - the service name 48 | * @returns {boolean} - if the service exist 49 | */ 50 | public has(name: string): boolean { 51 | return this._servicesRegistry.has(name); 52 | } 53 | 54 | /** 55 | * @returns {void} 56 | */ 57 | public reset(): void { 58 | this._servicesRegistry.forEach((service) => typeof service.reset === 'function' && service.reset()); 59 | } 60 | 61 | /** 62 | * @returns {void} 63 | */ 64 | public destroy(): void { 65 | this._servicesRegistry.forEach((service) => typeof service.destroy === 'function' && service.destroy()); 66 | this._eventManager.removeAll(); 67 | this._servicesRegistry.clear(); 68 | } 69 | } 70 | 71 | export { ServiceProvider }; 72 | -------------------------------------------------------------------------------- /src/common/storage/session-storage-manager.ts: -------------------------------------------------------------------------------- 1 | import { EventManager } from '@playkit-js/playkit-js'; 2 | import { BaseStorageManager } from './base-storage-manager'; 3 | import { KalturaPlayer } from '../../kaltura-player'; 4 | 5 | export default class SessionStorageManager extends BaseStorageManager { 6 | public static StorageKeys: { [key: string]: string } = { 7 | PLAYBACK_RATE: 'playbackRate' 8 | }; 9 | 10 | public static initialize(): void { 11 | this.init(this.name); 12 | } 13 | 14 | public static getStorageObject(): Storage { 15 | return sessionStorage; 16 | } 17 | 18 | /** 19 | * Attaches the player listeners to the local storage wrapper. 20 | * @private 21 | * @param {Player} player - The player reference. 22 | * @static 23 | * @returns {void} 24 | */ 25 | public static attach(player: KalturaPlayer): void { 26 | this._logger.debug('Attach session storage'); 27 | const eventManager = new EventManager(); 28 | eventManager.listen(player, player.Event.UI.USER_SELECTED_SPEED, () => { 29 | if (!player.isCasting()) { 30 | this.setItem(this.StorageKeys.PLAYBACK_RATE, player.playbackRate); 31 | } 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/common/utils/error-helper.ts: -------------------------------------------------------------------------------- 1 | import { Error } from '@playkit-js/playkit-js'; 2 | 3 | const isBackEndError = (error: Error): boolean => error.category === 2; 4 | const isBlockAction = (error: Error): boolean => error.code === 2001; 5 | const isMediaNotReady = (error: Error): boolean => error.code === 2002; 6 | const isScheduledRestrictedCode = (error: Error): boolean => error.code === 2003; 7 | const isGeolocationRestricted = (error: Error): boolean => error.data?.messages && error.data?.messages[0].code === 'COUNTRY_RESTRICTED'; 8 | const isSessionRestricted = (error: Error): boolean => error.data?.messages && error.data?.messages[0].code === 'SESSION_RESTRICTED'; 9 | const isIPRestricted = (error: Error): boolean => error.data?.messages && error.data?.messages[0].code === 'IP_RESTRICTED'; 10 | const isSitedRestricted = (error: Error): boolean => error.data?.messages && error.data?.messages[0].code === 'SITE_RESTRICTED'; 11 | const isScheduledRestricted = (error: Error): boolean => error.data?.messages && error.data?.messages[0].code === 'SCHEDULED_RESTRICTED'; 12 | 13 | const isSessionRestrictedError = (error: Error): boolean => isBackEndError(error) && isBlockAction(error) && isSessionRestricted(error); 14 | const isGeolocationError = (error: Error): boolean => isBackEndError(error) && isBlockAction(error) && isGeolocationRestricted(error); 15 | const isMediaNotReadyError = (error: Error): boolean => isBackEndError(error) && isMediaNotReady(error); 16 | const isIPRestrictedError = (error: Error): boolean => isBackEndError(error) && isBlockAction(error) && isIPRestricted(error); 17 | const isSitedRestrictedError = (error: Error): boolean => isBackEndError(error) && isBlockAction(error) && isSitedRestricted(error); 18 | const isScheduledRestrictedError = (error: Error): boolean => 19 | isBackEndError(error) && isScheduledRestrictedCode(error) && isScheduledRestricted(error); 20 | const isAccessControlRestrictedError = (error: Error): boolean => { 21 | return ( 22 | isBackEndError(error) && 23 | isBlockAction(error) && 24 | !isGeolocationRestricted(error) && 25 | !isSessionRestricted(error) && 26 | !isIPRestricted(error) && 27 | !isSitedRestricted(error) && 28 | !isScheduledRestricted(error) 29 | ); 30 | }; 31 | 32 | const conditionsToErrors: any[] = [ 33 | [isSessionRestrictedError, Error.Category.MEDIA_UNAVAILABLE], 34 | [isGeolocationError, Error.Category.GEO_LOCATION], 35 | [isMediaNotReadyError, Error.Category.MEDIA_NOT_READY], 36 | [isIPRestrictedError, Error.Category.IP_RESTRICTED], 37 | [isScheduledRestrictedError, Error.Category.SCHEDULED_RESTRICTED], 38 | [isSitedRestrictedError, Error.Category.SITE_RESTRICTED], 39 | [isAccessControlRestrictedError, Error.Category.ACCESS_CONTROL_BLOCKED] 40 | ]; 41 | 42 | function getErrorCategory(error: Error): number { 43 | const [, errorCategory] = conditionsToErrors.find((errorCondition) => errorCondition[0](error)) || []; 44 | return errorCategory || Error.Category.PLAYER; 45 | } 46 | 47 | export default getErrorCategory; 48 | -------------------------------------------------------------------------------- /src/common/utils/evaluate.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @private 3 | * @param {string} template - The template string to evaluate 4 | * @param {Object} model - The model to evaluate with 5 | * @return {string} - The evaluated string 6 | */ 7 | function evaluate(template: string, model: any = {}): string { 8 | try { 9 | let reg, 10 | res = template; 11 | for (const key in model) { 12 | let value = model[key] !== undefined && model[key] !== null ? model[key] : ''; 13 | if (typeof value === 'string' && value.indexOf('"') > -1) { 14 | value = value.replace(/"/g, '\\"'); 15 | } 16 | reg = new RegExp('{{' + key + '}}', 'g'); 17 | res = res.replace(reg, value); 18 | } 19 | return res; 20 | } catch (e) { 21 | return ''; 22 | } 23 | } 24 | 25 | export default evaluate; 26 | -------------------------------------------------------------------------------- /src/common/utils/external-stream-redirect-helper.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@playkit-js/playkit-js'; 2 | import { KalturaPlayerConfig } from '../../types'; 3 | 4 | /** 5 | * JSONP handler function, returns the direct manifest uri. 6 | * @private 7 | * @param {Object} data - The json object that returns from the server. 8 | * @param {string} uri - Original request uri. 9 | * @returns {string} - The direct uri. 10 | */ 11 | function getDirectManifestUri(data: any, uri: string): string { 12 | const getHostName = (uri): string => { 13 | const parser = document.createElement('a'); 14 | parser.href = uri; 15 | return parser.hostname; 16 | }; 17 | // if the json contains one url, it means it is a redirect url. if it contains few urls, it means its the flavours 18 | // so we should use the original url. 19 | const uriHost = getHostName(uri); 20 | let hasOneFlavor = false; 21 | let redirectedUriHost: false | string = ''; 22 | let redirectedUri = ''; 23 | if (data) { 24 | if (data.flavors && Array.isArray(data.flavors)) { 25 | hasOneFlavor = data.flavors.length === 1; 26 | redirectedUriHost = hasOneFlavor && getHostName(data.flavors[0].url); 27 | redirectedUri = data.flavors[0].url; 28 | } else if (data.result) { 29 | hasOneFlavor = true; 30 | redirectedUriHost = getHostName(data.result.url); 31 | redirectedUri = data.result.url; 32 | } 33 | } 34 | if (hasOneFlavor && uriHost !== redirectedUriHost) { 35 | return redirectedUri; 36 | } 37 | return uri; 38 | } 39 | 40 | /** 41 | * Get the redirect external stream handler. 42 | * @public 43 | * @param {KPOptionsObject} playerOptions - The player config. 44 | * @param {KPOptionsObject} mediaOptions - The media config. 45 | * @returns {void} 46 | */ 47 | function getRedirectExternalStreamsHandler(playerOptions: Partial, mediaOptions: KalturaPlayerConfig | any = {}): any { 48 | const configObj = {}; 49 | const playerRedirectExternalStreamsHandler = Utils.Object.getPropertyPath(playerOptions, 'sources.options.redirectExternalStreamsHandler'); 50 | const mediaRedirectExternalStreamsHandler = Utils.Object.getPropertyPath(mediaOptions, 'sources.options.redirectExternalStreamsHandler'); 51 | if (typeof playerRedirectExternalStreamsHandler !== 'function' && typeof mediaRedirectExternalStreamsHandler !== 'function') { 52 | Utils.Object.mergeDeep(configObj, { 53 | sources: { 54 | options: { 55 | redirectExternalStreamsHandler: getDirectManifestUri 56 | } 57 | } 58 | }); 59 | } 60 | return configObj; 61 | } 62 | 63 | export { getRedirectExternalStreamsHandler }; 64 | -------------------------------------------------------------------------------- /src/common/utils/session-id-cache.ts: -------------------------------------------------------------------------------- 1 | class SessionIdCache { 2 | private cache = new Map(); 3 | 4 | public set(key: string, value: string): void { 5 | this.cache.set(key, value); 6 | } 7 | 8 | public get(key: string): string { 9 | return this.cache.get(key); 10 | } 11 | 12 | public clear(): void { 13 | this.cache.clear(); 14 | } 15 | } 16 | 17 | export { SessionIdCache }; 18 | -------------------------------------------------------------------------------- /src/common/utils/session-id-generator.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@playkit-js/playkit-js'; 2 | 3 | class SessionIdGenerator { 4 | private static _value: string = ''; 5 | 6 | private static init(): void { 7 | SessionIdGenerator._value = `${Utils.Generator.guid()}:${Utils.Generator.guid()}`; 8 | } 9 | 10 | public static next(): string { 11 | if (!SessionIdGenerator._value) { 12 | this.init(); 13 | return SessionIdGenerator._value; 14 | } 15 | 16 | const next = SessionIdGenerator._value; 17 | 18 | const secondGuidInSessionIdRegex = /:((?:[a-z0-9]|-)*)/i; 19 | const secondGuidInSessionId = secondGuidInSessionIdRegex.exec(next); 20 | if (secondGuidInSessionId && secondGuidInSessionId[1]) { 21 | SessionIdGenerator._value = next.replace(secondGuidInSessionId[1], Utils.Generator.guid()); 22 | } 23 | 24 | return next; 25 | } 26 | } 27 | 28 | export { SessionIdGenerator }; 29 | -------------------------------------------------------------------------------- /src/common/utils/validation-error.ts: -------------------------------------------------------------------------------- 1 | const ValidationErrorType = { 2 | INITIAL_CONFIG_REQUIRED: 'Must provide initial providers config', 3 | PARTNER_ID_REQUIRED: 'Must provide partner id', 4 | TARGET_ID_REQUIRED: 'Must provide target id', 5 | DOM_ELEMENT_WITH_TARGET_ID_REQUIRED: 'Must provide DOM element with id of: ', 6 | TARGET_ID_ALREADY_USED: 'The target id provided is already in use. Id: ' 7 | }; 8 | 9 | export { ValidationErrorType }; 10 | -------------------------------------------------------------------------------- /src/exported.scss: -------------------------------------------------------------------------------- 1 | @import '~@playkit-js/playkit-js-ui'; -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import '../assets/style.css'; 2 | import * as core from '@playkit-js/playkit-js'; 3 | import * as ui from '@playkit-js/playkit-js-ui'; 4 | import * as providers from '@playkit-js/playkit-js-providers/ovp-provider'; 5 | // Import media source adapters 6 | import '@playkit-js/playkit-js-hls'; 7 | import '@playkit-js/playkit-js-dash'; 8 | 9 | import { getPlayers, getPlayer } from './proxy'; 10 | import { KalturaPlayer } from './kaltura-player'; 11 | import { setup } from './setup'; 12 | import { cast } from './common/cast'; 13 | import { playlist } from './common/playlist'; 14 | import { KALTURA_PLAYER_START_TIME_QS } from './common/utils/setup-helpers'; 15 | import { Ad, AdBreak } from './common/ads'; 16 | import { BasePlugin, registerPlugin } from './common/plugins'; 17 | import SessionStorageManager from './common/storage/session-storage-manager'; 18 | import LocalStorageManager from './common/storage/local-storage-manager'; 19 | 20 | core['Ad'] = Ad; 21 | core['AdBreak'] = AdBreak; 22 | core['BasePlugin'] = BasePlugin; 23 | core['registerPlugin'] = registerPlugin; 24 | 25 | const PLAYER_NAME = __NAME__; 26 | const PLAYER_TYPE = __PLAYER_TYPE__; 27 | const VERSION = __VERSION__; 28 | 29 | export * from './types'; 30 | 31 | export { 32 | KalturaPlayer, 33 | getPlayers, 34 | getPlayer, 35 | core, 36 | ui, 37 | providers, 38 | setup, 39 | cast, 40 | playlist, 41 | Ad, 42 | AdBreak, 43 | BasePlugin, 44 | registerPlugin, 45 | PLAYER_TYPE, 46 | VERSION, 47 | PLAYER_NAME, 48 | KALTURA_PLAYER_START_TIME_QS, 49 | LocalStorageManager, 50 | SessionStorageManager 51 | }; 52 | -------------------------------------------------------------------------------- /src/ott/player-defaults.ts: -------------------------------------------------------------------------------- 1 | import { Utils } from '@playkit-js/playkit-js'; 2 | import { getRedirectExternalStreamsHandler } from '../common/utils/external-stream-redirect-helper'; 3 | import { KalturaPlayerConfig } from '../types'; 4 | 5 | /** 6 | * Sets the default analytics plugin for the ott player. 7 | * @param {KPOptionsObject} options - The player config. 8 | * @private 9 | * @returns {void} 10 | */ 11 | export function setDefaultAnalyticsPlugin(options: KalturaPlayerConfig): void { 12 | const kavaPlugin = Utils.Object.getPropertyPath(options, 'plugins.kava'); 13 | if (!kavaPlugin) { 14 | Utils.Object.mergeDeep(options, { 15 | plugins: { 16 | kava: { 17 | disable: true 18 | } 19 | } 20 | }); 21 | } 22 | const ottAnalyticsPlugin = Utils.Object.getPropertyPath(options, 'plugins.ottAnalytics'); 23 | if (!ottAnalyticsPlugin) { 24 | Utils.Object.mergeDeep(options, { 25 | plugins: { 26 | ottAnalytics: {} 27 | } 28 | }); 29 | } 30 | } 31 | 32 | /** 33 | * get the default config for forcing external stream redirect. 34 | * @public 35 | * @param {KPOptionsObject} playerOptions - The player config. 36 | * @param {KPOptionsObject} mediaOptions - The media config. 37 | * @returns {Object} - config object 38 | */ 39 | export function getDefaultRedirectOptions(playerOptions: KalturaPlayerConfig, mediaOptions: KalturaPlayerConfig | any = {}): any { 40 | return Utils.Object.mergeDeep({}, getRedirectExternalStreamsHandler(playerOptions, mediaOptions)); 41 | } 42 | -------------------------------------------------------------------------------- /src/ott/plugins/plugins-config-store.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfigStore, templateRegex } from '../../common/plugins/plugins-config-store'; 2 | 3 | import { Utils } from '@playkit-js/playkit-js'; 4 | 5 | class PluginConfigStore extends BasePluginConfigStore { 6 | private _ottPluginsConfig: { [pluginName: string]: any } = { 7 | kava: { 8 | ks: '' 9 | } 10 | }; 11 | 12 | constructor() { 13 | super(); 14 | 15 | this._config = Utils.Object.mergeDeep({}, this._basePluginsConfig, this._ottPluginsConfig); 16 | } 17 | } 18 | 19 | export { PluginConfigStore, templateRegex }; 20 | -------------------------------------------------------------------------------- /src/ovp/player-defaults.ts: -------------------------------------------------------------------------------- 1 | import { Env, Utils, MediaType } from '@playkit-js/playkit-js'; 2 | import { getRedirectExternalStreamsHandler } from '../common/utils/external-stream-redirect-helper'; 3 | import { KalturaPlayerConfig } from '../types'; 4 | 5 | /** 6 | * Sets the default analytics plugin for the ovp player. 7 | * @param {KalturaPlayerConfig} options - The player config. 8 | * @private 9 | * @returns {void} 10 | */ 11 | export function setDefaultAnalyticsPlugin(options: KalturaPlayerConfig): void { 12 | let kavaPlugin = Utils.Object.getPropertyPath(options, 'plugins.kava'); 13 | if (!kavaPlugin) { 14 | kavaPlugin = Utils.Object.mergeDeep(options, { 15 | plugins: { 16 | kava: {} 17 | } 18 | }); 19 | } 20 | } 21 | 22 | /** 23 | * get the default config for forcing external stream redirect. 24 | * @public 25 | * @param {KalturaPlayerConfig} playerOptions - The player config. 26 | * @param {KalturaPlayerConfig} mediaOptions - The media config. 27 | * @returns {Object} - config object 28 | */ 29 | export function getDefaultRedirectOptions(playerOptions: Partial, mediaOptions?: KalturaPlayerConfig): any { 30 | const configObj = {}; 31 | if (mediaOptions?.sources?.type === MediaType.LIVE && (Env.browser.name === 'IE' || Env.device.model === 'Chromecast')) { 32 | const playerForceRedirectExternalStreams = Utils.Object.getPropertyPath(playerOptions, 'sources.options.forceRedirectExternalStreams'); 33 | const mediaForceRedirectExternalStreams = Utils.Object.getPropertyPath(mediaOptions, 'sources.options.forceRedirectExternalStreams'); 34 | if (typeof playerForceRedirectExternalStreams !== 'boolean' && typeof mediaForceRedirectExternalStreams !== 'boolean') { 35 | Utils.Object.mergeDeep(configObj, { 36 | sources: { 37 | options: { 38 | forceRedirectExternalStreams: true 39 | } 40 | } 41 | }); 42 | } 43 | } 44 | return Utils.Object.mergeDeep(configObj, getRedirectExternalStreamsHandler(playerOptions, mediaOptions)); 45 | } 46 | -------------------------------------------------------------------------------- /src/ovp/plugins/plugins-config-store.ts: -------------------------------------------------------------------------------- 1 | import { BasePluginConfigStore, templateRegex } from '../../common/plugins/plugins-config-store'; 2 | 3 | import { Utils } from '@playkit-js/playkit-js'; 4 | 5 | class PluginConfigStore extends BasePluginConfigStore { 6 | private _ovpPluginsConfig: { [pluginName: string]: any } = { 7 | ottAnalytics: {} 8 | }; 9 | 10 | constructor() { 11 | super(); 12 | 13 | this._config = Utils.Object.mergeDeep({}, this._basePluginsConfig, this._ovpPluginsConfig); 14 | } 15 | } 16 | 17 | export { PluginConfigStore, templateRegex }; 18 | -------------------------------------------------------------------------------- /src/ovp/poster.ts: -------------------------------------------------------------------------------- 1 | import { THUMBNAIL_REGEX } from '../common/thumbnail-manager'; 2 | import { PKDimensionsConfig, PKSourcesConfigObject } from '@playkit-js/playkit-js'; 3 | import { ProviderMediaConfigSourcesObject } from '@playkit-js/playkit-js-providers/types'; 4 | 5 | /** 6 | * Add poster with player dimensions to thumbnail API call 7 | * @param {PKSourcesConfigObject} playerSources - player sources container 8 | * @param {ProviderMediaConfigSourcesObject} mediaSources - media config sources container 9 | * @param {Object} dimensions - player dimensions object 10 | * @param {string} ks - ks 11 | * @private 12 | * @returns {void} 13 | */ 14 | function addKalturaPoster( 15 | playerSources: PKSourcesConfigObject, 16 | mediaSources: ProviderMediaConfigSourcesObject, 17 | dimensions: PKDimensionsConfig, 18 | ks?: string 19 | ): void { 20 | const playerPoster = playerSources.poster; 21 | const mediaConfigPoster = mediaSources.poster; 22 | const playerWidth = dimensions.width; 23 | const playerHeight = dimensions.height; 24 | const rawThumbnailUrl = mediaSources.rawThumbnailUrl; 25 | if ( 26 | typeof playerPoster === 'string' && 27 | THUMBNAIL_REGEX.test(playerPoster) && 28 | playerPoster === mediaConfigPoster && 29 | typeof rawThumbnailUrl === 'string' 30 | ) { 31 | playerSources.poster = `${rawThumbnailUrl}/height/${playerHeight}/width/${playerWidth}${ks ? `/ks/${ks}` : ''}`; 32 | } 33 | mediaSources.poster = playerSources.poster || ''; 34 | } 35 | 36 | export { addKalturaPoster }; 37 | -------------------------------------------------------------------------------- /src/proxy.ts: -------------------------------------------------------------------------------- 1 | import { KalturaPlayer } from './kaltura-player'; 2 | import { FakeEventTarget } from '@playkit-js/playkit-js'; 3 | 4 | const Players = {}; 5 | /** 6 | * get all instantiated players 7 | * @returns {KalturaPlayers} - map of player ids and their respective instantiated player 8 | */ 9 | function getPlayers(): Record { 10 | return Players; 11 | } 12 | 13 | /** 14 | * get a player instance by id 15 | * @param {string} id - the player ID 16 | * @returns {KalturaPlayer | null} - the player if found by the supplied ID or null if key doesn't exist 17 | */ 18 | function getPlayer(id: string): KalturaPlayer | null { 19 | if (Players[id]) { 20 | return Players[id]; 21 | } 22 | return null; 23 | } 24 | 25 | const proxyIgnoredProps: string[] = ['_remotePlayer', '_listeners', '_uiWrapper']; 26 | const proxyHandler: any = { 27 | get(kp: KalturaPlayer, prop: string) { 28 | if (prop === 'destroy') { 29 | const playerId = kp.config.targetId; 30 | delete Players[playerId]; 31 | } 32 | 33 | if (prop in FakeEventTarget.prototype || proxyIgnoredProps.includes(prop)) { 34 | return kp[prop]; 35 | } 36 | if (kp._remotePlayer && prop in kp._remotePlayer) { 37 | return kp._remotePlayer[prop]; 38 | } 39 | return kp[prop]; 40 | }, 41 | set(kp: KalturaPlayer, prop: string, value: any) { 42 | if (kp._remotePlayer && !proxyIgnoredProps.includes(prop)) { 43 | if (prop in kp._remotePlayer) { 44 | kp._remotePlayer[prop] = value; 45 | } 46 | } else { 47 | kp[prop] = value; 48 | } 49 | return true; 50 | } 51 | }; 52 | 53 | const getPlayerProxy = (options: any): KalturaPlayer => { 54 | const player = new KalturaPlayer(options); 55 | const proxy = new Proxy(player, proxyHandler); 56 | Players[options.targetId] = proxy; 57 | return proxy; 58 | }; 59 | 60 | export { getPlayerProxy, getPlayer, getPlayers }; 61 | -------------------------------------------------------------------------------- /src/setup.ts: -------------------------------------------------------------------------------- 1 | import { KalturaPlayer } from './kaltura-player'; 2 | import { getPlayerProxy } from './proxy'; 3 | import { 4 | applyCastSupport, 5 | applyStorageSupport, 6 | attachToFirstClick, 7 | getDefaultOptions, 8 | maybeApplyStartTimeQueryParam, 9 | maybeApplyEndTimeQueryParam, 10 | maybeApplyClipQueryParams, 11 | printKalturaPlayerVersionToLog, 12 | printSetupMessages, 13 | initializeStorageManagers, 14 | setLogOptions, 15 | setStorageConfig, 16 | setStorageTextStyle, 17 | supportLegacyOptions, 18 | validateConfig, 19 | validateProviderConfig, 20 | maybeLoadInitialServerResponse 21 | } from './common/utils/setup-helpers'; 22 | import { PartialKPOptionsObject } from './types'; 23 | 24 | /** 25 | * Setup the Kaltura Player. 26 | * @param {PartialKPOptionsObject|LegacyPartialKPOptionsObject} options - partial kaltura player options 27 | * @private 28 | * @returns {KalturaPlayer} - The Kaltura Player. 29 | */ 30 | function setup(options: PartialKPOptionsObject): KalturaPlayer { 31 | printKalturaPlayerVersionToLog(options); 32 | options = supportLegacyOptions(options); 33 | validateConfig(options); 34 | const defaultOptions = getDefaultOptions(options); 35 | validateProviderConfig(defaultOptions); 36 | setLogOptions(defaultOptions); 37 | maybeApplyStartTimeQueryParam(defaultOptions); 38 | maybeApplyEndTimeQueryParam(defaultOptions); 39 | maybeApplyClipQueryParams(defaultOptions); 40 | printSetupMessages(); 41 | initializeStorageManagers(); 42 | setStorageConfig(defaultOptions); 43 | const player = getPlayerProxy(defaultOptions); 44 | maybeLoadInitialServerResponse(player); 45 | setStorageTextStyle(player); 46 | applyStorageSupport(player); 47 | applyCastSupport(defaultOptions, player); 48 | attachToFirstClick(player); 49 | return player; 50 | } 51 | 52 | export { setup }; 53 | -------------------------------------------------------------------------------- /src/types/ads/ad-break-options.ts: -------------------------------------------------------------------------------- 1 | export interface PKAdBreakOptions { 2 | type?: string; 3 | position?: number; 4 | numAds?: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/ads/ad-break-types.ts: -------------------------------------------------------------------------------- 1 | export type PKAdBreakTypes = { [type: string]: string }; 2 | -------------------------------------------------------------------------------- /src/types/ads/ad-options.ts: -------------------------------------------------------------------------------- 1 | export interface PKAdOptions { 2 | system?: string; 3 | url?: string; 4 | contentType?: string; 5 | title?: string; 6 | position?: number; 7 | duration?: number; 8 | clickThroughUrl?: string; 9 | posterUrl?: string; 10 | skipOffset?: number; 11 | linear: boolean; 12 | width: number; 13 | height: number; 14 | bitrate: number; 15 | bumper: boolean; 16 | inStream?: boolean; 17 | vpaid?: boolean; 18 | streamId?: string; 19 | wrapperAdIds: Array; 20 | wrapperCreativeIds: Array; 21 | wrapperAdSystems: Array; 22 | } 23 | -------------------------------------------------------------------------------- /src/types/ads/ad-tag-types.ts: -------------------------------------------------------------------------------- 1 | export type PKAdTagTypes = { [type: string]: string }; 2 | -------------------------------------------------------------------------------- /src/types/ads/ads-controller-provider.ts: -------------------------------------------------------------------------------- 1 | import { IAdsPluginController } from './ads-plugin-controller'; 2 | 3 | export interface IAdsControllerProvider { 4 | getAdsController(): IAdsPluginController; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/ads/ads-controller.ts: -------------------------------------------------------------------------------- 1 | import { Ad, AdBreak } from '../../common/ads'; 2 | import { KPAdPod } from './advertising'; 3 | 4 | export interface IAdsController { 5 | allAdsCompleted: boolean; 6 | isAdBreak(): boolean; 7 | getAdBreaksLayout(): Array; 8 | getAdBreak(): AdBreak | undefined; 9 | getAd(): Ad | undefined; 10 | skipAd(): void; 11 | playAdNow(adPod: KPAdPod): void; 12 | } 13 | -------------------------------------------------------------------------------- /src/types/ads/ads-plugin-controller.ts: -------------------------------------------------------------------------------- 1 | import { KPAdPod } from './advertising'; 2 | 3 | export interface IAdsPluginController { 4 | skipAd(): void; 5 | playAdNow(adPod: KPAdPod): void; 6 | onPlaybackEnded(): Promise; 7 | active: boolean; 8 | done: boolean; 9 | name: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/types/ads/advertising.ts: -------------------------------------------------------------------------------- 1 | import { KPAdPrebidConfig, KPPrebidConfig } from './prebid-config'; 2 | 3 | /** 4 | * @typedef {Object} KPAdObject 5 | * @property {Array} url - List of urls, each one specifies the ad tag url that is requested from the ad server. The player will request the first url, if failed, it will request the second url and so on (aka waterfalling). 6 | * @property {Array} response - List of XMLs, each one specifies a VAST 2.0 document to be used as the ads response instead of making a request via an ad tag url. The player will use the first XML, if failed, it will use the second and so on (aka waterfalling). 7 | * @property {boolean} bumper - Specifies whether this is a bumper. 8 | * @property {KPAdPrebidConfig} prebid - Specifies whether this is a prebid ad and add the relevant config for prebid request. 9 | */ 10 | export type KPAdObject = { 11 | url?: Array; 12 | response?: Array; 13 | bumper?: boolean; 14 | prebid?: KPAdPrebidConfig; 15 | }; 16 | 17 | /** 18 | * @typedef {Array} KPAdPod 19 | */ 20 | export type KPAdPod = Array; 21 | 22 | /** 23 | * @typedef {Object} KPAdBreakObject 24 | * @property {number} position - The position, in seconds, to show the ad break. 25 | * @property {number} percentage - Alternative parameter to `position`. The position, in percentage of the media length, to show the ad break (optional). 26 | * @property {number} every - Alternative parameter to `position`. Play ad break every X seconds (optional). 27 | * @property {KPAdPod} ads - An array of ads to play (Ad pod). 28 | */ 29 | export type KPAdBreakObject = { 30 | position: number; 31 | percentage?: number; 32 | every?: number; 33 | ads: KPAdPod; 34 | }; 35 | 36 | /** 37 | * @typedef {Object} KPAdvertisingConfigObject 38 | * @property {KPPrebidConfig} prebid - The prebid config. 39 | * @property {Array} adBreaks - The ad breaks scheme. 40 | * @property {number} [playAdsAfterTime] - Only play ad breaks scheduled after this time (in seconds). This setting is strictly after - e.g. setting playAdsAfterTime to 15 will cause the player to ignore an ad break scheduled to play at 15s. 41 | * @property {boolean} [showAdBreakCuePoint] - Whether to show the ad breaks cue points. 42 | * @property {Object} [adBreakCuePointStyle] - Style options for the ad breaks cue points - See the options {@link https://github.com/kaltura/playkit-js-timeline/blob/main/docs/types.md#cuepointoptionsobject|Here}. 43 | */ 44 | export type KPAdvertisingConfigObject = { 45 | prebid?: KPPrebidConfig; 46 | adBreaks: Array; 47 | playAdsAfterTime?: number; 48 | showAdBreakCuePoint?: boolean; 49 | adBreakCuePointStyle?: Object; 50 | }; 51 | -------------------------------------------------------------------------------- /src/types/ads/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ad-break-options'; 2 | export * from './ad-break-types'; 3 | export * from './ad-options'; 4 | export * from './ad-tag-types'; 5 | export * from './ads-controller'; 6 | export * from './ads-controller-provider'; 7 | export * from './ads-plugin-controller'; 8 | export * from './advertising'; 9 | export * from './prebid-config'; 10 | -------------------------------------------------------------------------------- /src/types/ads/prebid-config.ts: -------------------------------------------------------------------------------- 1 | export interface KPAdPrebidConfig { 2 | adUnit: any; 3 | params?: Object; 4 | options?: Object; 5 | timeout: number; 6 | } 7 | 8 | export interface KPPrebidConfig extends KPAdPrebidConfig { 9 | libUrl: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/types/advertising-config.ts: -------------------------------------------------------------------------------- 1 | import { PrebidConfig } from './prebid-config'; 2 | 3 | /** 4 | * @typedef {Object} KPAdObject 5 | * @property {Array} url - List of urls; each one specifies the ad tag url that is requested from the ad server. The player will request the first url; if failed; it will request the second url and so on (aka waterfalling). 6 | * @property {Array} response - List of XMLs; each one specifies a VAST 2.0 document to be used as the ads response instead of making a request via an ad tag url. The player will use the first XML; if failed; it will use the second and so on (aka waterfalling). 7 | * @property {boolean} bumper - Specifies whether this is a bumper. 8 | * @property {PrebidConfig} prebid - Specifies whether this is a prebid ad and add the relevant config for prebid request. 9 | */ 10 | interface AdObject { 11 | url?: Array; 12 | response?: Array; 13 | bumper?: boolean; 14 | prebid?: PrebidConfig; 15 | } 16 | 17 | /** 18 | * @typedef {Object} KPAdBreakObject 19 | * @property {number} position - The position; in seconds; to show the ad break. 20 | * @property {number} percentage - Alternative parameter to `position`. The position; in percentage of the media length; to show the ad break (optional). 21 | * @property {number} every - Alternative parameter to `position`. Play ad break every X seconds (optional). 22 | * @property {AdPod} ads - An array of ads to play (Ad pod). 23 | */ 24 | interface AdBreakObject { 25 | position: number; 26 | percentage?: number; 27 | every?: number; 28 | ads: AdObject[]; 29 | } 30 | 31 | /** 32 | * @typedef {Object} KPAdvertisingConfigObject 33 | * @property {PrebidConfig} prebid - The prebid config. 34 | * @property {Array} adBreaks - The ad breaks scheme. 35 | * @property {number} [playAdsAfterTime] - Only play ad breaks scheduled after this time (in seconds). This setting is strictly after - e.g. setting playAdsAfterTime to 15 will cause the player to ignore an ad break scheduled to play at 15s. 36 | * @property {boolean} [showAdBreakCuePoint] - Whether to show the ad breaks cue points. 37 | * @property {Object} [adBreakCuePointStyle] - Style options for the ad breaks cue points - See the options {@link https://github.com/kaltura/playkit-js-timeline/blob/main/docs/types.md#cuepointoptionsobject|Here}. 38 | */ 39 | export interface AdvertisingConfig { 40 | prebid?: PrebidConfig; 41 | adBreaks: AdBreakObject[]; 42 | playAdsAfterTime?: number; 43 | showAdBreakCuePoint?: boolean; 44 | adBreakCuePointStyle?: Object; 45 | } 46 | -------------------------------------------------------------------------------- /src/types/cue-point.ts: -------------------------------------------------------------------------------- 1 | export interface CuePoint { 2 | id: string; 3 | startTime: number; 4 | endTime: number; 5 | metadata: any; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/events/event-types.ts: -------------------------------------------------------------------------------- 1 | import { PKEventTypes } from '@playkit-js/playkit-js'; 2 | import { UIEventType } from '@playkit-js/playkit-js-ui'; 3 | import { CastEventType } from '../../common/cast/cast-event-type'; 4 | import { PlaylistEventType } from '../../common/playlist/playlist-event-type'; 5 | 6 | export type KPEventTypes = { 7 | Core: PKEventTypes; 8 | UI: typeof UIEventType; 9 | Cast: typeof CastEventType; 10 | Playlist: typeof PlaylistEventType; 11 | VISIBILITY_CHANGE: 'visibilitychange'; 12 | REGISTERED_PLUGINS_LIST_EVENT: 'registeredpluginslistevent'; 13 | }; 14 | -------------------------------------------------------------------------------- /src/types/events/index.ts: -------------------------------------------------------------------------------- 1 | export * from './event-types'; 2 | -------------------------------------------------------------------------------- /src/types/exteranl-thumbnails-object.ts: -------------------------------------------------------------------------------- 1 | export interface ExternalThumbnailsConfig { 2 | vttUrl: string; 3 | } 4 | -------------------------------------------------------------------------------- /src/types/global/globals.d.ts: -------------------------------------------------------------------------------- 1 | // globals.d.ts 2 | declare var __kalturaplayerdata: any; 3 | declare var kalturaCustomPreset: any; 4 | declare var kalturaCustomPresetMap: any; 5 | declare var DEBUG_KALTURA_PLAYER: boolean; 6 | declare var __NAME__: string; 7 | declare var __VERSION__: string; 8 | declare var __PLAYER_TYPE__: string; 9 | declare var __PACKAGE_URL__: string; 10 | -------------------------------------------------------------------------------- /src/types/image-player-options.ts: -------------------------------------------------------------------------------- 1 | export interface ImageSourceOptions { 2 | thumbnailAPIParams: { [parmaName: string]: string }; 3 | } 4 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ads'; 2 | export * from './events'; 3 | export * from './playlist'; 4 | export * from './utils'; 5 | export * from './advertising-config'; 6 | export * from './cue-point'; 7 | export * from './exteranl-thumbnails-object'; 8 | export * from './image-player-options'; 9 | export * from './kaltura-player-options'; 10 | export * from './log-level'; 11 | export * from './media-config'; 12 | export * from './media-source-options'; 13 | export * from './media-capabilities'; 14 | export * from './network-config'; 15 | export * from './playback-config'; 16 | export * from './playlist-object'; 17 | export * from './plugins'; 18 | export * from './prebid-config'; 19 | export * from './sources-config'; 20 | export * from './thumbnail-config'; 21 | export * from './ui-config'; 22 | export * from './visibility-config'; 23 | -------------------------------------------------------------------------------- /src/types/kaltura-player-options.ts: -------------------------------------------------------------------------------- 1 | import { LogConfig } from './log-level'; 2 | import { PlaybackConfig } from './playback-config'; 3 | import { AdvertisingConfig } from './advertising-config'; 4 | import { PlaylistConfig } from './playlist-object'; 5 | import { UiConfig } from './ui-config'; 6 | import { ViewabilityConfig } from './visibility-config'; 7 | import { NetworkConfig } from './network-config'; 8 | import { PluginsConfig } from './plugins'; 9 | 10 | import { 11 | PKAbrConfigObject, 12 | PKDimensionsConfig, 13 | PKSessionConfigObject, 14 | PKSourcesConfigObject, 15 | PKTextConfigObject 16 | } from '@playkit-js/playkit-js'; 17 | import { ProviderOptionsObject } from "@playkit-js/playkit-js-providers/types"; 18 | 19 | export interface KalturaPlayerConfig { 20 | targetId: string; 21 | log?: LogConfig; 22 | disableUserCache?: boolean; 23 | text?: PKTextConfigObject; 24 | playback: PlaybackConfig; 25 | sources: PKSourcesConfigObject; 26 | plugins: PluginsConfig; 27 | advertising: AdvertisingConfig; 28 | session?: PKSessionConfigObject; 29 | provider: ProviderOptionsObject; 30 | playlist?: PlaylistConfig; 31 | dimensions?: PKDimensionsConfig; 32 | ui: UiConfig; 33 | cast?: { [key: string]: any }; 34 | productVersion?: string; 35 | viewability: ViewabilityConfig; 36 | network?: NetworkConfig; 37 | abr?: PKAbrConfigObject; 38 | uiConfData?: UIConfDataObject; 39 | } 40 | 41 | export type PartialKPOptionsObject = Omit< 42 | KalturaPlayerConfig, 43 | 'productVersion' 44 | >; 45 | 46 | export interface LegacyPartialKPOptionsObject { 47 | targetId: string; 48 | logLevel?: string; 49 | disableUserCache?: boolean; 50 | // TODO - fix 51 | // player?: PKPlayerOptionsObject; 52 | player?: any; 53 | provider: ProviderOptionsObject; 54 | ui?: UiConfig; 55 | } 56 | 57 | export interface UIConfDataObject { 58 | width?: string; 59 | height?: string; 60 | name?: string; 61 | } 62 | -------------------------------------------------------------------------------- /src/types/log-level.ts: -------------------------------------------------------------------------------- 1 | export interface LogConfig { 2 | playerVersion?: boolean; 3 | level: string; 4 | handler?: (messages: any[], context: Object) => void; 5 | useDebugInfo?: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /src/types/media-capabilities.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {Object} HEVCConfigObject 3 | * @property {number} width - Optional width of the video 4 | * @property {number} height - Optional height of the video 5 | * @property {number} bitrate - Optional number of bits used to encode a second of video 6 | * @property {number} framerate - Optional number of frames used in one second 7 | */ 8 | export type HEVCConfigObject = { 9 | width?: number; 10 | height?: number; 11 | bitrate?: number; 12 | framerate?: number; 13 | }; 14 | 15 | /** 16 | * @typedef {Object} HEVCSupportedObject 17 | * @property {number} isHEVCSupported - Specifies HEVC supported option by the browser 18 | * @property {number} isPowerEfficient - Specifies power efficiency supported option 19 | */ 20 | export type HEVCSupportedObject = { 21 | isHEVCSupported: number; 22 | isPowerEfficient: number; 23 | }; 24 | 25 | /** 26 | * @typedef {Object} DRMSupportedObject 27 | * @property {number} isDRMSupported - Specifies DRM supported option by the browser 28 | * @property {Array} supportedDRMs - List of supported DRMs (optional values: widevine; playready; fairplay) 29 | */ 30 | export type DRMSupportedObject = { 31 | isDRMSupported: number; 32 | supportedDRMs: Array; 33 | }; 34 | 35 | /** 36 | * @typedef {Object} MediaCapabilitiesObject 37 | */ 38 | export type MediaCapabilitiesObject = HEVCSupportedObject & DRMSupportedObject; 39 | 40 | /** 41 | * @typedef {Object.} SupportedOptionsType 42 | */ 43 | export type SupportedOptionsType = { [supportedOption: string]: number }; 44 | -------------------------------------------------------------------------------- /src/types/media-config.ts: -------------------------------------------------------------------------------- 1 | import { PlaybackConfig } from './playback-config'; 2 | import { ProviderMediaConfigSourcesObject, ProviderMediaConfigSessionObject } from "@playkit-js/playkit-js-providers/types"; 3 | 4 | 5 | /** 6 | * @typedef {Object} KPMediaConfig 7 | * @property {ProviderMediaConfigSourcesObject} sources 8 | * @property {ProviderMediaConfigSessionObject} session 9 | * @property {{[plugin: string]: Object}} plugins 10 | */ 11 | export interface KPMediaConfig extends PlaybackConfig { 12 | sources: ProviderMediaConfigSourcesObject; 13 | session?: ProviderMediaConfigSessionObject; 14 | plugins?: { [plugin: string]: Object }; 15 | } 16 | -------------------------------------------------------------------------------- /src/types/media-source-options.ts: -------------------------------------------------------------------------------- 1 | export interface MediaSourceOptionsObject { 2 | forceRedirectExternalStreams: boolean; 3 | redirectExternalStreamsHandler: () => void | undefined; 4 | redirectExternalStreamsTimeout: number | undefined; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/network-config.ts: -------------------------------------------------------------------------------- 1 | export interface NetworkConfig { 2 | requestFilter?: () => void; 3 | responseFilter?: () => void; 4 | maxStaleLevelReloads: number; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/playback-config.ts: -------------------------------------------------------------------------------- 1 | import { PKPlaybackConfigObject } from '@playkit-js/playkit-js'; 2 | 3 | export interface PlaybackConfig extends PKPlaybackConfigObject { 4 | autopause: boolean; 5 | loop: boolean; 6 | enableCachedUrls: boolean; 7 | } 8 | -------------------------------------------------------------------------------- /src/types/playlist-object.ts: -------------------------------------------------------------------------------- 1 | import { PlaylistOptions } from './playlist'; 2 | import { PlaylistCountdownOptions } from './playlist'; 3 | import { PlaylistItem } from '../common/playlist/playlist-item'; 4 | import { ProviderPlaylistMetadataObject } from "@playkit-js/playkit-js-providers/types"; 5 | 6 | export interface PlaylistConfig { 7 | id: string; 8 | metadata: ProviderPlaylistMetadataObject; 9 | poster?: string; 10 | options?: PlaylistOptions; 11 | countdown?: PlaylistCountdownOptions; 12 | items: Array; 13 | } 14 | -------------------------------------------------------------------------------- /src/types/playlist/KPPlaylistObject.ts: -------------------------------------------------------------------------------- 1 | import { PlaylistItem } from '../../common/playlist/playlist-item'; 2 | import { PlaylistConfigObject } from './playlist-config-object'; 3 | import { ProviderPlaylistMetadataObject } from "@playkit-js/playkit-js-providers/types"; 4 | 5 | /** 6 | * @typedef {Object} KPPlaylistObject 7 | * @property {string} id - This is playlist's ID. 8 | * @property {ProviderPlaylistMetadataObject} metadata - This is the playlist metadata. 9 | * @property {KPPlaylistOptions} options - These are the playlist options. 10 | * @property {KPPlaylistCountdownOptions} countdown - This is the playlist countdown configuration. 11 | * @property {Array} items - These are the playlist items. 12 | */ 13 | export interface KPPlaylistObject extends PlaylistConfigObject { 14 | id?: string; 15 | metadata?: ProviderPlaylistMetadataObject; 16 | poster?: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/types/playlist/index.ts: -------------------------------------------------------------------------------- 1 | export * from './KPPlaylistObject'; 2 | export * from './playlis-countdown-options'; 3 | export * from './playlist-config-object'; 4 | export * from './playlist-item-config'; 5 | export * from './playlist-options'; 6 | -------------------------------------------------------------------------------- /src/types/playlist/playlis-countdown-options.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {Object} KPPlaylistCountdownOptions 3 | * @property {number} [timeToShow] - Shows when the countdown is scheduled to appear (by default, this is towards the end). 4 | * @property {number} [duration=10] - Shows for how long the countdown will appear. 5 | * @property {boolean} [showing=true] - Determines whether to show the countdown. 6 | */ 7 | export interface PlaylistCountdownOptions { 8 | timeToShow?: number; 9 | duration: number; 10 | showing: boolean; 11 | } 12 | -------------------------------------------------------------------------------- /src/types/playlist/playlist-config-object.ts: -------------------------------------------------------------------------------- 1 | import { PlaylistOptions } from './playlist-options'; 2 | import { PlaylistCountdownOptions } from './playlis-countdown-options'; 3 | import { PlaylistItem } from '../../common/playlist/playlist-item'; 4 | 5 | export interface PlaylistConfigObject { 6 | options?: PlaylistOptions; 7 | countdown?: PlaylistCountdownOptions; 8 | items: Array; 9 | } 10 | -------------------------------------------------------------------------------- /src/types/playlist/playlist-item-config.ts: -------------------------------------------------------------------------------- 1 | import { PlaylistCountdownOptions } from './playlis-countdown-options'; 2 | /** 3 | * @typedef {Object} KPPlaylistItemConfigObject 4 | * @property {KPPlaylistCountdownOptions} [countdown] - Countdown options 5 | */ 6 | export type KPPlaylistItemConfigObject = { 7 | countdown?: PlaylistCountdownOptions; 8 | }; 9 | -------------------------------------------------------------------------------- /src/types/playlist/playlist-options.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @typedef {Object} KPPlaylistOptions 3 | * @property {boolean} [autoContinue=true] - Determines whether to continue to the next item automatically. 4 | * @property {boolean} [loop=false] - Determines whether to play the playlist in a loop. When selected, the playlist will play automatically even if autoContinue is set to false. 5 | * @property {string} [startAtEntryId] - Determines which entry id to start to the play the playlist from. 6 | */ 7 | export interface PlaylistOptions { 8 | autoContinue: boolean; 9 | loop: boolean; 10 | imageDuration: number; 11 | documentDuration: number; 12 | startAtEntryId?: string; 13 | } 14 | -------------------------------------------------------------------------------- /src/types/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export * from './plugins-config'; 2 | export * from './plugin-class-type'; 3 | -------------------------------------------------------------------------------- /src/types/plugins/plugin-class-type.ts: -------------------------------------------------------------------------------- 1 | import { KalturaPlayer } from "../../kaltura-player"; 2 | import { BasePlugin } from "../../common/plugins"; 3 | 4 | export interface PluginClassType { 5 | new (name: string, player: KalturaPlayer, config?: any): BasePlugin; 6 | defaultConfig: any; 7 | isValid: () => boolean; 8 | } 9 | -------------------------------------------------------------------------------- /src/types/plugins/plugins-config.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../common/plugins'; 2 | 3 | export interface PluginsConfig { 4 | [plugin: string]: BasePlugin; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/prebid-config.ts: -------------------------------------------------------------------------------- 1 | export interface AdPrebidConfig { 2 | adUnit: Object; 3 | params?: Object; 4 | options?: Object; 5 | timeout: number; 6 | } 7 | 8 | export interface PrebidConfig extends AdPrebidConfig { 9 | libUrl: string; 10 | } 11 | -------------------------------------------------------------------------------- /src/types/sources-config.ts: -------------------------------------------------------------------------------- 1 | import { ExternalThumbnailsConfig } from './exteranl-thumbnails-object'; 2 | import { MediaSourceOptionsObject } from './media-source-options'; 3 | import { ImageSourceOptions } from './image-player-options'; 4 | import { ProviderMediaConfigSourcesObject } from "@playkit-js/playkit-js-providers/types"; 5 | 6 | export interface SourcesConfig 7 | extends Omit { 8 | thumbnails?: ExternalThumbnailsConfig; 9 | options: MediaSourceOptionsObject; 10 | startTime: number; 11 | imageSourceOptions?: ImageSourceOptions; 12 | poster?: string; 13 | } 14 | -------------------------------------------------------------------------------- /src/types/thumbnail-config.ts: -------------------------------------------------------------------------------- 1 | export type KPThumbnailConfig = { 2 | thumbsSprite: string; 3 | thumbsWidth: number; 4 | thumbsSlices: number; 5 | }; 6 | -------------------------------------------------------------------------------- /src/types/ui-config.ts: -------------------------------------------------------------------------------- 1 | import { UIOptionsObject } from '@playkit-js/playkit-js-ui'; 2 | 3 | export interface UiConfig extends UIOptionsObject { 4 | disable?: boolean; 5 | css?: string; 6 | customPreset?: { template: () => any; condition: () => any }[]; 7 | } 8 | -------------------------------------------------------------------------------- /src/types/utils/class-constructor.ts: -------------------------------------------------------------------------------- 1 | export type ClassConstructor = new (...args: any[]) => T; 2 | -------------------------------------------------------------------------------- /src/types/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './class-constructor'; 2 | -------------------------------------------------------------------------------- /src/types/visibility-config.ts: -------------------------------------------------------------------------------- 1 | export interface ViewabilityConfig { 2 | observedThresholds: Array; 3 | playerThreshold: number; 4 | } 5 | -------------------------------------------------------------------------------- /tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["plugin:mocha/recommended"], 3 | "plugins": ["mocha"], 4 | "globals": { 5 | "sinon": true, 6 | "__VERSION__": true, 7 | "__NAME__": true 8 | }, 9 | "rules": { 10 | "mocha/max-top-level-suites": "off", 11 | "mocha/no-skipped-tests": "off", 12 | "mocha/no-setup-in-describe": "off", 13 | "mocha/no-nested-tests": "off", 14 | "mocha/no-sibling-hooks": "off", 15 | "mocha/no-exclusive-tests": "error", 16 | "mocha/no-mocha-arrows": "off", 17 | "max-len": ["warn", { "code": 50000 }] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/assets/audios.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/tests/assets/audios.mp4 -------------------------------------------------------------------------------- /tests/assets/mov_bbb.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaltura/kaltura-player-js/9ac280fc45447884ecf6c7a532911335552f869b/tests/assets/mov_bbb.mp4 -------------------------------------------------------------------------------- /tests/e2e/common/cuepoints/cuepoint-manager.spec.js: -------------------------------------------------------------------------------- 1 | import { expect } from 'chai'; 2 | import SourcesConfig from '../../configs/sources.json'; 3 | import { getConfigStructure } from '../../../utils/test-utils'; 4 | import { KalturaPlayer as Player } from '../../../../src/kaltura-player'; 5 | import { CuePointManager } from '../../../../src/common/cuepoint/cuepoint-manager'; 6 | 7 | describe('CuePointManager', () => { 8 | let config, player, sandbox; 9 | 10 | before(() => { 11 | config = getConfigStructure(); 12 | }); 13 | 14 | beforeEach(() => { 15 | player = new Player(config); 16 | sandbox = sinon.createSandbox(); 17 | }); 18 | 19 | afterEach(() => { 20 | player.destroy(); 21 | sandbox.restore(); 22 | }); 23 | 24 | it('should get cue-point manager', () => { 25 | expect(player.cuePointManager).instanceOf(CuePointManager); 26 | }); 27 | 28 | it('should create and add text-track', () => { 29 | player.setMedia({ sources: SourcesConfig.Mp4 }); 30 | expect(player.cuePointManager._textTrack).to.eql(undefined); 31 | player.cuePointManager.addCuePoints([]); 32 | player.ready().then(() => { 33 | expect(player.cuePointManager._textTrack).instanceOf(TextTrack); 34 | }); 35 | }); 36 | 37 | it('should add/get/remove/clear-all cue points', () => { 38 | const cuePoints = [ 39 | { 40 | id: 'test-id-1', 41 | startTime: 1, 42 | endTime: 6 43 | }, 44 | { 45 | id: 'test-id-2', 46 | startTime: 6, 47 | endTime: 10 48 | }, 49 | { 50 | id: 'test-id-3', 51 | startTime: 10, 52 | endTime: 15 53 | } 54 | ]; 55 | player.setMedia({ sources: SourcesConfig.Mp4 }); 56 | player.ready().then(() => { 57 | expect(player.cuePointManager.getAllCuePoints().length).eql(0); 58 | player.cuePointManager.addCuePoints(cuePoints); 59 | expect(player.cuePointManager.getAllCuePoints().length).eql(3); 60 | const cuePoint = player.cuePointManager._getTextTrackCueById('test-id-1'); 61 | expect(cuePoint.id).to.eql('test-id-1'); 62 | player.cuePointManager._removeTextTrackCue(cuePoint); 63 | expect(player.cuePointManager.getAllCuePoints().length).eql(2); 64 | player.cuePointManager._clearAllTextTrackCues(); 65 | expect(player.cuePointManager.getAllCuePoints().length).eql(0); 66 | }); 67 | }); 68 | }); 69 | -------------------------------------------------------------------------------- /tests/e2e/common/plugin/base-plugin.spec.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../../../src'; 2 | 3 | describe('BasePlugin', () => { 4 | let basePlugin; 5 | const config = { x: 1, y: 2 }; 6 | 7 | beforeEach(() => { 8 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 9 | // @ts-ignore 10 | basePlugin = new BasePlugin('basePlugin', {}, config); 11 | }); 12 | 13 | afterEach(() => { 14 | basePlugin = null; 15 | }); 16 | 17 | it('should create all BasePlugin properties', () => { 18 | basePlugin.logger.should.exist; 19 | basePlugin.player.should.exist; 20 | basePlugin.name.should.exist; 21 | basePlugin.eventManager.should.exist; 22 | basePlugin.config.should.deep.equal(config); 23 | }); 24 | 25 | it('should return the plugin name', () => { 26 | basePlugin.getName().should.equal('basePlugin'); 27 | }); 28 | 29 | it('should return the plugin config', () => { 30 | basePlugin.getConfig().should.deep.equal(config); 31 | }); 32 | 33 | it('should return copy of the plugin config', () => { 34 | basePlugin.getConfig().x = 100; 35 | basePlugin.getConfig().y = 200; 36 | basePlugin.getConfig().x.should.equals(1); 37 | basePlugin.getConfig().y.should.equals(2); 38 | }); 39 | 40 | it('should return the config attribute value', () => { 41 | basePlugin.getConfig('x').should.deep.equal(1); 42 | }); 43 | 44 | it('should update the plugin config', () => { 45 | const update = { y: 'hello' }; 46 | basePlugin.updateConfig(update); 47 | basePlugin.getConfig().should.deep.equal({ x: 1, y: 'hello' }); 48 | }); 49 | 50 | it('should throw isValid() exception', () => { 51 | let exceptionOccurred = false; 52 | try { 53 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 54 | // @ts-ignore 55 | BasePlugin.isValid(); 56 | } catch (e) { 57 | e.code.should.equals(7004); 58 | e.data.should.equals('isValid()'); 59 | exceptionOccurred = true; 60 | } 61 | exceptionOccurred.should.be.true; 62 | }); 63 | 64 | it('should run super destroy()', () => { 65 | basePlugin.destroy(); 66 | }); 67 | 68 | it('should run super reset()', () => { 69 | basePlugin.reset(); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /tests/e2e/common/plugin/test-plugins/async-reject-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../../../../src'; 2 | import { Utils } from '@playkit-js/playkit-js'; 3 | import { KalturaPlayer } from '../../../../../src/kaltura-player'; 4 | import { DeferredPromise } from '../../../../../src/types/utils/deferred-promise'; 5 | 6 | export default class AsyncRejectPlugin extends BasePlugin { 7 | public static DELAY_ASYNC = 300; 8 | public static isValid(): boolean { 9 | return true; 10 | } 11 | 12 | private promise: DeferredPromise; 13 | 14 | constructor(name: string, player: KalturaPlayer, config: any) { 15 | super(name, player, config); 16 | this.promise = Utils.Object.defer(); 17 | setTimeout(() => { 18 | this.promise.reject(); 19 | }, AsyncRejectPlugin.DELAY_ASYNC); 20 | } 21 | 22 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 23 | // @ts-ignore 24 | public get ready(): Promise { 25 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 26 | // @ts-ignore 27 | return this.promise; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/e2e/common/plugin/test-plugins/async-resolve-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../../../../src'; 2 | import { Utils } from '@playkit-js/playkit-js'; 3 | import { DeferredPromise } from '../../../../../src/types/utils/deferred-promise'; 4 | import { KalturaPlayer } from '../../../../../src/kaltura-player'; 5 | 6 | export default class AsyncResolvePlugin extends BasePlugin { 7 | public static DELAY_ASYNC = 500; 8 | public static isValid(): boolean { 9 | return true; 10 | } 11 | private promise: DeferredPromise; 12 | 13 | constructor(name: string, player: KalturaPlayer, config: any) { 14 | super(name, player, config); 15 | this.promise = Utils.Object.defer(); 16 | setTimeout(() => { 17 | this.promise.resolve(); 18 | }, AsyncResolvePlugin.DELAY_ASYNC); 19 | } 20 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 21 | // @ts-ignore 22 | public get ready(): Promise { 23 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 24 | // @ts-ignore 25 | return this.promise; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tests/e2e/common/plugin/test-plugins/colors-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../../../../src'; 2 | import { KalturaPlayer as Player } from '../../../../../src/kaltura-player'; 3 | 4 | export default class ColorsPlugin extends BasePlugin { 5 | private _favouriteColor: string = ''; 6 | private _size: number = 0; 7 | private _colors: Array = []; 8 | 9 | public static defaultConfig: any = { 10 | size: 3, 11 | favouriteColor: 'green' 12 | }; 13 | 14 | public static isValid(): boolean { 15 | return true; 16 | } 17 | 18 | constructor(name: string, player: Player, config: any) { 19 | super(name, player, config); 20 | this._configure(); 21 | this._setup(); 22 | } 23 | 24 | private _configure(): void { 25 | this._size = this.config.size; 26 | this._favouriteColor = this.config.favouriteColor; 27 | this.logger.info('_configure', this.config); 28 | } 29 | 30 | private _setup(): void { 31 | this._colors = [this._favouriteColor, 'blue', 'pink']; 32 | this.logger.info('_setup', this._colors); 33 | } 34 | 35 | public destroy(): void { 36 | this._colors = []; 37 | this._favouriteColor = ''; 38 | this._size = 0; 39 | this.logger.info('destroy', this._colors, this._favouriteColor, this._size); 40 | } 41 | 42 | public reset(): void { 43 | this._colors = ['pink']; 44 | this._size = 1; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /tests/e2e/common/plugin/test-plugins/numbers-plugin.ts: -------------------------------------------------------------------------------- 1 | import { BasePlugin } from '../../../../../src'; 2 | import { KalturaPlayer as Player } from '../../../../../src/kaltura-player'; 3 | 4 | export default class NumbersPlugin extends BasePlugin { 5 | private _firstCellValue: number = 0; 6 | private _lastCellValue: number = 0; 7 | private _size: number = 0; 8 | private _numbers: Array = []; 9 | 10 | protected static defaultConfig: any = { 11 | size: 10, 12 | firstCellValue: 4, 13 | lastCellValue: 6 14 | }; 15 | 16 | public static isValid(): boolean { 17 | return true; 18 | } 19 | 20 | constructor(name: string, player: Player, config: any) { 21 | super(name, player, config); 22 | this._configure(); 23 | this._setup(); 24 | } 25 | 26 | private _configure(): void { 27 | this._size = this.config.size; 28 | this._firstCellValue = this.config.firstCellValue; 29 | this._lastCellValue = this.config.lastCellValue; 30 | this.logger.info('_configure', this.config); 31 | } 32 | 33 | private _setup(): void { 34 | this._numbers[0] = this._firstCellValue; 35 | for (let i = 1; i < this._size - 1; i++) { 36 | this._numbers[i] = (i * i) / 2; 37 | } 38 | this._numbers[this._size - 1] = this._lastCellValue; 39 | this.logger.info('_setup', this._numbers); 40 | } 41 | 42 | public destroy(): void { 43 | this._numbers = []; 44 | this._firstCellValue = 0; 45 | this._lastCellValue = 0; 46 | this._size = 0; 47 | this.logger.info('destroy', this._numbers, this._firstCellValue, this._lastCellValue, this._size); 48 | } 49 | 50 | public reset(): void { 51 | this._numbers = [1, 2, 3]; 52 | this._size = 3; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /tests/e2e/common/service-provider.spec.ts: -------------------------------------------------------------------------------- 1 | import { ServiceProvider } from '../../../src/common/service-provider'; 2 | import { KalturaPlayer } from '../../../src/kaltura-player'; 3 | 4 | describe('ServiceProvider', () => { 5 | const fakePlayer: KalturaPlayer = { 6 | addEventListener: (): void => {}, 7 | removeEventListener: (): void => {}, 8 | Event: { 9 | Core: { 10 | PLAYER_RESET: 'playerreset' 11 | } 12 | } 13 | } as KalturaPlayer; 14 | let serviceProvider; 15 | beforeEach(() => { 16 | serviceProvider = new ServiceProvider(fakePlayer); 17 | }); 18 | afterEach(() => { 19 | serviceProvider.destroy(); 20 | }); 21 | 22 | it('should register custom service', () => { 23 | serviceProvider.has('custom').should.be.false; 24 | serviceProvider.register('custom', { key: 1 }); 25 | serviceProvider.has('custom').should.be.true; 26 | serviceProvider.get('custom').key.should.equals(1); 27 | }); 28 | 29 | it('should not register custom service if already registered', () => { 30 | serviceProvider.register('custom', { key: 1 }); 31 | serviceProvider.register('custom', { key: 2 }); 32 | serviceProvider.get('custom').key.should.equals(1); 33 | }); 34 | 35 | it('should call to service destroy on player destroy', (done) => { 36 | serviceProvider.register('custom', { destroy: () => done() }); 37 | serviceProvider.destroy(); 38 | }); 39 | }); 40 | -------------------------------------------------------------------------------- /tests/e2e/common/storage/storage-wrapper.spec.js: -------------------------------------------------------------------------------- 1 | import StorageWrapper from '../../../../src/common/storage/storage-wrapper'; 2 | 3 | const STORAGE_PREFIX = __NAME__ + '_'; 4 | 5 | describe('StorageWrapper', () => { 6 | describe('LocalStorage', () => { 7 | afterEach(() => { 8 | window.localStorage.clear(); 9 | }); 10 | 11 | it('should have size of 0', () => { 12 | StorageWrapper.getStorageSize(window.localStorage).should.equal(0); 13 | }); 14 | 15 | it('should set an item in the local storage', () => { 16 | if (StorageWrapper.isStorageAvailable(window.localStorage)) { 17 | const key = 'test'; 18 | StorageWrapper.setItem(key, 1, window.localStorage); 19 | StorageWrapper.getStorageSize(window.localStorage).should.equal(1); 20 | window.localStorage[STORAGE_PREFIX + key].should.exist; 21 | window.localStorage[STORAGE_PREFIX + key].should.equal('1'); 22 | } 23 | }); 24 | 25 | it('should get an item from the local storage', () => { 26 | if (StorageWrapper.isStorageAvailable(window.localStorage)) { 27 | const key = 'test'; 28 | StorageWrapper.setItem(key, 2, window.localStorage); 29 | StorageWrapper.getStorageSize(window.localStorage).should.equal(1); 30 | const value = StorageWrapper.getItem(key, window.localStorage); 31 | value.should.equal(2); 32 | } 33 | }); 34 | 35 | it('should validate a wrong key', (done) => { 36 | try { 37 | StorageWrapper.setItem(2, 2, window.localStorage); 38 | } catch (e) { 39 | done(); 40 | } 41 | }); 42 | }); 43 | 44 | describe('SessionStorage', () => { 45 | afterEach(() => { 46 | window.sessionStorage.clear(); 47 | }); 48 | 49 | it('should have size of 0', () => { 50 | StorageWrapper.getStorageSize(window.sessionStorage).should.equal(0); 51 | }); 52 | 53 | it('should set an item in the session storage', () => { 54 | if (StorageWrapper.isStorageAvailable(window.sessionStorage)) { 55 | const key = 'test'; 56 | StorageWrapper.setItem(key, 1, window.sessionStorage); 57 | StorageWrapper.getStorageSize(window.sessionStorage).should.equal(1); 58 | window.sessionStorage[STORAGE_PREFIX + key].should.exist; 59 | window.sessionStorage[STORAGE_PREFIX + key].should.equal('1'); 60 | } 61 | }); 62 | 63 | it('should get an item from the session storage', () => { 64 | if (StorageWrapper.isStorageAvailable(window.sessionStorage)) { 65 | const key = 'test'; 66 | StorageWrapper.setItem(key, 2, window.sessionStorage); 67 | StorageWrapper.getStorageSize(window.sessionStorage).should.equal(1); 68 | const value = StorageWrapper.getItem(key, window.sessionStorage); 69 | value.should.equal(2); 70 | } 71 | }); 72 | }); 73 | }); 74 | -------------------------------------------------------------------------------- /tests/e2e/common/utils/evaluate.spec.js: -------------------------------------------------------------------------------- 1 | import evaluate from '../../../../src/common/utils/evaluate'; 2 | 3 | describe('evaluate', () => { 4 | const dataObject = { 5 | a: { 6 | a1: '{{token1}}', 7 | a2: '{{token2}}' 8 | }, 9 | b: { 10 | b1: '{{token3}}', 11 | b2: '{{token4}}' 12 | } 13 | }; 14 | const template = JSON.stringify(dataObject); 15 | const model = { token1: 1, token2: 2 }; 16 | const modelWithDoubleQuotes = { 17 | token1: 'my expression with "double quotes"', 18 | token2: 2 19 | }; 20 | 21 | it('should evaluate and replace template tokens which have model values', () => { 22 | const evaluatedTemplate = evaluate(template, model); 23 | const evaluatedDataObj = JSON.parse(evaluatedTemplate); 24 | evaluatedDataObj.a.a1.should.be.equal('1'); 25 | evaluatedDataObj.a.a2.should.be.equal('2'); 26 | }); 27 | 28 | it("should evaluate and not replace template tokens which don't have model values", () => { 29 | const evaluatedTemplate = evaluate(template, model); 30 | const evaluatedDataObj = JSON.parse(evaluatedTemplate); 31 | evaluatedDataObj.b.b1.should.be.equal('{{token3}}'); 32 | evaluatedDataObj.b.b2.should.be.equal('{{token4}}'); 33 | }); 34 | 35 | it('should escape model values which have double quotes', () => { 36 | const evaluatedTemplate = evaluate(template, modelWithDoubleQuotes); 37 | const evaluatedDataObj = JSON.parse(evaluatedTemplate); 38 | evaluatedDataObj.a.a1.should.be.equal('my expression with "double quotes"'); 39 | evaluatedDataObj.a.a2.should.be.equal('2'); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /tests/e2e/common/utils/viewability-manager.spec.ts: -------------------------------------------------------------------------------- 1 | import * as TestUtils from '../../../utils/test-utils'; 2 | import { ViewabilityManager, ViewabilityType } from '../../../../src/common/utils/viewability-manager'; 3 | 4 | describe('ViewabilityManager', () => { 5 | const targetId = 'ViewabilityManagerSpecDiv'; 6 | let viewabilityManager; 7 | 8 | before(() => { 9 | TestUtils.createElement('DIV', targetId); 10 | }); 11 | 12 | afterEach(() => { 13 | viewabilityManager.destroy(); 14 | }); 15 | 16 | after(() => { 17 | TestUtils.removeElement(targetId); 18 | }); 19 | 20 | it('should create a viewability manager with an empty config and observe a div', (done) => { 21 | viewabilityManager = new ViewabilityManager(); 22 | const handleVisibility = function (): any { 23 | done(); 24 | }; 25 | viewabilityManager.observe(document.getElementById(targetId), handleVisibility); 26 | }); 27 | 28 | it('should create a viewability manager with a given config and observe a div', (done) => { 29 | const viewabilityConfig = { 30 | observedThresholds: [10, 30], 31 | playerThreshold: 20 32 | }; 33 | viewabilityManager = new ViewabilityManager(viewabilityConfig); 34 | const handleVisibility = function (): any { 35 | done(); 36 | }; 37 | viewabilityManager.observe(document.getElementById(targetId), handleVisibility); 38 | }); 39 | 40 | it('should observe twice the same div and check both listeners are invoked', (done) => { 41 | viewabilityManager = new ViewabilityManager(); 42 | const handleVisibility1 = function (): any { 43 | viewabilityManager.observe(document.getElementById(targetId), handleVisibility2); 44 | }; 45 | const handleVisibility2 = function (): any { 46 | done(); 47 | viewabilityManager.unObserve(document.getElementById(targetId), handleVisibility2); 48 | }; 49 | viewabilityManager.observe(document.getElementById(targetId), handleVisibility1); 50 | }); 51 | 52 | it('should check types TAB and VIEWPORT were sent correct', (done) => { 53 | viewabilityManager = new ViewabilityManager(); 54 | const handleVisibility = function (visible, viewabilityType): any { 55 | if (viewabilityType === ViewabilityType.VIEWPORT) { 56 | viewabilityManager._targetsObserved.getAll()[0].lastVisible = true; 57 | viewabilityManager._handleTabVisibilityChange(); 58 | } else if (viewabilityType === ViewabilityType.TAB) { 59 | done(); 60 | } 61 | }; 62 | viewabilityManager.observe(document.getElementById(targetId), handleVisibility); 63 | }); 64 | }); 65 | -------------------------------------------------------------------------------- /tests/e2e/configs/plugins.json: -------------------------------------------------------------------------------- 1 | { 2 | "all_plugins_default_config": { 3 | "plugins": { 4 | "colors": {}, 5 | "numbers": {} 6 | }, 7 | "all_plugins_custom_config": { 8 | "plugins": { 9 | "colors": { 10 | "favouriteColor": "black" 11 | }, 12 | "numbers": { 13 | "size": 25, 14 | "firstCellValue": 100, 15 | "lastCellValue": 200 16 | } 17 | } 18 | }, 19 | "only_colors_plugin": { 20 | "plugins": { 21 | "colors": {} 22 | } 23 | }, 24 | "only_numbers_plugin": { 25 | "plugins": { 26 | "numbers": {} 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tests/e2e/configs/sources.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hls": { 3 | "hls": [ 4 | { 5 | "mimetype": "application/x-mpegurl", 6 | "url": "http://cdnbakmi.kaltura.com/p/243342/sp/24334200/playManifest/entryId/0_uka1msg4/flavorIds/1_vqhfu6uy,1_80sohj7p/format/applehttp/protocol/http/a.m3u8" 7 | } 8 | ] 9 | }, 10 | "Mp4": { 11 | "progressive": [ 12 | { 13 | "mimetype": "video/mp4", 14 | "url": "/base/tests/assets/audios.mp4", 15 | "id": "1_rsrdfext_10081,url" 16 | } 17 | ] 18 | }, 19 | "MultipleSources": { 20 | "progressive": [ 21 | { 22 | "mimetype": "video/mp4", 23 | "url": "./base/tests/assets/audios.mp4", 24 | "id": "id1", 25 | "width": 200, 26 | "height": 100, 27 | "bandwidth": 100000, 28 | "label": "label1" 29 | }, 30 | { 31 | "mimetype": "video/mp4", 32 | "url": "/base/tests/assets/mov_bbb.mp4", 33 | "id": "id2", 34 | "width": 100, 35 | "height": 50, 36 | "bandwidth": 200000, 37 | "label": "label2" 38 | } 39 | ] 40 | }, 41 | "UnknownMimetype": { 42 | "progressive": [ 43 | { 44 | "mimetype": "someMimeType", 45 | "url": "some/url", 46 | "id": "someId" 47 | } 48 | ] 49 | }, 50 | "CorruptedUrl": { 51 | "progressive": [ 52 | { 53 | "mimetype": "video/mp4", 54 | "url": "some/corrupted/url", 55 | "id": "1_rsrdfext_10081,url" 56 | } 57 | ] 58 | }, 59 | "Live": { 60 | "hls": [ 61 | { 62 | "mimetype": "application/x-mpegurl", 63 | "url": "http://wms.shared.streamshow.it/carinatv/carinatv/playlist.m3u8" 64 | } 65 | ] 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /tests/e2e/ott/player-defaults.spec.js: -------------------------------------------------------------------------------- 1 | import { getDefaultRedirectOptions } from '../../../src/ott/player-defaults'; 2 | 3 | describe('redirectExternalStreamsHandler', () => { 4 | it('should return the default', () => { 5 | const defaultConfig = getDefaultRedirectOptions({}); 6 | (typeof defaultConfig.sources.options.redirectExternalStreamsHandler === 'function').should.be.true; 7 | }); 8 | 9 | it('should return void if already configured on player config', () => { 10 | const defaultConfig = getDefaultRedirectOptions({ 11 | sources: { 12 | options: { 13 | redirectExternalStreamsHandler: () => {} 14 | } 15 | } 16 | }); 17 | (defaultConfig.sources === undefined).should.be.true; 18 | }); 19 | 20 | it('should return void if already configured on media config', () => { 21 | const defaultConfig = getDefaultRedirectOptions( 22 | {}, 23 | { 24 | sources: { 25 | options: { 26 | redirectExternalStreamsHandler: () => {} 27 | } 28 | } 29 | } 30 | ); 31 | (defaultConfig.sources === undefined).should.be.true; 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /tests/e2e/ott/poster.spec.js: -------------------------------------------------------------------------------- 1 | import { addKalturaPoster } from '../../../src/ott/poster'; 2 | 3 | describe('addKalturaPoster', () => { 4 | it('should change poster of mediaSources to string', () => { 5 | const mediaSources = { 6 | poster: [ 7 | { url: 'https//my/kaltura/poster', width: 0, height: 0 }, 8 | { url: 'https//my/kaltura/poster', width: 0, height: 0 } 9 | ] 10 | }; 11 | const playerSources = { poster: 'https//my/kaltura/poster' }; 12 | addKalturaPoster(playerSources, mediaSources, { width: 640, height: 360 }); 13 | mediaSources.poster.should.have.string(playerSources.poster); 14 | }); 15 | 16 | it('should align poster of mediaSources with poster of playerSources', () => { 17 | const mediaSources = { poster: 'https//my/kaltura/poster' }; 18 | const playerSources = { 19 | poster: [ 20 | { url: 'https//my/kaltura/poster', width: 0, height: 0 }, 21 | { url: 'https//my/kaltura/poster', width: 0, height: 0 } 22 | ] 23 | }; 24 | addKalturaPoster(playerSources, mediaSources, { width: 640, height: 360 }); 25 | mediaSources.poster.should.equal(playerSources.poster); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /tests/index.js: -------------------------------------------------------------------------------- 1 | import chai from 'chai'; 2 | import sinonChai from 'sinon-chai'; 3 | import sinon from 'sinon/pkg/sinon-esm'; 4 | 5 | chai.should(); 6 | chai.use(sinonChai); 7 | global.chai = chai; 8 | global.expect = chai.expect; 9 | global.should = chai.should; 10 | global.sinon = sinon; 11 | 12 | const testsContext = require.context('./e2e', true); 13 | testsContext.keys().forEach(testsContext); 14 | -------------------------------------------------------------------------------- /tests/utils/test-utils.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Configuration structure of the player. 3 | * @returns {Object} - The configuration structure of the player. 4 | */ 5 | function getConfigStructure(): any { 6 | return { 7 | provider: {}, 8 | ui: {}, 9 | plugins: {}, 10 | advertising: { 11 | adBreaks: [] 12 | }, 13 | sources: {}, 14 | text: { 15 | enableCEA708Captions: true 16 | }, 17 | playback: { 18 | preload: 'none', 19 | autoplay: false, 20 | muted: false, 21 | playbackRates: [2, 3, 4], 22 | streamPriority: [ 23 | { 24 | engine: 'html5', 25 | format: 'hls' 26 | }, 27 | { 28 | engine: 'html5', 29 | format: 'dash' 30 | }, 31 | { 32 | engine: 'html5', 33 | format: 'progressive' 34 | } 35 | ] 36 | } 37 | }; 38 | } 39 | 40 | /** 41 | * Creates a dom element. 42 | * @param {string} type - The element type. 43 | * @param {string} id - The element id. 44 | * @param {string} opt_parentId - Optional parent id. 45 | * @returns {HTMLDivElement} 46 | */ 47 | function createElement(type: string, id: string, opt_parentId?: string): HTMLElement { 48 | const element = document.createElement(type); 49 | element.id = id; 50 | if (!opt_parentId) { 51 | document.body.appendChild(element); 52 | } else { 53 | const parent = document.getElementById(opt_parentId); 54 | if (parent) { 55 | parent.appendChild(element); 56 | } else { 57 | document.body.appendChild(element); 58 | } 59 | } 60 | return element; 61 | } 62 | 63 | /** 64 | * Removes a dom element. 65 | * @param {string} id - The element id. 66 | * @returns {void} 67 | */ 68 | function removeElement(id): void { 69 | const element = document.getElementById(id); 70 | element.parentNode.removeChild(element); 71 | } 72 | 73 | /** 74 | * Removes all the video elements that created by the test from the document. 75 | * @returns {void} 76 | */ 77 | function removeVideoElementsFromTestPage(): void { 78 | const element = document.getElementsByTagName('video'); 79 | for (let i = element.length - 1; i >= 0; i--) { 80 | element[i].parentNode.removeChild(element[i]); 81 | } 82 | } 83 | 84 | /** 85 | * Sets value of server config 86 | */ 87 | function setServerConfig(value): void { 88 | window.__kalturaplayerdata = value; 89 | } 90 | 91 | export { createElement, removeElement, removeVideoElementsFromTestPage, getConfigStructure, setServerConfig }; 92 | -------------------------------------------------------------------------------- /ts-typed/base-middleware.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace KalturaPlayerTypes { 2 | export interface BaseMiddleware { 3 | callNext(next: Function): void; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /ts-typed/base-plugin.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace KalturaPlayerTypes { 2 | export interface BasePlugin { 3 | player: KalturaPlayerTypes.Player; 4 | eventManager: KalturaPlayerTypes.EventManager; 5 | config: any; 6 | logger: KalturaPlayerTypes.Logger; 7 | getName(): string; 8 | destroy(): void; 9 | dispatchEvent(name: string, payload?: any): void; 10 | loadMedia(): void; 11 | updateConfig(update: Object): void; 12 | ready: Promise; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ts-typed/cue-point-manager.d.ts: -------------------------------------------------------------------------------- 1 | import {TimedMetadata} from '@playkit-js/playkit-js'; 2 | declare namespace KalturaPlayerTypes { 3 | export interface CuePoint { 4 | id: string; 5 | startTime: number; 6 | endTime: number; 7 | metadata: any; 8 | } 9 | export interface CuePointManager { 10 | getAllCuePoints(): Array; 11 | getActiveCuePoints(): Array; 12 | addCuePoints(cuePointData: Array): void; 13 | reset(): void; 14 | destroy(): void; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ts-typed/engine-decorator.d.ts: -------------------------------------------------------------------------------- 1 | interface FakeEvent { 2 | type: string; 3 | } 4 | declare namespace KalturaPlayerTypes { 5 | export interface IEngineDecorator { 6 | dispatchEvent(event: FakeEvent): boolean; 7 | active: boolean; 8 | } 9 | export interface IEngineDecoratorProvider { 10 | getEngineDecorator(engine: any, dispatchEventHandler: Function): IEngineDecorator; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ts-typed/event-manager.d.ts: -------------------------------------------------------------------------------- 1 | type Target = KalturaPlayerTypes.Player | KalturaPlayerTypes.FakeEventTarget | HTMLElement | Document; 2 | type CallbackFunction = (...args: any) => void; 3 | 4 | declare namespace KalturaPlayerTypes { 5 | export interface EventManager { 6 | listen: (target: Target, event: typeof EventType, cb: CallbackFunction) => void; 7 | listenOnce: (target: Target, event: typeof EventType, cb: CallbackFunction) => void; 8 | unlisten: (target: Target, event: typeof EventType, cb?: CallbackFunction) => void; 9 | destroy: () => void; 10 | removeAll: () => void; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ts-typed/fake-event-target.d.ts: -------------------------------------------------------------------------------- 1 | interface FakeEvent {} 2 | 3 | declare namespace KalturaPlayerTypes { 4 | export interface FakeEventTarget { 5 | addEventListener(type: string, listener: (...args: any) => void); 6 | removeEventListener(type: string, listener: (...args: any) => void); 7 | dispatchEvent(event: FakeEvent); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ts-typed/kaltura-player.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'global' { 2 | declare global { 3 | const KalturaPlayer: { 4 | providers: { 5 | RequestBuilder: any; 6 | ResponseTypes: any; 7 | ProviderParser: any; 8 | }; 9 | ui: { 10 | Event: { 11 | withEventManager: any; 12 | }; 13 | EventType: Record; 14 | redux: { 15 | connect: (...args: any) => any; 16 | useSelector: (...args: any) => any; 17 | }; 18 | reducers: Record; types: Record}>; 19 | createPortal: (children: any, domElement: HTMLElement) => preact.VNode; 20 | utils: { 21 | getLogger: (name: string) => KalturaPlayerTypes.Logger; 22 | bindActions(actions: Record): (...args: any) => void; 23 | KeyMap: Record; 24 | toHHMMSS: (seconds: number) => string; 25 | }; 26 | components: { 27 | SeekBarPlaybackContainer: any; 28 | Overlay: any; 29 | withPlayer: any; 30 | Tooltip: any; 31 | Icon: any; 32 | IconType: any; 33 | IconState: any; 34 | PLAYER_SIZE: Record; 35 | Remove: string; 36 | Settings: { 37 | displayName: string; 38 | }; 39 | PrevNext: any; 40 | PrePlaybackPlayOverlay: any; 41 | }; 42 | style: any; 43 | preactHooks: any; 44 | preacti18n: any; 45 | }; 46 | core: { 47 | EventType: Record; 48 | FakeEvent: any; 49 | FakeEventTarget: { 50 | new (...args: any[]): KalturaPlayerTypes.FakeEventTarget; 51 | }; 52 | Error: any; 53 | StateType: Record; 54 | MediaType: Record; 55 | registerPlugin(name: string, component: any): void; 56 | BasePlugin: { 57 | new (...args: any[]): KalturaPlayerTypes.BasePlugin; 58 | }; 59 | BaseMiddleware: { 60 | new (): KalturaPlayerTypes.BaseMiddleware; 61 | }; 62 | FakeEventTarget: { 63 | new (): KalturaPlayerTypes.FakeEventTarget; 64 | }; 65 | utils: { 66 | Object: { 67 | mergeDeep(target: Record, ...sources: Record[]); 68 | }; 69 | }; 70 | }; 71 | cuepoint: {[key: string]: string}; 72 | getPlayer(targetId?: string): any; 73 | setup(options: any): KalturaPlayer; 74 | }; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ts-typed/logger.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace KalturaPlayerTypes { 2 | export interface Logger { 3 | debug(message: any, ...optionalParams: any[]): void; 4 | 5 | info(message: any, ...optionalParams: any[]): void; 6 | 7 | trace(message: any, ...optionalParams: any[]): void; 8 | 9 | warn(message: any, ...optionalParams: any[]): void; 10 | 11 | error(message: any, ...optionalParams: any[]): void; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ts-typed/player.d.ts: -------------------------------------------------------------------------------- 1 | interface FakeEvent {} 2 | 3 | type CoreEventListener = (event: FakeEvent) => boolean | void; 4 | 5 | declare namespace KalturaPlayerTypes { 6 | export interface Player { 7 | dimensions: {width: number; height: number}; 8 | attachMediaSource(): void; 9 | detachMediaSource(): void; 10 | getActiveTracks(): {video: {width: number; height: number}}; 11 | pause(): void; 12 | play(): void; 13 | isLive: () => boolean; 14 | isDvr: () => boolean; 15 | isImage: () => boolean; 16 | dispatchEvent(event: FakeEvent): boolean; 17 | seekToLiveEdge(): void; 18 | destroy(): void; 19 | reset(): void; 20 | registerService(name: string, service: Object): void; 21 | hasService(name: string): boolean; 22 | getService(name: string): Object; 23 | getView: () => Node; 24 | getMediaInfo: () => any; 25 | paused: boolean; 26 | seeking: boolean; 27 | isOnLiveEdge: () => boolean; 28 | loadMedia: (mediaInfo: KalturaPlayerTypes.MediaInfo, mediaOptions?: KalturaPlayerTypes.Sources) => Promise; 29 | setMedia: (options: any) => void; 30 | getVideoElement(): HTMLVideoElement; 31 | addEventListener(type: string, listener: CoreEventListener): void; 32 | removeEventListener: (type: string, listener: CoreEventListener) => void; 33 | Event: Record; 34 | Error: Record; 35 | currentTime: number; 36 | playbackRate: number; 37 | duration: number; 38 | ended: boolean; 39 | env: KalturaPlayerTypes.Env; 40 | configure: Function; 41 | ui: any; 42 | config: KalturaPlayerTypes.PlayerConfig; 43 | provider: any; 44 | engineType: string; 45 | cuePointManager: KalturaPlayerTypes.CuePointManager; 46 | ready: () => Promise; 47 | sources: KalturaPlayerTypes.Sources; 48 | src?: string; 49 | poster?: string; 50 | getThumbnail: (time: number) => { 51 | height: number; 52 | url: string; 53 | width: number; 54 | x: number; 55 | y: number; 56 | }; 57 | shouldAddKs: () => boolean; 58 | updateKalturaPoster(playerSources: PKSourcesConfigObject, mediaSources: ProviderMediaConfigSourcesObject, dimensions: Object); 59 | playlist: KalturaPlayerTypes.Playlist; 60 | getTracks: (trackType: string) => Array; 61 | Track: Record; 62 | MediaType: Record; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /ts-typed/playlist.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace KalturaPlayerTypes { 2 | export interface PlaylistItem { 3 | config: any; 4 | index: number; 5 | plugins: Record; 6 | sources: any; 7 | } 8 | 9 | export interface Playlist { 10 | playNext: () => void; 11 | playPrev: () => void; 12 | playItem: (index: number) => void; 13 | reset: () => void; 14 | next: PlaylistItem | null; 15 | prev: PlaylistItem | null; 16 | countdown: { 17 | duration: number; 18 | showing: boolean; 19 | }; 20 | current: PlaylistItem; 21 | id: string; 22 | items: Array; 23 | metadata: { 24 | description: string; 25 | name: string; 26 | }; 27 | poster: string; 28 | options: { 29 | autoContinue: boolean; 30 | loop: boolean; 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ts-typed/provider-loader.d.ts: -------------------------------------------------------------------------------- 1 | declare namespace KalturaPlayerTypes { 2 | export interface ILoader { 3 | requests: RequestBuilder[]; 4 | response: any; 5 | isValid(): boolean; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /tsconfig-lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "emitDeclarationOnly": true, 5 | "declaration": true, 6 | "declarationMap": true 7 | }, 8 | "include": ["src/**/*"] 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "ESNext", 5 | "baseUrl": ".", 6 | "sourceMap": true, 7 | "strict": false, 8 | "strictNullChecks": true, 9 | "moduleResolution": "Node", 10 | "resolveJsonModule": true, 11 | "strictPropertyInitialization": true, 12 | "esModuleInterop": true, 13 | "lib": ["dom", "ESNext"], 14 | "outDir": "./lib/", 15 | "allowSyntheticDefaultImports": true, 16 | "paths": { 17 | "@playkit-js/playkit-js-providers": [ 18 | "@playkit-js/playkit-js-providers/ovp-provider", 19 | "@playkit-js/playkit-js-providers/ott-provider" 20 | ], 21 | "player-defaults": ["./src/ovp/player-defaults", "./src/ott/player-defaults"], 22 | "plugins-config-store": ["./src/ovp/plugins/plugins-config-store", "./src/ott/plugins/plugins-config-store"], 23 | "poster": ["./src/ovp/poster", "./src/ott/poster"] 24 | } 25 | }, 26 | "include": ["src/**/*"] 27 | } 28 | --------------------------------------------------------------------------------