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