blondedude092

OIPlayer jQuery Player

Apr 3rd, 2016
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /*
  2.  * OIPlayer - jQuery plugin to control html5 video and audio tags and serve alternatives if needed.
  3.  *
  4.  * Copyright (c) 2009-2012 André van Toly
  5.  * Licensed under GPL http://www.gnu.org/licenses/gpl.html
  6.  *
  7.  * Inits and controls video- or audioplayer based on the html5 video- or audiotag. Depends on jquery.
  8.  * It enables the use of three players in a generic way: html5 media-tag, Java applet Cortado (for ogg)
  9.  * and Flash FlowPlayer (for mp4 and flv). Sifts through the sources provided by the mediatag to find
  10.  * a suitable player, replaces the mediatag with it and enables some generic controls.
  11.  * This script borrows heavily from the rather brilliant one used at Steal This Footage which enables
  12.  * a multitude of players (but defies MSIE ;-) http://footage.stealthisfilm.com/
  13.  *
  14.  * MSIE bug (!) : currently I could find no way to makes this plugin behave correctly in MSIE on multiple
  15.  * mediatags in one go. You will have to wrap each mediatag in a div or some other element before
  16.  * feeding it to the plugin.
  17.  *
  18.  * Uses these parameters and/or the audio/video tag attributes like height, width, poster etc.
  19.  * An audio tag can have an image in its body to use as a poster cq. background.
  20.  *
  21.  * @params:
  22.  *   id - id of the element that contains the media tag
  23.  *   config - configuration parameters
  24.  *       'server' : server url (for Flash or Java in some browsers)
  25.  *       'jar' : location of Cortado JAR file
  26.  *       'flash' : location of flowplayer.swf
  27.  *       'controls' : Configure controls, per default possible values are 'true', 'top', 'white', 'dark', 'top dark' and 'top white'.
  28.  *                    Simply 'true' means show me controls below player,
  29.  *                    'top' will add a css class of that name and will hide/show controls on top of the player window,
  30.  *                    and 'white' and 'dark' refer to light or dark styled versions which both can be used below or on top of your video.
  31.  *                    Or add a css class of your own to edit the appearance of the controls.
  32.  *       'log' : when your specify 'info' some debug messages are shown about the media playing
  33.  *
  34.  * @changes: replaced jquery.ui.slider with "own" scrubber, improved controls
  35.  * @version: '$Id$'
  36. */
  37.  
  38. jQuery.fn.oiplayer = function(settings) {
  39.     var config = {
  40.         server : 'http://www.openimages.eu',
  41.         jar : '/oiplayer/plugins/cortado-ovt-stripped-0.6.0.jar',
  42.         flash : '/oiplayer/plugins/flowplayer-3.2.7.swf',
  43.         controls : true,
  44.         log: 'error'
  45.     };
  46.     if (settings) $.extend(config, settings);
  47.    
  48.     var players = new Array();
  49.     this.each(function() {
  50.         var current = this;
  51.         var mediatags = $(this).find('video,audio');
  52.         if (mediatags.length == 0) {
  53.             /* navigate MSIE8 around a bug (?) introduced in jquery 1.4.4 (does not recognize audio or video)
  54.             that seems partly fixed in jquery 1.5.1 (does not recognize "video, audio" but recognizes them solo) */
  55.             mediatags = $(this).find('video');
  56.             var audiotags = $(this).find('audio');
  57.             $.merge(mediatags, audiotags);
  58.         }
  59.         $.each(mediatags, function(i, mt) {
  60.             var sources = $(mt).find('source');
  61.             if (sources.length == 0) {
  62.                 /* this may work in older MSIE versions  */
  63.                 sources = $(current).find('source');
  64.                 //alert("src: " + $(sources).attr('src'));
  65.             }
  66.            
  67.             /* video/audio tag is wrapped in a div */
  68.             if (!isIpad() && !isIphone()) {
  69.                 $(mt).wrap('<div class="oiplayer"><div class="player"></div></div>');
  70.             }
  71.            
  72.             /* create a player (video or audio tag, flowplayer flash, cortado applet) */
  73.             var div = $(mt).closest('div.oiplayer');
  74.             var player = createPlayer(mt, sources, config);
  75.             $(div).addClass(player.type);
  76.             player.div = div;
  77.            
  78.             if (player.myname.indexOf('cortado') > -1) {
  79.                 $(div).find('div.player').empty();
  80.                 $(div).find('div.player').append(player.player);
  81.             }
  82.             if ((isIpad() || isIphone()) && player.type == 'audio') {
  83.                 $(mt).css('height', '0px').hide();   /* hide audio tag on iPad */
  84.             }
  85.             if ($.browser.msie && (player.myname.indexOf('cortado') > -1 || player.myname == 'flowplayer')) {
  86.                 $(current).find('.html5warning').hide();
  87.             }
  88.            
  89.             var poster = createPoster(div, player);
  90.             $(div).prepend(poster);
  91.             $(div).height(player.height);
  92.             //console.log("ctrls: " + config.controls + " , " + player.url);
  93.             if (config.controls && player.url != undefined) {
  94.                
  95.                 if (isIphone() || isIpad()) {
  96.                     $(mt).after(controlsHtml(player));
  97.                     player.ctrls = $(mt).next('div.oipcontrols');
  98.                     $(player.ctrls).addClass('ios');
  99.                    
  100.                 } else {
  101.                     $(div).append(controlsHtml(player));
  102.                     player.ctrls = $(div).find('div.oipcontrols');
  103.                    
  104.                     $(mt).removeAttr('controls');
  105.                 }
  106.                
  107.                 if (config.controls == true) {
  108.                     $(div).height( $(div).height() + 30 );  // due to some quirk in webkit
  109.                     player.ctrlspos = 'bottom';
  110.                    
  111.                 } else {
  112.                     if (player.myname.indexOf('cortado') > -1 || isIphone() || isIpad()) {
  113.                         /* remove .top when not compatible */
  114.                         config.controls = config.controls.replace('top', '');
  115.                         if (config.controls.length == 0) { config.controls = 'white'; }
  116.                     }
  117.                     $(player.ctrls).addClass(config.controls);
  118.                     if (config.controls.indexOf('top') > -1) {
  119.                         player.ctrlspos = 'top';
  120.                         if (player.type != 'audio' && player.state != 'init') {
  121.                             $(player.ctrls).hide();
  122.                         }
  123.                     } else {
  124.                         if (player.type != 'audio') {
  125.                             //$(div).height( $(div).height() + $(player.ctrls).height() );
  126.                             $(div).height( $(div).height() + 30 );  // due to some quirk in webkit
  127.                         }
  128.                         player.ctrlspos = 'bottom';
  129.                     }
  130.                 }
  131.                 var ctrlsWidth = $.oiplayer.controlswidth(player);
  132.                 if (player.type == 'video' || $(player.div).find('img').length > 0) {
  133.                     $(player.ctrls).css('margin-left', Math.round( (player.width - ctrlsWidth) / 2) + 'px');
  134.                 } else {
  135.                     $(player.ctrls).css('margin-left', '0px');
  136.                 }
  137.             }
  138.            
  139.             if (player.url == undefined) {  // no compatible sources to play
  140.                 $(div).addClass('inavailable');
  141.                 $(div).append('<p>No compatible source found to play.</p>');
  142.             }
  143.            
  144.             if (config.log == 'info') {
  145.                 $.oiplayer.msg(player, player.info);
  146.             }
  147.            
  148.             players.push(player);
  149.  
  150.         }); // end for each
  151.     });
  152.    
  153.     /* html ready, bind controls */
  154.     $.each(players, function(i, pl) {
  155.         $(pl.div).find('.preview').click(function(ev) {
  156.             ev.preventDefault();
  157.             $.oiplayer.start(pl);
  158.         });
  159.        
  160.         if (config.controls) {
  161.             $(pl.ctrls).find('div.play a').click(function(ev) {
  162.                 ev.preventDefault();
  163.                 if (pl.state == 'pause') {
  164.                     pl.play();
  165.                     if ($(pl.ctrls).find('div.pause').length == 0) {
  166.                         $(pl.ctrls).find('div.play').addClass('pause');
  167.                     }
  168.                 } else if (pl.state == 'play') {
  169.                     pl.pause();
  170.                     $(pl.ctrls).find('div.play').removeClass('pause');
  171.                 } else {
  172.                     $.oiplayer.start(pl);
  173.                 }
  174.             });
  175.  
  176.             $(pl.ctrls).find('div.sound a').click(function(ev){
  177.                 ev.preventDefault();
  178.                 $(pl.ctrls).find('div.sound').toggleClass('muted');
  179.                 pl.mute();
  180.             });
  181.             $(pl.ctrls).find('div.screen a').click(function(ev){
  182.                 ev.preventDefault();
  183.                 fullscreen(pl);
  184.             });
  185.            
  186.             $(pl.ctrls).find('div.back').click(function(ev){
  187.                 jumpScrubberOnClick(pl, ev);
  188.             });
  189.             $(pl.ctrls).find('div.loaded').click(function(ev){
  190.                 jumpScrubberOnClick(pl, ev);
  191.             });
  192.             $(pl.ctrls).find('div.played').click(function(ev){
  193.                 jumpScrubberOnClick(pl, ev);
  194.             });
  195.             $(pl.ctrls).find('div.pos a').click(function(ev){ ev.preventDefault(); });
  196.             $(pl.ctrls).find('div.oiprogress-push').mousedown(function(ev){
  197.                 ev.preventDefault();
  198.                 $(this).find('a').css("background-position", "0 -100px");
  199.                 startScrubbing(pl, ev, this);
  200.             });
  201.            
  202.             // show/hide
  203.             if (pl.ctrlspos == 'top' && pl.type != 'audio') {
  204.                 $(pl.div).mouseover(
  205.                     function(ev) {
  206.                         $(pl.ctrls).fadeIn();
  207.                     }).mouseleave(
  208.                     function(ev) {
  209.                         if (pl.state != 'init') {
  210.                             $(pl.ctrls).fadeOut('slow');
  211.                         }
  212.                     }
  213.                 );
  214.             }
  215.         } // config.controls
  216.  
  217.         $(pl.div).bind("oiplayerended", function(ev, pl) {
  218.             $(pl.ctrls).fadeIn('slow');
  219.         });
  220.        
  221.     });
  222.  
  223.     function startScrubbing(player, ev, self) {
  224.         //hidePreview(player);
  225.         if (player.type == 'video') { $(player.div).find('.preview').fadeOut('normal'); }
  226.         player.prevstate = player.state;
  227.         player.pause();
  228.        
  229.         var width = $(player.ctrls).find('div.oiprogress').innerWidth();
  230.         player.sPerPx = player.duration / (width - 11);
  231.         player.startTime = player.position();
  232.         player.scrubStart = $(self).offset()['left'];   // self is .push
  233.        
  234.         $(player.div).mousemove(function(ev) {
  235.             ev.preventDefault();
  236.             updateScrubber(player, ev);
  237.         });
  238.         $(player.div).mouseup(function(ev) {
  239.             ev.preventDefault();
  240.             $(player.ctrls).find('div.pos a').css("background-position", "0 -75px");
  241.             endScrubbing(player, ev);
  242.         });
  243.  
  244.     }
  245.    
  246.     function updateScrubber(player, ev) {
  247.         var pxDelta = ev.pageX - player.scrubStart;
  248.         var seek = player.startTime + pxDelta * player.sPerPx;
  249.         if (seek >= player.duration) {
  250.             seek = player.duration - 0.1;
  251.         }
  252.         if (seek < 0) { seek = 0; }
  253.         $.oiplayer.position(player, seek);
  254.         player.seek(seek);
  255.     }
  256.  
  257.     function endScrubbing(player, ev) {
  258.         if (player.prevstate == 'init') { player.state = 'init'; }
  259.         if (player.prevstate == 'play') { player.play(); }
  260.        
  261.         $(player.div).unbind("mousemove");
  262.         $(player.div).unbind("mouseup");
  263.     }
  264.    
  265.     function jumpScrubberOnClick(player, ev) {
  266.         var width = $(player.ctrls).find('div.oiprogress').innerWidth();
  267.         var x = ev.pageX - $(player.ctrls).find('div.oiprogress').offset()['left'] - 5;
  268.         x = Math.max(Math.min(x, width), 0);
  269.         var seek = (x / width) * player.duration;
  270.        
  271.         //hidePreview(player);
  272.         if (player.type == 'video') { $(player.div).find('.preview').fadeOut('normal'); }
  273.  
  274.         var perc = (seek / player.duration) * 100;
  275.         perc = perc + "%";
  276.         $(player.ctrls).find('div.played').animate({ width:perc }, 200);
  277.         $(player.ctrls).find('div.oiprogress-push').animate(
  278.             { left: perc },
  279.             200,
  280.             function() { $.oiplayer.position(player, seek); }
  281.         );
  282.         player.seek(seek);
  283.     }
  284.    
  285.     function fullscreen(player) {
  286.         if (isIpad() || isIphone()) {
  287.             player.player.webkitEnterFullscreen();
  288.             return;
  289.         }
  290.         if (player.owidth == undefined) {
  291.             player.owidth = player.width;
  292.             player.oheight = player.height;
  293.         }
  294.         $(player.div).toggleClass('fullscreen');
  295.        
  296.         // flash stuff
  297.         if (player.myname == 'flowplayer') {
  298.             // for flash
  299.             var pos = player.position();
  300.             var state = player.state;
  301.             var fp_id = player.player.id();
  302.             player.player.unload();
  303.             var pl_div = $(player.div).find('div.player');
  304.             $(pl_div).empty().attr('id', fp_id); // re-use fp id
  305.         }
  306.        
  307.         if ($(player.div).is('.fullscreen')) {
  308.             player.origoverflow = document.documentElement.style.overflow;
  309.             document.documentElement.style.overflow = 'hidden';
  310.  
  311.             // new dimensions
  312.             $(player.div).width('100%').height('100%');
  313.             player.width = $(window).width();
  314.             if (player.ctrlspos == 'top') {
  315.                 player.height = $(window).height();
  316.             } else {
  317.                 player.height = $(player.div).height() - $(player.ctrls).height();
  318.             }
  319.             $(player.player).width(player.width).height(player.height);
  320.             $(player.div).find('div.player').height(player.height);
  321.             $(player.div).find('.preview').width(player.width).height(player.height);
  322.             $(window).scrollTop(0).scrollLeft(0);
  323.            
  324.             // controls
  325.             var controls_width = $.oiplayer.controlswidth(player);
  326.             $(player.ctrls).css('margin-left', Math.round( (player.width - controls_width) / 2) + 'px');
  327.             // 'hide' other media players (display:hidden often disables them)
  328.             $('div.oiplayer').not('.fullscreen').css('margin-left', '-9999px');
  329.            
  330.             $(document).bind('keydown', function(ev) {
  331.                 // bind escape key to switch back from fullscreen
  332.                 if (ev.keyCode == '27') { fullscreen(player); }
  333.             });
  334.            
  335.             if (player.ctrlspos == 'top' && player.type != 'audio') {
  336.                 // unbind previous show/hide and let this one take over
  337.                 $(player.div).unbind('mouseover').unbind('mouseleave');
  338.                 $(player.div).mouseover(
  339.                     function(ev) {
  340.                         $(player.ctrls).fadeIn();
  341.                     }).mouseout(
  342.                     function(ev) {
  343.                         if (player.state != 'init' && ev.pageY > ($(this).offset().top + $(this).height())) {
  344.                             $(player.ctrls).fadeOut('slow');
  345.                         }
  346.                     }
  347.                 );
  348.             }
  349.            
  350.         } else {
  351.             $(document).unbind('keydown');
  352.             $('div.oiplayer').css('margin-left', '0');    // show other mediaplayers again
  353.             document.documentElement.style.overflow = player.origoverflow;
  354.            
  355.             // reset dimensions
  356.             player.width = player.owidth;
  357.             player.height = player.oheight;
  358.             $(player.player).width(player.width).height(player.height);
  359.             $(player.div).find('div.player').height(player.height);
  360.             $(player.div).find('.preview').width(player.width).height(player.height);
  361.            
  362.             // reposition controls
  363.             if (player.ctrlspos == 'top') {
  364.                 $(player.div).width(player.width).height(player.height);
  365.             } else {
  366.                 $(player.div).width(player.width).height(player.height + $(player.ctrls).height());
  367.             }
  368.             $(player.ctrls).css('margin-left', Math.round( (player.width - $.oiplayer.controlswidth(player)) / 2) + 'px');
  369.            
  370.         }
  371.  
  372.         // flash stuff
  373.         if (player.myname == 'flowplayer') {
  374.             player.create(fp_id, player.url, player.config);    // recreate fp with id
  375.             setTimeout(function() {
  376.                 player.seek(pos);
  377.                 if (state == 'play') { player.play(); }
  378.             }, 1000);  // give fp time to reload
  379.         }
  380.     }
  381.    
  382.     /*
  383.      * Creates player based upon selected url
  384.      * @param el        video or audio element
  385.      * @param source    source tags
  386.      * @param config    configuration
  387.      * @return Player
  388.      */
  389.     function createPlayer(el, sources, config) {
  390.         var player;
  391.         var types = $.map(sources, function(i) {
  392.             return $(i).attr('type');
  393.         });
  394.         var urls = $.map(sources, function(i) {
  395.             return $(i).attr('src');
  396.         });
  397.         if (urls.length == 0) { // no sources in body
  398.             urls[0] = $(el).attr('src');
  399.             types[0] = "unknown";   // TODO ?
  400.         }
  401.         var eas = extraAttributes(el);
  402.  
  403.         var selectedPlayer = selectPlayer(el, types, urls);
  404.         if (selectedPlayer.type == 'media') {
  405.             player = new MediaPlayer();
  406.         } else if (selectedPlayer.type == 'cortado') {
  407.             player = new CortadoPlayer();
  408.         } else if (selectedPlayer.type == 'msie_cortado') {
  409.             player = new MSCortadoPlayer();
  410.         } else if (selectedPlayer.type == 'flash') {
  411.             player = new FlowPlayer();
  412.         } else {
  413.             player = new Player();
  414.             player.type = "none";
  415.         }
  416.         if (eas.duration != null) {
  417.             player.duration = eas.duration;
  418.         }
  419.         if (eas.start != null) {
  420.             player.start = eas.start;
  421.         }
  422.         if (eas.id != null) {
  423.             player.id = eas.id;
  424.         }
  425.         player.info = selectedPlayer.type + ":" + selectedPlayer.url;
  426.         player.init(el, selectedPlayer.url, config);
  427.         return player;
  428.     }
  429.    
  430.     /*
  431.      * Selects which player to use and returns a proposal.type and proposal.url.
  432.      * Adapt this to change the prefered order, here the order is: video/audio, cortado, msie_cortado, flash.
  433.      * @param el    video or audio element
  434.      * @param types mimetype (and codec) attributes
  435.      * @param urls  media links
  436.      */
  437.     function selectPlayer(el, types, urls) {
  438.         var proposal = new Object();
  439.         var probably = canPlayMedia(types, urls);
  440.         if (probably != undefined) {
  441.             proposal.type = "media";
  442.             proposal.url = probably;
  443.             return proposal;    // optimization
  444.         }
  445.         if (proposal.type == undefined) {
  446.             probably = canPlayCortado(types, urls);
  447.             if (probably != undefined && (supportMimetype('application/x-java-applet') || navigator.javaEnabled())) {
  448.                 if ($.browser.msie) {   // Argh! A browser check!
  449.                     /* IE always reports true on navigator.javaEnabled(),
  450.                        that's why we need to check for the java plugin IE style.
  451.                        It needs an element with id 'clientcaps' somewhere in the page.
  452.                     */
  453.                     var javaVersionIE = clientcaps.getComponentVersion("{08B0E5C0-4FCB-11CF-AAA5-00401C608500}", "ComponentID");
  454.                     if (javaVersionIE) {
  455.                         proposal.type = "msie_cortado";
  456.                         proposal.url = probably;
  457.                     }
  458.                     if (el.tagName.toLowerCase() == 'audio') {      // always use cortado on msie
  459.                         proposal.type = "msie_cortado";
  460.                         proposal.url = probably;
  461.                     }
  462.                 } else {
  463.                     proposal.type = "cortado";
  464.                     proposal.url = probably;
  465.                 }
  466.             }
  467.         }
  468.         if (proposal.type == undefined || proposal.type.indexOf('cortado') > -1) {
  469.             var flash_url;
  470.             for (var i = 0; i < types.length; i++) {
  471.                 if (types[i].indexOf("video/flv") > -1 || types[i].indexOf("video/x-flv") > -1) {
  472.                     proposal.url = urls[i];
  473.                     proposal.type = "flash";
  474.                     return proposal;
  475.                 }
  476.             }
  477.             for (var i = 0; i < types.length; i++) {
  478.                 if (types[i].indexOf("video/mp4") > -1
  479.                     /* || types[i].indexOf("video/mpeg") > -1 */ ) {
  480.                     proposal.url = urls[i];
  481.                     proposal.type = "flash";
  482.                     return proposal;
  483.                 }
  484.             }
  485.         }
  486.        
  487.         /* try anyway with media tag */
  488.         if (types.length > 0 && types[0] == "unknown") {
  489.             proposal.url = urls[0];
  490.             proposal.type = "media";
  491.             return proposal;
  492.         }
  493.         return proposal;
  494.     }
  495.    
  496.     /*
  497.      * Examines mimetypes and returns belonging ogg url it expects to be able to play.
  498.      */
  499.     function canPlayCortado(types, urls) {
  500.         var url;
  501.         for (var i = 0; i < types.length; i++) {
  502.             if (types[i].indexOf("video/ogg") > -1 ||
  503.                 types[i].indexOf("audio/ogg") > -1 ||
  504.                 types[i].indexOf("application/ogg") > -1 ||
  505.                 types[i].indexOf("application/x-ogg") > -1) {
  506.                 url = urls[i];
  507.                 break;
  508.             }
  509.         }
  510.         return url;
  511.     }
  512.    
  513.     /*
  514.      * Returns (first) url it expects to be able to play with html5 video- or audiotag based on mimetype.
  515.      */
  516.     function canPlayMedia(types, urls) {
  517.         var vEl = document.createElement("video");
  518.         var aEl = document.createElement("audio");
  519.         if (vEl.canPlayType || aEl.canPlayType) {
  520.             for (var i = 0; i < types.length; i++) {
  521.                 if (vEl.canPlayType( types[i] ) == "probably" || aEl.canPlayType( types[i] ) == "probably") {
  522.                     return urls[i]; // this is the best we can do
  523.                 }
  524.                 if (vEl.canPlayType( types[i] ) == "maybe" || aEl.canPlayType( types[i] ) == "maybe") {
  525.                     return urls[i]; // if we find nothing better
  526.                 }
  527.             }
  528.         }
  529.     }
  530.  
  531.     function supportMimetype(mt) {
  532.         var support = false;    /* navigator.mimeTypes is unsupported by MSIE ! */
  533.         if (navigator.mimeTypes && navigator.mimeTypes.length > 0) {
  534.             for (var i = 0; i < navigator.mimeTypes.length; i++) {
  535.                 if (navigator.mimeTypes[i].type.indexOf(mt) > -1) {
  536.                     support = true;
  537.                 }
  538.             }
  539.         }
  540.         return support;
  541.     }
  542.  
  543.     function createPoster(el, player) {
  544.         var src = player.poster;
  545.         if (!src && player.type == 'audio') { // for audio-tags (no attribute poster but image inside audio-tag)
  546.             var img = $(el).find('img')[0];
  547.             /* make height and width of audio those of img inside audio body */
  548.             player.width = $(img).attr('width') > 0 ? parseInt($(img).attr('width')) : player.width;
  549.             player.height = $(img).attr('height') > 0 ? parseInt($(img).attr('height')) : player.height;
  550.             src = $(img).attr('src');
  551.             $(img).remove();
  552.         }
  553.         if (src) {
  554.             return '<img class="preview ' + player.type + '" src="' + src + '" width="' + player.width + '" height="' + player.height + '" alt="click to play" title="click to play" />';
  555.         }
  556.     }
  557.        
  558.     function controlsHtml(player) {
  559.         var html = '<div class="oipcontrols">' +
  560.                       '<div class="play"><a href="#play">play</a></div>' +
  561.                       '<div class="time">00:00</div>' +
  562.                       '<div class="progress">' +
  563.                         '<div class="oiprogress"><div class="back bar"></div><div class="loaded bar"></div><div class="played bar"></div><div class="oiprogress-container"><div class="oiprogress-push"><div class="pos"><a href="#pos">pos</a></div></div></div></div>' +
  564.                       '</div>' +
  565.                       '<div class="timeleft">-' + (player.position() > 0 ? $.oiplayer.totime(player.duration - player.position()) : $.oiplayer.totime(player.duration)) + '</div>' +
  566.                       (player.type == 'video' && !isIphone() ? '<div class="screen"><a href="#fullscreen">fullscreen</a></div>' : '') +
  567.                       (isIpad() ? '' : '<div class="sound"><a href="#sound">mute</a></div>') +
  568.                    '</div>';
  569.         return html;
  570.     }
  571.  
  572.     /*
  573.      * Returns attributes and values hidden in classes of an element, f.e. oip_ea_attr_value
  574.      */
  575.     function extraAttributes(el) {
  576.         var attributes = new Object();
  577.         if ($(el).attr("class")) {
  578.             var classes = $(el).attr("class").split(' ');
  579.             for (var i in classes) {
  580.                 var cl = classes[i];
  581.                 if (cl.indexOf("oip_ea_") == -1) continue;
  582.                 var a = cl.substring("oip_ea_".length);
  583.                 var v = a.indexOf("_");
  584.                 attributes[a.substring(0, v)] = a.substring(v + 1);
  585.             }
  586.         }
  587.         return attributes;
  588.     }
  589.    
  590.     /* sorry about these :-( could not find suitable abilities checks */
  591.     function isIphone() {   // iPhone and iPod act the same
  592.         return navigator.userAgent.match(/iPhone|iPod/i) != null;
  593.     }
  594.     function isIpad() {
  595.         return navigator.userAgent.match(/iPad/i) != null;
  596.     }
  597.  
  598.     return this; // plugin convention
  599. };
  600.  
  601.  
  602. //  ------------------------------------------------------------------------------------------------
  603. //  Global functions
  604. //  ------------------------------------------------------------------------------------------------
  605.  
  606. $.oiplayer = {
  607.    
  608.     /*
  609.      * Follows progress of player and calls interface update
  610.      * @param player Object of player
  611.      */
  612.     follow: function (player) {
  613.         var i = now = 0;
  614.         player.fpstate = 'following';
  615.         var progress = null;
  616.         clearInterval(progress);
  617.         progress = setInterval(function() {
  618.             var pos = player.position();
  619.             if (pos != now) {
  620.                 now = pos;
  621.             } else {
  622.                 i++;
  623.             }
  624.             /* player is paused while scrubbing */
  625.             if (player.state != 'pause' && player.state != 'ended') {  
  626.                 $.oiplayer.position(player, pos);
  627.             }
  628.             if (i > 999) {
  629.                 clearInterval(progress);
  630.             }
  631.         }, 100);
  632.     },
  633.    
  634.     start: function (player) {
  635.         $.oiplayer.hidepreview(player);
  636.         if (player.state == 'init' || player.state == 'ended' || player.fpstate == undefined) {
  637.             $(player.div).trigger("oiplayerplay", [player]);
  638.         }
  639.         if (player.config.controls) {
  640.             $(player.ctrls).find('div.play').addClass('pause');
  641.             $.oiplayer.follow(player);
  642.         }
  643.         player.play();
  644.         if (player.config.log == 'info') {
  645.             $.oiplayer.msg(player, "Playing... " + player.info + " (" + player.duration + ")");
  646.         }
  647.     },
  648.    
  649.     hidepreview: function(player) {
  650.         if (player.type == 'video') {
  651.             $(player.div).find('.preview').fadeOut('normal');
  652.         } else {
  653.             $(player.div).find('.preview').css("z-index", "1");
  654.         }
  655.     },
  656.    
  657.     /*
  658.      * CSS position of slider / scrubber
  659.      */
  660.     position: function(player, pos) {
  661.         if (!isNaN(pos) && pos > 0) {
  662.             var perc = (pos / player.duration) * 100;
  663.             var plperc = (perc < 50 ? perc + 1 : perc) + "%";
  664.             perc = perc + "%";
  665.             $(player.ctrls).find('div.oiprogress-push').css('left', perc);
  666.             $(player.ctrls).find('div.played').width(plperc);
  667.             if (player.duration > 0) {
  668.                 $(player.ctrls).find('div.timeleft').text("-" + $.oiplayer.totime(player.duration - pos));
  669.             }
  670.             $(player.ctrls).find('div.time').text( $.oiplayer.totime(pos) );
  671.             prevpos = pos;
  672.         }
  673.  
  674.         /* .time .timeleft .changed */
  675.         $(player.ctrls).find('div.time').text( $.oiplayer.totime(pos) );
  676.         $(player.ctrls).find('div.timeleft').text('-' + $.oiplayer.totime(player.duration - pos) );
  677.         if (pos > 0) {
  678.             $(player.ctrls).find('div.progress').addClass('changed');
  679.         } else {
  680.             $(player.ctrls).find('div.progress').removeClass('changed');
  681.         }
  682.    
  683.     },
  684.    
  685.     /*
  686.      * Returns div player is wrapped in
  687.      */
  688.     div: function(player) {
  689.         if (player.myname == 'flowplayer') {
  690.             return $(player.player.getParent()).closest('div.oiplayer');
  691.         } else {
  692.             return $(player.player).closest('div.oiplayer');
  693.         }        
  694.     },
  695.  
  696.     controlswidth: function(player) {
  697.         if (player.ctrlspos == 'top') {
  698.             var controls_width = player.width - 32;
  699.         } else {
  700.             var controls_width = player.width;        
  701.         }
  702.         if (controls_width > 620) { controls_width = 620; }
  703.         $(player.ctrls).width(controls_width);
  704.         $(player.ctrls).find('div.sliderwrap').width(controls_width - 190);
  705.         return controls_width;
  706.     },
  707.        
  708.     /*
  709.      * Can come in handy in stead of using 'console.log("bla")' in some browsers,
  710.      * f.e.: '$.oiplayer.msg(this.player, "Play: " + this.url)'.
  711.      */
  712.     msg: function(player, msg) {
  713.         $('<div class="oiplayerinfo"></div>').text(msg).insertAfter(player.div).hide().fadeIn();
  714.     },
  715.    
  716.     /*
  717.      * Returns time formatted as 00:00
  718.      */
  719.     totime: function (pos) {
  720.         if (pos < 0) { pos = 0; }
  721.         function toTime(sec) {
  722.             var h = Math.floor(sec / 3600);
  723.             var min = Math.floor(sec / 60);
  724.             var sec = Math.floor(sec - (min * 60));
  725.             if (h >= 1) {
  726.                 min -= h * 60;
  727.                 return h + ":" + addZero(min) + ":" + addZero(sec);
  728.             }
  729.             return addZero(min) + ":" + addZero(sec);
  730.         }
  731.    
  732.         function addZero(time) {
  733.             time = parseInt(time, 10);
  734.             return time < 10 ? "0" + time : time;
  735.         }
  736.         return toTime(Math.floor(pos));
  737.     }
  738. }
  739.  
  740.  
  741. //  ------------------------------------------------------------------------------------------------
  742. //  Prototypes of several players
  743. //  ------------------------------------------------------------------------------------------------
  744.  
  745. function Player() {
  746.     this.myname = "super";
  747. }
  748. Player.prototype.init = function(el, url, config) {
  749.     this._init(el, url, config);
  750. }
  751. Player.prototype.mute = function() { }
  752. Player.prototype.play = function() { }
  753. Player.prototype.pause = function() { }
  754. /* current position of audio or video */
  755. Player.prototype.position = function() { }
  756. /* go to this position */
  757. Player.prototype.seek = function(pos) { }
  758. Player.prototype.info = function() { }
  759.  
  760. Player.prototype._init = function(el, url, config) {
  761.     this.state = 'init';
  762.     this.el = el;
  763.     this.player = el;
  764.     this.url = url;
  765.     this.config = config;
  766.     this.type = el.tagName.toLowerCase(); // video or audio
  767.     this.poster = $(this.player).attr('poster');
  768.     this.autoplay = $(this.player).attr('autoplay');
  769.     if (this.autoplay == undefined) this.autoplay = false;
  770.     this.autobuffer = $(this.player).attr('autobuffer');
  771.     if (this.autobuffer == undefined) this.autobuffer = false;
  772.     this.controls = $(this.player).attr('controls');
  773.     if (this.controls == undefined) this.controls = false;
  774.     if (this.duration == undefined) this.duration = 0;
  775.     this.width = $(this.player).attr('width') > 0 ? parseInt($(this.player).attr('width')) : 320;
  776.     if (this.type == 'audio') {
  777.         var default_height = 32;
  778.     } else {
  779.         var default_height = 240;
  780.     }
  781.     this.height = $(this.player).attr('height') > 0 ? parseInt($(this.player).attr('height')) : default_height;
  782.     if (this.type == 'audio') { $(this.player).removeAttr('width').removeAttr('height'); }
  783. }
  784.  
  785. function MediaPlayer() {
  786.     this.myname = "mediaplayer";
  787. }
  788. MediaPlayer.prototype = new Player();
  789. MediaPlayer.prototype.init = function(el, url, config) {
  790.     this._init(el, url, config);
  791.     this.url = url;
  792.     if (config.controls) {
  793.         var self = this;
  794.         self.buffered = 0;
  795.         this.player.addEventListener("durationchange",
  796.             function(ev) {
  797.                 if (!isNaN(self.player.duration) && self.player.duration > 0 && self.player.duration != 'Infinity') {
  798.                     self.duration = self.player.duration;
  799.                     if (config.log == 'info') {
  800.                         $.oiplayer.msg(self, "set duration: " + self.duration);
  801.                     }
  802.                     $(self.ctrls).find('div.timeleft').text("-" + $.oiplayer.totime(self.duration));
  803.                 }
  804.             }, false);
  805.         this.player.addEventListener("progress",
  806.             function(ev) {  /* FF will support this in v4 */
  807.                 if (self.player.buffered && self.player.buffered.length > 0) {
  808.                      var buf = self.player.buffered.end(0);
  809.                      if (buf > self.buffered) {
  810.                           self.buffered = buf;
  811.                           var perc = (buf / self.duration) * 100 + '%';
  812.                           $(self.ctrls).find('div.loaded').width(perc);
  813.                      }
  814.                 }
  815.             }, false);
  816.         this.player.addEventListener("canplaythrough",
  817.             function(ev) {
  818.                 if (self.player.buffered && self.player.buffered.length > 0) {
  819.                      var buf = self.player.buffered.end(0);
  820.                      if (buf > self.buffered) {
  821.                           self.buffered = buf;
  822.                           var perc = (buf / self.duration) * 100 + '%';
  823.                           $(self.ctrls).find('div.loaded').width(perc);
  824.                      }
  825.                      if (this.autoplay) { $.oiplayer.start(self); }
  826.                 }
  827.             }, false);
  828.         this.player.addEventListener("loadedmetadata",
  829.             function(ev) {
  830.                 if (self.type == 'video' && (self.width == 320 || self.height == 240)) {
  831.                     self.width = $(self.player).attr('width') > 0 ? parseInt($(self.player).attr('width')) : self.player.videoWidth;
  832.                     self.height = $(self.player).attr('height') > 0 ? parseInt($(self.player).attr('height')) : self.player.videoHeight;
  833.                     $.oiplayer.controlswidth(self);
  834.                     $(self.div).width(self.width).height(self.height);
  835.                 }
  836.             }, false);
  837.         this.player.addEventListener("loadeddata",
  838.             function(ev) {  /* FF will support this in v4 */
  839.                 if (self.player.buffered && self.player.buffered.length > 0) {
  840.                      var buf = self.player.buffered.end(0);
  841.                      if (buf > self.buffered) {
  842.                           self.buffered = buf;
  843.                           var perc = (buf / self.duration) * 100 + '%';
  844.                           $(self.ctrls).find('div.loaded').width(perc);
  845.                      }
  846.                 }
  847.             }, false);
  848.         this.player.addEventListener("playing",
  849.             function(ev) {
  850.                 if (self.state == 'init' || self.stat == 'ended') { /* when started outside controls */
  851.                     $.oiplayer.start(self);
  852.                 }
  853.                 self.state = 'play';
  854.                 $(self.ctrls).find('div.play').addClass('pause');
  855.             }, false);
  856.         this.player.addEventListener("pause",
  857.             function(ev) {
  858.                 self.state = 'pause';
  859.                 $(self.ctrls).find('div.play').removeClass('pause');
  860.             }, false);
  861.         this.player.addEventListener("volumechange",
  862.             function(ev) {
  863.                 if (self.player.muted) {
  864.                     $(self.ctrls).find('div.sound').addClass('muted');
  865.                 } else {
  866.                     $(self.ctrls).find('div.sound').removeClass('muted');
  867.                 }
  868.             }, false);
  869.         this.player.addEventListener("ended",
  870.             function(ev) {
  871.                 if (self.state != 'ended') {
  872.                     self.state = 'ended';
  873.                     $(self.div).trigger("oiplayerended", [self]);
  874.                 }
  875.                 $(self.div).find('div.play').removeClass('pause');
  876.             }, false);
  877.     }
  878.     return this.player;
  879. }
  880. MediaPlayer.prototype.play = function() {
  881.     if (this.player.readyState == '0') {
  882.         this.player.load();
  883.     }
  884.     this.player.play();
  885.     this.state = 'play';
  886. }
  887. MediaPlayer.prototype.pause = function() {
  888.     this.player.pause();
  889.     this.state = 'pause';
  890. }
  891. MediaPlayer.prototype.mute = function() {
  892.     if (this.player.muted) {
  893.         this.player.muted = false;
  894.         //this.player.volume = 1.0;
  895.     } else {
  896.         this.player.muted = true;
  897.         //this.player.volume = 0;
  898.     }
  899. }
  900. MediaPlayer.prototype.position = function() {
  901.     try {
  902.         this.pos = this.player.currentTime;
  903.         return this.pos;
  904.     } catch(err) {
  905.         $.oiplayer.msg(self, "Error: " + err);
  906.     }
  907.     return -1;
  908. }
  909. MediaPlayer.prototype.seek = function(pos) {
  910.     // TODO: investigate pause() and play() needed?
  911.     //this.player.pause();
  912.     this.player.currentTime = pos;   // float
  913.     //this.player.play();
  914. }
  915. MediaPlayer.prototype.info = function() {
  916.     /*  duration able in webkit,
  917.         unable in mozilla without: https://developer.mozilla.org/en/Configuring_servers_for_Ogg_media
  918.     */
  919.     //return "Duration: " + this.player.duration + " readyState: " + this.player.readyState;
  920. }
  921.  
  922. function CortadoPlayer() {
  923.     this.myname = "cortadoplayer";
  924. }
  925. CortadoPlayer.prototype = new Player();
  926. CortadoPlayer.prototype.init = function(el, url, config) {
  927.     this._init(el, url, config);
  928.     this.url = url;
  929.     var jar = config.server + config.jar;
  930.     var usevideo = true;
  931.     var useheight = this.height;
  932.     if (this.type == 'audio') {
  933.         usevideo = false;
  934.         useheight = 12;
  935.     }
  936.    
  937.     this.player = document.createElement('object'); // create new element!
  938.     $(this.player).attr('classid', 'java:com.fluendo.player.Cortado.class');
  939.     $(this.player).attr('style', 'display:block;width:' + this.width + 'px;height:' + useheight + 'px;');
  940.     $(this.player).attr('type', 'application/x-java-applet');
  941.     $(this.player).attr('archive', jar);
  942.     if (this.width)  $(this.player).attr('width', this.width);
  943.     if (this.height) $(this.player).attr('height', this.height);
  944.     var params = {
  945.         'code' : 'com.fluendo.player.Cortado.class',
  946.         'archive' : jar,
  947.         'url': url,
  948.          // 'local': 'false',
  949.         'duration': Math.round(this.duration),
  950.         'keepAspect': 'true',
  951.         'showStatus' : this.controls,
  952.         'video': usevideo,
  953.         'audio': 'true',
  954.         'seekable': 'auto',
  955.         'autoPlay': this.autoplay,
  956.         'bufferSize': '256',
  957.         'bufferHigh': '50',
  958.         'bufferLow': '5'
  959.     }
  960.     for (name in params) {
  961.         var p = document.createElement('param');
  962.         p.name = name;
  963.         p.value = params[name];
  964.         this.player.appendChild(p);
  965.     }
  966.     return this.player;
  967. }
  968.  
  969. CortadoPlayer.prototype.play = function() {
  970.     this.player.doPlay();
  971.     this.state = 'play';
  972. }
  973. CortadoPlayer.prototype.pause = function() {
  974.     this.player.doPause();
  975.     this.state = 'pause';
  976.     if (this.position() >= this.duration) {
  977.         this.state = 'ended';
  978.         $(this.div).trigger("oiplayerended", [this]);
  979.         try {
  980.             this.player.doStop();
  981.         } catch(err) { }
  982.     }
  983. }
  984. CortadoPlayer.prototype.mute = function() {
  985.     $.oiplayer.msg(this, "Sorry. Cortado currently does not support changing volume with Javascript.");
  986. }
  987. CortadoPlayer.prototype.position = function() {
  988.     if (this.state != 'init') {
  989.         this.pos = this.player.getPlayPosition();
  990.         return this.pos;
  991.     } else {
  992.         return 0;
  993.     }
  994. }
  995. CortadoPlayer.prototype.seek = function(pos) {
  996.     // doSeek(double pos); seek to a new position, must be between 0.0 and 1.0.
  997.     // impossible when duration is unknown (and not really smooth in cortado?)
  998.     // seems to be broke anyway (read similar in some MediaWiki cvs posts)
  999.     this.player.doSeek(pos / this.duration);
  1000. }
  1001. CortadoPlayer.prototype.info = function() {
  1002.     //return "Playing: " + this.url";
  1003. }
  1004.  
  1005. function MSCortadoPlayer() {
  1006.     this.myname = "msie_cortadoplayer";
  1007. }
  1008. MSCortadoPlayer.prototype = new CortadoPlayer();
  1009. MSCortadoPlayer.prototype.init = function(el, url, config) {
  1010.     this._init(el, url, config);
  1011.     /* msie (or windows java) can only load an applet from the root of a site, not a directory or context */
  1012.     var jar = config.server + config.jar;
  1013.     var usevideo = true;
  1014.     var useheight = this.height;
  1015.     if (this.type == 'audio') {
  1016.         usevideo = false;
  1017.         useheight = 12;
  1018.     }
  1019.     var element = document.createElement('div');
  1020.     var obj_html = '' +
  1021.     '<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" '+
  1022.     '  codebase="http://java.sun.com/update/1.5.0/jinstall-1_5_0-windows-i586.cab" '+
  1023.     //'  id="msie_cortadoplayer_' + id + '" '+
  1024.     '  id="msie_cortadoplayer_oiplayer"' +
  1025.     '  allowscriptaccess="always" width="' + this.width + '" height="' + useheight + '">'+
  1026.     ' <param name="code" value="com.fluendo.player.Cortado" />'+
  1027.     ' <param name="archive" value="' + jar + '" />'+
  1028.     ' <param name="url" value="' + this.url + '" /> '+
  1029.     ' <param name="duration" value="' + Math.round(this.duration) + '" /> '+
  1030.     ' <param name="local" value="true" /> ' +
  1031.     ' <param name="keepAspect" value="true" /> ' +
  1032.     ' <param name="video" value="' + usevideo + '" /> ' +
  1033.     ' <param name="audio" value="true" /> ' +
  1034.     ' <param name="seekable" value="auto" /> '+
  1035.     ' <param name="showStatus" value="' + this.controls + '" /> '+
  1036.     ' <param name="bufferSize" value="256" /> '+
  1037.     ' <param name="bufferHigh" value="50" /> '+
  1038.     ' <param name="bufferLow" value="5" /> '+
  1039.     ' <param name="autoPlay" value="' + this.autoplay + '" /> '+
  1040.     ' <strong>Your browser does not have a Java Plug-in. <a href="http://java.com/download">Get the latest Java Plug-in here</a>.</strong>' +
  1041.     '</object>';
  1042.     $(element).html(obj_html);
  1043.     this.player = element.firstChild;
  1044.     return this.player;
  1045. }
  1046.  
  1047. function FlowPlayer() {
  1048.     this.myname = "flowplayer";
  1049. }
  1050. FlowPlayer.prototype = new Player();
  1051. FlowPlayer.prototype.init = function(el, url, config) {
  1052.     this._init(el, url, config);
  1053.     var div = document.createElement('div');
  1054.     $(el).closest('div.oiplayer').html(div);
  1055.     $(div).addClass('player');
  1056.    
  1057.     return this.create(div, url, config);
  1058. }
  1059. FlowPlayer.prototype.create = function(el, url, config) {
  1060.     var flwplayer = config.server + config.flash;
  1061.     var duration = (this.duration == undefined ? 0 : Math.round(this.duration));
  1062.    
  1063.     this.player = $f(el, { src: flwplayer, width: this.width, height: this.height, wmode: 'opaque' }, {
  1064.         clip: {
  1065.             url: this.url,
  1066.             autoPlay: this.autoplay,
  1067.             duration: duration,
  1068.             scaling: 'fit',
  1069.             autoBuffering: true
  1070.             //bufferLength: 3
  1071.         },
  1072.         plugins: { controls: null }
  1073.     });
  1074.    
  1075.     if (config.controls) {
  1076.         var self = this;
  1077.         var clip = this.player.getCommonClip();
  1078.         this.player.onMute(function() {
  1079.             $(self.div).find('div.sound').addClass('muted');
  1080.         });
  1081.         this.player.onUnmute(function() {
  1082.             $(self.div).find('div.sound').removeClass('muted');
  1083.         });
  1084.         this.player.onLoad(function() {
  1085.             var checkDuration = null;
  1086.             clearInterval(checkDuration);
  1087.             checkDuration = setInterval(function() {
  1088.                 if (self.duration < 1) {
  1089.                     var fd = self.player.getCommonClip().fullDuration;
  1090.                     try {
  1091.                         var fd = self.player.getCommonClip().fullDuration;
  1092.                     } catch(err) { }
  1093.                     if (fd > 0) {
  1094.                         self.duration = fd;
  1095.                     }
  1096.                 } else {
  1097.                     clearInterval(checkDuration);
  1098.                     if (config.log == 'info') { $.oiplayer.msg(self, "set duration: " + self.duration); }
  1099.                     try {
  1100.                         var bufferStatus = self.player.getStatus().bufferEnd;
  1101.                         var perc = (bufferStatus / self.duration) * 100;
  1102.                         perc = perc + "%";
  1103.                         $(self.div).find('div.loaded').width(perc);
  1104.                     } catch(err) { }
  1105.                 }
  1106.             }, 500);
  1107.         });
  1108.         clip.onBufferFull(function() {  
  1109.             /* means enough buffer to play (not necessarily completely downloaded, fp has no means to track progress) */
  1110.             //$(self.div).find('div.loaded').width('100%');
  1111.         });
  1112.         clip.onStart(function() {
  1113.             /* Seems duration is not available until start: http://flowplayer.org/forum/3/18755
  1114.                With 'autoBuffering: true' clip starts automatically and pauses at first frame. */
  1115.             var fd = self.player.getClip().fullDuration;
  1116.             if (fd > 0) { self.duration = fd; }
  1117.             if (self.autoplay) {
  1118.                 $.oiplayer.follow(self);
  1119.                 $.oiplayer.hidepreview(self);
  1120.                 $(self.div).find('div.play').addClass('pause');
  1121.                 self.state = 'play';
  1122.             }
  1123.             if (self.fpstate == 'ended') {
  1124.                 $.oiplayer.start(self);
  1125.             }
  1126.         });
  1127.         clip.onPause(function() {
  1128.             $(self.div).find('div.play').removeClass('pause');
  1129.             self.state = 'pause';
  1130.         });
  1131.         clip.onResume(function() {
  1132.             $(self.div).find('div.play').addClass('pause');
  1133.             if (self.fpstate == undefined && self.duration > 0) {
  1134.                 $.oiplayer.start(self);
  1135.             }
  1136.             self.state = 'play';
  1137.         });
  1138.         clip.onFinish(function() {
  1139.             self.fpstate = 'ended';
  1140.             if (self.state != 'ended') {
  1141.                 self.state = 'ended';
  1142.                 $(self.div).trigger("oiplayerended", [self]);
  1143.             }
  1144.             $(self.div).find('div.play').removeClass('pause');
  1145.         });
  1146.     }
  1147.     return this.player;
  1148. }
  1149. FlowPlayer.prototype.play = function() {
  1150.     /* flowplayer states:
  1151.     -1  unloaded
  1152.     0   loaded
  1153.     1   unstarted
  1154.     2   buffering
  1155.     3   playing
  1156.     4   paused
  1157.     5   ended */
  1158.     if (this.player.getState() == 4) {
  1159.         this.player.resume();
  1160.     } else {
  1161.         this.player.play();
  1162.     }
  1163.     this.state = 'play';
  1164. }
  1165. FlowPlayer.prototype.pause = function() {
  1166.     if (this.player.getState() == 3) this.player.pause();
  1167.     this.state = 'pause';
  1168. }
  1169. FlowPlayer.prototype.mute = function() {
  1170.     if (this.player.getStatus().muted == true) {
  1171.         this.player.unmute();
  1172.     } else {
  1173.         this.player.mute();
  1174.     }
  1175. }
  1176. FlowPlayer.prototype.position = function() {
  1177.     this.pos = parseInt(this.player.getTime());
  1178.     return this.pos;
  1179. }
  1180. FlowPlayer.prototype.seek = function(pos) {
  1181.     pos = parseInt(pos);
  1182.     this.player.seek(pos);
  1183. }
  1184. FlowPlayer.prototype.info = function() {
  1185.     //return "Playing: " + this.url;
  1186. }
Advertisement
Add Comment
Please, Sign In to add comment