├── .eslintignore ├── media ├── kolor.mp4 ├── kolor.ogg ├── robbe.mp4 ├── robbe.ogg ├── kolor.webm ├── robbe.webm ├── robbe-mask.png ├── robbe-altmask.png └── README.md ├── .npmignore ├── dist ├── README.md ├── 1.0.0 │ └── jquery-seeThru.min.js ├── 1.0.1 │ └── jquery-seeThru.min.js ├── 1.0.2 │ └── jquery-seeThru.min.js ├── 1.0.3 │ └── jquery-seeThru.min.js ├── 1.1.0 │ └── jquery-seeThru.min.js ├── 1.1.1 │ └── jquery-seeThru.min.js ├── 1.1.2 │ └── jquery-seeThru.min.js ├── 1.1.3 │ └── jquery-seeThru.min.js ├── 2.0.0 │ └── seeThru.min.js ├── 2.0.1 │ └── seeThru.min.js ├── seeThru.min.js ├── 4.0.0 │ └── seeThru.min.js ├── 2.1.0 │ └── seeThru.min.js ├── 2.1.1 │ └── seeThru.min.js ├── 2.1.2 │ └── seeThru.min.js ├── 2.1.3 │ └── seeThru.min.js ├── 2.1.4 │ └── seeThru.min.js ├── 2.1.5 │ └── seeThru.min.js ├── 2.1.6 │ └── seeThru.min.js ├── 2.1.7 │ └── seeThru.min.js ├── 2.1.8 │ └── seeThru.min.js ├── 2.1.9 │ └── seeThru.min.js ├── 3.0.1 │ └── seeThru.min.js ├── 3.0.0 │ └── seeThru.min.js ├── 3.1.0 │ └── seeThru.min.js ├── 3.1.1 │ └── seeThru.min.js ├── 3.1.2 │ └── seeThru.min.js ├── 3.2.0 │ └── seeThru.min.js ├── 3.2.1 │ └── seeThru.min.js └── 3.3.0 │ └── seeThru.min.js ├── .gitignore ├── src └── README.md ├── bower.json ├── .github └── workflows │ └── test.yml ├── .editorconfig ├── Gruntfile.js ├── LICENSE ├── .eslintrc.yml ├── package.json ├── karma.conf.js ├── bin └── converter.js └── test └── test.js /.eslintignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | karma.conf.js 4 | -------------------------------------------------------------------------------- /media/kolor.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/kolor.mp4 -------------------------------------------------------------------------------- /media/kolor.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/kolor.ogg -------------------------------------------------------------------------------- /media/robbe.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/robbe.mp4 -------------------------------------------------------------------------------- /media/robbe.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/robbe.ogg -------------------------------------------------------------------------------- /media/kolor.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/kolor.webm -------------------------------------------------------------------------------- /media/robbe.webm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/robbe.webm -------------------------------------------------------------------------------- /media/robbe-mask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/robbe-mask.png -------------------------------------------------------------------------------- /media/robbe-altmask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m90/seeThru/HEAD/media/robbe-altmask.png -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | media/ 3 | dist/* 4 | !dist/*.js 5 | bower.json 6 | seethru.json 7 | .jshintrc -------------------------------------------------------------------------------- /dist/README.md: -------------------------------------------------------------------------------- 1 | The version in `dist/` will always be the latest build. See the folders for legacy versions. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-project 2 | *.sublime-workspace 3 | npm-debug.log 4 | node_modules/ 5 | test/non-jquery.html -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | ### Download Notes 2 | The minified version can be found in the repo's `dist` folder 3 | 4 | ![Footer image](http://m90.github.io/seeThru/img/footer.png) 5 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seethru", 3 | "version": "4.0.0", 4 | "main": "dist/seeThru.min.js", 5 | "ignore": [ 6 | "Gruntfile.js", 7 | "package.json", 8 | "seethru.json", 9 | ".jshintrc", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "media" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Run tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - uses: actions/setup-node@v2 11 | - name: Install dependencies 12 | run: npm i 13 | - name: Run tests 14 | run: npm t 15 | -------------------------------------------------------------------------------- /media/README.md: -------------------------------------------------------------------------------- 1 | ### Example video files 2 | 3 | These are properly set up example video files for your testing convenience. 4 | 5 | They are **[CC-BY-SA 3.0](http://creativecommons.org/licenses/by-sa/3.0/)** licensed, character "Mr. Kolor" by **[Kathi Käppel](http://www.kathikaeppel.com)**, animation and everything else by **[Frederik Ring](http://www.frederikring.com)**. 6 | ![Footer image](http://m90.github.io/seeThru/img/footer.png) 7 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | # tab indentation for js, json and less 16 | [*.js, *.json] 17 | indent_style = tab 18 | 19 | # npm style indent for package.json 20 | [package.json] 21 | indent_style = space 22 | indent_size = 2 23 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON('package.json'), 4 | uglify: { 5 | options: { 6 | banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("dd-mm-yyyy") %> see https://github.com/m90/seeThru for details */\n' 7 | }, 8 | dist: { 9 | files: { 10 | 'dist/<%= pkg.version %>/seeThru.min.js': 'src/seeThru.js', 11 | 'dist/seeThru.min.js': 'src/seeThru.js' 12 | } 13 | } 14 | }, 15 | jsonlint: { 16 | configfiles: { 17 | src: ['*.json'] 18 | } 19 | }, 20 | eslint: { 21 | target: ['.'] 22 | } 23 | }); 24 | 25 | grunt.loadNpmTasks('grunt-contrib-uglify'); 26 | grunt.loadNpmTasks('grunt-jsonlint'); 27 | grunt.loadNpmTasks('grunt-eslint'); 28 | grunt.registerTask('lint', ['eslint', 'jsonlint']); 29 | grunt.registerTask('default', ['lint', 'uglify']); 30 | }; 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Frederik Ring 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | extends: eslint:recommended 2 | rules: 3 | indent: 4 | - 2 5 | - tab 6 | quotes: 7 | - 2 8 | - single 9 | linebreak-style: 10 | - 2 11 | - unix 12 | semi: 13 | - 2 14 | - always 15 | comma-spacing: 16 | - 2 17 | - 18 | before: false 19 | after: true 20 | comma-style: 21 | - 2 22 | - last 23 | brace-style: 24 | - 2 25 | - 1tbs 26 | - 27 | allowSingleLine: true 28 | key-spacing: 29 | - 2 30 | - 31 | beforeColon: false 32 | afterColon: true 33 | space-infix-ops: 34 | - 2 35 | - 36 | int32Hint: false 37 | keyword-spacing: 2 38 | object-curly-spacing: 39 | - 2 40 | - always 41 | array-bracket-spacing: 42 | - 2 43 | - never 44 | computed-property-spacing: 45 | - 2 46 | - never 47 | space-in-parens: 48 | - 2 49 | - never 50 | space-before-function-paren: 51 | - 2 52 | - always 53 | space-before-blocks: 54 | - 2 55 | - always 56 | no-unneeded-ternary: 2 57 | no-throw-literal: 2 58 | no-useless-call: 2 59 | no-multi-spaces: 2 60 | no-useless-concat: 2 61 | radix: 2 62 | no-extra-bind: 2 63 | no-multiple-empty-lines: 2 64 | array-callback-return: 2 65 | curly: 66 | - 2 67 | - multi-line 68 | eqeqeq: 2 69 | guard-for-in: 2 70 | no-eval: 2 71 | no-new-wrappers: 2 72 | no-self-compare: 2 73 | no-useless-escape: 2 74 | dot-notation: 2 75 | env: 76 | jquery: true 77 | qunit: true 78 | amd: true 79 | browser: true 80 | node: true 81 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "seethru", 3 | "description": "HTML5 video with alpha channel transparencies", 4 | "version": "4.0.0", 5 | "author": "Frederik Ring ", 6 | "contributors": [ 7 | "Caio Matias ", 8 | "CookiesEater ", 9 | "DiSoul ", 10 | "Jakob Eriksen ", 11 | "Lukas Drgon ", 12 | "Mandana Eibegger ", 13 | "Matt Stone ", 14 | "Robbert Helling ", 15 | "Zabellfour " 16 | ], 17 | "scripts": { 18 | "posttest": "grunt lint", 19 | "test": "karma start karma.conf.js" 20 | }, 21 | "main": "src/seeThru.js", 22 | "repository": "https://github.com/m90/seeThru.git", 23 | "homepage": "https://github.com/m90/seeThru", 24 | "bugs": { 25 | "url": "https://github.com/m90/seeThru/issues" 26 | }, 27 | "bin": { 28 | "seethru-convert": "./bin/converter.js" 29 | }, 30 | "keywords": [ 31 | "html5", 32 | "video", 33 | "transparency", 34 | "alpha-channel", 35 | "keying", 36 | "canvas", 37 | "jquery-plugin" 38 | ], 39 | "license": "MIT", 40 | "devDependencies": { 41 | "grunt": "^1.4.0", 42 | "grunt-cli": "^1.2.0", 43 | "grunt-contrib-uglify": "^3.3.0", 44 | "grunt-eslint": "^20.0.0", 45 | "grunt-jsonlint": "^1.0.4", 46 | "jquery": "^3.5.0", 47 | "karma": "^6.3.14", 48 | "karma-chrome-launcher": "^2.1.1", 49 | "karma-cli": "^1.0.1", 50 | "karma-qunit": "^1.2.1", 51 | "qunitjs": "^2.3.3" 52 | }, 53 | "dependencies": { 54 | "fluent-ffmpeg": "^2.1.2", 55 | "yargs": "^14.0.0" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Sat Jun 17 2017 19:11:18 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['qunit'], 13 | 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'media/kolor.mp4', 18 | 'node_modules/jquery/dist/jquery.js', 19 | 'src/seeThru.js', 20 | 'test/*.js' 21 | ], 22 | 23 | 24 | // list of files to exclude 25 | exclude: [ 26 | ], 27 | 28 | 29 | // preprocess matching files before serving them to the browser 30 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 31 | preprocessors: { 32 | }, 33 | 34 | 35 | // test results reporter to use 36 | // possible values: 'dots', 'progress' 37 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 38 | reporters: ['progress'], 39 | 40 | 41 | // web server port 42 | port: 9876, 43 | 44 | 45 | // enable / disable colors in the output (reporters and logs) 46 | colors: true, 47 | 48 | 49 | // level of logging 50 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 51 | logLevel: config.LOG_INFO, 52 | 53 | 54 | // enable / disable watching file and executing tests whenever any file changes 55 | autoWatch: false, 56 | 57 | 58 | // start these browsers 59 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 60 | browsers: ['ChromHeadlessAllowAutoplay'], 61 | 62 | customLaunchers: { 63 | ChromHeadlessAllowAutoplay: { 64 | base: 'ChromeHeadless', 65 | flags: ['--autoplay-policy=no-user-gesture-required'] 66 | } 67 | }, 68 | 69 | // Continuous Integration mode 70 | // if true, Karma captures browsers, runs the tests and exits 71 | singleRun: true, 72 | 73 | // Concurrency level 74 | // how many browser should be started simultaneous 75 | concurrency: Infinity 76 | }) 77 | } 78 | -------------------------------------------------------------------------------- /bin/converter.js: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /* eslint-disable semi */ 3 | ':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" 4 | 5 | /* eslint-disable no-console */ 6 | 7 | var FFmpeg = require('fluent-ffmpeg'); 8 | var fs = require('fs'); 9 | 10 | var argv = require('yargs') 11 | .option('in', { 12 | alias: 'i', 13 | describe: 'The file to convert' 14 | }) 15 | .option('out', { 16 | alias: 'o', 17 | describe: 'Where to write the conversion result' 18 | }) 19 | .option('ffmpeg-path', { 20 | describe: 'Location ffmpeg executable to use' 21 | }) 22 | .option('ffprobe-path', { 23 | describe: 'Location ffprobe executable to use' 24 | }) 25 | .usage('Usage: $0 --in [originalfile] --out [convertedfile]') 26 | .demandOption(['in', 'out']) 27 | .argv; 28 | 29 | var src = argv.in; 30 | 31 | if (argv.ffmpegPath) { 32 | FFmpeg.setFfmpegPath(argv.ffmpegPath); 33 | } 34 | 35 | if (argv.ffprobePath) { 36 | FFmpeg.setFfprobePath(argv.ffprobePath); 37 | } 38 | 39 | new FFmpeg({ source: src }).ffprobe(function (err, metadata) { 40 | 41 | if (err) { 42 | throw err; 43 | } else if (!metadata) { 44 | console.error('Failed reading metadata from video'); 45 | process.exit(1); 46 | } 47 | 48 | var fileExt = src.split('.')[src.split('.').length - 1]; 49 | var fileFormats = metadata.format.format_name.split(','); 50 | var intermediateFormat = fileFormats.indexOf(fileExt) > -1 ? fileExt : fileFormats[0]; 51 | var alpha = new FFmpeg({ source: src }); 52 | 53 | /* jshint multistr: true */ 54 | alpha.addOption( 55 | '-vf', 56 | '[in] format=rgba,\ 57 | split [T1], fifo, lutrgb=r=maxval:g=maxval:b=maxval,\ 58 | [T2] overlay [out];\ 59 | [T1] fifo, lutrgb=r=minval:g=minval:b=minval [T2]' 60 | ).withNoAudio().withVideoCodec(metadata.streams[0].codec_name); 61 | 62 | alpha.on('error', function (err) { 63 | console.error('An error occurred generating the alpha channel: ' + err.message); 64 | process.exit(1); 65 | }).on('end', function () { 66 | 67 | var rgb = new FFmpeg({ source: src }); 68 | 69 | rgb.addOption( 70 | '-vf', 71 | '[in] scale=iw:ih,\ 72 | pad=iw:2*ih [top];\ 73 | movie=seethru-tmp-alpha.mov,\ 74 | scale=iw:ih [bottom];\ 75 | [top][bottom] overlay=0:h [out]' 76 | ).withVideoCodec(metadata.streams[0].codec_name); 77 | 78 | if (metadata.streams.length > 1) { 79 | rgb.withAudioCodec(metadata.streams[1].codec_name); 80 | } 81 | 82 | rgb.on('end', function () { 83 | fs.unlink('seethru-tmp-alpha.' + intermediateFormat, function () { 84 | console.log('Processing ' + src + ' finished!'); 85 | }); 86 | }).on('error', function (err) { 87 | console.error('An error occurred combining the video sources: ' + err.message); 88 | process.exit(1); 89 | }).saveToFile(argv.out); 90 | 91 | }).saveToFile('seethru-tmp-alpha.' + intermediateFormat); 92 | 93 | }); 94 | -------------------------------------------------------------------------------- /dist/1.0.0/jquery-seeThru.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery-seeThru 1.0.0 06-05-2013 see https://github.com/m90/jquery-seeThru for details*/ 2 | (function(e){function t(t,a){var i=e("").attr({width:t.width,height:t.height}).get(0).getContext("2d");i.drawImage(a,0,0,t.width,t.height);for(var h=i.getImageData(0,0,t.width,t.height),n=3,r=h.data.length;r>n;n+=4)h.data[n-1]=h.data[n-2]=h.data[n-3]=h.data[n],h.data[n]=255;return h}function a(e,t){for(var a=3,i=e.data.length;i>a;a+=4)e.data[a]=t[a-1],e.data[a-3]=e.data[a-3]/(t[a-1]?t[a-1]/255:1),e.data[a-2]=e.data[a-2]/(t[a-1]?t[a-1]/255:1),e.data[a-1]=e.data[a-1]/(t[a-1]?t[a-1]/255:1)}var i={init:function(i){i||(i={});var h=e.extend({start:"autoplay",end:"loop",mask:"",alphaMask:!1,width:"",height:"",unmult:!1,shimRAF:!0},i);return h.shimRAF&&!window.requestAnimationFrame&&function(){for(var e=0,t=["ms","moz","webkit","o"],a=0;t.length>a&&!window.requestAnimationFrame;++a)window.requestAnimationFrame=window[t[a]+"RequestAnimationFrame"],window.cancelAnimationFrame=window[t[a]+"CancelAnimationFrame"]||window[t[a]+"CancelRequestAnimationFrame"];window.requestAnimationFrame||(window.requestAnimationFrame=function(t){var a=(new Date).getTime(),i=Math.max(0,16-(a-e)),h=window.setTimeout(function(){t(a+i)},i);return e=a+i,h}),window.cancelAnimationFrame||(window.cancelAnimationFrame=function(e){clearTimeout(e)})}(),this.each(function(){e(this).data("seeThru")&&e.error("seeThru already initialized on selected element");var i,n=!1,r=h.alphaMask===!0;e(h.mask).length&&(i=e(h.mask)[0],"IMG"===i.tagName?(e(i).hide(),n=!0):e.error("Mask element must be ")),"VIDEO"===this.tagName?(e(this).bind("loadedmetadata.seeThru",function(){function s(e){w.drawImage(o,0,0,m.width,m.height*u);var t=w.getImageData(0,0,m.width,m.height),i=w.getImageData(0,m.height,m.width,m.height).data;h.unmult&&a(t,i);for(var n=3,r=t.data.length;r>n;n+=4)t.data[n]=h.alphaMask?i[n-1]:Math.max(i[n-1],i[n-2],i[n-3]);g.putImageData(t,0,0,0,0,m.width,m.height),e&&(p=requestAnimationFrame(function(){s(!0)}))}var d=e(this),o=this,u=(e(window),n?1:2),m={width:parseInt(h.width,10),height:parseInt(h.height,10)};m.height&&m.width||(d.attr("width")||d.attr("height")?d.attr("height")?d.attr("width")?(m.width=m.width||parseInt(o.width,10),m.height=m.height||parseInt(o.height,10)/u):(m.width=m.width||parseInt(o.height,10)*(o.videoWidth/Math.floor(o.videoHeight/u)),m.height=m.height||parseInt(o.height,10)):(m.width=m.width||parseInt(o.width,10),m.height=m.height||parseInt(o.width,10)/(o.videoWidth/Math.floor(o.videoHeight/u))):(m.width=m.width||o.videoWidth,m.height=m.height||o.videoHeight/u));var l=e("",{"class":"seeThru-buffer"}).attr({width:m.width,height:2*m.height}).hide(),c=e("",{"class":"seeThru-display"}).attr({width:m.width,height:m.height}),g=c[0].getContext("2d"),w=l[0].getContext("2d");c.bind("mouseenter mouseleave click mousedown mouseup mousemove mouseover hover dblclick contextmenu focus blur",function(e){d.trigger(e)}),n&&(i.width=m.width,i.height=m.height,r?w.putImageData(t(m,i),0,m.height):w.drawImage(i,0,m.height,m.width,m.height)),"stop"===h.end&&o.loop&&(o.loop=!1);var p;d.hide().data("seeThru",{staticMask:n,alphaMask:r,interval:p}).after(l,c),d.bind("play.seeThru",function(){cancelAnimationFrame(p),p=requestAnimationFrame(function(){s(!0)}),d.data("seeThru").interval=p}).bind("pause.seeThru",function(){cancelAnimationFrame(p)}),"autoplay"===h.start?d.trigger("play.seeThru"):"clicktoplay"===h.start?(o.play(),o.pause(),s(),c.one("click.seeThru",function(){o.play()})):"external"===h.start?(o.play(),o.pause(),d.bind("timeupdate.seeThru",function(){s()})):o.play(),"loop"===h.end?d.bind("ended.seeThru",function(){o.play()}):"rewind"===h.end?d.bind("ended.seeThru",function(){o.pause(),o.currentTime=0,"clicktoplay"==h.start&&c.one("click.seeThru",function(){o.play()})}):d.bind("ended.seeThru",function(){o.pause(),"clicktoplay"==h.start&&c.one("click.seeThru",function(){o.play()})})}),this.videoWidth&&this.videoHeight&&e(this).trigger("loadedmetadata.seeThru")):e.error("Selected element must be