/*see play.js in same dir for source*/ /* Copyright(c)2008-2017 Internet Archive. Software license AGPL version 3. */ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Latest variant of video/audio-related playback // For /details/[IDENTIFIER] /* global jwplayer */ if (typeof jwplayer !== 'undefined' && jwplayer.version) { if (parseInt(jwplayer.version, 10) >= 7) jwplayer.key = 'ZV+cHpnETSSMPgD9dAAhnY6l+yhfV818mrpe4Q==';else if (parseInt(jwplayer.version, 10) >= 6) jwplayer.key = 'sZbikYlI/xtW0U/3Tw1DOdjC1EahhtUCJF5KggVdqDY='; } (function jquery_no_conflict($) { // NOTE "getState().toUpperCase()" for case change from jw6 (upper) to jw7 (lower) (see also jwv) // any methods or vars here are like private-to-outside globals and same for all "Play objects" var stash = {}; // global config, for all Play objects var ios = navigator.userAgent.indexOf('iPhone') > 0 || navigator.userAgent.indexOf('iPad') > 0 || navigator.userAgent.indexOf('iPod') > 0; // playing video size for normal /details/ pages var VIDEO_HEIGHT = 480; var VIDEO_WIDTH = 640; // (for 4:3 aspect -- scales for other aspects) var CONTROLS_HEIGHT = 30; var AUDIO_WIDTH = 350; var AUDIO_HEIGHT = CONTROLS_HEIGHT; var CONTROLS_MAX_WIDTH = 800; var IA_CLICK_WIDTH = 24; var PLAYLIST_ENTRY_HEIGHT = 20; var HEIGHT_ALIST = 370; // NOTE: max height; if few list entries, will be less var HEIGHT_VLIST = 100; // NOTE: max height; if few list entries, will be less var METADATA_HEIGHT = 100; // metadata peekaboo min height! (for "responsive") var Play = function () { // [playlist] should by an array, something like (ideally) one of: // [ {"file":"chapter1.mp4"}, {"file":"chapter2.mp4"}, .. ] // [ {"sources":[{"file":"video.mp4"},{"file":"video.ogv"},{..}]}, .. ] function Play(jid, playlist) { var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, _ref$start = _ref.start, start = _ref$start === undefined ? 0 : _ref$start, _ref$embed = _ref.embed, embed = _ref$embed === undefined ? false : _ref$embed, _ref$flash = _ref.flash, flash = _ref$flash === undefined ? false : _ref$flash, _ref$hide_list = _ref.hide_list, hide_list = _ref$hide_list === undefined ? false : _ref$hide_list, _ref$autoplay = _ref.autoplay, autoplay = _ref$autoplay === undefined ? false : _ref$autoplay, _ref$audio = _ref.audio, audio = _ref$audio === undefined ? false : _ref$audio, _ref$width = _ref.width, width = _ref$width === undefined ? 0 : _ref$width, _ref$height = _ref.height, height = _ref$height === undefined ? 0 : _ref$height, _ref$responsive = _ref.responsive, responsive = _ref$responsive === undefined ? false : _ref$responsive, _ref$aspectratio = _ref.aspectratio, aspectratio = _ref$aspectratio === undefined ? false : _ref$aspectratio, _ref$noshare = _ref.noshare, noshare = _ref$noshare === undefined ? false : _ref$noshare, _ref$nolinks = _ref.nolinks, nolinks = _ref$nolinks === undefined ? false : _ref$nolinks, _ref$logo = _ref.logo, logo = _ref$logo === undefined ? false : _ref$logo, _ref$so = _ref.so, so = _ref$so === undefined ? false : _ref$so, _ref$tv = _ref.tv, tv = _ref$tv === undefined ? false : _ref$tv, _ref$tvStart = _ref.tvStart, tvStart = _ref$tvStart === undefined ? 0 : _ref$tvStart, _ref$tvEnd = _ref.tvEnd, tvEnd = _ref$tvEnd === undefined ? 0 : _ref$tvEnd, _ref$tvContributor = _ref.tvContributor, tvContributor = _ref$tvContributor === undefined ? false : _ref$tvContributor, _ref$tvSource = _ref.tvSource, tvSource = _ref$tvSource === undefined ? false : _ref$tvSource, _ref$play_just = _ref.play_just1, play_just1 = _ref$play_just === undefined ? false : _ref$play_just, _ref$list_height = _ref.list_height, list_height = _ref$list_height === undefined ? 0 : _ref$list_height, _ref$skinC = _ref.skinC, skinC = _ref$skinC === undefined ? false : _ref$skinC, _ref$skinB = _ref.skinB, skinB = _ref$skinB === undefined ? false : _ref$skinB, _ref$identifier = _ref.identifier, identifier = _ref$identifier === undefined ? false : _ref$identifier, _ref$onTime = _ref.onTime, onTime = _ref$onTime === undefined ? false : _ref$onTime, _ref$onComplete = _ref.onComplete, onComplete = _ref$onComplete === undefined ? false : _ref$onComplete, _ref$onDisplayClick = _ref.onDisplayClick, onDisplayClick = _ref$onDisplayClick === undefined ? false : _ref$onDisplayClick, _ref$onReady = _ref.onReady, onReady = _ref$onReady === undefined ? false : _ref$onReady, _ref$collection = _ref.collection, collection = _ref$collection === undefined ? false : _ref$collection, _ref$waveformer = _ref.waveformer, waveformer = _ref$waveformer === undefined ? false : _ref$waveformer, _ref$speed = _ref.speed, speed = _ref$speed === undefined ? 1.0 : _ref$speed, _ref$details = _ref.details, details = _ref$details === undefined ? location.href : _ref$details; _classCallCheck(this, Play); // xxxx should wrap innards with try/catch // eslint-disable-next-line no-alert if (!jid) return alert('please pass in a unique identifier for this object'); if (typeof stash[jid] !== 'undefined') { if (typeof playlist === 'undefined') return stash[jid]; // return prior created object delete stash[jid]; // new jwplayer + playlist for prior jid } stash[jid] = this; // stash a pointer so that a repeat call to Play(jid) returns prior object // more (per instance) variables (cant be overridden/changed/seen by caller): var self = this; var tvTitle = tv && playlist.length === 1 ? playlist[0].title : ''; var list_2cols = responsive && audio; var jwv = parseInt(jwplayer.version, 10 // eg: 6 or 7 );var jidsel = '#' + jid; var jidlist = '#' + jid + '__list'; var readyIA = false; var DAR = 4 / 3; var flashAnamorphic = false; var first_seeked_playlist = false; var first_onmeta = false; var jwwidth = 0; var mousedover = false; var skin = 'six'; var waveformed = false; var buttons = false; var pause_first_seek = embed && !tv && !audio && !autoplay && start; var update_url_onload = true; var onCompleteStop = false; // playlists by default keep going to song B when song A is done // convenient, no? Stateless function, global to all Play objects // eslint-disable-next-line no-console var log = location.host.substr(0, 4) !== 'www-' ? function () {} : console.log.bind(console); // eslint-disable-next-line prefer-rest-params log('PLAY CONFIG:', arguments[2] // xxx v6.8 for /details/anamorphic has wrong width in flash mode! so squishface unlike v6.1 );self.adjustVideoWidth = function (player, onMetaSizingIn) { var onMetaSizing = onMetaSizingIn; if (player.getRenderingMode() === 'flash') { // reset in case anamorphic videos mixed in with non... flashAnamorphic = false; // jw v6.8 -- ensure list hasnt been filtered down (see "same_len" above) if (player.getPlaylist().length === playlist.length && player.height === onMetaSizing.height) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = playlist[player.geetPlaylistIndex()].sources[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var src = _step.value; // find correct playing element in "sources" (bec. we may be in SD/HD toggle state!) if (src.width > 0 && src.width !== onMetaSizing.width) { // think we have an anamorphic video on our hands! reset the width... // eg: /details/anamorphic log('playing #', 'file:', src.file, '(', src.width, 'x', src.height, ')'); log('likely anamorphic, since metadata.width==', onMetaSizing.width, ', overridding width'); flashAnamorphic = true; onMetaSizing.width = src.width; break; } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } } } if (onMetaSizing.height && onMetaSizing.width && onMetaSizing.height > 0 && onMetaSizing.width > 0 && parseInt(onMetaSizing.height, 10) > 0) { DAR = parseInt(onMetaSizing.width, 10) / parseInt(onMetaSizing.height, 10); log('DAR: ', DAR, onMetaSizing.width, 'x', onMetaSizing.height); } if (embed) self.embedResize(); }; self.embedResize = function () { if (!jwplayer || !jwplayer(jid)) return; if (audio) { jwplayer(jid).resize(Math.min(CONTROLS_MAX_WIDTH, $(window).width()) - IA_CLICK_WIDTH, AUDIO_HEIGHT); return; } // window max avail width and height for us var WW = $(window).width(); var WH = $(window).height() - list_height; if (!flashAnamorphic || DAR <= 0) { jwplayer(jid).resize(WW, WH); return; } // First see if we fit inside with max height of avail window var h2 = $(window).height(); var w2 = Math.round(h2 * DAR); if (w2 > WW) { log('FLASH! too big..'); w2 = $(window).width(); h2 = Math.round(w2 / DAR); } log('FLASH! Resize to: ', w2, 'x', h2); jwplayer(jid).resize(w2, h2); $(jidsel).parent().css({ margin: 'auto' } // re-center ); }; self.playN = function (idx, onPLI) { var $rows = $(jidlist).find('.jwrow, .jwrowV2'); $rows.removeClass('playing'); if (!readyIA) return false; $($rows.get(idx)).addClass('playing'); if (!onPLI) jwplayer(jid).playlistItem(idx); return false; }; // xxx suck, ubuntu new firefox re-seeks to start w/o double doing this, etc.... self.seeker_playlist = function () { if (first_seeked_playlist) return; first_seeked_playlist = true; if (pause_first_seek) { // oh cry/facepalm... // /embed/ia20thanniversaryevent?start=2150 // is now NOT wanted to autoplay ( unless _also_ has ""&autoplay=1" ) jwplayer(jid).onPlay(function () { if (!pause_first_seek) return; log('onPlay()'); pause_first_seek = false; self.pause(); log('... paused first seek!'); }); } if (!start) return; // NOTE: special since phantomJS testing looks for this logging in production // eslint-disable-next-line no-console if (typeof console !== 'undefined' && console.log) // eslint-disable-next-line no-console console.log('seeker_playlist() to ', start, pause_first_seek ? ' NOSTART' : ' AUTOSTART'); self.pause(); jwplayer(jid).seek(start); }; self.embed_setup = function () { $(window).on('resize orientationchange', function () { // Bind window resize to resize the player clearTimeout(Play.throttler2); Play.throttler2 = setTimeout(function () { // resize/orient flip -- resize and reflow elements new Play(jid).embedResize(); }, 250); }); }; self.details_setup = function () { var startPlaylistIdx = 0; var re = '^/details/' + identifier + '/([^&?]+)'; var mat = location.pathname.match(re); if (mat) { var file = decodeURIComponent(mat[1].replace(/\+/g, '%20')); log('looking for: ', file // log(playlist) // eslint-disable-next-line guard-for-in );for (var ii in playlist) { var idx = Number(ii // convert from string! );if (playlist[idx].orig === file) { log('player should seek to track #', idx); startPlaylistIdx = idx; break; } } } if (!startPlaylistIdx && !start && !autoplay) update_url_onload = false; if (!start && !autoplay && !tv && startPlaylistIdx) pause_first_seek = true; if (!autoplay && (startPlaylistIdx || start)) { log('seek #', startPlaylistIdx, ' to ', start); var jw = jwplayer(jid); jw.playlistItem(startPlaylistIdx); } }; self.pause = function () { var jw = jwplayer(jid); if (readyIA && jw && jw.getState && jw.getState().toUpperCase() === 'PLAYING') jw.pause(); }; self.remove = function () { self.pause(); var jw = jwplayer(jid); if (readyIA && jw && (jwv === 7 ? jw.getConfig() : jw.config)) jw.remove(); delete stash[jid]; }; self.speed = function (valIn) { var val = valIn; if (typeof valIn === 'undefined') { var rate = $('#' + jid + ' video').get(0).playbackRate; if (rate <= 0.5) val = 1.0;else if (rate >= 3.0) val = 0.5;else val = rate + 1.0; } var vid = $('#' + jid + ' video').get(0); vid.playbackRate = val; log('speed to ' + val); return false; }; self.addClickablePlaylist = function () { if (hide_list) return; // nothing to do! var jwlist = jwplayer(jid).getPlaylist(); var same_len = true; if (jwlist.length !== playlist.length) { log('NOTE: jw playlist filtered down -- ', playlist.length, '==>', jwlist.length, ' items'); same_len = false; } var ialist = ''; var ialistC1 = ''; var ialistC2 = ''; $.each(jwlist, function (idx, val) { var ttl = typeof val.title === 'undefined' ? '' : val.title.replace(/^\d+\. /, ''); // xxx "1. Camaro" ==> "Camaro"" // In v6.8 flash mode (only), duration no longer is passed back via "getPlaylist()" 8-( // so try the original list sent to jwplayer config if we can... var duration = typeof val.duration !== 'undefined' ? val.duration : false; if (duration === false) { duration = same_len && typeof playlist[idx] !== 'undefined' && typeof playlist[idx].duration !== 'undefined' ? playlist[idx].duration : 0; } if (duration <= 0) duration = false; if (list_2cols) { var str = '\n\n
\n ' + (idx + 1) + '\n \n ' + ttl + '\n \n -\n \n ' + (duration ? Play.sec2hms(duration) : '') + '\n \n
\n
'; if (idx < playlist.length / 2) ialistC1 += str;else ialistC2 += str; } else { ialist += '\n\n
\n
\n ' + (duration ? Play.sec2hms(duration) : '') + '\n
\n
\n ' + (idx + 1) + '\n
\n
\n ' + ttl + '\n
\n
\n
'; } }); if (list_2cols) { ialist = '
\n
\n ' + ialistC1 + '\n
\n
\n ' + ialistC2 + '\n
\n
'; } var css = {}; if (responsive) { css.width = width; css.margin = 'auto'; if (audio && skin !== 'five' && skin !== 'bekle') { // stay as wide as the player is... which has a max-width in this skin... css['max-width'] = CONTROLS_MAX_WIDTH; } if (!audio) $(jidsel).css('margin', 'auto'); } $(jidlist).addClass(list_2cols ? 'jwlistV2' : 'jwlist').css(css).html(ialist); log(playlist // log(JSON.stringify(playlist,undefined,2)) ); }; self.debug = function () { // eslint-disable-next-line no-debugger debugger; }; /* eslint-disable no-param-reassign */ // ^^^ this class was designed _deliberately_ using scoping techniques _outside_ of the // methods to allow them to be set/manipulated _per instance_ but auto binding closure // around each instance/object -- so from here for awhile, disabling that eslint rule... self.responsiveResize = function (first) { if (!responsive) return; var playoff = $(jidsel).offset(); var maxH = $(window).height() - playoff.top - METADATA_HEIGHT; if (audio) { if (playlist && playlist.length > 0 && playlist[0].image) AUDIO_HEIGHT = 140; // (typically png is 800x140 now) // OK, so we will be using "maxH" for the **playlist**. // Reduce by player/waveform height now... // but make sure at least ~8 rows (or 4 if oldtimeradio item ;-) always show // (eg: insanely short browser??) maxH -= AUDIO_HEIGHT; maxH = Math.max(240, maxH); if (!embed) { log('responsiveResize() maxH:', maxH); list_height = maxH; log($(jidlist).length); $(jidlist).css({ 'max-height': maxH, 'overflow-x': 'hidden', 'overflow-y': 'auto' }); } width = '100%'; $('#theatre-controls .fave-share').removeClass('fave-share'); $('#theatre-controls').offset({ top: playoff.top }).css({ visibility: 'visible', 'background-color': 'black' }); } else { var aspect = DAR; if (playlist && playlist.length > 0 && playlist[0].sources && playlist[0].sources.length > 0 && playlist[0].sources[0].width && playlist[0].sources[0].height) { aspect = playlist[0].sources[0].width / playlist[0].sources[0].height; log('aspect ratio appears to be: ', aspect); } var maxW = $('.container-ia:last').width(); log('video max rect avail: ', maxW, 'x', maxH); var vidW = void 0; var vidH = void 0; var _arr = [960, 840, 720, 600, 480, 360, 240, 180]; for (var _i = 0; _i < _arr.length; _i++) { vidH = _arr[_i]; vidW = Math.round(vidH * aspect); log('video size try fit: ', vidW, 'x', vidH); if (vidW <= maxW && vidH <= maxH || vidW <= 320) break; } width = vidW; // '100%' height = vidH; if (typeof AJS !== 'undefined') // eslint-disable-next-line no-undef AJS.theatre_controls_position(false, 0, width, height); } if (first) { // we havent setup the player yet, but want to setup a watcher // for browser resize or mobile orientation changing $(window).on('resize orientationchange', function () { clearTimeout(Play.throttler); Play.throttler = setTimeout(function () { // resize/orient flip -- resize and reflow elements new Play(jid).responsiveResize(); }, 250); }); } else if (!audio) { jwplayer(jid).resize(width, height); } }; // ---------- START OBJECT CONSTRUCTOR -------- if (nolinks) { identifier = false; collection = false; noshare = true; } speed = parseFloat(speed); if (typeof $.cookie !== 'undefined' && $.cookie('avspeed')) speed = parseFloat($.cookie('avspeed')); if (!$(jidsel).length) { log('play.js requires #', jid, ' element on page -- not found'); return false; } self.responsiveResize(true); if (identifier !== false) details = 'https://archive.org/details/' + identifier; if (tv && tvEnd) details += '/start/' + tvStart + '/end/' + tvEnd; if (typeof playlist === 'undefined') { playlist = [{ sources: [{ file: '/download/family-rolled/family-rolled.mp4' }, { file: '/download/family-rolled/family-rolled.ogv' }], image: '/download/family-rolled/format=Thumbnail&ignore=x.jpg' }]; start = true; hide_list = true; } if (!hide_list) { if (!list_height) // if user hasn't specified... list_height = audio ? HEIGHT_ALIST : HEIGHT_VLIST; // now drop down list_height if there aren't many playlist elements... list_height = Math.min(list_height, playlist.length * PLAYLIST_ENTRY_HEIGHT); } if (!responsive && !(width > 0 && height > 0)) { if (embed) { var winw = $(window).width(); var winh = $(window).height(); width = audio ? Math.min(winw, CONTROLS_MAX_WIDTH) : winw; height = audio ? AUDIO_HEIGHT + list_height : winh - list_height; } else if (!aspectratio) { width = audio ? AUDIO_WIDTH : VIDEO_WIDTH; height = audio ? AUDIO_HEIGHT + list_height : VIDEO_HEIGHT; } } jwwidth = audio ? width - IA_CLICK_WIDTH : width; if (audio && embed && identifier !== false) { var audiorow = '\n
\n
\n \n \n \n
\n
'; $(audiorow).insertBefore(jidsel); $('#ia' + jid + ' a').tooltip({}); } $.each(playlist, function (idx, val) { // log(val.sources) if (typeof val.autoplay !== 'undefined') { // for playlist: A B C D; if C has autoplay=false // it means play A and (auto)play B -- but stop when B is done if (!onCompleteStop) onCompleteStop = []; onCompleteStop[idx - 1] = !val.autoplay; } if (typeof val.sources === 'undefined') { if (typeof val.file !== 'undefined') val.sources = [{ file: val.file, height: 480 }]; } if (typeof val.sources === 'undefined') { // eslint-disable-next-line no-alert alert(idx + ': sources undefined!' // xxx ); } // log(val.sources) }); if (!hide_list) { var sty = list_2cols ? '' : 'style="height:' + list_height + 'px"'; var ialist = '
'; $(ialist).insertAfter(jidsel); } if (tvTitle) { // remove the end time (for brevity) for the "click to play" center button playlist[0].title = playlist[0].title.replace(/( \d+:\d+[amp]+)-\d+:\d+[amp]+ /, '$1 '); } if (jwv === 7 && playlist[0].image) playlist[0].image = playlist[0].image.replace(/%2F/g, '/' // for jwplayer v7+ );var jwcfg = { // *could* consider this if we think jwplayer playlists are reasonble in v6.8 now.... // "listbar":{layout:'basic',position:'bottom',size:list_height}, playlist: JSON.parse(JSON.stringify(playlist)), // deep copy; jw v6.8 _changes_ our list! analytics: { enabled: false, cookies: false }, // dont track our users xxx abouttext: 'this item, formats, and more at Internet Archive', aboutlink: details, startparam: 'start', logo: {}, sharing: {}, autostart: autoplay, // || (start && !ios) ? true : false), fallback: so, width: isNaN(jwwidth) ? '100%' : jwwidth, height: audio ? 30 : height // + list_height // *could* consider this if we think jw playlists are reasonble in v6.8 now // alert(width+' x '+height+'/'+list_height) };if (responsive && !embed) { jwcfg.displaytitle = false; // dont show title of 1st track next to big PLAY button } else if (aspectratio) { jwcfg.width = '100%'; jwcfg.aspectratio = aspectratio; delete jwcfg.height; } if (responsive && audio && !embed) { jwcfg.displaytitle = false; // dont show title of 1st track next to big PLAY button skin = 'bekle'; // allow user (for now) to pick 1 of 8 skins (six.xml is builtin default) var skinarg = location.search.match(/\?skin=(\d+)/); if (skinarg && skinarg.length) { var skins = ['beelden', 'bekle', 'five', 'glow', 'roundster', 'stormtrooper', 'vapor']; skin = skins[skinarg[1] % skins.length]; } if (skin === 'bekle') jwcfg.skin = '/jw/6.8/bekleA.xml';else jwcfg.skin = '/jw/6.8/skins/' + skin + '.xml'; log('TRYING SKIN: ', jwcfg.skin); if (skin === 'five' || skin === 'bekle') jwcfg.stretching = 'exactFit'; } if (identifier !== false) { var startend = tv && tvEnd ? '?start=' + tvStart + '&end=' + tvEnd : ''; // xxx check if multiple identifiers: // xxx *SHOULD* be able to just encode "embedcode" like iatest.js does, WTF?!?!! var embedcode = ('').replace(/embed\/MEDIAID/, 'embed/' + identifier + startend).replace(/\s+/g, ' '); var embedcodeWP = '[archiveorg ' + identifier + startend + ' width=640 height=' + (audio ? AUDIO_HEIGHT : VIDEO_HEIGHT) + ' frameborder=0 webkitallowfullscreen=true mozallowfullscreen=true]'; jwcfg.mediaid = identifier; if (!noshare && !audio) jwcfg.sharing.code = encodeURI(embedcode); if (audio) jwcfg.embedcode = embedcode; // (IA extension used by play.js) // IFF these exist, fill them in! $('#embedcodehere').text(embedcode); $('#embedcodehereWP').text(embedcodeWP); } if (!noshare && !audio) { // xxx check if multiple identifiers.... // xxx _SHOULD_ be able to just use "jwplayer().getConfig().sharing.code" (iatest.js) WTF?! jwcfg.sharing.link = details; } if (jwv !== 7 && responsive && !embed || typeof jwcfg.sharing.link === 'undefined' && typeof jwcfg.sharing.code === 'undefined') delete jwcfg.sharing; if (jwcfg.sharing) { buttons = true; if (jwv === 7) jwcfg.sharing.sites = ['facebook', 'twitter', 'pinterest', 'tumblr', 'reddit', 'googleplus', 'email']; } if (!audio && collection && !tv) jwcfg.related = { file: '/services/collection-rss.php?collection=' + collection }; if (ios && audio) jwcfg.mobilecontrols = true; // turn of iOS native controls and go w/ JW controls xxx if (flash) jwcfg.primary = 'flash'; if (skinB) jwcfg.skin = '/jw/6.8/bekleB.xml'; if (skinC) jwcfg.skin = '/jw/6.8/bekleC.xml'; if (embed && !audio && !nolinks || logo) { jwcfg.logo = { file: '//archive.org/jw/6.8/glogo-ghost.png', link: details, position: 'bottom-right', margin: 2, hide: false }; } if (!audio && !embed) { // later, if playing in flash mode *and* we determine the video is anamorphic, // we need to set this now so we stretch "disproportionally" to our correctly figured W/H. // Would *prefer* to only set if we detect flash and anamorphic, but we can't apply this // flash setting later in v6.8 anymore... // // jwcfg.stretching = "exactFit" // bleah Jan12,2014 -- cant do this w/o breaking *all* // fullscreen !16x9 videos on 16x9 monitors... reverting to anamorphic video is wrong aspect // when in flash mode (jw bug -- no workaround now) } if (play_just1 || onCompleteStop) { var onCompleteOrig = onComplete; onComplete = function onComplete(jw) { var evt = { done: play_just1 || onCompleteStop[jw.getPlaylistIndex()] }; if (evt.done) jw.stop // dont wanna auto-advance to next track in playlist ();if (onCompleteOrig) onCompleteOrig(jw, evt); }; } // this class was designed _deliberately_ using scoping techniques _outside_ of the // methods to allow them to be set/manipulated _per instance_ but auto binding closure // vvv around each instance/object -- we can now re-enable that eslint rule... /* eslint-enable no-param-reassign */ log(jwcfg); jwplayer(jid).setup(jwcfg); jwplayer(jid).onReady(function () { log('IA ', jid, ' is ready'); var player = jwplayer(jid // xxx revisit since arrow fn update made "this"!==player );log('NOTE: JW version: ', jwplayer.version, 'Rendering mode:', player.getRenderingMode()); if (onTime) log('NOTE: onTime() is in use!'); if (onTime) player.onTime(function () { return onTime(player); }); if (onComplete) player.onComplete(function () { return onComplete(player); }); if (onDisplayClick) player.onDisplayClick(function () { return onDisplayClick(player); }); readyIA = true; // NOTE: we now do this here because jwplayer can shrink down the passed in playlist on us! self.addClickablePlaylist(); if (audio && responsive && !embed) self.responsiveResize(); if (onReady) onReady(player // trap for SPACE key press to toggle pause/play );$(jidsel).parent().mouseover(function () { mousedover = true; }); $(jidsel).parent().mouseout(function () { mousedover = false; }); $(document).keyup(function (e) { if (e.keyCode === 32 && mousedover) { player.pause(); e.preventDefault(); e.stopPropagation(); return false; } return true; }); if (responsive && !audio) $(jidsel).css('margin', 'auto'); var flashy = player.getRenderingMode() === 'flash'; if (audio) { $(jidsel).css('min-height', AUDIO_HEIGHT // bug IMHO in jwplayer -- for all mobile sets to 200!! );if (responsive) { if (AUDIO_HEIGHT > CONTROLS_HEIGHT) { if (flashy) { // bug in jwplayer -- flash height set right, but parent/container wrong! $(jidsel + '_wrapper').height(AUDIO_HEIGHT); } else { // xxx force controlbar to always show when using waveforms! $(jidsel + ' .jwcontrolbar').show().fadeTo(0, 1); player.resize(player.getWidth(), player.getHeight()); } } } else if (flashy) { $(jidsel).parent().parent().find('.iajw,.iajwBG').css('visibility', 'visible'); } else { $(jidsel).parent().find('.iajw,.iajwBG').css('visibility', 'visible'); } } else { if (embed && !nolinks) { var butid = 'btn1'; var ttl = tvTitle ? tvTitle.replace(/ : /g, '\n') + '\n\nClick above for more information and clips\nat the Internet Archive' : 'More Formats from Internet Archive'; player.addButton('/images/glogo20x20.png', ttl, function () { window.top.location.href = details; }, butid); if (tv) { if (tvSource !== false) { player.addButton('/images/tv/' + identifier.split('_')[0] + '.png', 'Look for this show on ' + tvContributor + ' website', function () { window.top.location.href = tvSource; }, 'btn2'); buttons = true; } // fix for newlines in html5 mode (only text not HTM newlines work in flash): $(jidsel + '_dock_' + butid + '_tooltip .jwcontents').css('white-space', 'pre-wrap'); } } if (embed && !noshare && !tv && identifier !== false) { player.addButton('/jw/6.8/embed.png', 'Embedding Examples and Help', function () { window.top.location.href = '/help/video.php?identifier=' + identifier; }, 'btn2'); buttons = true; } } if (!responsive && !audio && !embed && typeof $.cookie !== 'undefined') { var hover = flashy ? 'Click to have player try HTML5 first, then flash' : 'Click to have player try flash first, then HTML5'; player.addButton('/jw/6.8/flash.png', hover, function () { if (flashy) $.cookie('avpref2', null, { path: '/' });else $.cookie('avpref2', 'flash', { path: '/' } // reload the page );window.top.location.href = location.href; window.top.location.reload(true); }, 'btn3'); buttons = true; } if (!embed && !flashy && !buttons) $('body').addClass('jw_nodock'); if (responsive && !embed && !audio && typeof AJS !== 'undefined') // eslint-disable-next-line no-undef AJS.theatre_controls_position(false, 0, width, height); if (!embed && responsive) self.details_setup();else if (embed && location.host.match(/archive\.org$/) && location.pathname.match(/^\/embed\//)) self.embed_setup(); }).onMeta(function play_onMeta(obj) { // only call all this once, because sometime between Feb and May 2014, // firefox+flash start sending onMeta() *very* frequently, not just once, // and we need to only "first seek" once, especially! if (!first_onmeta) { first_onmeta = true; log('onMeta() fired'); $('body').addClass('responsive-playing'); if (!audio && embed && obj.width && obj.height) self.adjustVideoWidth(this, obj // xxx suck, ubuntu new firefox re-seeks to start w/o double doing this, etc.... );if (start) { log('SEEK TO: ', start); self.pause(); jwplayer(jid).seek(start); } } }).onPlaylistItem(function (obj) { log('onPlaylistItem: ', obj.index); var player = jwplayer(jid // xxx revisit since arrow fn update made "this"!==player );self.playN(obj.index, true); self.seeker_playlist // NOTE: if we decide to do this for video, we WONT do it for TV.. ();if (audio && !tv && !embed && identifier && typeof history.replaceState !== 'undefined' && player.config && player.config.playlist && player.config.playlist.length > 1 && player.config.playlist[obj.index] && player.config.playlist[obj.index].orig) { if (update_url_onload) { var url = '/details/' + identifier + '/' + encodeURIComponent(player.config.playlist[obj.index].orig).replace(/%2F/g, '/').replace(/%20/g, '+'); // eslint-disable-next-line no-undef var playset = typeof AJS !== 'undefined' && AJS.arg('playset', 1) ? '&playset=1&autoplay=1' : ''; history.replaceState({}, null, url + playset); } else { log('looks like /details/ page loaded cold-state -- leave url AS IS'); update_url_onload = true; } } if (speed !== 1.0) setTimeout(function () { self.speed(speed); }, 1000); if (waveformer && !waveformed) { var flashy = player.getRenderingMode() === 'flash'; var $wrapme = $(jidsel); if (flashy) $wrapme = $wrapme.parent(); $wrapme.wrap('
'); var jWD = $('#' + waveformer).width // xxxx deal w/ browser resize and orientation changes ();var jHT = $wrapme.height(); $('#' + waveformer).prepend('
'); player.onTime(function (evt) { if (!evt.duration) return; $('#waveformer').css({ width: Math.round(jWD * (evt.position / evt.duration)) }); }); waveformed = true; setTimeout(function () { if (!flashy) $(jidsel).css('background-color', 'transparent'); $('#' + waveformer).css('background-color', '#ddd'); }, 1000); } }).onError(function (obj) { log('err'); log(obj); $(jidsel).css({ 'background-color': 'black' } // throw "onError event" ); }); setTimeout(function () { var $e = false; if (!jwplayer || !jwplayer(jid) || typeof jwplayer(jid).getRenderingMode === 'undefined') { if (so) { $e = $('
').attr({ class: 'text-danger', style: 'text-align:center;background-color:white' }).html('Looks like you cannot play our media.
You may have a better experience with a newer browser like Firefox or install/update Flash'); } else { $e = $('
').attr({ class: 'text-danger', style: 'text-align:center;background-color:white' }).html('Guessing you cannot play our media?
\n Your browser may be too old to play html5 video tags *and* does not have the flash\n plugin, is disabled, or is a very old version of flash?
\n Get current Flash version'); } if (embed) $e.insertBefore($(jidsel));else $e.insertAfter($(jidsel)); } }, 15000 // 15 seconds );return this; } // END OF OBJECT CONSTRUCTOR // From here on down, these methods are "class"/static and not "instance" methods // returns number of seconds (may be float) as string "hh:mm:ss" // note will omit "hh:" if 0 (unless pass in truthy alwaysHH) // Stateless function, global to all Play objects _createClass(Play, null, [{ key: 'sec2hms', value: function sec2hms(secIn, alwaysHH) { var sec = Math.round(secIn); var hr = Math.floor(sec / 3600); var min = Math.floor((sec - hr * 3600) / 60); sec -= hr * 3600 + min * 60; // left 0-pad to 2 digits as needed var hms = ''; var tmp = ''; if (alwaysHH || hr > 0) { tmp = '00' + hr; hms += tmp.substr(tmp.length - 2, 2); hms += ':'; } tmp = '00' + min; hms += tmp.substr(tmp.length - 2, 2); hms += ':'; tmp = '00' + sec; hms += tmp.substr(tmp.length - 2, 2); return hms; } // [nicked from jwplayer JS v6 code] // Converts a time-representing string to a number. // @param {String} The input string. Supported are 00:03:00.1 / 03:00.1 / 180.1s / 3.2m / 3.2h // @return {Number} The number of seconds. }, { key: 'seconds', value: function seconds(strIn) { var str = strIn.replace(',', '.'); var arr = str.split(':'); var sec = 0; if (str.substr(-1) === 's') { sec = Number(str.substr(0, str.length - 1)); } else if (str.substr(-1) === 'm') { sec = Number(str.substr(0, str.length - 1)) * 60; } else if (str.substr(-1) === 'h') { sec = Number(str.substr(0, str.length - 1)) * 3600; } else if (arr.length > 1) { sec = Number(arr[arr.length - 1]); sec += Number(arr[arr.length - 2]) * 60; if (arr.length === 3) sec += Number(arr[arr.length - 3]) * 3600; } else { sec = Number(str); } return sec; } }, { key: 'seek', value: function seek(link) { var mat = (link.href + '/').match(/[/#]start\/([\d.]+)\//) || link.href.match(/[?&]start=([\d.]+)/); if (!mat) return true; var startsec = mat[1]; jwplayer().seek(startsec // if we have a relatively modern browser, simply update the browser url );if (typeof history.pushState === 'undefined') location.href = link.href; // older browwser -- full page refresh else history.pushState({}, null, link.href // newer! );return false; } /* static except(e){ // report back home an exception was thrown! const img = new Image(1,1) img.src = "http://analytics.archive.org/e.gif" + "?a="+ encodeURIComponent(navigator.userAgent) + '&e='+ encodeURIComponent(e.toString()) + (e.stack && typeof(e.stack)=='string' ? '&s='+ encodeURIComponent(e.stack) : '') } */ }]); return Play; }(); // end class Play /* // trap for ESCAPE key pressed to close a popup $(document).keydown(function(e) { if (e.keyCode==27) $('#jpop').remove() }) */ // allow "Play(.., ..)" globally: window.Play = function (id, playlist, options) { return new Play(id, playlist, options); }; // only these (static) methods are available globally, eg: Play.seek(..) var _arr2 = ['sec2hms', 'seconds', 'seek']; for (var _i2 = 0; _i2 < _arr2.length; _i2++) { var meth = _arr2[_i2]; window.Play[meth] = Play[meth]; } })(jQuery);