├── .editorconfig ├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .nvmrc ├── .travis.yml ├── .yo-rc.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs └── index.md ├── index.html ├── jsdoc.json ├── package-lock.json ├── package.json ├── scripts ├── karma.conf.js └── rollup.config.js ├── src └── plugin.js └── test └── plugin.test.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_style = space 8 | indent_size = 2 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Briefly describe the issue. 3 | Include a [reduced test case](https://css-tricks.com/reduced-test-cases/). 4 | 5 | ## Steps to reproduce 6 | Explain in detail the exact steps necessary to reproduce the issue. 7 | 8 | 1. 9 | 2. 10 | 3. 11 | 12 | ## Results 13 | ### Expected 14 | Please describe what you expected to see. 15 | 16 | ### Actual 17 | Please describe what actually happened. 18 | 19 | ### Error output 20 | If there are any errors at all, please include them here. 21 | 22 | ## Additional Information 23 | Please include any additional information necessary here. Including the following: 24 | 25 | ### versions 26 | #### videojs 27 | what version of videojs does this occur with? 28 | 29 | #### browsers 30 | what browser are affected? 31 | 32 | #### OSes 33 | what platforms (operating systems and devices) are affected? 34 | 35 | ### plugins 36 | are any videojs plugins being used on the page? If so, please list them below. 37 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | Please describe the change as necessary. 3 | If it's a feature or enhancement please be as detailed as possible. 4 | If it's a bug fix, please link the issue that it fixes or describe the bug in as much detail. 5 | 6 | ## Specific Changes proposed 7 | Please list the specific changes involved in this pull request. 8 | 9 | ## Requirements Checklist 10 | - [ ] Feature implemented / Bug fixed 11 | - [ ] If necessary, more likely in a feature request than a bug fix 12 | - [ ] Unit Tests updated or fixed 13 | - [ ] Docs/guides updated 14 | - [ ] Reviewed by Two Core Contributors 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | Thumbs.db 3 | ehthumbs.db 4 | Desktop.ini 5 | .DS_Store 6 | ._* 7 | 8 | # Editors 9 | *~ 10 | *.swp 11 | *.tmproj 12 | *.tmproject 13 | *.sublime-* 14 | .idea/ 15 | .project/ 16 | .settings/ 17 | .vscode/ 18 | 19 | # Logs 20 | logs 21 | *.log 22 | npm-debug.log* 23 | 24 | # Dependency directories 25 | bower_components/ 26 | node_modules/ 27 | 28 | # Build-related directories 29 | dist/ 30 | docs/api/ 31 | test/dist/ 32 | .eslintcache 33 | .yo-rc.json 34 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Intentionally left blank, so that npm does not ignore anything by default, 2 | # but relies on the package.json "files" array to explicitly define what ends 3 | # up in the package. 4 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | lts/* 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: xenial 2 | language: node_js 3 | # node version is specified using the .nvmrc file 4 | cache: npm 5 | before_install: 6 | - npm install -g greenkeeper-lockfile@1 7 | before_script: 8 | - greenkeeper-lockfile-update 9 | after_script: 10 | - greenkeeper-lockfile-upload 11 | addons: 12 | firefox: latest 13 | chrome: stable 14 | services: 15 | - xvfb 16 | -------------------------------------------------------------------------------- /.yo-rc.json: -------------------------------------------------------------------------------- 1 | { 2 | "generator-videojs-plugin": { 3 | "bcov": false, 4 | "scope": "", 5 | "name": "offset", 6 | "description": "", 7 | "author": "Carles Galan Cladera ", 8 | "license": "mit", 9 | "css": false, 10 | "ie8": true, 11 | "docs": true, 12 | "lang": false, 13 | "bower": false, 14 | "ghooks": "test", 15 | "sass": false, 16 | "husky": "test", 17 | "prepush": false, 18 | "precommit": true, 19 | "pluginType": "advanced" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## [2.1.3](https://github.com/cladera/videojs-offset/compare/v2.1.2...v2.1.3) (2021-03-16) 3 | 4 | ### Bug Fixes 5 | 6 | * update currentTime value in Video.js cache ([5f44f3e](https://github.com/cladera/videojs-offset/commit/5f44f3e)), closes [#43](https://github.com/cladera/videojs-offset/issues/43) 7 | 8 | 9 | 10 | ## [2.1.2](https://github.com/cladera/videojs-offset/compare/v2.1.1...v2.1.2) (2019-06-09) 11 | 12 | ### Bug Fixes 13 | 14 | * cover buffered override ([ea0a25f](https://github.com/cladera/videojs-offset/commit/ea0a25f)) 15 | * cover startOffset and endOffset getters ([a4ea42e](https://github.com/cladera/videojs-offset/commit/a4ea42e)) 16 | * video doesn't stop at specific time ([6fd6c01](https://github.com/cladera/videojs-offset/commit/6fd6c01)), closes [#34](https://github.com/cladera/videojs-offset/issues/34) 17 | 18 | 19 | ## [2.1.1](https://github.com/cladera/videojs-offset/compare/v2.1.0...v2.1.1) (2019-02-08) 20 | 21 | ### Bug Fixes 22 | 23 | * do not override player when start offset is not defined ([b117bad](https://github.com/cladera/videojs-offset/commit/b117bad)), closes [#40](https://github.com/cladera/videojs-offset/issues/40) 24 | * load progress bar position ([e628786](https://github.com/cladera/videojs-offset/commit/e628786)), closes [#28](https://github.com/cladera/videojs-offset/issues/28) 25 | 26 | 27 | # [2.1.0](https://github.com/cladera/videojs-offset/compare/v2.0.0-beta.2...v2.1.0) (2019-02-04) 28 | 29 | ### Bug Fixes 30 | 31 | * remaining time ([6d5a4a6](https://github.com/cladera/videojs-offset/commit/6d5a4a6)), closes [#24](https://github.com/cladera/videojs-offset/issues/24) 32 | * string inputs ([f521253](https://github.com/cladera/videojs-offset/commit/f521253)), closes [#25](https://github.com/cladera/videojs-offset/issues/25) 33 | 34 | ### Chores 35 | 36 | * upgrade generator ([b58736d](https://github.com/cladera/videojs-offset/commit/b58736d)) 37 | 38 | CHANGELOG 39 | ========= 40 | 41 | ## HEAD (Unreleased) 42 | _(none)_ 43 | 44 | -------------------- 45 | 46 | ## 2.0.0-beta.1 (2017-09-27) 47 | _(none)_ 48 | 49 | ## 2.0.0-beta.0 (2017-05-12) 50 | _(none)_ 51 | 52 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have Node.js 8 or higher and npm installed. 8 | 9 | 1. Fork this repository and clone your fork 10 | 1. Install dependencies: `npm install` 11 | 1. Run a development server: `npm start` 12 | 13 | ### Making Changes 14 | 15 | Refer to the [video.js plugin conventions][conventions] for more detail on best practices and tooling for video.js plugin authorship. 16 | 17 | When you've made your changes, push your commit(s) to your fork and issue a pull request against the original repository. 18 | 19 | ### Running Tests 20 | 21 | Testing is a crucial part of any software project. For all but the most trivial changes (typos, etc) test cases are expected. Tests are run in actual browsers using [Karma][karma]. 22 | 23 | - In all available and supported browsers: `npm test` 24 | - In a specific browser: `npm run test:chrome`, `npm run test:firefox`, etc. 25 | - While development server is running (`npm start`), navigate to [`http://localhost:9999/test/`][local] 26 | 27 | 28 | [karma]: http://karma-runner.github.io/ 29 | [local]: http://localhost:9999/test/ 30 | [conventions]: https://github.com/videojs/generator-videojs-plugin/blob/master/docs/conventions.md 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Carles Galan Cladera 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # videojs-offset 2 | 3 | VideoJs plugin to virtually "cut" an ondemand video 4 | 5 | ## Table of Contents 6 | 7 | 8 | 9 | ## Installation 10 | 11 | - [Installation](#installation) 12 | - [Usage](#usage) 13 | - [` 35 | 36 | 45 | ``` 46 | 47 | ### Browserify/CommonJS 48 | 49 | When using with Browserify, install videojs-offset via npm and `require` the plugin as you would any other module. 50 | 51 | ```js 52 | var videojs = require('video.js'); 53 | 54 | // The actual plugin function is exported by this module, but it is also 55 | // attached to the `Player.prototype`; so, there is no need to assign it 56 | // to a variable. 57 | require('videojs-offset'); 58 | 59 | var player = videojs('my-video'); 60 | 61 | player.offset({ 62 | start: 10, 63 | end: 300, 64 | restart_beginning: false //Should the video go to the beginning when it ends 65 | }); 66 | ``` 67 | 68 | ### RequireJS/AMD 69 | 70 | When using with RequireJS (or another AMD library), get the script in whatever way you prefer and `require` the plugin as you normally would: 71 | 72 | ```js 73 | require(['video.js', 'videojs-offset'], function(videojs) { 74 | var player = videojs('my-video'); 75 | 76 | player.offset({ 77 | start: 10, 78 | end: 300, 79 | restart_beginning: false //Should the video go to the beginning when it ends 80 | }); 81 | }); 82 | ``` 83 | 84 | ## License 85 | 86 | MIT. Copyright (c) Carles Galan Cladera <cgcladera@gmail.com> 87 | 88 | 89 | [videojs]: http://videojs.com/ 90 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Documentation for videojs-offset 2 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-offset Demo 6 | 7 | 8 | 9 | 13 | 17 | 18 | 19 | 20 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["plugins/markdown"] 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-offset", 3 | "version": "2.1.3", 4 | "description": "", 5 | "main": "dist/videojs-offset.cjs.js", 6 | "jsnext:main": "src/js/index.js", 7 | "engines": { 8 | "node": ">=8", 9 | "npm": ">=5" 10 | }, 11 | "generator-videojs-plugin": { 12 | "version": "7.6.1" 13 | }, 14 | "scripts": { 15 | "prebuild": "npm run clean", 16 | "build": "npm-run-all -p build:*", 17 | "build:js": "rollup -c scripts/rollup.config.js", 18 | "clean": "shx rm -rf ./dist ./test/dist", 19 | "postclean": "shx mkdir -p ./dist ./test/dist", 20 | "docs": "npm-run-all docs:*", 21 | "docs:api": "jsdoc src -g plugins/markdown -r -d docs/api", 22 | "docs:toc": "doctoc --notitle README.md", 23 | "lint": "vjsstandard", 24 | "server": "karma start scripts/karma.conf.js --singleRun=false --auto-watch", 25 | "start": "npm-run-all -p server watch", 26 | "pretest": "npm-run-all lint build", 27 | "test": "npm-run-all test:*", 28 | "test:unit": "karma start scripts/karma.conf.js", 29 | "test:verify": "vjsverify --verbose", 30 | "posttest": "shx cat test/dist/coverage/text.txt", 31 | "update-changelog": "conventional-changelog -p videojs -i CHANGELOG.md -s", 32 | "preversion": "npm test", 33 | "version": "is-prerelease || npm run update-changelog && git add CHANGELOG.md", 34 | "watch": "npm-run-all -p watch:*", 35 | "watch:js": "npm run build:js -- -w", 36 | "prepublishOnly": "npm-run-all build test:verify" 37 | }, 38 | "keywords": [ 39 | "videojs", 40 | "videojs-plugin" 41 | ], 42 | "author": "Carles Galan Cladera ", 43 | "license": "MIT", 44 | "files": [ 45 | "CONTRIBUTING.md", 46 | "dist/", 47 | "docs/", 48 | "index.html", 49 | "scripts/", 50 | "src/", 51 | "test/" 52 | ], 53 | "dependencies": { 54 | "global": "^4.3.2", 55 | "video.js": "^6 || ^7" 56 | }, 57 | "devDependencies": { 58 | "@videojs/generator-helpers": "~1.0.0", 59 | "jsdoc": "github:BrandonOCasey/jsdoc#fix/security-issue", 60 | "karma": "^3.0.0", 61 | "rollup": "^1.1.0", 62 | "sinon": "^7.2.2", 63 | "videojs-generate-karma-config": "~5.0.2", 64 | "videojs-generate-rollup-config": "~3.0.2", 65 | "videojs-generator-verify": "~1.2.0", 66 | "videojs-standard": "^8.0.1" 67 | }, 68 | "config": { 69 | "ghooks": { 70 | "pre-push": "npm run test" 71 | } 72 | }, 73 | "module": "dist/videojs-offset.es.js", 74 | "vjsstandard": { 75 | "ignore": [ 76 | "dist", 77 | "docs", 78 | "test/dist" 79 | ] 80 | }, 81 | "browserslist": [ 82 | "defaults", 83 | "ie 11" 84 | ], 85 | "husky": { 86 | "hooks": { 87 | "pre-commit": "lint-staged" 88 | } 89 | }, 90 | "lint-staged": { 91 | "*.js": [ 92 | "vjsstandard --fix", 93 | "git add" 94 | ], 95 | "README.md": [ 96 | "doctoc --notitle", 97 | "git add" 98 | ] 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /scripts/karma.conf.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-karma-config'); 2 | 3 | module.exports = function(config) { 4 | 5 | // see https://github.com/videojs/videojs-generate-karma-config 6 | // for options 7 | const options = { 8 | browsers: () => { 9 | return ['ChromeHeadless']; 10 | }, 11 | detectBrowsers: false 12 | }; 13 | 14 | config = generate(config, options); 15 | 16 | // any other custom stuff not supported by options here! 17 | }; 18 | -------------------------------------------------------------------------------- /scripts/rollup.config.js: -------------------------------------------------------------------------------- 1 | const generate = require('videojs-generate-rollup-config'); 2 | 3 | // see https://github.com/videojs/videojs-generate-rollup-config 4 | // for options 5 | const options = {}; 6 | const config = generate(options); 7 | 8 | // Add additonal builds/customization here! 9 | 10 | // export the builds to rollup 11 | export default Object.values(config.builds); 12 | -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import {version as VERSION} from '../package.json'; 3 | 4 | // Default options for the plugin. 5 | const defaults = {}; 6 | 7 | // Cross-compatibility for Video.js 5 and 6. 8 | const registerPlugin = videojs.registerPlugin || videojs.plugin; 9 | // const dom = videojs.dom || videojs; 10 | 11 | /** 12 | * Checks whether the clip should be ended. 13 | * 14 | * @function onPlayerTimeUpdate 15 | * 16 | */ 17 | const onPlayerTimeUpdate = function() { 18 | const curr = this.currentTime(); 19 | 20 | if (curr < 0) { 21 | this.currentTime(0); 22 | this.play(); 23 | } 24 | if (this._offsetEnd > 0 && curr > (this._offsetEnd - this._offsetStart)) { 25 | this.off('timeupdate', onPlayerTimeUpdate); 26 | this.pause(); 27 | this.trigger('ended'); 28 | 29 | // Re-bind to timeupdate next time the video plays 30 | this.one('play', () => { 31 | this.on('timeupdate', onPlayerTimeUpdate); 32 | }); 33 | 34 | if (!this._restartBeginning) { 35 | this.currentTime(this._offsetEnd - this._offsetStart); 36 | } else { 37 | this.trigger('loadstart'); 38 | this.currentTime(0); 39 | } 40 | } 41 | }; 42 | /** 43 | * Function to invoke when the player is ready. 44 | * 45 | * This is a great place for your plugin to initialize itself. When this 46 | * function is called, the player will have its DOM and child components 47 | * in place. 48 | * 49 | * @function onPlayerReady 50 | * @param {Player} player 51 | * A Video.js player. 52 | * @param {Object} [options={}] 53 | * An object of options left to the plugin author to define. 54 | */ 55 | const onPlayerReady = (player, options) => { 56 | player.one('play', () => { 57 | player.on('timeupdate', onPlayerTimeUpdate); 58 | }); 59 | }; 60 | 61 | /** 62 | * A video.js plugin. 63 | * 64 | * In the plugin function, the value of `this` is a video.js `Player` 65 | * instance. You cannot rely on the player being in a "ready" state here, 66 | * depending on how the plugin is invoked. This may or may not be important 67 | * to you; if not, remove the wait for "ready"! 68 | * 69 | * @function offset 70 | * @param {Object} [options={}] 71 | * An object of options left to the plugin author to define. 72 | */ 73 | const offset = function(options) { 74 | options = options || {}; 75 | const Player = this.constructor; 76 | 77 | this._offsetStart = parseFloat(options.start || '0'); 78 | this._offsetEnd = parseFloat(options.end || '0'); 79 | this._restartBeginning = options.restart_beginning || false; 80 | 81 | if (!Player.__super__ || !Player.__super__.__offsetInit) { 82 | Player.__super__ = { 83 | __offsetInit: true, 84 | duration: Player.prototype.duration, 85 | currentTime: Player.prototype.currentTime, 86 | bufferedPercent: Player.prototype.bufferedPercent, 87 | remainingTime: Player.prototype.remainingTime, 88 | buffered: Player.prototype.buffered 89 | }; 90 | 91 | Player.prototype.duration = function() { 92 | if (this._offsetEnd !== undefined && this._offsetStart !== undefined) { 93 | if (this._offsetEnd > 0) { 94 | return this._offsetEnd - this._offsetStart; 95 | } 96 | return Player.__super__.duration.apply(this, arguments) - this._offsetStart; 97 | } 98 | return Player.__super__.duration.apply(this, arguments); 99 | }; 100 | 101 | Player.prototype.currentTime = function(seconds) { 102 | if (seconds !== undefined) { 103 | if (this._offsetStart !== undefined) { 104 | return Player.__super__.currentTime 105 | .call(this, seconds + this._offsetStart); 106 | } 107 | return Player.__super__.currentTime.call(this, seconds); 108 | } 109 | 110 | if (this._offsetStart !== undefined) { 111 | const t = Player.__super__.currentTime 112 | .apply(this) - this._offsetStart; 113 | 114 | this.getCache().currentTime = t; 115 | return t; 116 | } 117 | return Player.__super__.currentTime.apply(this); 118 | }; 119 | 120 | Player.prototype.remainingTime = function() { 121 | return this.duration() - this.currentTime(); 122 | }; 123 | 124 | Player.prototype.startOffset = function() { 125 | return this._offsetStart; 126 | }; 127 | 128 | Player.prototype.endOffset = function() { 129 | if (this._offsetEnd > 0) { 130 | return this._offsetEnd; 131 | } 132 | return this.duration(); 133 | }; 134 | 135 | Player.prototype.buffered = function() { 136 | const buff = Player.__super__.buffered.call(this); 137 | const ranges = []; 138 | 139 | for (let i = 0; i < buff.length; i++) { 140 | ranges[i] = [ 141 | Math.max(0, buff.start(i) - this._offsetStart), 142 | Math.min(Math.max(0, buff.end(i) - this._offsetStart), this.duration()) 143 | ]; 144 | } 145 | 146 | return videojs.createTimeRanges(ranges); 147 | }; 148 | } 149 | 150 | this.ready(() => { 151 | onPlayerReady(this, videojs.mergeOptions(defaults, options)); 152 | }); 153 | }; 154 | 155 | // Register the plugin with video.js. 156 | registerPlugin('offset', offset); 157 | // Include the version number. 158 | offset.VERSION = VERSION; 159 | 160 | export default offset; 161 | -------------------------------------------------------------------------------- /test/plugin.test.js: -------------------------------------------------------------------------------- 1 | import document from 'global/document'; 2 | 3 | import QUnit from 'qunit'; 4 | import sinon from 'sinon'; 5 | import videojs from 'video.js'; 6 | 7 | import plugin from '../src/plugin'; 8 | 9 | const Player = videojs.getComponent('Player'); 10 | 11 | QUnit.test('the environment is sane', function(assert) { 12 | assert.strictEqual(typeof Array.isArray, 'function', 'es5 exists'); 13 | assert.strictEqual(typeof sinon, 'object', 'sinon exists'); 14 | assert.strictEqual(typeof videojs, 'function', 'videojs exists'); 15 | assert.strictEqual(typeof plugin, 'function', 'plugin is a function'); 16 | }); 17 | 18 | QUnit.module('videojs-offset', { 19 | 20 | beforeEach() { 21 | 22 | // Mock the environment's timers because certain things - particularly 23 | // player readiness - are asynchronous in video.js 5. This MUST come 24 | // before any player is created; otherwise, timers could get created 25 | // with the actual timer methods! 26 | this.clock = sinon.useFakeTimers(); 27 | 28 | this.fixture = document.getElementById('qunit-fixture'); 29 | this.video = document.createElement('video'); 30 | this.fixture.appendChild(this.video); 31 | this.player = videojs(this.video); 32 | this.sandbox = sinon.createSandbox(); 33 | }, 34 | 35 | afterEach() { 36 | this.player.dispose(); 37 | this.clock.restore(); 38 | this.sandbox.restore(); 39 | } 40 | }); 41 | 42 | QUnit.test('registers itself with video.js', function(assert) { 43 | assert.expect(2); 44 | 45 | assert.strictEqual( 46 | typeof Player.prototype.offset, 47 | 'function', 48 | 'videojs-offset plugin was registered' 49 | ); 50 | 51 | this.player.offset({ 52 | start: 10, 53 | end: 300 54 | }); 55 | 56 | // Tick the clock forward enough to trigger the player to be "ready". 57 | this.clock.tick(1); 58 | 59 | assert.ok( 60 | this.player.duration() === 290, 61 | 'the plugin alters video duration adjusting to start|end options' 62 | ); 63 | }); 64 | 65 | QUnit.test('remaining time', function(assert) { 66 | assert.expect(1); 67 | 68 | this.player.offset({ 69 | start: 10, 70 | end: 300 71 | }); 72 | 73 | // Tick the clock forward enough to trigger the player to be "ready". 74 | this.clock.tick(1); 75 | 76 | this.player.currentTime(2); 77 | 78 | assert.ok( 79 | this.player.remainingTime() === 288, 80 | 'the plugin alters remaining time' 81 | ); 82 | }); 83 | 84 | QUnit.test('configure start and end as as strings', function(assert) { 85 | assert.expect(1); 86 | 87 | this.player.offset({ 88 | start: '10.5', 89 | end: '300.5' 90 | }); 91 | 92 | // Tick the clock forward enough to trigger the player to be "ready". 93 | this.clock.tick(1); 94 | 95 | this.player.currentTime(2); 96 | 97 | assert.ok( 98 | this.player.currentTime() === 2, 99 | 'the plugin alters seeking by applying the start correction' 100 | ); 101 | }); 102 | 103 | QUnit.test('should override buffered method', function(assert) { 104 | assert.expect(2); 105 | 106 | const initRange = videojs.createTimeRanges([[0, 30]]); 107 | 108 | this.sandbox 109 | .stub(Player.__super__, 'buffered') 110 | .returns(initRange); 111 | 112 | this.player.offset({ 113 | start: 5, 114 | end: 25 115 | }); 116 | 117 | const buff = this.player.buffered(); 118 | 119 | assert.ok(buff.start(0) === 0, 'start should be 0. Actual: ' + buff.start(0)); 120 | assert.ok(buff.end(0) === 20, 'end equal to video duration. Actual: ' + buff.end(0)); 121 | }); 122 | 123 | QUnit.test('start offset and end offset getters', function(assert) { 124 | assert.expect(3); 125 | 126 | this.player.offset({ 127 | start: 10, 128 | end: 300 129 | }); 130 | 131 | assert.ok(this.player.startOffset() === 10, 'should return start offset'); 132 | assert.ok(this.player.endOffset() === 300, 'should return end offset'); 133 | 134 | // Reset the player instance 135 | this.player = videojs(this.video); 136 | 137 | this.sandbox.stub(this.player, 'duration').returns(500); 138 | 139 | this.player.offset({ 140 | start: 10 141 | }); 142 | 143 | assert.ok(this.player.endOffset() === 500, 'should return the video duration'); 144 | 145 | }); 146 | 147 | QUnit.test('rest time update handler when video reaches the end', function(assert) { 148 | 149 | let triggerReady; 150 | let triggerPlay; 151 | let triggerTimeupdate; 152 | let currentTime = 0; 153 | const _thisPlayer = this.player; 154 | 155 | this.sandbox.stub(this.player, 'ready').callsFake(function(cb) { 156 | triggerReady = function() { 157 | cb.call(_thisPlayer); 158 | }; 159 | }); 160 | 161 | this.sandbox.stub(this.player, 'one') 162 | .withArgs('play', sinon.match.any) 163 | .callsFake(function(event, cb) { 164 | triggerPlay = function() { 165 | cb.call(_thisPlayer); 166 | }; 167 | }); 168 | 169 | const addEventListenerStub = this.sandbox.stub(this.player, 'on'); 170 | 171 | addEventListenerStub.withArgs('timeupdate', sinon.match.any) 172 | .callsFake(function(event, cb) { 173 | triggerTimeupdate = function(curr) { 174 | currentTime = curr; 175 | cb.call(_thisPlayer); 176 | }; 177 | }); 178 | addEventListenerStub.callThrough(); 179 | 180 | this.sandbox.stub(this.player, 'currentTime').callsFake(function(curr) { 181 | if (!curr && curr !== 0) { 182 | return currentTime; 183 | } 184 | currentTime = curr; 185 | }); 186 | 187 | this.sandbox.spy(this.player, 'off'); 188 | this.sandbox.spy(this.player, 'pause'); 189 | this.sandbox.spy(this.player, 'trigger'); 190 | 191 | this.player.offset({ 192 | start: 5, 193 | end: 300, 194 | restart_beginning: true /* eslint-disable-line */ 195 | }); 196 | 197 | triggerReady(); 198 | triggerPlay(); 199 | 200 | // Reset one so we can verify later that it was called again 201 | this.player.one.resetHistory(); 202 | 203 | triggerTimeupdate(300); 204 | 205 | assert.ok(this.player.pause.called === true, 'should pause the video'); 206 | assert.ok( 207 | this.player.off.calledWith('timeupdate', sinon.match.any), 208 | 'should unsubscribe from timeupdate events' 209 | ); 210 | assert.ok(this.player.trigger.calledWith('ended'), 'should trigger ended event'); 211 | assert.equal(currentTime, 0, 'should get back to the beginning'); 212 | assert.ok( 213 | this.player.one.calledWith('play', sinon.match.func), 214 | 'should subscribe to next play event' 215 | ); 216 | 217 | // Clean on's calls history 218 | this.player.on.resetHistory(); 219 | triggerPlay(); 220 | 221 | assert.ok( 222 | this.player.on.calledWith('timeupdate', sinon.match.func), 223 | 'should subscribe to time update after the first play' 224 | ); 225 | 226 | }); 227 | --------------------------------------------------------------------------------