// JavaScript Document/** Yahoo Media Player - resumeTrack extension Enables resuming of tracks from the last seek position. @author: Eric Fehrenbacher @company: Yahoo! @version 0.1.2 */ var TrackResume = function() { // reference to YMP this.player = YAHOO.MediaPlayer; // coookie handler this.cookie = new CookieCutter(); // just some setup options this.config = { volume: this.player.getVolume(), elapsed: 0, duration: 0, token: '', paused: false, cookieCrumb: { volume : 'ympVOL', paused : 'ympPAU', elapsed : 'ympTET', duration : 'ympTDR', token : 'ympTTK' } }; // reference to the currently playing track this.track = null; // keep the volume if we are resuming from another page this.volume = this.cookie.get(this.config.cookieCrumb.volume) || this.config.volume; this.volumeStack = []; // elapsed time of the currently playing track this.elapsed = this.cookie.get(this.config.cookieCrumb.elapsed) || this.config.elapsed; // total time of the currently playing track this.duration = this.cookie.get(this.config.cookieCrumb.duration) || this.config.duration; // md5 hash of token // we use md5 to keep this cookie size down to 120 bits and to guarantee the track is unique this.token = this.cookie.get(this.config.cookieCrumb.token) || this.config.token; // was the track paused when we left the player last time this.paused = (this.cookie.get(this.config.cookieCrumb.paused) == 1) ? true : this.config.paused; // this.init(); }; TrackResume.create = function(args) { YAHOO.mediaplayer.TrackResume = new TrackResume(args); return YAHOO.mediaplayer.TrackResume; }; TrackResume.prototype = { /** Gets fired during the construction of the object @method init @param {Object} options */ init: function(options) { // adjust the volume to it's previous level this.adjustVolume(); // track hash of active track when play is clicked this.player.onTrackStart.subscribe(this.onPlay, this, true); // track hash of active track when pausing this.player.onTrackPause.subscribe(this.onPause, this, true); // track elapsed time of active track this.player.onProgress.subscribe(this.onProgress, this, true); // handle resume play this.player.onMediaUpdate.subscribe(this.onUpdate, this, true); }, /** @method play */ play: function(track, elapsed) { this.updateSeekPosition(); track = track || this.track; elapsed = elapsed || this.elapsed; this.player.play(track, elapsed); }, /** @method pause */ pause: function(track, elapsed) { track = track || this.track; elapsed = elapsed || this.elapsed; // reduce the volume before we play so that no one here's the brief noise var volume = volume = this.player.getVolume(); this.player.setVolume(0); this.play(track, elapsed); /* this is a total hack :) because we don't have any exposed methods for setting the seek time of the track except for the 'play' method, we have to actually 'play' the track and then 'pause' it. the problem with this is that the 'play' method fires asyncronously which means that calling the 'pause' method following the 'play' method will most likely fail due to the fact that the 'play' method is not finished and cancels the 'pause' the solution here is to use an interval to execute the pause method only after the state of the player is in 'play' mode. a more legitimate solution would be to have a method exposed that allows us to set the seek position in any state. so even if the track is paused the player seeks to the requested position */ this.playCheck = YAHOO.ympyui.lang.later(100, this, function(volume) { if (this.player.getPlayerState() == 2) { this.playCheck.cancel(); this.updateSeekPosition(); this.player.pause(); this.player.setVolume(volume); } }, [volume], true); }, /** */ setVolume: function() { this.volume = this.player.getVolume(); var saveVolume = true; if (this.volumeStack.length < 3) { saveVolume = false; } else { for (var i = 0; i < this.volumeStack.length; i++) { if (this.volumeStack[i] != this.volume) { saveVolume = false; } } } this.volumeStack.splice(0, 0, this.volume); this.volumeStack.length = 3; if (saveVolume) { this.cookie.set(this.config.cookieCrumb.volume, this.volume, 90); } }, /** */ adjustVolume: function(volume) { this.volume = volume || this.volume; this.player.setVolume(this.volume); }, /** @method setCurrentTrack @param {Object} track */ setCurrentTrack: function(track) { this.track = track.mediaObject; var token = MD5(this.track.token); this.elapsed = (token != this.token) ? 0 : this.elapsed; this.token = token; this.cookie.set(this.config.cookieCrumb.token, token, 90); }, /** @method setTrackTime @param {Object} options */ setTrackTime: function(options) { if (options.duration > 0) { this.elapsed = options.elapsed; this.cookie.set(this.config.cookieCrumb.elapsed, options.elapsed, 90); this.cookie.set(this.config.cookieCrumb.duration, options.duration, 90); return true; } return false; }, /** @method setPausedState @param {Boolean} state Wheather YMP is currently paused. true || false */ setPausedState: function(state) { this.paused = state; this.cookie.set(this.config.cookieCrumb.paused, (this.paused ? 1 : 0), 90); }, /** @method updateSeekPosition */ updateSeekPosition: function() { YAHOO.mediaplayer.TrackSeek && YAHOO.mediaplayer.TrackSeek.onProgress({elapsed: this.elapsed, duration: this.duration}); }, /** Event handler for 'play' @method onPlay @param {Object} track */ onPlay: function(track) { //console.log("onPlay::this.elapsed",this.elapsed); this.setCurrentTrack(track); this.setPausedState(false); this.play(this.track, this.elapsed); }, /** Event handler This function tracks the elapsed time of the currently playing track @method onProgress @param {Object} options */ onProgress: function(options) { //console.log("onProgress::this.elapsed",this.elapsed); this.setTrackTime(options); this.setVolume(); }, /** Event handler for 'pause' @method onPause @param {Object} track */ onPause: function(track) { this.setPausedState(true); }, /** Event handler for when a mediaObject exists and is updated */ onUpdate: function(mediaObject) { if (MD5(mediaObject.token) == this.token) { this.track = mediaObject; if (this.paused) { this.pause(this.track, this.elapsed); } else { this.play(this.track, this.elapsed); } } } }; /* This creates a new TrackResume object and attaches to the MediaPlayer */ (typeof YAHOO != 'undefined') && YAHOO.MediaPlayer.onAPIReady.subscribe(TrackResume.create);