├── .babelrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── bower.json ├── dist ├── videojs-vimeo.js └── videojs-vimeo.min.js ├── index.html ├── jsdoc.json ├── package.json ├── scripts ├── banner.ejs ├── build-test.js ├── postversion.js ├── server.js └── version.js └── src └── Vimeo.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [["es2015", {"loose": true}]], 3 | "plugins": ["transform-object-assign"] 4 | } 5 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.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 | # Yeoman meta-data 29 | .yo-rc.json 30 | 31 | # Build-related directories 32 | docs/api/ 33 | es5/ 34 | test/dist/ 35 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } 4 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - 'node' 5 | - '4.4' 6 | - '0.12' 7 | - '0.10' 8 | 9 | before_script: 10 | 11 | # Set up a virtual screen for Firefox. 12 | - export DISPLAY=:99.0 13 | - sh -e /etc/init.d/xvfb start 14 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # CONTRIBUTING 2 | 3 | We welcome contributions from everyone! 4 | 5 | ## Getting Started 6 | 7 | Make sure you have NodeJS 0.10 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 standards][standards] 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 | 20 | [standards]: https://github.com/videojs/generator-videojs-plugin/docs/standards.md 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Benoit Tremblay and videojs-vimeo contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Videojs Vimeo plugin 2 | 3 | Videojs Vimeo plugin using the official Vimeo Player API. This is heavily 4 | inspired by the official [VideoJS YouTube project](https://github.com/videojs/videojs-youtube). 5 | 6 | ## Installation 7 | 8 | For now, the package is not published on any package manager — download the dist file or 9 | point your package manage at this repo. 10 | 11 | ## Usage 12 | 13 | See [index.html](https://github.com/videojs/videojs-vimeo/blob/master/index.html) 14 | 15 | [videojs]: http://videojs.com/ 16 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-vimeo", 3 | "author": "Jimmy Bourassa <jbourassa@didacte.com>", 4 | "license": "MIT", 5 | "main": [ 6 | "dist/videojs-vimeo.min.js" 7 | ], 8 | "keywords": [ 9 | "videojs", 10 | "videojs-plugin" 11 | ] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /dist/videojs-vimeo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * videojs-vimeo 3 | * @version 3.0.0 4 | * @copyright 2016 Benoit Tremblay 5 | * @license MIT 6 | */ 7 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.videojsVimeo = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o=n.length)break;i=n[o++]}else{if(o=n.next(),o.done)break;i=o.value}var a=i,u=e.getAttribute("data-vimeo-"+a);(u||""===u)&&(t[a]=""===u?1:u)}return t}function l(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return new Promise(function(n,r){if(!s(e))throw new TypeError("“"+e+"” is not a vimeo.com url.");var o="https://vimeo.com/api/oembed.json?url="+encodeURIComponent(e);for(var i in t)t.hasOwnProperty(i)&&(o+="&"+i+"="+encodeURIComponent(t[i]));var a="XDomainRequest"in window?new XDomainRequest:new XMLHttpRequest;a.open("GET",o,!0),a.onload=function(){if(404===a.status)return void r(new Error("“"+e+"” was not found."));if(403===a.status)return void r(new Error("“"+e+"” is not embeddable."));try{var t=JSON.parse(a.responseText);n(t)}catch(e){r(e)}},a.onerror=function(){var e=a.status?" ("+a.status+")":"";r(new Error("There was an error fetching the embed code from Vimeo"+e+"."))},a.send()})}function h(e,t){var n=e.html;if(!t)throw new TypeError("An element must be provided");if(null!==t.getAttribute("data-vimeo-initialized"))return t.querySelector("iframe");var r=document.createElement("div");return r.innerHTML=n,t.appendChild(r.firstChild),t.setAttribute("data-vimeo-initialized","true"),t.querySelector("iframe")}function d(){var e=arguments.length<=0||void 0===arguments[0]?document:arguments[0],t=[].slice.call(e.querySelectorAll("[data-vimeo-id], [data-vimeo-url]")),n=function(e){"console"in window&&console.error&&console.error("There was an error creating an embed: "+e)},r=function(){if(i){if(a>=o.length)return"break";u=o[a++]}else{if(a=o.next(),a.done)return"break";u=a.value}var e=u;try{if(null!==e.getAttribute("data-vimeo-defer"))return"continue";var t=f(e),r=c(t);l(r,t).then(function(t){return h(t,e)}).catch(n)}catch(e){n(e)}};e:for(var o=t,i=Array.isArray(o),a=0,o=i?o:o[Symbol.iterator]();;){var u,s=r();switch(s){case"break":break e;case"continue":continue}}}function p(e){return"string"==typeof e&&(e=JSON.parse(e)),e}function v(e,t,n){if(e.element.contentWindow.postMessage){var r={method:t};void 0!==n&&(r.value=n);var o=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\d+).*$/,"$1"));o>=8&&o<10&&(r=JSON.stringify(r)),e.element.contentWindow.postMessage(r,e.origin)}}function y(e,t){t=p(t);var o=[],i=void 0;if(t.event){if("error"===t.event)for(var a=n(e,t.data.method),u=a,s=Array.isArray(u),c=0,u=s?u:u[Symbol.iterator]();;){var f;if(s){if(c>=u.length)break;f=u[c++]}else{if(c=u.next(),c.done)break;f=c.value}var l=f,h=new Error(t.data.message);h.name=t.data.name,l.reject(h),r(e,t.data.method,l)}o=n(e,"event:"+t.event),i=t.data}else t.method&&(o=n(e,t.method),i=t.value,r(e,t.method));for(var d=o,v=Array.isArray(d),y=0,d=v?d:d[Symbol.iterator]();;){var m;if(v){if(y>=d.length)break;m=d[y++]}else{if(y=d.next(),y.done)break;m=y.value}var g=m;try{if("function"==typeof g){g.call(e,i);continue}g.resolve(i)}catch(e){}}}var m="undefined"!=typeof Array.prototype.indexOf,g="undefined"!=typeof window.postMessage;if(!m||!g)throw new Error("Sorry, the Vimeo Player API is not available in this browser.");var w="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{},b=(e(function(e,t){!function(e){function t(e,t){function r(e){return this&&this.constructor===r?(this._keys=[],this._values=[],this._itp=[],this.objectOnly=t,void(e&&n.call(this,e))):new r(e)}return t||w(e,"size",{get:y}),e.constructor=r,r.prototype=e,r}function n(e){this.add?e.forEach(this.add,this):e.forEach(function(e){this.set(e[0],e[1])},this)}function r(e){return this.has(e)&&(this._keys.splice(g,1),this._values.splice(g,1),this._itp.forEach(function(e){g0&&e(n,s))}catch(e){i.call(new u(s),e)}}}function i(t){var r=this;r.triggered||(r.triggered=!0,r.def&&(r=r.def),r.msg=t,r.state=2,r.chain.length>0&&e(n,r))}function a(e,t,n,r){for(var o=0;o1&&window.console&&console.warn&&console.warn("A jQuery object with multiple elements was passed, using the first element."),e=e[0]),"string"==typeof e&&(e=document.getElementById(e)),!a(e))throw new TypeError("You must pass either a valid element or a valid id.");if("IFRAME"!==e.nodeName){var r=e.querySelector("iframe");r&&(e=r)}if("IFRAME"===e.nodeName&&!s(e.getAttribute("src")||""))throw new Error("The player element passed isn’t a Vimeo embed.");if(x.has(e))return x.get(e);this.element=e,this.origin="*";var i=new E(function(r,i){var a=function(e){if(s(e.origin)&&t.element.contentWindow===e.source){"*"===t.origin&&(t.origin=e.origin);var n=p(e.data),o="event"in n&&"ready"===n.event,i="method"in n&&"ping"===n.method;return o||i?(t.element.setAttribute("data-ready","true"),void r()):void y(t,n)}};if(window.addEventListener?window.addEventListener("message",a,!1):window.attachEvent&&window.attachEvent("onmessage",a),"IFRAME"!==t.element.nodeName){var u=f(e,n),d=c(u);l(d,u).then(function(n){var r=h(n,e);return t.element=r,o(e,r),n}).catch(function(e){return i(e)})}});return j.set(this,i),x.set(this.element,this),"IFRAME"===this.element.nodeName&&v(this,"ping"),this}return Player.prototype.then=function(e){var t=arguments.length<=1||void 0===arguments[1]?function(){}:arguments[1];return this.ready().then(e,t)},Player.prototype.callMethod=function(e){var n=this,r=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return new E(function(o,i){return n.ready().then(function(){t(n,e,{resolve:o,reject:i}),v(n,e,r)})})},Player.prototype.get=function(e){var n=this;return new E(function(r,o){return e=i(e,"get"),n.ready().then(function(){t(n,e,{resolve:r,reject:o}),v(n,e)})})},Player.prototype.set=function(e,n){var r=this;return E.resolve(n).then(function(n){if(e=i(e,"set"),void 0===n||null===n)throw new TypeError("There must be a value to set.");return r.ready().then(function(){return new E(function(o,i){t(r,e,{resolve:o,reject:i}),v(r,e,n)})})})},Player.prototype.on=function(e,r){if(!e)throw new TypeError("You must pass an event name.");if(!r)throw new TypeError("You must pass a callback function.");if("function"!=typeof r)throw new TypeError("The callback must be a function.");var o=n(this,"event:"+e);0===o.length&&this.callMethod("addEventListener",e).catch(function(){}),t(this,"event:"+e,r)},Player.prototype.off=function(e,t){if(!e)throw new TypeError("You must pass an event name.");if(t&&"function"!=typeof t)throw new TypeError("The callback must be a function.");var n=r(this,"event:"+e,t);n&&this.callMethod("removeEventListener",e).catch(function(e){})},Player.prototype.loadVideo=function(e){return this.callMethod("loadVideo",e)},Player.prototype.ready=function(){var e=j.get(this);return E.resolve(e)},Player.prototype.enableTextTrack=function(e,t){if(!e)throw new TypeError("You must pass a language.");return this.callMethod("enableTextTrack",{language:e,kind:t})},Player.prototype.disableTextTrack=function(){return this.callMethod("disableTextTrack")},Player.prototype.pause=function(){return this.callMethod("pause")},Player.prototype.play=function(){return this.callMethod("play")},Player.prototype.unload=function(){return this.callMethod("unload")},Player.prototype.getAutopause=function(){return this.get("autopause")},Player.prototype.setAutopause=function(e){return this.set("autopause",e)},Player.prototype.getColor=function(){return this.get("color")},Player.prototype.setColor=function(e){return this.set("color",e)},Player.prototype.getCurrentTime=function(){return this.get("currentTime")},Player.prototype.setCurrentTime=function(e){return this.set("currentTime",e)},Player.prototype.getDuration=function(){return this.get("duration")},Player.prototype.getEnded=function(){return this.get("ended")},Player.prototype.getLoop=function(){return this.get("loop")},Player.prototype.setLoop=function(e){return this.set("loop",e)},Player.prototype.getPaused=function(){return this.get("paused")},Player.prototype.getTextTracks=function(){return this.get("textTracks")},Player.prototype.getVideoEmbedCode=function(){return this.get("videoEmbedCode")},Player.prototype.getVideoId=function(){return this.get("videoId")},Player.prototype.getVideoTitle=function(){return this.get("videoTitle")},Player.prototype.getVideoWidth=function(){return this.get("videoWidth")},Player.prototype.getVideoHeight=function(){return this.get("videoHeight")},Player.prototype.getVideoUrl=function(){return this.get("videoUrl")},Player.prototype.getVolume=function(){return this.get("volume")},Player.prototype.setVolume=function(e){return this.set("volume",e)},Player}();return d(),Player}); 11 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 12 | },{}],2:[function(require,module,exports){ 13 | (function (global){ 14 | 'use strict'; 15 | 16 | exports.__esModule = true; 17 | 18 | var _video = (typeof window !== "undefined" ? window['videojs'] : typeof global !== "undefined" ? global['videojs'] : null); 19 | 20 | var _video2 = _interopRequireDefault(_video); 21 | 22 | var _player = require('@vimeo/player'); 23 | 24 | var _player2 = _interopRequireDefault(_player); 25 | 26 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 27 | 28 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 29 | 30 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 31 | 32 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 33 | 34 | var Component = _video2.default.getComponent('Component'); 35 | var Tech = _video2.default.getComponent('Tech'); 36 | var cssInjected = false; 37 | 38 | /** 39 | * Vimeo - Wrapper for Video Player API 40 | * 41 | * @param {Object=} options Object of option names and values 42 | * @param {Function=} ready Ready callback function 43 | * @extends Tech 44 | * @class Vimeo 45 | */ 46 | 47 | var Vimeo = function (_Tech) { 48 | _inherits(Vimeo, _Tech); 49 | 50 | function Vimeo(options, ready) { 51 | _classCallCheck(this, Vimeo); 52 | 53 | var _this = _possibleConstructorReturn(this, _Tech.call(this, options, ready)); 54 | 55 | injectCss(); 56 | _this.setPoster(options.poster); 57 | _this.initVimeoPlayer(); 58 | return _this; 59 | } 60 | 61 | Vimeo.prototype.initVimeoPlayer = function initVimeoPlayer() { 62 | var _this2 = this; 63 | 64 | var vimeoOptions = { 65 | url: this.options_.source.src, 66 | byline: false, 67 | portrait: false, 68 | title: false 69 | }; 70 | 71 | if (this.options_.autoplay) { 72 | vimeoOptions.autoplay = true; 73 | } 74 | if (this.options_.height) { 75 | vimeoOptions.height = this.options_.height; 76 | } 77 | if (this.options_.width) { 78 | vimeoOptions.width = this.options_.width; 79 | } 80 | if (this.options_.maxheight) { 81 | vimeoOptions.maxheight = this.options_.maxheight; 82 | } 83 | if (this.options_.maxwidth) { 84 | vimeoOptions.maxwidth = this.options_.maxwidth; 85 | } 86 | if (this.options_.loop) { 87 | vimeoOptions.loop = this.options_.loop; 88 | } 89 | 90 | this._player = new _player2.default(this.el(), vimeoOptions); 91 | this.initVimeoState(); 92 | 93 | ['play', 'pause', 'ended', 'timeupdate', 'progress', 'seeked'].forEach(function (e) { 94 | _this2._player.on(e, function (progress) { 95 | if (_this2._vimeoState.progress.duration != progress.duration) { 96 | _this2.trigger('durationchange'); 97 | } 98 | _this2._vimeoState.progress = progress; 99 | _this2.trigger(e); 100 | }); 101 | }); 102 | 103 | this._player.on('pause', function () { 104 | return _this2._vimeoState.playing = false; 105 | }); 106 | this._player.on('play', function () { 107 | _this2._vimeoState.playing = true; 108 | _this2._vimeoState.ended = false; 109 | }); 110 | this._player.on('ended', function () { 111 | _this2._vimeoState.playing = false; 112 | _this2._vimeoState.ended = true; 113 | }); 114 | this._player.on('volumechange', function (v) { 115 | return _this2._vimeoState.volume = v; 116 | }); 117 | this._player.on('error', function (e) { 118 | return _this2.trigger('error', e); 119 | }); 120 | 121 | this.triggerReady(); 122 | }; 123 | 124 | Vimeo.prototype.initVimeoState = function initVimeoState() { 125 | var state = this._vimeoState = { 126 | ended: false, 127 | playing: false, 128 | volume: 0, 129 | progress: { 130 | seconds: 0, 131 | percent: 0, 132 | duration: 0 133 | } 134 | }; 135 | 136 | this._player.getCurrentTime().then(function (time) { 137 | return state.progress.seconds = time; 138 | }); 139 | this._player.getDuration().then(function (time) { 140 | return state.progress.duration = time; 141 | }); 142 | this._player.getPaused().then(function (paused) { 143 | return state.playing = !paused; 144 | }); 145 | this._player.getVolume().then(function (volume) { 146 | return state.volume = volume; 147 | }); 148 | }; 149 | 150 | Vimeo.prototype.createEl = function createEl() { 151 | var div = _video2.default.createEl('div', { 152 | id: this.options_.techId 153 | }); 154 | 155 | div.style.cssText = 'width:100%;height:100%;top:0;left:0;position:absolute'; 156 | div.className = 'vjs-vimeo'; 157 | 158 | return div; 159 | }; 160 | 161 | Vimeo.prototype.controls = function controls() { 162 | return true; 163 | }; 164 | 165 | Vimeo.prototype.supportsFullScreen = function supportsFullScreen() { 166 | return true; 167 | }; 168 | 169 | Vimeo.prototype.src = function src() { 170 | // @note: Not sure why this is needed but videojs requires it 171 | return this.options_.source; 172 | }; 173 | 174 | Vimeo.prototype.currentSrc = function currentSrc() { 175 | return this.options_.source.src; 176 | }; 177 | 178 | // @note setSrc is used in other usecases (YouTube, Html) it doesn't seem required here 179 | // setSrc() {} 180 | 181 | Vimeo.prototype.currentTime = function currentTime() { 182 | return this._vimeoState.progress.seconds; 183 | }; 184 | 185 | Vimeo.prototype.setCurrentTime = function setCurrentTime(time) { 186 | this._player.setCurrentTime(time); 187 | }; 188 | 189 | Vimeo.prototype.volume = function volume() { 190 | return this._vimeoState.volume; 191 | }; 192 | 193 | Vimeo.prototype.setVolume = function setVolume(v) { 194 | return this._player.setVolume(volume); 195 | }; 196 | 197 | Vimeo.prototype.duration = function duration() { 198 | return this._vimeoState.progress.duration; 199 | }; 200 | 201 | Vimeo.prototype.buffered = function buffered() { 202 | var progress = this._vimeoState.progress; 203 | return _video2.default.createTimeRange(0, progress.percent * progress.duration); 204 | }; 205 | 206 | Vimeo.prototype.paused = function paused() { 207 | return !this._vimeoState.playing; 208 | }; 209 | 210 | Vimeo.prototype.pause = function pause() { 211 | this._player.pause(); 212 | }; 213 | 214 | Vimeo.prototype.play = function play() { 215 | this._player.play(); 216 | }; 217 | 218 | Vimeo.prototype.muted = function muted() { 219 | return this._vimeoState.volume === 0; 220 | }; 221 | 222 | Vimeo.prototype.ended = function ended() { 223 | return this._vimeoState.ended; 224 | }; 225 | 226 | // Vimeo does has a mute API and native controls aren't being used, 227 | // so setMuted doesn't really make sense and shouldn't be called. 228 | // setMuted(mute) {} 229 | 230 | 231 | return Vimeo; 232 | }(Tech); 233 | 234 | Vimeo.prototype.featuresTimeupdateEvents = true; 235 | 236 | Vimeo.isSupported = function () { 237 | return true; 238 | }; 239 | 240 | // Add Source Handler pattern functions to this tech 241 | Tech.withSourceHandlers(Vimeo); 242 | 243 | Vimeo.nativeSourceHandler = {}; 244 | 245 | /** 246 | * Check if Vimeo can play the given videotype 247 | * @param {String} type The mimetype to check 248 | * @return {String} 'maybe', or '' (empty string) 249 | */ 250 | Vimeo.nativeSourceHandler.canPlayType = function (source) { 251 | if (source === 'video/vimeo') { 252 | return 'maybe'; 253 | } 254 | 255 | return ''; 256 | }; 257 | 258 | /* 259 | * Check Vimeo can handle the source natively 260 | * 261 | * @param {Object} source The source object 262 | * @return {String} 'maybe', or '' (empty string) 263 | * @note: Copied over from YouTube — not sure this is relevant 264 | */ 265 | Vimeo.nativeSourceHandler.canHandleSource = function (source) { 266 | if (source.type) { 267 | return Vimeo.nativeSourceHandler.canPlayType(source.type); 268 | } else if (source.src) { 269 | return Vimeo.nativeSourceHandler.canPlayType(source.src); 270 | } 271 | 272 | return ''; 273 | }; 274 | 275 | // @note: Copied over from YouTube — not sure this is relevant 276 | Vimeo.nativeSourceHandler.handleSource = function (source, tech) { 277 | tech.src(source.src); 278 | }; 279 | 280 | // @note: Copied over from YouTube — not sure this is relevant 281 | Vimeo.nativeSourceHandler.dispose = function () {}; 282 | 283 | Vimeo.registerSourceHandler(Vimeo.nativeSourceHandler); 284 | 285 | // Since the iframe can't be touched using Vimeo's way of embedding, 286 | // let's add a new styling rule to have the same style as `vjs-tech` 287 | function injectCss() { 288 | if (cssInjected) { 289 | return; 290 | } 291 | cssInjected = true; 292 | var css = '\n .vjs-vimeo iframe {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n '; 293 | var head = document.head || document.getElementsByTagName('head')[0]; 294 | 295 | var style = document.createElement('style'); 296 | style.type = 'text/css'; 297 | 298 | if (style.styleSheet) { 299 | style.styleSheet.cssText = css; 300 | } else { 301 | style.appendChild(document.createTextNode(css)); 302 | } 303 | 304 | head.appendChild(style); 305 | } 306 | 307 | Component.registerComponent('Vimeo', Vimeo); 308 | Tech.registerTech('Vimeo', Vimeo); 309 | 310 | // Include the version number. 311 | Vimeo.VERSION = '0.0.1'; 312 | 313 | exports.default = Vimeo; 314 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 315 | },{"@vimeo/player":1}]},{},[2])(2) 316 | }); -------------------------------------------------------------------------------- /dist/videojs-vimeo.min.js: -------------------------------------------------------------------------------- 1 | !function e(t,n,o){function r(a,u){if(!n[a]){if(!t[a]){var s="function"==typeof require&&require;if(!u&&s)return s(a,!0);if(i)return i(a,!0);var c=new Error("Cannot find module '"+a+"'");throw c.code="MODULE_NOT_FOUND",c}var f=n[a]={exports:{}};t[a][0].call(f.exports,function(e){var n=t[a][1][e];return r(n?n:e)},f,f.exports,e,t,n,o)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;a=n.length)break;i=n[r++]}else{if(r=n.next(),r.done)break;i=r.value}var a=i,u=e.getAttribute("data-vimeo-"+a);(u||""===u)&&(t[a]=""===u?1:u)}return t}function p(e){var t=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return new Promise(function(n,o){if(!c(e))throw new TypeError("“"+e+"” is not a vimeo.com url.");var r="https://vimeo.com/api/oembed.json?url="+encodeURIComponent(e);for(var i in t)t.hasOwnProperty(i)&&(r+="&"+i+"="+encodeURIComponent(t[i]));var a="XDomainRequest"in window?new XDomainRequest:new XMLHttpRequest;a.open("GET",r,!0),a.onload=function(){if(404===a.status)return void o(new Error("“"+e+"” was not found."));if(403===a.status)return void o(new Error("“"+e+"” is not embeddable."));try{var t=JSON.parse(a.responseText);n(t)}catch(e){o(e)}},a.onerror=function(){var e=a.status?" ("+a.status+")":"";o(new Error("There was an error fetching the embed code from Vimeo"+e+"."))},a.send()})}function h(e,t){var n=e.html;if(!t)throw new TypeError("An element must be provided");if(null!==t.getAttribute("data-vimeo-initialized"))return t.querySelector("iframe");var o=document.createElement("div");return o.innerHTML=n,t.appendChild(o.firstChild),t.setAttribute("data-vimeo-initialized","true"),t.querySelector("iframe")}function d(){var e=arguments.length<=0||void 0===arguments[0]?document:arguments[0],t=[].slice.call(e.querySelectorAll("[data-vimeo-id], [data-vimeo-url]")),n=function(e){"console"in window&&console.error&&console.error("There was an error creating an embed: "+e)},o=function(){if(i){if(a>=r.length)return"break";u=r[a++]}else{if(a=r.next(),a.done)return"break";u=a.value}var e=u;try{if(null!==e.getAttribute("data-vimeo-defer"))return"continue";var t=l(e),o=f(t);p(o,t).then(function(t){return h(t,e)}).catch(n)}catch(e){n(e)}};e:for(var r=t,i=Array.isArray(r),a=0,r=i?r:r[Symbol.iterator]();;){var u,s=o();switch(s){case"break":break e;case"continue":continue}}}function y(e){return"string"==typeof e&&(e=JSON.parse(e)),e}function v(e,t,n){if(e.element.contentWindow.postMessage){var o={method:t};void 0!==n&&(o.value=n);var r=parseFloat(navigator.userAgent.toLowerCase().replace(/^.*msie (\d+).*$/,"$1"));r>=8&&r<10&&(o=JSON.stringify(o)),e.element.contentWindow.postMessage(o,e.origin)}}function m(e,t){t=y(t);var n=[],i=void 0;if(t.event){if("error"===t.event)for(var a=o(e,t.data.method),u=a,s=Array.isArray(u),c=0,u=s?u:u[Symbol.iterator]();;){var f;if(s){if(c>=u.length)break;f=u[c++]}else{if(c=u.next(),c.done)break;f=c.value}var l=f,p=new Error(t.data.message);p.name=t.data.name,l.reject(p),r(e,t.data.method,l)}n=o(e,"event:"+t.event),i=t.data}else t.method&&(n=o(e,t.method),i=t.value,r(e,t.method));for(var h=n,d=Array.isArray(h),v=0,h=d?h:h[Symbol.iterator]();;){var m;if(d){if(v>=h.length)break;m=h[v++]}else{if(v=h.next(),v.done)break;m=v.value}var g=m;try{if("function"==typeof g){g.call(e,i);continue}g.resolve(i)}catch(e){}}}var g="undefined"!=typeof Array.prototype.indexOf,w="undefined"!=typeof window.postMessage;if(!g||!w)throw new Error("Sorry, the Vimeo Player API is not available in this browser.");var _="undefined"!=typeof window?window:"undefined"!=typeof e?e:"undefined"!=typeof self?self:{},b=(t(function(e,t){!function(e){function t(e,t){function o(e){return this&&this.constructor===o?(this._keys=[],this._values=[],this._itp=[],this.objectOnly=t,void(e&&n.call(this,e))):new o(e)}return t||w(e,"size",{get:v}),e.constructor=o,o.prototype=e,o}function n(e){this.add?e.forEach(this.add,this):e.forEach(function(e){this.set(e[0],e[1])},this)}function o(e){return this.has(e)&&(this._keys.splice(g,1),this._values.splice(g,1),this._itp.forEach(function(e){g0&&e(n,s))}catch(e){i.call(new u(s),e)}}}function i(t){var o=this;o.triggered||(o.triggered=!0,o.def&&(o=o.def),o.msg=t,o.state=2,o.chain.length>0&&e(n,o))}function a(e,t,n,o){for(var r=0;r1&&window.console&&console.warn&&console.warn("A jQuery object with multiple elements was passed, using the first element."),t=t[0]),"string"==typeof t&&(t=document.getElementById(t)),!u(t))throw new TypeError("You must pass either a valid element or a valid id.");if("IFRAME"!==t.nodeName){var r=t.querySelector("iframe");r&&(t=r)}if("IFRAME"===t.nodeName&&!c(t.getAttribute("src")||""))throw new Error("The player element passed isn’t a Vimeo embed.");if(k.has(t))return k.get(t);this.element=t,this.origin="*";var a=new T(function(e,r){var a=function(t){if(c(t.origin)&&n.element.contentWindow===t.source){"*"===n.origin&&(n.origin=t.origin);var o=y(t.data),r="event"in o&&"ready"===o.event,i="method"in o&&"ping"===o.method;return r||i?(n.element.setAttribute("data-ready","true"),void e()):void m(n,o)}};if(window.addEventListener?window.addEventListener("message",a,!1):window.attachEvent&&window.attachEvent("onmessage",a),"IFRAME"!==n.element.nodeName){var u=l(t,o),s=f(u);p(s,u).then(function(e){var o=h(e,t);return n.element=o,i(t,o),e}).catch(function(e){return r(e)})}});return j.set(this,a),k.set(this.element,this),"IFRAME"===this.element.nodeName&&v(this,"ping"),this}return e.prototype.then=function(e){var t=arguments.length<=1||void 0===arguments[1]?function(){}:arguments[1];return this.ready().then(e,t)},e.prototype.callMethod=function(e){var t=this,o=arguments.length<=1||void 0===arguments[1]?{}:arguments[1];return new T(function(r,i){return t.ready().then(function(){n(t,e,{resolve:r,reject:i}),v(t,e,o)})})},e.prototype.get=function(e){var t=this;return new T(function(o,r){return e=a(e,"get"),t.ready().then(function(){n(t,e,{resolve:o,reject:r}),v(t,e)})})},e.prototype.set=function(e,t){var o=this;return T.resolve(t).then(function(t){if(e=a(e,"set"),void 0===t||null===t)throw new TypeError("There must be a value to set.");return o.ready().then(function(){return new T(function(r,i){n(o,e,{resolve:r,reject:i}),v(o,e,t)})})})},e.prototype.on=function(e,t){if(!e)throw new TypeError("You must pass an event name.");if(!t)throw new TypeError("You must pass a callback function.");if("function"!=typeof t)throw new TypeError("The callback must be a function.");var r=o(this,"event:"+e);0===r.length&&this.callMethod("addEventListener",e).catch(function(){}),n(this,"event:"+e,t)},e.prototype.off=function(e,t){if(!e)throw new TypeError("You must pass an event name.");if(t&&"function"!=typeof t)throw new TypeError("The callback must be a function.");var n=r(this,"event:"+e,t);n&&this.callMethod("removeEventListener",e).catch(function(e){})},e.prototype.loadVideo=function(e){return this.callMethod("loadVideo",e)},e.prototype.ready=function(){var e=j.get(this);return T.resolve(e)},e.prototype.enableTextTrack=function(e,t){if(!e)throw new TypeError("You must pass a language.");return this.callMethod("enableTextTrack",{language:e,kind:t})},e.prototype.disableTextTrack=function(){return this.callMethod("disableTextTrack")},e.prototype.pause=function(){return this.callMethod("pause")},e.prototype.play=function(){return this.callMethod("play")},e.prototype.unload=function(){return this.callMethod("unload")},e.prototype.getAutopause=function(){return this.get("autopause")},e.prototype.setAutopause=function(e){return this.set("autopause",e)},e.prototype.getColor=function(){return this.get("color")},e.prototype.setColor=function(e){return this.set("color",e)},e.prototype.getCurrentTime=function(){return this.get("currentTime")},e.prototype.setCurrentTime=function(e){return this.set("currentTime",e)},e.prototype.getDuration=function(){return this.get("duration")},e.prototype.getEnded=function(){return this.get("ended")},e.prototype.getLoop=function(){return this.get("loop")},e.prototype.setLoop=function(e){return this.set("loop",e)},e.prototype.getPaused=function(){return this.get("paused")},e.prototype.getTextTracks=function(){return this.get("textTracks")},e.prototype.getVideoEmbedCode=function(){return this.get("videoEmbedCode")},e.prototype.getVideoId=function(){return this.get("videoId")},e.prototype.getVideoTitle=function(){return this.get("videoTitle")},e.prototype.getVideoWidth=function(){return this.get("videoWidth")},e.prototype.getVideoHeight=function(){return this.get("videoHeight")},e.prototype.getVideoUrl=function(){return this.get("videoUrl")},e.prototype.getVolume=function(){return this.get("volume")},e.prototype.setVolume=function(e){return this.set("volume",e)},e}();return d(),M})}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],2:[function(e,t,n){(function(t){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function u(){if(!d){d=!0;var e="\n .vjs-vimeo iframe {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n }\n ",t=document.head||document.getElementsByTagName("head")[0],n=document.createElement("style");n.type="text/css",n.styleSheet?n.styleSheet.cssText=e:n.appendChild(document.createTextNode(e)),t.appendChild(n)}}n.__esModule=!0;var s="undefined"!=typeof window?window.videojs:"undefined"!=typeof t?t.videojs:null,c=o(s),f=e(1),l=o(f),p=c.default.getComponent("Component"),h=c.default.getComponent("Tech"),d=!1,y=function(e){function t(n,o){r(this,t);var a=i(this,e.call(this,n,o));return u(),a.setPoster(n.poster),a.initVimeoPlayer(),a}return a(t,e),t.prototype.initVimeoPlayer=function(){var e=this,t={url:this.options_.source.src,byline:!1,portrait:!1,title:!1};this.options_.autoplay&&(t.autoplay=!0),this.options_.height&&(t.height=this.options_.height),this.options_.width&&(t.width=this.options_.width),this.options_.maxheight&&(t.maxheight=this.options_.maxheight),this.options_.maxwidth&&(t.maxwidth=this.options_.maxwidth),this.options_.loop&&(t.loop=this.options_.loop),this._player=new l.default(this.el(),t),this.initVimeoState(),["play","pause","ended","timeupdate","progress","seeked"].forEach(function(t){e._player.on(t,function(n){e._vimeoState.progress.duration!=n.duration&&e.trigger("durationchange"),e._vimeoState.progress=n,e.trigger(t)})}),this._player.on("pause",function(){return e._vimeoState.playing=!1}),this._player.on("play",function(){e._vimeoState.playing=!0,e._vimeoState.ended=!1}),this._player.on("ended",function(){e._vimeoState.playing=!1,e._vimeoState.ended=!0}),this._player.on("volumechange",function(t){return e._vimeoState.volume=t}),this._player.on("error",function(t){return e.trigger("error",t)}),this.triggerReady()},t.prototype.initVimeoState=function(){var e=this._vimeoState={ended:!1,playing:!1,volume:0,progress:{seconds:0,percent:0,duration:0}};this._player.getCurrentTime().then(function(t){return e.progress.seconds=t}),this._player.getDuration().then(function(t){return e.progress.duration=t}),this._player.getPaused().then(function(t){return e.playing=!t}),this._player.getVolume().then(function(t){return e.volume=t})},t.prototype.createEl=function(){var e=c.default.createEl("div",{id:this.options_.techId});return e.style.cssText="width:100%;height:100%;top:0;left:0;position:absolute",e.className="vjs-vimeo",e},t.prototype.controls=function(){return!0},t.prototype.supportsFullScreen=function(){return!0},t.prototype.src=function(){return this.options_.source},t.prototype.currentSrc=function(){return this.options_.source.src},t.prototype.currentTime=function(){return this._vimeoState.progress.seconds},t.prototype.setCurrentTime=function(e){this._player.setCurrentTime(e)},t.prototype.volume=function(){return this._vimeoState.volume},t.prototype.setVolume=function(e){return this._player.setVolume(volume)},t.prototype.duration=function(){return this._vimeoState.progress.duration},t.prototype.buffered=function(){var e=this._vimeoState.progress;return c.default.createTimeRange(0,e.percent*e.duration)},t.prototype.paused=function(){return!this._vimeoState.playing},t.prototype.pause=function(){this._player.pause()},t.prototype.play=function(){this._player.play()},t.prototype.muted=function(){return 0===this._vimeoState.volume},t.prototype.ended=function(){return this._vimeoState.ended},t}(h);y.prototype.featuresTimeupdateEvents=!0,y.isSupported=function(){return!0},h.withSourceHandlers(y),y.nativeSourceHandler={},y.nativeSourceHandler.canPlayType=function(e){return"video/vimeo"===e?"maybe":""},y.nativeSourceHandler.canHandleSource=function(e){return e.type?y.nativeSourceHandler.canPlayType(e.type):e.src?y.nativeSourceHandler.canPlayType(e.src):""},y.nativeSourceHandler.handleSource=function(e,t){t.src(e.src)},y.nativeSourceHandler.dispose=function(){},y.registerSourceHandler(y.nativeSourceHandler),p.registerComponent("Vimeo",y),h.registerTech("Vimeo",y),y.VERSION="0.0.1",n.default=y}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}]},{},[2]); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | videojs-vimeo Demo 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /jsdoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": ["plugins/markdown"] 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "videojs-vimeo", 3 | "version": "2.0.2", 4 | "description": "Videojs Vimeo plugin using the official Vimeo Player API.", 5 | "main": "es5/Vimeo.js", 6 | "scripts": { 7 | "prebuild": "npm run clean", 8 | "build": "npm-run-all -p build:*", 9 | "build:js": "npm-run-all build:js:babel build:js:browserify build:js:bannerize build:js:collapse build:js:uglify", 10 | "build:js:babel": "babel src -d es5", 11 | "build:js:bannerize": "bannerize dist/videojs-vimeo.js --banner=scripts/banner.ejs", 12 | "build:js:browserify": "browserify . -g browserify-shim -s videojs-vimeo -o dist/videojs-vimeo.js", 13 | "build:js:collapse": "bundle-collapser dist/videojs-vimeo.js -o dist/videojs-vimeo.min.js", 14 | "build:js:uglify": "uglifyjs dist/videojs-vimeo.min.js --comments --mangle --compress -o dist/videojs-vimeo.min.js", 15 | "clean": "rimraf dist test/dist es5 && mkdirp dist test/dist es5", 16 | "lint": "vjsstandard", 17 | "start": "babel-node scripts/server.js", 18 | "version": "babel-node scripts/version.js", 19 | "postversion": "babel-node scripts/postversion.js", 20 | "prepublish": "npm run build" 21 | }, 22 | "keywords": [ 23 | "videojs", 24 | "videojs-plugin", 25 | "vimeo" 26 | ], 27 | "author": "Benoit Tremblay ", 28 | "license": "MIT", 29 | "browserify": { 30 | "transform": [ 31 | "browserify-versionify" 32 | ] 33 | }, 34 | "browserify-shim": { 35 | "qunit": "global:QUnit", 36 | "sinon": "global:sinon", 37 | "video.js": "global:videojs" 38 | }, 39 | "style": "dist/videojs-vimeo.css", 40 | "videojs-plugin": { 41 | "style": "dist/videojs-vimeo.css", 42 | "script": "dist/videojs-vimeo.min.js" 43 | }, 44 | "vjsstandard": { 45 | "ignore": [ 46 | "dist", 47 | "docs", 48 | "es5", 49 | "scripts", 50 | "test/dist" 51 | ] 52 | }, 53 | "files": [ 54 | "CONTRIBUTING.md", 55 | "bower.json", 56 | "dist/", 57 | "docs/", 58 | "es5/", 59 | "index.html", 60 | "scripts/", 61 | "src/" 62 | ], 63 | "dependencies": { 64 | "@vimeo/player": "^2.0.1", 65 | "browserify-versionify": "^1.0.6", 66 | "video.js": "^5.16" 67 | }, 68 | "devDependencies": { 69 | "babel-cli": "^6.14.0", 70 | "babel-plugin-transform-object-assign": "^6.8.0", 71 | "babel-preset-es2015": "^6.14.0", 72 | "babelify": "^7.3.0", 73 | "bannerize": "^1.0.2", 74 | "bluebird": "^3.2.2", 75 | "browserify": "^12.0.2", 76 | "browserify-shim": "^3.8.12", 77 | "budo": "^8.0.4", 78 | "bundle-collapser": "^1.2.1", 79 | "ghooks": "^1.3.2", 80 | "glob": "^6.0.3", 81 | "global": "^4.3.0", 82 | "karma": "^0.13.19", 83 | "karma-chrome-launcher": "^0.2.2", 84 | "karma-detect-browsers": "^2.0.2", 85 | "karma-firefox-launcher": "^0.1.7", 86 | "karma-ie-launcher": "^0.2.0", 87 | "karma-qunit": "^0.1.9", 88 | "karma-safari-launcher": "^0.1.1", 89 | "lodash": "^4.11.2", 90 | "mkdirp": "^0.5.1", 91 | "npm-run-all": "^1.5.1", 92 | "qunitjs": "^1.21.0", 93 | "rimraf": "^2.5.1", 94 | "sinon": "~1.14.0", 95 | "uglify-js": "^2.6.1", 96 | "videojs-standard": "^4.0.0" 97 | }, 98 | "config": { 99 | "ghooks": { 100 | "pre-push": "npm run lint" 101 | } 102 | }, 103 | "directories": { 104 | "test": "test" 105 | }, 106 | "repository": { 107 | "type": "git", 108 | "url": "git+https://github.com/videojs/videojs-vimeo.git" 109 | }, 110 | "bugs": { 111 | "url": "https://github.com/videojs/videojs-vimeo/issues" 112 | }, 113 | "homepage": "https://github.com/videojs/videojs-vimeo#readme" 114 | } 115 | -------------------------------------------------------------------------------- /scripts/banner.ejs: -------------------------------------------------------------------------------- 1 | /** 2 | * <%- pkg.name %> 3 | * @version <%- pkg.version %> 4 | * @copyright <%- date.getFullYear() %> <%- pkg.author %> 5 | * @license <%- pkg.license %> 6 | */ 7 | -------------------------------------------------------------------------------- /scripts/build-test.js: -------------------------------------------------------------------------------- 1 | import browserify from 'browserify'; 2 | import fs from 'fs'; 3 | import glob from 'glob'; 4 | 5 | /* eslint no-console: 0 */ 6 | 7 | glob('test/**/*.test.js', (err, files) => { 8 | if (err) { 9 | throw err; 10 | } 11 | browserify(files) 12 | .transform('babelify') 13 | .transform('browserify-shim', {global: true}) 14 | .bundle() 15 | .pipe(fs.createWriteStream('test/dist/bundle.js')); 16 | }); 17 | -------------------------------------------------------------------------------- /scripts/postversion.js: -------------------------------------------------------------------------------- 1 | import {exec} from 'child_process'; 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | /* eslint no-console: 0 */ 6 | 7 | /** 8 | * Determines whether or not the project has the Bower setup by checking for 9 | * the presence of a bower.json file. 10 | * 11 | * @return {Boolean} 12 | */ 13 | const hasBower = () => { 14 | try { 15 | fs.statSync(path.join(__dirname, '../bower.json')); 16 | return true; 17 | } catch (x) { 18 | return false; 19 | } 20 | }; 21 | 22 | // If the project supports Bower, roll HEAD back one commit to avoid having 23 | // the tagged commit - with `dist/` - in the main history. 24 | if (hasBower()) { 25 | exec('git reset --hard HEAD~1', (err, stdout, stderr) => { 26 | if (err) { 27 | process.stdout.write(err.stack); 28 | process.exit(err.status || 1); 29 | } else { 30 | process.stdout.write(stdout); 31 | } 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /scripts/server.js: -------------------------------------------------------------------------------- 1 | import Promise from 'bluebird'; 2 | import browserify from 'browserify'; 3 | import budo from 'budo'; 4 | import fs from 'fs'; 5 | import glob from 'glob'; 6 | import _ from 'lodash'; 7 | import mkdirp from 'mkdirp'; 8 | import path from 'path'; 9 | 10 | /* eslint no-console: 0 */ 11 | 12 | const pkg = require(path.join(__dirname, '../package.json')); 13 | 14 | // Replace "%s" tokens with the plugin name in a string. 15 | const nameify = (str) => 16 | str.replace(/%s/g, pkg.name.split('/').reverse()[0]); 17 | 18 | const srces = { 19 | js: 'src/vimeo.js', 20 | }; 21 | 22 | const dests = { 23 | js: nameify('dist/%s.js'), 24 | }; 25 | 26 | const tasks = { 27 | 28 | js: browserify({ 29 | debug: true, 30 | entries: [srces.js], 31 | standalone: nameify('%s'), 32 | transform: [ 33 | 'babelify', 34 | ['browserify-shim', {global: true}] 35 | ] 36 | }), 37 | 38 | tests: browserify({ 39 | debug: true, 40 | entries: srces.tests, 41 | transform: [ 42 | 'babelify', 43 | ['browserify-shim', {global: true}] 44 | ] 45 | }) 46 | }; 47 | 48 | /** 49 | * Runs one of the builds from the tasks object. 50 | * 51 | * @param {String} name 52 | * Should match a key from the `tasks` object. 53 | * 54 | * @return {Promise} 55 | */ 56 | const build = (name) => { 57 | if (Array.isArray(name)) { 58 | return Promise.all(name.map(build)); 59 | } 60 | 61 | // This returns a Promise even in the case of synchronous tasks because 62 | // a consistent contract is useful. Ideally, we'll make the synchronous 63 | // tasks asynchronous, but it's not critical. 64 | return new Promise((resolve, reject) => { 65 | if (typeof tasks[name] === 'function') { 66 | tasks[name](resolve, reject); 67 | } else { 68 | tasks[name] 69 | .bundle() 70 | .pipe(fs.createWriteStream(dests[name])) 71 | .on('finish', resolve) 72 | .on('error', reject); 73 | } 74 | }); 75 | }; 76 | 77 | mkdirp.sync('dist'); 78 | 79 | // Start the server _after_ the initial bundling is done. 80 | build(['js']).then(() => { 81 | const server = budo({ 82 | port: 9999, 83 | stream: process.stdout 84 | }).on('reload', (f) => console.log('reloading %s', f || 'everything')); 85 | 86 | /** 87 | * A collection of functions which are mapped to strings that are used to 88 | * generate RegExp objects. If a filepath matches the RegExp, the function 89 | * will be used to handle that watched file. 90 | * 91 | * @type {Object} 92 | */ 93 | const handlers = { 94 | 95 | /** 96 | * Handler for JavaScript source and tests. 97 | * 98 | * @param {String} event 99 | * @param {String} file 100 | */ 101 | '^(src|test)/.+\.js$': _.debounce((event, file) => { 102 | console.log('bundling javascript and tests'); 103 | build(['js', 'tests']).then(() => server.reload()); 104 | }) 105 | }; 106 | 107 | /** 108 | * Finds the first handler function for the file that matches a RegExp 109 | * derived from the keys. 110 | * 111 | * @param {String} file 112 | * @return {Function|Undefined} 113 | */ 114 | const findHandler = (file) => { 115 | const keys = Object.keys(handlers); 116 | 117 | for (let i = 0; i < keys.length; i++) { 118 | const regexp = new RegExp(keys[i]); 119 | 120 | if (regexp.test(file)) { 121 | return handlers[keys[i]]; 122 | } 123 | } 124 | }; 125 | 126 | server 127 | .live() 128 | .watch([ 129 | 'index.html', 130 | 'src/**/*.js', 131 | 'test/**/*.js', 132 | '!test/dist/**/*.js', 133 | 'test/index.html' 134 | ]) 135 | .on('watch', (event, file) => { 136 | const handler = findHandler(file); 137 | 138 | console.log(`detected a "${event}" event in "${file}"`); 139 | 140 | if (handler) { 141 | handler(event, file); 142 | } else { 143 | server.reload(); 144 | } 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /scripts/version.js: -------------------------------------------------------------------------------- 1 | import {exec} from 'child_process'; 2 | import fs from 'fs'; 3 | import path from 'path'; 4 | 5 | /* eslint no-console: 0 */ 6 | 7 | const pkg = require(path.join(__dirname, '../package.json')); 8 | 9 | /** 10 | * Determines whether or not the project has the CHANGELOG setup by checking 11 | * for the presence of a CHANGELOG.md file and the necessary dependency and 12 | * npm script. 13 | * 14 | * @return {Boolean} 15 | */ 16 | const hasChangelog = () => { 17 | try { 18 | fs.statSync(path.join(__dirname, '../CHANGELOG.md')); 19 | } catch (x) { 20 | return false; 21 | } 22 | return pkg.devDependencies.hasOwnProperty('chg') && 23 | pkg.scripts.hasOwnProperty('change'); 24 | }; 25 | 26 | /** 27 | * Determines whether or not the project has the Bower setup by checking for 28 | * the presence of a bower.json file. 29 | * 30 | * @return {Boolean} 31 | */ 32 | const hasBower = () => { 33 | try { 34 | fs.statSync(path.join(__dirname, '../bower.json')); 35 | return true; 36 | } catch (x) { 37 | return false; 38 | } 39 | }; 40 | 41 | const commands = []; 42 | 43 | // If the project has a CHANGELOG, update it for the new release. 44 | if (hasChangelog()) { 45 | commands.push(`chg release "${pkg.version}"`); 46 | commands.push('git add CHANGELOG.md'); 47 | } 48 | 49 | // If the project supports Bower, perform special extra versioning step. 50 | if (hasBower()) { 51 | commands.push('git add package.json'); 52 | commands.push(`git commit -m "${pkg.version}"`); 53 | 54 | // We only need a build in the Bower-supported case because of the 55 | // temporary addition of the dist/ directory. 56 | commands.push('npm run build'); 57 | commands.push('git add -f dist'); 58 | } 59 | 60 | if (commands.length) { 61 | exec(commands.join(' && '), (err, stdout, stderr) => { 62 | if (err) { 63 | process.stdout.write(err.stack); 64 | process.exit(err.status || 1); 65 | } else { 66 | process.stdout.write(stdout); 67 | } 68 | }); 69 | } 70 | -------------------------------------------------------------------------------- /src/Vimeo.js: -------------------------------------------------------------------------------- 1 | import videojs from 'video.js'; 2 | import VimeoPlayer from '@vimeo/player'; 3 | 4 | const Component = videojs.getComponent('Component'); 5 | const Tech = videojs.getComponent('Tech'); 6 | let cssInjected = false; 7 | 8 | // Since the iframe can't be touched using Vimeo's way of embedding, 9 | // let's add a new styling rule to have the same style as `vjs-tech` 10 | function injectCss() { 11 | if (cssInjected) { 12 | return; 13 | } 14 | cssInjected = true; 15 | const css = ` 16 | .vjs-vimeo iframe { 17 | position: absolute; 18 | top: 0; 19 | left: 0; 20 | width: 100%; 21 | height: 100%; 22 | } 23 | `; 24 | const head = document.head || document.getElementsByTagName('head')[0]; 25 | 26 | const style = document.createElement('style'); 27 | 28 | style.type = 'text/css'; 29 | 30 | if (style.styleSheet) { 31 | style.styleSheet.cssText = css; 32 | } else { 33 | style.appendChild(document.createTextNode(css)); 34 | } 35 | 36 | head.appendChild(style); 37 | } 38 | 39 | /** 40 | * Vimeo - Wrapper for Video Player API 41 | * 42 | * @param {Object=} options Object of option names and values 43 | * @param {Function=} ready Ready callback function 44 | * @extends Tech 45 | * @class Vimeo 46 | */ 47 | class Vimeo extends Tech { 48 | constructor(options, ready) { 49 | super(options, ready); 50 | 51 | injectCss(); 52 | this.setPoster(options.poster); 53 | this.initVimeoPlayer(); 54 | } 55 | 56 | initVimeoPlayer() { 57 | const vimeoOptions = { 58 | url: this.options_.source.src, 59 | byline: false, 60 | portrait: false, 61 | title: false 62 | }; 63 | 64 | if (this.options_.autoplay) { 65 | vimeoOptions.autoplay = true; 66 | } 67 | if (this.options_.height) { 68 | vimeoOptions.height = this.options_.height; 69 | } 70 | if (this.options_.width) { 71 | vimeoOptions.width = this.options_.width; 72 | } 73 | if (this.options_.maxheight) { 74 | vimeoOptions.maxheight = this.options_.maxheight; 75 | } 76 | if (this.options_.maxwidth) { 77 | vimeoOptions.maxwidth = this.options_.maxwidth; 78 | } 79 | if (this.options_.loop) { 80 | vimeoOptions.loop = this.options_.loop; 81 | } 82 | if (this.options_.color) { 83 | // vimeo is the only API on earth to reject hex color with leading # 84 | vimeoOptions.color = this.options_.color.replace(/^#/, ''); 85 | } 86 | 87 | this._player = new VimeoPlayer(this.el(), vimeoOptions); 88 | this.initVimeoState(); 89 | 90 | ['play', 'pause', 'ended', 'timeupdate', 'progress', 'seeked'].forEach(e => { 91 | this._player.on(e, (progress) => { 92 | if (this._vimeoState.progress.duration !== progress.duration) { 93 | this.trigger('durationchange'); 94 | } 95 | this._vimeoState.progress = progress; 96 | this.trigger(e); 97 | }); 98 | }); 99 | 100 | this._player.on('pause', () => this._vimeoState.playing = false); 101 | this._player.on('play', () => { 102 | this._vimeoState.playing = true; 103 | this._vimeoState.ended = false; 104 | }); 105 | this._player.on('ended', () => { 106 | this._vimeoState.playing = false; 107 | this._vimeoState.ended = true; 108 | }); 109 | this._player.on('volumechange', (v) => this._vimeoState.volume = v); 110 | this._player.on('error', e => this.trigger('error', e)); 111 | 112 | this.triggerReady(); 113 | } 114 | 115 | initVimeoState() { 116 | const state = this._vimeoState = { 117 | ended: false, 118 | playing: false, 119 | volume: 0, 120 | progress: { 121 | seconds: 0, 122 | percent: 0, 123 | duration: 0 124 | } 125 | }; 126 | 127 | this._player.getCurrentTime().then(time => state.progress.seconds = time); 128 | this._player.getDuration().then(time => state.progress.duration = time); 129 | this._player.getPaused().then(paused => state.playing = !paused); 130 | this._player.getVolume().then(volume => state.volume = volume); 131 | } 132 | 133 | createEl() { 134 | const div = videojs.createEl('div', { 135 | id: this.options_.techId 136 | }); 137 | 138 | div.style.cssText = 'width:100%;height:100%;top:0;left:0;position:absolute'; 139 | div.className = 'vjs-vimeo'; 140 | 141 | return div; 142 | } 143 | 144 | controls() { 145 | return true; 146 | } 147 | 148 | supportsFullScreen() { 149 | return true; 150 | } 151 | 152 | src() { 153 | // @note: Not sure why this is needed but videojs requires it 154 | return this.options_.source; 155 | } 156 | 157 | currentSrc() { 158 | return this.options_.source.src; 159 | } 160 | 161 | // @note setSrc is used in other usecases (YouTube, Html) it doesn't seem required here 162 | // setSrc() {} 163 | 164 | currentTime() { 165 | return this._vimeoState.progress.seconds; 166 | } 167 | 168 | setCurrentTime(time) { 169 | this._player.setCurrentTime(time); 170 | } 171 | 172 | volume() { 173 | return this._vimeoState.volume; 174 | } 175 | 176 | setVolume(volume) { 177 | return this._player.setVolume(volume); 178 | } 179 | 180 | duration() { 181 | return this._vimeoState.progress.duration; 182 | } 183 | 184 | buffered() { 185 | const progress = this._vimeoState.progress; 186 | 187 | return videojs.createTimeRange(0, progress.percent * progress.duration); 188 | } 189 | 190 | paused() { 191 | return !this._vimeoState.playing; 192 | } 193 | 194 | pause() { 195 | this._player.pause(); 196 | } 197 | 198 | play() { 199 | this._player.play(); 200 | } 201 | 202 | muted() { 203 | return this._vimeoState.volume === 0; 204 | } 205 | 206 | ended() { 207 | return this._vimeoState.ended; 208 | } 209 | 210 | // Vimeo does has a mute API and native controls aren't being used, 211 | // so setMuted doesn't really make sense and shouldn't be called. 212 | // setMuted(mute) {} 213 | } 214 | 215 | Vimeo.prototype.featuresTimeupdateEvents = true; 216 | 217 | Vimeo.isSupported = function() { 218 | return true; 219 | }; 220 | 221 | // Add Source Handler pattern functions to this tech 222 | Tech.withSourceHandlers(Vimeo); 223 | 224 | Vimeo.nativeSourceHandler = {}; 225 | 226 | /** 227 | * Check if Vimeo can play the given videotype 228 | * @param {String} type The mimetype to check 229 | * @return {String} 'maybe', or '' (empty string) 230 | */ 231 | Vimeo.nativeSourceHandler.canPlayType = function(source) { 232 | if (source === 'video/vimeo') { 233 | return 'maybe'; 234 | } 235 | 236 | return ''; 237 | }; 238 | 239 | /* 240 | * Check Vimeo can handle the source natively 241 | * 242 | * @param {Object} source The source object 243 | * @return {String} 'maybe', or '' (empty string) 244 | * @note: Copied over from YouTube — not sure this is relevant 245 | */ 246 | Vimeo.nativeSourceHandler.canHandleSource = function(source) { 247 | if (source.type) { 248 | return Vimeo.nativeSourceHandler.canPlayType(source.type); 249 | } else if (source.src) { 250 | return Vimeo.nativeSourceHandler.canPlayType(source.src); 251 | } 252 | 253 | return ''; 254 | }; 255 | 256 | // @note: Copied over from YouTube — not sure this is relevant 257 | Vimeo.nativeSourceHandler.handleSource = function(source, tech) { 258 | tech.src(source.src); 259 | }; 260 | 261 | // @note: Copied over from YouTube — not sure this is relevant 262 | Vimeo.nativeSourceHandler.dispose = function() { }; 263 | 264 | Vimeo.registerSourceHandler(Vimeo.nativeSourceHandler); 265 | 266 | Component.registerComponent('Vimeo', Vimeo); 267 | Tech.registerTech('Vimeo', Vimeo); 268 | 269 | // Include the version number. 270 | Vimeo.VERSION = '0.0.1'; 271 | 272 | export default Vimeo; 273 | --------------------------------------------------------------------------------