1 /** The minplayer namespace. */
  2 var minplayer = minplayer || {};
  3 
  4 // Add a way to instanciate using jQuery prototype.
  5 if (!jQuery.fn.minplayer) {
  6 
  7   /**
  8    * @constructor
  9    *
 10    * Define a jQuery minplayer prototype.
 11    *
 12    * @param {object} options The options for this jQuery prototype.
 13    * @return {Array} jQuery object.
 14    */
 15   jQuery.fn.minplayer = function(options) {
 16     return jQuery(this).each(function() {
 17       if (!minplayer.plugin.instances[options.id]) {
 18         new minplayer.player(jQuery(this), options);
 19       }
 20     });
 21   };
 22 }
 23 
 24 /**
 25  * @constructor
 26  * @extends minplayer.display
 27  * @class The core media player class which governs the media player
 28  * functionality.
 29  *
 30  * <p><strong>Usage:</strong>
 31  * <pre><code>
 32  *
 33  *   // Create a media player.
 34  *   var player = jQuery("#player").minplayer({
 35  *
 36  *   });
 37  *
 38  * </code></pre>
 39  * </p>
 40  *
 41  * @param {object} context The jQuery context.
 42  * @param {object} options This components options.
 43  */
 44 minplayer.player = function(context, options) {
 45 
 46   // Make sure we provide default options...
 47   options = jQuery.extend({
 48     id: 'player',
 49     controller: 'default',
 50     template: 'default',
 51     swfplayer: '',
 52     wmode: 'transparent',
 53     preload: true,
 54     autoplay: false,
 55     loop: false,
 56     width: '100%',
 57     height: '350px',
 58     debug: false,
 59     volume: 80,
 60     files: [],
 61     file: '',
 62     preview: '',
 63     attributes: {}
 64   }, options);
 65 
 66   // Derive from display
 67   minplayer.display.call(this, context, options);
 68 };
 69 
 70 /** Derive from minplayer.display. */
 71 minplayer.player.prototype = new minplayer.display();
 72 
 73 /** Reset the constructor. */
 74 minplayer.player.prototype.constructor = minplayer.player;
 75 
 76 /**
 77  * @see minplayer.plugin.construct
 78  */
 79 minplayer.player.prototype.construct = function() {
 80 
 81   // Set the name of this plugin.
 82   this.options.name = 'player';
 83 
 84   // Call the minplayer display constructor.
 85   minplayer.display.prototype.construct.call(this);
 86 
 87   /** Variable to store the current media player. */
 88   this.currentPlayer = 'html5';
 89 
 90   // Add key events to the window.
 91   this.addKeyEvents();
 92 
 93   // Now load these files.
 94   this.load(this.getFiles());
 95 };
 96 
 97 /**
 98  * Sets an error on the player.
 99  *
100  * @param {string} error The error to display on the player.
101  */
102 minplayer.player.prototype.error = function(error) {
103   if (this.elements.error) {
104 
105     // Set the error text.
106     this.elements.error.text(error);
107     if (error) {
108       this.elements.error.show();
109     }
110     else {
111       this.elements.error.hide();
112     }
113   }
114 };
115 
116 /**
117  * Adds key events to the player.
118  */
119 minplayer.player.prototype.addKeyEvents = function() {
120 
121   // Bind keyup to the current window.
122   jQuery(window).bind('keyup', {obj: this}, function(event) {
123     // Escape out of fullscreen if they press ESC or Q.
124     var isFull = event.data.obj.display.hasClass('fullscreen');
125     if (isFull && (event.keyCode === 113 || event.keyCode === 27)) {
126       event.data.obj.display.removeClass('fullscreen');
127     }
128   });
129 };
130 
131 /**
132  * Returns all the media files available for this player.
133  *
134  * @return {array} All the media files for this player.
135  */
136 minplayer.player.prototype.getFiles = function() {
137   var files = [];
138   var mediaSrc = null;
139 
140   // Get the files involved...
141   if (this.elements.media) {
142     mediaSrc = this.elements.media.attr('src');
143     if (mediaSrc) {
144       files.push({'path': mediaSrc});
145     }
146     jQuery('source', this.elements.media).each(function() {
147       files.push({
148         'path': jQuery(this).attr('src'),
149         'mimetype': jQuery(this).attr('type'),
150         'codecs': jQuery(this).attr('codecs')
151       });
152     });
153   }
154 
155   return files;
156 };
157 
158 /**
159  * Returns the full media player object.
160  * @param {array} files An array of files to chose from.
161  * @return {object} The best media file to play in the current browser.
162  */
163 minplayer.player.prototype.getMediaFile = function(files) {
164 
165   // If there are no files then return null.
166   if (!files) {
167     return null;
168   }
169 
170   // If the file is a single string, then return the file object.
171   if (typeof files === 'string') {
172     return new minplayer.file({'path': files});
173   }
174 
175   // If the file is already a file object then just return.
176   if (files.path) {
177     return new minplayer.file(files);
178   }
179 
180   // Add the files and get the best player to play.
181   var i = files.length, bestPriority = 0, mFile = null, file = null;
182   while (i--) {
183     file = files[i];
184 
185     // Get the minplayer file object.
186     if (typeof file === 'string') {
187       file = new minplayer.file({'path': file});
188     }
189     else {
190       file = new minplayer.file(file);
191     }
192 
193     // Determine the best file for this browser.
194     if (file.priority > bestPriority) {
195       mFile = file;
196     }
197   }
198 
199   // Return the best minplayer file.
200   return mFile;
201 };
202 
203 /**
204  * Load a set of files or a single file for the media player.
205  *
206  * @param {array} files An array of files to chose from to load.
207  */
208 minplayer.player.prototype.load = function(files) {
209 
210   // Set the id and class.
211   var id = '', pClass = '';
212 
213   // If no file was provided, then get it.
214   this.options.files = files || this.options.files;
215   this.options.file = this.getMediaFile(this.options.files);
216 
217   // Do nothing if there isn't a file.
218   if (!this.options.file) {
219     this.error('No media found.');
220     return;
221   }
222 
223   if (!this.options.file.player) {
224     this.error('Cannot play media: ' + this.options.file.mimetype);
225     return;
226   }
227 
228   // Reset the error.
229   this.error();
230 
231   // Only destroy if the current player is different than the new player.
232   var player = this.options.file.player.toString();
233 
234   // If there isn't media or if the players are different.
235   if (!this.player || (player !== this.currentPlayer)) {
236 
237     // Set the current media player.
238     this.currentPlayer = player;
239 
240     // The display for this media player.
241     var display = this.elements.display;
242 
243     // Do nothing if we don't have a display.
244     if (!display) {
245       this.error('No media display found.');
246       return;
247     }
248 
249     // If the media exists, then destroy it.
250     if (this.player) {
251       this.player.destory();
252     }
253 
254     // Get the class name and create the new player.
255     pClass = minplayer.players[this.options.file.player];
256 
257     // Create the new media player.
258     var _this = this;
259     this.player = new pClass(display, this.options, function(player) {
260 
261       // Iterate through each plugin.
262       _this.eachPlugin(function(plugin) {
263 
264         // Set the player.
265         plugin.setPlayer(player);
266 
267         // Bind to the error event.
268         plugin.bind('error', function(event, data) {
269           _this.error(data);
270         });
271 
272         // Bind to the fullscreen event.
273         plugin.bind('fullscreen', function(event, data) {
274           _this.resize();
275         });
276       });
277 
278       // Now load this media.
279       player.load();
280     });
281   }
282 
283   // If the media object already exists...
284   else if (this.player) {
285 
286     // Now load the different media file.
287     this.player.load(this.options.file);
288   }
289 };
290 
291 /**
292  * Called when the player is resized.
293  */
294 minplayer.player.prototype.resize = function() {
295 
296   // Call onRezie for each plugin.
297   this.eachPlugin(function(plugin) {
298     plugin.onResize();
299   });
300 };
301 
302 /**
303  * Play the currently loaded media file.  Use load first to load a
304  * media file into the media player.
305  */
306 minplayer.player.prototype.play = function() {
307   if (this.player) {
308     this.player.play();
309   }
310 };
311 
312 /**
313  * Pause the media.
314  */
315 minplayer.player.prototype.pause = function() {
316   if (this.player) {
317     this.player.pause();
318   }
319 };
320 
321 /**
322  * Stop the media.
323  */
324 minplayer.player.prototype.stop = function() {
325   if (this.player) {
326     this.player.stop();
327   }
328 };
329 
330 /**
331  * Seek the media to the provided position.
332  *
333  * @param {number} pos The position to seek.  0 to 1.
334  */
335 minplayer.player.prototype.seek = function(pos) {
336   if (this.player) {
337     this.player.seek(pos);
338   }
339 };
340 
341 /**
342  * Set the volume of the media being played.
343  *
344  * @param {number} vol The volume to set.  0 to 1.
345  */
346 minplayer.player.prototype.setVolume = function(vol) {
347   if (this.player) {
348     this.player.setVolume(vol);
349   }
350 };
351 
352 /**
353  * Get the current volume setting.
354  *
355  * @param {function} callback The callback that is called when the volume
356  * is known.
357  * @return {number} The current volume level. 0 to 1.
358  */
359 minplayer.player.prototype.getVolume = function(callback) {
360   return this.player ? this.player.getVolume(callback) : 0;
361 };
362 
363 /**
364  * Get the current media duration.
365  *
366  * @param {function} callback The callback that is called when the duration
367  * is known.
368  * @return {number} The current media duration.
369  */
370 minplayer.player.prototype.getDuration = function(callback) {
371   return this.player ? this.player.getDuration(callback) : 0;
372 };
373