diff --git a/buffering.d.ts b/buffering.d.ts new file mode 100644 index 00000000..63549488 --- /dev/null +++ b/buffering.d.ts @@ -0,0 +1,2 @@ +export declare class VgBufferingModule { +} diff --git a/buffering.js b/buffering.js new file mode 100644 index 00000000..3c963de2 --- /dev/null +++ b/buffering.js @@ -0,0 +1,32 @@ +"use strict"; +var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { + var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); + else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; +}; +var __metadata = (this && this.__metadata) || function (k, v) { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; +var core_1 = require('@angular/core'); +var common_1 = require('@angular/common'); +var vg_buffering_1 = require('./src/vg-buffering/vg-buffering'); +var VgBufferingModule = (function () { + function VgBufferingModule() { + } + VgBufferingModule = __decorate([ + core_1.NgModule({ + imports: [common_1.CommonModule], + declarations: [ + vg_buffering_1.VgBuffering + ], + exports: [ + vg_buffering_1.VgBuffering + ] + }), + __metadata('design:paramtypes', []) + ], VgBufferingModule); + return VgBufferingModule; +}()); +exports.VgBufferingModule = VgBufferingModule; +//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVmZmVyaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYnVmZmVyaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQSxxQkFBOEIsZUFBZSxDQUFDLENBQUE7QUFDOUMsdUJBQTZCLGlCQUFpQixDQUFDLENBQUE7QUFFL0MsNkJBQTBCLGlDQUFpQyxDQUFDLENBQUE7QUFXNUQ7SUFBQTtJQUFnQyxDQUFDO0lBVGpDO1FBQUMsZUFBUSxDQUFDO1lBQ04sT0FBTyxFQUFFLENBQUUscUJBQVksQ0FBRTtZQUN6QixZQUFZLEVBQUU7Z0JBQ1YsMEJBQVc7YUFDZDtZQUNELE9BQU8sRUFBRTtnQkFDTCwwQkFBVzthQUNkO1NBQ0osQ0FBQzs7eUJBQUE7SUFDOEIsd0JBQUM7QUFBRCxDQUFDLEFBQWpDLElBQWlDO0FBQXBCLHlCQUFpQixvQkFBRyxDQUFBIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUgfSAgICAgIGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcblxuaW1wb3J0IHtWZ0J1ZmZlcmluZ30gZnJvbSAnLi9zcmMvdmctYnVmZmVyaW5nL3ZnLWJ1ZmZlcmluZyc7XG5cbkBOZ01vZHVsZSh7XG4gICAgaW1wb3J0czogWyBDb21tb25Nb2R1bGUgXSxcbiAgICBkZWNsYXJhdGlvbnM6IFtcbiAgICAgICAgVmdCdWZmZXJpbmdcbiAgICBdLFxuICAgIGV4cG9ydHM6IFtcbiAgICAgICAgVmdCdWZmZXJpbmdcbiAgICBdXG59KVxuZXhwb3J0IGNsYXNzIFZnQnVmZmVyaW5nTW9kdWxlIHt9XG4iXX0= \ No newline at end of file diff --git a/buffering.ts b/buffering.ts new file mode 100644 index 00000000..9b6ac014 --- /dev/null +++ b/buffering.ts @@ -0,0 +1,15 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import {VgBuffering} from './src/vg-buffering/vg-buffering'; + +@NgModule({ + imports: [ CommonModule ], + declarations: [ + VgBuffering + ], + exports: [ + VgBuffering + ] +}) +export class VgBufferingModule {} diff --git a/examples/single-media-player/src/app.module.js b/examples/single-media-player/src/app.module.js index 54af81de..7ff5d32b 100644 --- a/examples/single-media-player/src/app.module.js +++ b/examples/single-media-player/src/app.module.js @@ -13,6 +13,7 @@ var platform_browser_1 = require('@angular/platform-browser'); var core_2 = require('videogular2/core'); var controls_1 = require('videogular2/controls'); var overlay_play_1 = require('videogular2/overlay-play'); +var buffering_1 = require('videogular2/buffering'); var single_media_player_1 = require('./single-media-player'); var AppModule = (function () { function AppModule() { @@ -23,7 +24,8 @@ var AppModule = (function () { platform_browser_1.BrowserModule, core_2.VgCore, controls_1.VgControlsModule, - overlay_play_1.VgOverlayPlayModule + overlay_play_1.VgOverlayPlayModule, + buffering_1.VgBufferingModule ], declarations: [single_media_player_1.SingleMediaPlayer], bootstrap: [single_media_player_1.SingleMediaPlayer] diff --git a/examples/single-media-player/src/app.module.js.map b/examples/single-media-player/src/app.module.js.map index 6ed4d18e..5792a930 100644 --- a/examples/single-media-player/src/app.module.js.map +++ b/examples/single-media-player/src/app.module.js.map @@ -1 +1 @@ -{"version":3,"file":"app.module.js","sourceRoot":"","sources":["app.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBAAuB,eAAe,CAAC,CAAA;AACvC,iCAA4B,2BAA2B,CAAC,CAAA;AACxD,qBAAqB,kBAAkB,CAAC,CAAA;AACxC,yBAA+B,sBAAsB,CAAC,CAAA;AACtD,6BAAkC,0BAA0B,CAAC,CAAA;AAC7D,oCAAgC,uBAAuB,CAAC,CAAA;AAYxD;IAAA;IACA,CAAC;IAXD;QAAC,eAAQ,CAAC;YACN,OAAO,EAAE;gBACL,gCAAa;gBACb,aAAM;gBACN,2BAAgB;gBAChB,kCAAmB;aACtB;YACD,YAAY,EAAE,CAAC,uCAAiB,CAAC;YACjC,SAAS,EAAE,CAAC,uCAAiB,CAAC;SACjC,CAAC;;iBAAA;IAEF,gBAAC;AAAD,CAAC,AADD,IACC;AADY,iBAAS,YACrB,CAAA"} \ No newline at end of file +{"version":3,"file":"app.module.js","sourceRoot":"","sources":["app.module.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,qBAAuB,eAAe,CAAC,CAAA;AACvC,iCAA4B,2BAA2B,CAAC,CAAA;AACxD,qBAAqB,kBAAkB,CAAC,CAAA;AACxC,yBAA+B,sBAAsB,CAAC,CAAA;AACtD,6BAAkC,0BAA0B,CAAC,CAAA;AAC7D,0BAAgC,uBAAuB,CAAC,CAAA;AACxD,oCAAgC,uBAAuB,CAAC,CAAA;AAaxD;IAAA;IACA,CAAC;IAZD;QAAC,eAAQ,CAAC;YACN,OAAO,EAAE;gBACL,gCAAa;gBACb,aAAM;gBACN,2BAAgB;gBAChB,kCAAmB;gBACnB,6BAAiB;aACpB;YACD,YAAY,EAAE,CAAC,uCAAiB,CAAC;YACjC,SAAS,EAAE,CAAC,uCAAiB,CAAC;SACjC,CAAC;;iBAAA;IAEF,gBAAC;AAAD,CAAC,AADD,IACC;AADY,iBAAS,YACrB,CAAA"} \ No newline at end of file diff --git a/examples/single-media-player/src/app.module.ts b/examples/single-media-player/src/app.module.ts index 9971e68a..5e686d99 100644 --- a/examples/single-media-player/src/app.module.ts +++ b/examples/single-media-player/src/app.module.ts @@ -3,6 +3,7 @@ import {BrowserModule} from '@angular/platform-browser'; import {VgCore} from 'videogular2/core'; import {VgControlsModule} from 'videogular2/controls'; import {VgOverlayPlayModule} from 'videogular2/overlay-play'; +import {VgBufferingModule} from 'videogular2/buffering'; import {SingleMediaPlayer} from './single-media-player'; @NgModule({ @@ -10,7 +11,8 @@ import {SingleMediaPlayer} from './single-media-player'; BrowserModule, VgCore, VgControlsModule, - VgOverlayPlayModule + VgOverlayPlayModule, + VgBufferingModule ], declarations: [SingleMediaPlayer], bootstrap: [SingleMediaPlayer] diff --git a/examples/single-media-player/src/single-media-player.html b/examples/single-media-player/src/single-media-player.html index 8f6df19c..7f50212a 100644 --- a/examples/single-media-player/src/single-media-player.html +++ b/examples/single-media-player/src/single-media-player.html @@ -1,5 +1,6 @@ + diff --git a/src/services/vg-api.ts b/src/services/vg-api.ts index 6d6188b9..6007e9c3 100644 --- a/src/services/vg-api.ts +++ b/src/services/vg-api.ts @@ -4,7 +4,7 @@ import {VgStates} from "../states/vg-states"; @Injectable() export class VgAPI { - medias:Object = {}; + medias:Object = {};// TODO: refactor to Set videogularElement: any; playerReadyEvent: EventEmitter = new EventEmitter(true); diff --git a/src/vg-buffering/vg-buffering.d.ts b/src/vg-buffering/vg-buffering.d.ts new file mode 100644 index 00000000..d5f305ea --- /dev/null +++ b/src/vg-buffering/vg-buffering.d.ts @@ -0,0 +1,22 @@ +import { ElementRef } from '@angular/core'; +import { VgAPI } from '../services/vg-api'; +import { IPlayable } from "../vg-media/i-playable"; +export declare class VgBuffering { + API: VgAPI; + elem: HTMLElement; + vgFor: string; + target: IPlayable; + checkBufferInterval: number; + displayState: string; + constructor(ref: ElementRef, API: VgAPI); + onPlayerReady(): void; + checkInterval: number; + currentPlayPos: number; + lastPlayPos: number; + bufferingDetected: boolean; + bufferCheck(): void; + startBufferCheck(): void; + stopBufferCheck(): void; + show(): void; + hide(): void; +} diff --git a/src/vg-buffering/vg-buffering.spec.d.ts b/src/vg-buffering/vg-buffering.spec.d.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/vg-buffering/vg-buffering.spec.ts b/src/vg-buffering/vg-buffering.spec.ts new file mode 100644 index 00000000..0c6e03ba --- /dev/null +++ b/src/vg-buffering/vg-buffering.spec.ts @@ -0,0 +1,110 @@ +import {VgBuffering} from "./vg-buffering"; +import {VgAPI} from "../services/vg-api"; +import {IPlayable} from "../vg-media/i-playable"; +import {ElementRef} from "@angular/core"; + +describe('Volume control', () => { + let vgBuffering:VgBuffering; + let ref:ElementRef; + let api:VgAPI; + + beforeEach(() => { + ref = { + nativeElement: { + getAttribute: (name) => { + return name; + } + } + }; + + api = new VgAPI(); + vgBuffering = new VgBuffering(ref, api); + }); + + describe('onPlayerReady', ()=>{ + it('should subscribe to play and pause media events', ()=>{ + spyOn(api, 'getMediaById').and.returnValue({ + subscriptions: { + play: {subscribe: jasmine.createSpy('play') }, + pause: {subscribe: jasmine.createSpy('pause') } + } + }); + vgBuffering.onPlayerReady(); + expect(vgBuffering.target.subscriptions.play.subscribe).toHaveBeenCalled(); + expect(vgBuffering.target.subscriptions.pause.subscribe).toHaveBeenCalled(); + }); + }); + + describe('startBufferCheck', ()=>{ + it('should register bufferCheck in a setInterval', () => { + spyOn(window, 'setInterval').and.returnValue(100); + vgBuffering.checkInterval = 77; + vgBuffering.startBufferCheck(); + expect(window.setInterval).toHaveBeenCalledWith( + vgBuffering.bufferCheck, + 77 + ); + expect(vgBuffering.checkBufferInterval).toBe(100); + }); + }); + + describe('stopBufferCheck', ()=>{ + it('should unregister bufferCheck from setInterval', () => { + spyOn(window, 'clearInterval'); + vgBuffering.stopBufferCheck(); + expect(window.clearInterval).toHaveBeenCalledWith( + vgBuffering.checkBufferInterval + ); + }); + it('should set props to hide buffering indicator', () => { + vgBuffering.bufferingDetected = true; + spyOn(vgBuffering, 'hide'); + vgBuffering.stopBufferCheck(); + expect(vgBuffering.bufferingDetected).toBe(false); + expect(vgBuffering.hide).toHaveBeenCalled(); + }); + }); + + describe('show', ()=>{ + it('should set displayState to "block"', () => { + vgBuffering.displayState = 'none'; + vgBuffering.show(); + expect(vgBuffering.displayState).toBe('block'); + }); + }); + + describe('hide', ()=>{ + it('should set displayState to "none"', () => { + vgBuffering.displayState = 'block'; + vgBuffering.hide(); + expect(vgBuffering.displayState).toBe('none'); + }); + }); + + describe('bufferCheck', ()=>{ + beforeEach(()=>{ + vgBuffering.target = {currentTime:0}; + }); + it('should set bufferingDetected to true', () => { + spyOn(vgBuffering, 'show'); + vgBuffering.bufferingDetected = false; + vgBuffering.target.currentTime = 10; + vgBuffering.lastPlayPos = 10; + vgBuffering.bufferCheck(); + expect(vgBuffering.bufferingDetected).toBe(true); + expect(vgBuffering.lastPlayPos).toBe(10); + expect(vgBuffering.show).toHaveBeenCalled(); + }); + + it('should set bufferingDetected to false', () => { + spyOn(vgBuffering, 'hide'); + vgBuffering.bufferingDetected = true; + vgBuffering.target.currentTime = 20; + vgBuffering.lastPlayPos = 10; + vgBuffering.bufferCheck(); + expect(vgBuffering.bufferingDetected).toBe(false); + expect(vgBuffering.lastPlayPos).toBe(20); + expect(vgBuffering.hide).toHaveBeenCalled(); + }); + }); +}); \ No newline at end of file diff --git a/src/vg-buffering/vg-buffering.ts b/src/vg-buffering/vg-buffering.ts new file mode 100644 index 00000000..0befd6fb --- /dev/null +++ b/src/vg-buffering/vg-buffering.ts @@ -0,0 +1,160 @@ +import {Component, ElementRef, HostBinding} from '@angular/core'; + +import {VgAPI} from '../services/vg-api'; +import {IPlayable} from "../vg-media/i-playable"; +import {VgStates} from "../states/vg-states"; + +@Component({ + selector: 'vg-buffering', + host: { + 'class': 'vg-buffering' + }, + template: + `
+
+
+
+
`, + styles: [` + :host { + z-index: 201; + } + .vg-buffering { + position: absolute; + display: block; + width: 100%; + height: 100%; + } + + .vg-buffering .bufferingContainer { + width: 100%; + position: absolute; + cursor: pointer; + top: 50%; + margin-top: -50px; + + zoom: 1; + filter: alpha(opacity=60); + opacity: 0.6; + } + + /* Loading Spinner + * http://www.alessioatzeni.com/blog/css3-loading-animation-loop/ + */ + .vg-buffering .loadingSpinner { + background-color: rgba(0, 0, 0, 0); + border: 5px solid rgba(255, 255, 255, 1); + opacity: .9; + border-top: 5px solid rgba(0, 0, 0, 0); + border-left: 5px solid rgba(0, 0, 0, 0); + border-radius: 50px; + box-shadow: 0 0 35px #FFFFFF; + width: 50px; + height: 50px; + margin: 0 auto; + -moz-animation: spin .5s infinite linear; + -webkit-animation: spin .5s infinite linear; + } + + .vg-buffering .loadingSpinner .stop { + -webkit-animation-play-state: paused; + -moz-animation-play-state: paused; + } + + @-moz-keyframes spin { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(360deg); + } + } + + @-moz-keyframes spinoff { + 0% { + -moz-transform: rotate(0deg); + } + 100% { + -moz-transform: rotate(-360deg); + } + } + + @-webkit-keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + } + } + + @-webkit-keyframes spinoff { + 0% { + -webkit-transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(-360deg); + } + } + `] +}) +export class VgBuffering { + elem:HTMLElement; + vgFor: string; + target: IPlayable; + checkBufferInterval: number; + + @HostBinding('style.display') displayState: string = 'none'; + + constructor(ref:ElementRef, public API: VgAPI) { + this.elem = ref.nativeElement; + API.playerReadyEvent.subscribe((api) => this.onPlayerReady()); + this.bufferCheck = this.bufferCheck.bind(this); + } + + onPlayerReady() { + this.vgFor = this.elem.getAttribute('vg-for'); + this.target = this.API.getMediaById(this.vgFor); + + this.target.subscriptions.play.subscribe(this.startBufferCheck.bind(this)); + this.target.subscriptions.pause.subscribe(this.stopBufferCheck.bind(this)); + } + + checkInterval: number = 50; + currentPlayPos: number = 0; + lastPlayPos: number = 0; + bufferingDetected: boolean; + + // http://stackoverflow.com/a/23828241/779529 + bufferCheck() { + this.currentPlayPos = this.target.currentTime + const offset = 1 / this.checkInterval + if (!this.bufferingDetected && this.currentPlayPos < (this.lastPlayPos + offset)) { + this.bufferingDetected = true; + this.show(); + } + if (this.bufferingDetected && this.currentPlayPos > (this.lastPlayPos + offset)) { + this.bufferingDetected = false; + this.hide(); + } + this.lastPlayPos = this.currentPlayPos + } + + startBufferCheck() { + this.checkBufferInterval = window.setInterval( this.bufferCheck, this.checkInterval); + } + + stopBufferCheck() { + window.clearInterval(this.checkBufferInterval); + this.bufferingDetected = false; + this.hide(); + } + + show() { + this.displayState = 'block'; + } + + hide() { + this.displayState = 'none'; + } +} diff --git a/src/vg-ima-ads/vg-ima-ads.ts b/src/vg-ima-ads/vg-ima-ads.ts index cc1967cb..ff7d1fb2 100644 --- a/src/vg-ima-ads/vg-ima-ads.ts +++ b/src/vg-ima-ads/vg-ima-ads.ts @@ -15,7 +15,7 @@ import {VgFullscreenAPI} from '../services/vg-fullscreen-api'; position: absolute; width: 100%; height: 100%; - z-index: 201; + z-index: 300; } .vg-ima-ads { position: absolute; diff --git a/src/vg-media/i-playable.d.ts b/src/vg-media/i-playable.d.ts index 8f5d2559..a71648c3 100644 --- a/src/vg-media/i-playable.d.ts +++ b/src/vg-media/i-playable.d.ts @@ -1,3 +1,4 @@ +import { Observable } from "rxjs/Observable"; export interface IPlayable { id: string; elem: any; @@ -9,8 +10,24 @@ export interface IPlayable { isWaiting: boolean; isCompleted: boolean; state: string; - subscriptions: any; + subscriptions: IMediaSubscriptions; duration: number; currentTime: number; dispatchEvent?: Function; } +export interface IMediaSubscriptions { + canPlay: Observable; + canPlayThrough: Observable; + loadedMetadata: Observable; + waiting: Observable; + progress: Observable; + ended: Observable; + playing: Observable; + play: Observable; + pause: Observable; + timeUpdate: Observable; + volumeChange: Observable; + error: Observable; + startAds: Observable; + endAds: Observable; +} diff --git a/src/vg-media/i-playable.ts b/src/vg-media/i-playable.ts index 8f4144dc..676965a0 100644 --- a/src/vg-media/i-playable.ts +++ b/src/vg-media/i-playable.ts @@ -1,3 +1,5 @@ +import {Observable} from "rxjs/Observable"; + export interface IPlayable { id:string; elem:any; @@ -9,8 +11,25 @@ export interface IPlayable { isWaiting:boolean; isCompleted:boolean; state:string; - subscriptions:any; + subscriptions:IMediaSubscriptions; duration:number; currentTime:number; dispatchEvent?:Function; } + +export interface IMediaSubscriptions { + canPlay: Observable; + canPlayThrough: Observable; + loadedMetadata: Observable; + waiting: Observable; + progress: Observable; + ended: Observable; + playing: Observable; + play: Observable; + pause: Observable; + timeUpdate: Observable; + volumeChange: Observable; + error: Observable; + startAds: Observable; + endAds: Observable; +} \ No newline at end of file diff --git a/src/vg-media/vg-media.d.ts b/src/vg-media/vg-media.d.ts index 16461916..4e44fa77 100644 --- a/src/vg-media/vg-media.d.ts +++ b/src/vg-media/vg-media.d.ts @@ -1,5 +1,5 @@ import { ElementRef, OnInit } from '@angular/core'; -import { IPlayable } from "./i-playable"; +import { IPlayable, IMediaSubscriptions } from "./i-playable"; export declare class VgMedia implements OnInit, IPlayable { elem: any; private _vgMaster; @@ -7,7 +7,7 @@ export declare class VgMedia implements OnInit, IPlayable { state: string; time: any; buffer: any; - subscriptions: any; + subscriptions: IMediaSubscriptions | any; canPlay: boolean; canPlayThrough: boolean; isMetadataLoaded: boolean; diff --git a/src/vg-media/vg-media.ts b/src/vg-media/vg-media.ts index 3c5f9acb..df323282 100644 --- a/src/vg-media/vg-media.ts +++ b/src/vg-media/vg-media.ts @@ -1,6 +1,6 @@ import {ElementRef, OnInit, Directive, Input} from '@angular/core'; -import {IPlayable} from "./i-playable"; +import {IPlayable, IMediaSubscriptions} from "./i-playable"; import {Observable} from "rxjs/Observable"; import {VgEvents} from "../events/vg-events"; import {VgStates} from "../states/vg-states"; @@ -23,7 +23,7 @@ export class VgMedia implements OnInit, IPlayable { time:any = {current: 0, total: 0, left: 0}; buffer:any = {end: 0}; - subscriptions:any = {}; + subscriptions:IMediaSubscriptions | any; canPlay:boolean = false; canPlayThrough:boolean = false; @@ -36,38 +36,39 @@ export class VgMedia implements OnInit, IPlayable { } ngOnInit() { - this.subscriptions.canPlay = Observable.fromEvent(this.elem, VgEvents.VG_CAN_PLAY); - this.subscriptions.canPlayThrough = Observable.fromEvent(this.elem, VgEvents.VG_CAN_PLAY_THROUGH); - this.subscriptions.loadedMetadata = Observable.fromEvent(this.elem, VgEvents.VG_LOADED_METADATA); - this.subscriptions.waiting = Observable.fromEvent(this.elem, VgEvents.VG_WAITING); - this.subscriptions.progress = Observable.fromEvent(this.elem, VgEvents.VG_PROGRESS); - this.subscriptions.ended = Observable.fromEvent(this.elem, VgEvents.VG_ENDED); - this.subscriptions.playing = Observable.fromEvent(this.elem, VgEvents.VG_PLAYING); - this.subscriptions.play = Observable.fromEvent(this.elem, VgEvents.VG_PLAY); - this.subscriptions.pause = Observable.fromEvent(this.elem, VgEvents.VG_PAUSE); - this.subscriptions.timeUpdate = Observable.fromEvent(this.elem, VgEvents.VG_TIME_UPDATE); - this.subscriptions.volumeChange = Observable.fromEvent(this.elem, VgEvents.VG_VOLUME_CHANGE); - this.subscriptions.error = Observable.fromEvent(this.elem, VgEvents.VG_ERROR); - this.subscriptions.startAds = Observable.fromEvent(window, VgEvents.VG_START_ADS); - this.subscriptions.endAds = Observable.fromEvent(window, VgEvents.VG_END_ADS); - - // See changes on child elements to reload the video file - this.subscriptions.mutation = Observable.create( - (observer) => { - let domObs = new MutationObserver((mutations) => { - observer.next(mutations); - }); - - domObs.observe(this.elem, { childList: true }); - - return () => { - domObs.disconnect(); - }; - } - ); + this.subscriptions = { + canPlay: Observable.fromEvent(this.elem, VgEvents.VG_CAN_PLAY), + canPlayThrough: Observable.fromEvent(this.elem, VgEvents.VG_CAN_PLAY_THROUGH), + loadedMetadata: Observable.fromEvent(this.elem, VgEvents.VG_LOADED_METADATA), + waiting: Observable.fromEvent(this.elem, VgEvents.VG_WAITING), + progress: Observable.fromEvent(this.elem, VgEvents.VG_PROGRESS), + ended: Observable.fromEvent(this.elem, VgEvents.VG_ENDED), + playing: Observable.fromEvent(this.elem, VgEvents.VG_PLAYING), + play: Observable.fromEvent(this.elem, VgEvents.VG_PLAY), + pause: Observable.fromEvent(this.elem, VgEvents.VG_PAUSE), + timeUpdate: Observable.fromEvent(this.elem, VgEvents.VG_TIME_UPDATE), + volumeChange: Observable.fromEvent(this.elem, VgEvents.VG_VOLUME_CHANGE), + error: Observable.fromEvent(this.elem, VgEvents.VG_ERROR), + startAds: Observable.fromEvent(window, VgEvents.VG_START_ADS), + endAds: Observable.fromEvent(window, VgEvents.VG_END_ADS), + // See changes on child elements to reload the video file + mutation: Observable.create( + (observer) => { + let domObs = new MutationObserver((mutations) => { + observer.next(mutations); + }); + + domObs.observe(this.elem, { childList: true }); + + return () => { + domObs.disconnect(); + }; + } + ) + }; - this.subscriptions.mutation.subscribe(this.onMutation.bind(this)); + this.subscriptions.mutation.subscribe(this.onMutation.bind(this)); this.subscriptions.canPlay.subscribe(this.onCanPlay.bind(this)); this.subscriptions.canPlayThrough.subscribe(this.onCanPlayThrough.bind(this)); this.subscriptions.loadedMetadata.subscribe(this.onLoadMetadata.bind(this));