index.js 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747
  1. /* global window document */
  2. /* eslint-disable vars-on-top, no-var, object-shorthand, no-console */
  3. (function(window) {
  4. var representationsEl = document.getElementById('representations');
  5. representationsEl.addEventListener('change', function() {
  6. var selectedIndex = representationsEl.selectedIndex;
  7. if (!selectedIndex || selectedIndex < 1 || !window.vhs) {
  8. return;
  9. }
  10. var selectedOption = representationsEl.options[representationsEl.selectedIndex];
  11. if (!selectedOption) {
  12. return;
  13. }
  14. var id = selectedOption.value;
  15. window.vhs.representations().forEach(function(rep) {
  16. rep.playlist.disabled = rep.id !== id;
  17. });
  18. window.pc.fastQualityChange_();
  19. });
  20. var isManifestObjectType = function(url) {
  21. return (/application\/vnd\.videojs\.vhs\+json/).test(url);
  22. };
  23. var hlsOptGroup = document.querySelector('[label="hls"]');
  24. var dashOptGroup = document.querySelector('[label="dash"]');
  25. var drmOptGroup = document.querySelector('[label="drm"]');
  26. var liveOptGroup = document.querySelector('[label="live"]');
  27. var llliveOptGroup = document.querySelector('[label="low latency live"]');
  28. var manifestOptGroup = document.querySelector('[label="json manifest object"]');
  29. var sourceList;
  30. var hlsDataManifest;
  31. var dashDataManifest;
  32. var addSourcesToDom = function() {
  33. if (!sourceList || !hlsDataManifest || !dashDataManifest) {
  34. return;
  35. }
  36. sourceList.forEach(function(source) {
  37. var option = document.createElement('option');
  38. option.innerText = source.name;
  39. option.value = source.uri;
  40. if (source.keySystems) {
  41. option.setAttribute('data-key-systems', JSON.stringify(source.keySystems, null, 2));
  42. }
  43. if (source.mimetype) {
  44. option.setAttribute('data-mimetype', source.mimetype);
  45. }
  46. if (source.features.indexOf('low-latency') !== -1) {
  47. llliveOptGroup.appendChild(option);
  48. } else if (source.features.indexOf('live') !== -1) {
  49. liveOptGroup.appendChild(option);
  50. } else if (source.keySystems) {
  51. drmOptGroup.appendChild(option);
  52. } else if (source.mimetype === 'application/x-mpegurl') {
  53. hlsOptGroup.appendChild(option);
  54. } else if (source.mimetype === 'application/dash+xml') {
  55. dashOptGroup.appendChild(option);
  56. }
  57. });
  58. var hlsOption = document.createElement('option');
  59. var dashOption = document.createElement('option');
  60. dashOption.innerText = 'Dash Manifest Object Test, does not survive page reload';
  61. dashOption.value = `data:application/vnd.videojs.vhs+json,${dashDataManifest}`;
  62. hlsOption.innerText = 'HLS Manifest Object Test, does not survive page reload';
  63. hlsOption.value = `data:application/vnd.videojs.vhs+json,${hlsDataManifest}`;
  64. manifestOptGroup.appendChild(hlsOption);
  65. manifestOptGroup.appendChild(dashOption);
  66. };
  67. var sourcesXhr = new window.XMLHttpRequest();
  68. sourcesXhr.addEventListener('load', function() {
  69. sourceList = JSON.parse(sourcesXhr.responseText);
  70. addSourcesToDom();
  71. });
  72. sourcesXhr.open('GET', './scripts/sources.json');
  73. sourcesXhr.send();
  74. var hlsManifestXhr = new window.XMLHttpRequest();
  75. hlsManifestXhr.addEventListener('load', function() {
  76. hlsDataManifest = hlsManifestXhr.responseText;
  77. addSourcesToDom();
  78. });
  79. hlsManifestXhr.open('GET', './scripts/hls-manifest-object.json');
  80. hlsManifestXhr.send();
  81. var dashManifestXhr = new window.XMLHttpRequest();
  82. dashManifestXhr.addEventListener('load', function() {
  83. dashDataManifest = dashManifestXhr.responseText;
  84. addSourcesToDom();
  85. });
  86. dashManifestXhr.open('GET', './scripts/dash-manifest-object.json');
  87. dashManifestXhr.send();
  88. // all relevant elements
  89. var urlButton = document.getElementById('load-url');
  90. var sources = document.getElementById('load-source');
  91. var stateEls = {};
  92. var getInputValue = function(el) {
  93. if (el.type === 'url' || el.type === 'text' || el.nodeName.toLowerCase() === 'textarea') {
  94. if (isManifestObjectType(el.value)) {
  95. return '';
  96. }
  97. return encodeURIComponent(el.value);
  98. } else if (el.type === 'select-one') {
  99. return el.options[el.selectedIndex].value;
  100. } else if (el.type === 'checkbox') {
  101. return el.checked;
  102. }
  103. console.warn('unhandled input type ' + el.type);
  104. return '';
  105. };
  106. var setInputValue = function(el, value) {
  107. if (el.type === 'url' || el.type === 'text' || el.nodeName.toLowerCase() === 'textarea') {
  108. el.value = decodeURIComponent(value);
  109. } else if (el.type === 'select-one') {
  110. for (var i = 0; i < el.options.length; i++) {
  111. if (el.options[i].value === value) {
  112. el.options[i].selected = true;
  113. }
  114. }
  115. } else {
  116. // get the `value` into a Boolean.
  117. el.checked = JSON.parse(value);
  118. }
  119. };
  120. var newEvent = function(name) {
  121. var event;
  122. if (typeof window.Event === 'function') {
  123. event = new window.Event(name);
  124. } else {
  125. event = document.createEvent('Event');
  126. event.initEvent(name, true, true);
  127. }
  128. return event;
  129. };
  130. // taken from video.js
  131. var getFileExtension = function(path) {
  132. var splitPathRe;
  133. var pathParts;
  134. if (typeof path === 'string') {
  135. splitPathRe = /^(\/?)([\s\S]*?)((?:\.{1,2}|[^\/]*?)(\.([^\.\/\?]+)))(?:[\/]*|[\?].*)$/i;
  136. pathParts = splitPathRe.exec(path);
  137. if (pathParts) {
  138. return pathParts.pop().toLowerCase();
  139. }
  140. }
  141. return '';
  142. };
  143. var saveState = function() {
  144. var query = '';
  145. if (!window.history.replaceState) {
  146. return;
  147. }
  148. Object.keys(stateEls).forEach(function(elName) {
  149. var symbol = query.length ? '&' : '?';
  150. query += symbol + elName + '=' + getInputValue(stateEls[elName]);
  151. });
  152. window.history.replaceState({}, 'vhs demo', query);
  153. };
  154. window.URLSearchParams = window.URLSearchParams || function(locationSearch) {
  155. this.get = function(name) {
  156. var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(locationSearch);
  157. return results ? decodeURIComponent(results[1]) : null;
  158. };
  159. };
  160. // eslint-disable-next-line
  161. var loadState = function() {
  162. var params = new window.URLSearchParams(window.location.search);
  163. return Object.keys(stateEls).reduce(function(acc, elName) {
  164. acc[elName] = typeof params.get(elName) !== 'object' ? params.get(elName) : getInputValue(stateEls[elName]);
  165. return acc;
  166. }, {});
  167. };
  168. // eslint-disable-next-line
  169. var reloadScripts = function(urls, cb) {
  170. var el = document.getElementById('reload-scripts');
  171. if (!el) {
  172. el = document.createElement('div');
  173. el.id = 'reload-scripts';
  174. document.body.appendChild(el);
  175. }
  176. while (el.firstChild) {
  177. el.removeChild(el.firstChild);
  178. }
  179. var loaded = [];
  180. var checkDone = function() {
  181. if (loaded.length === urls.length) {
  182. cb();
  183. }
  184. };
  185. urls.forEach(function(url) {
  186. var script = document.createElement('script');
  187. // scripts marked as defer will be loaded asynchronously but will be executed in the order they are in the DOM
  188. script.defer = true;
  189. // dynamically created scripts are async by default unless otherwise specified
  190. // async scripts are loaded asynchronously but also executed as soon as they are loaded
  191. // we want to load them in the order they are added therefore we want to turn off async
  192. script.async = false;
  193. script.src = url;
  194. script.onload = function() {
  195. loaded.push(url);
  196. checkDone();
  197. };
  198. el.appendChild(script);
  199. });
  200. };
  201. var regenerateRepresentations = function() {
  202. while (representationsEl.firstChild) {
  203. representationsEl.removeChild(representationsEl.firstChild);
  204. }
  205. var selectedIndex;
  206. window.vhs.representations().forEach(function(rep, i) {
  207. var option = document.createElement('option');
  208. option.value = rep.id;
  209. option.innerText = JSON.stringify({
  210. id: rep.id,
  211. videoCodec: rep.codecs.video,
  212. audioCodec: rep.codecs.audio,
  213. bandwidth: rep.bandwidth,
  214. heigth: rep.heigth,
  215. width: rep.width
  216. });
  217. if (window.pc.media().id === rep.id) {
  218. selectedIndex = i;
  219. }
  220. representationsEl.appendChild(option);
  221. });
  222. representationsEl.selectedIndex = selectedIndex;
  223. };
  224. function getBuffered(buffered) {
  225. var bufferedText = '';
  226. if (!buffered) {
  227. return bufferedText;
  228. }
  229. if (buffered.length) {
  230. bufferedText += buffered.start(0) + ' - ' + buffered.end(0);
  231. }
  232. for (var i = 1; i < buffered.length; i++) {
  233. bufferedText += ', ' + buffered.start(i) + ' - ' + buffered.end(i);
  234. }
  235. return bufferedText;
  236. }
  237. var setupSegmentMetadata = function(player) {
  238. // setup segment metadata
  239. var segmentMetadata = document.querySelector('#segment-metadata');
  240. player.one('loadedmetadata', function() {
  241. var tracks = player.textTracks();
  242. var segmentMetadataTrack;
  243. for (var i = 0; i < tracks.length; i++) {
  244. if (tracks[i].label === 'segment-metadata') {
  245. segmentMetadataTrack = tracks[i];
  246. }
  247. }
  248. while (segmentMetadata.children.length) {
  249. segmentMetadata.removeChild(segmentMetadata.firstChild);
  250. }
  251. if (segmentMetadataTrack) {
  252. segmentMetadataTrack.addEventListener('cuechange', function() {
  253. var cues = segmentMetadataTrack.activeCues || [];
  254. while (segmentMetadata.children.length) {
  255. segmentMetadata.removeChild(segmentMetadata.firstChild);
  256. }
  257. for (var j = 0; j < cues.length; j++) {
  258. var text = JSON.stringify(JSON.parse(cues[j].text), null, 2);
  259. var li = document.createElement('li');
  260. var pre = document.createElement('pre');
  261. pre.classList.add('border', 'rounded', 'p-2');
  262. pre.textContent = text;
  263. li.appendChild(pre);
  264. segmentMetadata.appendChild(li);
  265. }
  266. });
  267. }
  268. });
  269. };
  270. var setupPlayerStats = function(player) {
  271. player.on('dispose', () => {
  272. if (window.statsTimer) {
  273. window.clearInterval(window.statsTimer);
  274. window.statsTimer = null;
  275. }
  276. });
  277. var currentTimeStat = document.querySelector('.current-time-stat');
  278. var bufferedStat = document.querySelector('.buffered-stat');
  279. var videoBufferedStat = document.querySelector('.video-buffered-stat');
  280. var audioBufferedStat = document.querySelector('.audio-buffered-stat');
  281. var seekableStartStat = document.querySelector('.seekable-start-stat');
  282. var seekableEndStat = document.querySelector('.seekable-end-stat');
  283. var videoBitrateState = document.querySelector('.video-bitrate-stat');
  284. var measuredBitrateStat = document.querySelector('.measured-bitrate-stat');
  285. var videoTimestampOffset = document.querySelector('.video-timestampoffset');
  286. var audioTimestampOffset = document.querySelector('.audio-timestampoffset');
  287. player.on('timeupdate', function() {
  288. currentTimeStat.textContent = player.currentTime().toFixed(1);
  289. });
  290. window.statsTimer = window.setInterval(function() {
  291. var oldStart;
  292. var oldEnd;
  293. var seekable = player.seekable();
  294. if (seekable && seekable.length) {
  295. oldStart = seekableStartStat.textContent;
  296. if (seekable.start(0).toFixed(1) !== oldStart) {
  297. seekableStartStat.textContent = seekable.start(0).toFixed(1);
  298. }
  299. oldEnd = seekableEndStat.textContent;
  300. if (seekable.end(0).toFixed(1) !== oldEnd) {
  301. seekableEndStat.textContent = seekable.end(0).toFixed(1);
  302. }
  303. }
  304. // buffered
  305. bufferedStat.textContent = getBuffered(player.buffered());
  306. // exit early if no VHS
  307. if (!player.tech(true).vhs) {
  308. videoBufferedStat.textContent = '';
  309. audioBufferedStat.textContent = '';
  310. videoBitrateState.textContent = '';
  311. measuredBitrateStat.textContent = '';
  312. videoTimestampOffset.textContent = '';
  313. audioTimestampOffset.textContent = '';
  314. return;
  315. }
  316. videoBufferedStat.textContent = getBuffered(player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.videoBuffer &&
  317. player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.videoBuffer.buffered);
  318. // demuxed audio
  319. var audioBuffer = getBuffered(player.tech(true).vhs.playlistController_.audioSegmentLoader_.sourceUpdater_.audioBuffer &&
  320. player.tech(true).vhs.playlistController_.audioSegmentLoader_.sourceUpdater_.audioBuffer.buffered);
  321. // muxed audio
  322. if (!audioBuffer) {
  323. audioBuffer = getBuffered(player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.audioBuffer &&
  324. player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.audioBuffer.buffered);
  325. }
  326. audioBufferedStat.textContent = audioBuffer;
  327. if (player.tech(true).vhs.playlistController_.audioSegmentLoader_.sourceUpdater_.audioBuffer) {
  328. audioTimestampOffset.textContent = player.tech(true).vhs.playlistController_.audioSegmentLoader_.sourceUpdater_.audioBuffer.timestampOffset;
  329. } else if (player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.audioBuffer) {
  330. audioTimestampOffset.textContent = player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.audioBuffer.timestampOffset;
  331. }
  332. if (player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.videoBuffer) {
  333. videoTimestampOffset.textContent = player.tech(true).vhs.playlistController_.mainSegmentLoader_.sourceUpdater_.videoBuffer.timestampOffset;
  334. }
  335. // bitrates
  336. var playlist = player.tech_.vhs.playlists.media();
  337. if (playlist && playlist.attributes && playlist.attributes.BANDWIDTH) {
  338. videoBitrateState.textContent = (playlist.attributes.BANDWIDTH / 1024).toLocaleString(undefined, {
  339. maximumFractionDigits: 1
  340. }) + ' kbps';
  341. }
  342. if (player.tech_.vhs.bandwidth) {
  343. measuredBitrateStat.textContent = (player.tech_.vhs.bandwidth / 1024).toLocaleString(undefined, {
  344. maximumFractionDigits: 1
  345. }) + ' kbps';
  346. }
  347. }, 100);
  348. };
  349. [
  350. 'debug',
  351. 'autoplay',
  352. 'muted',
  353. 'fluid',
  354. 'minified',
  355. 'sync-workers',
  356. 'liveui',
  357. 'llhls',
  358. 'url',
  359. 'type',
  360. 'keysystems',
  361. 'buffer-water',
  362. 'exact-manifest-timings',
  363. 'pixel-diff-selector',
  364. 'network-info',
  365. 'dts-offset',
  366. 'override-native',
  367. 'preload',
  368. 'mirror-source'
  369. ].forEach(function(name) {
  370. stateEls[name] = document.getElementById(name);
  371. });
  372. window.startDemo = function(cb) {
  373. var state = loadState();
  374. Object.keys(state).forEach(function(elName) {
  375. setInputValue(stateEls[elName], state[elName]);
  376. });
  377. Array.prototype.forEach.call(sources.options, function(s, i) {
  378. if (s.value === state.url) {
  379. sources.selectedIndex = i;
  380. }
  381. });
  382. stateEls.fluid.addEventListener('change', function(event) {
  383. saveState();
  384. if (event.target.checked) {
  385. window['player-fixture'].style.aspectRatio = '16/9';
  386. window['player-fixture'].style.minHeight = 'initial';
  387. } else {
  388. window['player-fixture'].style.aspectRatio = '';
  389. window['player-fixture'].style.minHeight = '250px';
  390. }
  391. window.player.fluid(event.target.checked);
  392. });
  393. stateEls.muted.addEventListener('change', function(event) {
  394. saveState();
  395. window.player.muted(event.target.checked);
  396. });
  397. stateEls.autoplay.addEventListener('change', function(event) {
  398. saveState();
  399. window.player.autoplay(event.target.checked);
  400. });
  401. // stateEls that reload the player and scripts
  402. [
  403. 'mirror-source',
  404. 'sync-workers',
  405. 'preload',
  406. 'llhls',
  407. 'buffer-water',
  408. 'override-native',
  409. 'liveui',
  410. 'pixel-diff-selector',
  411. 'network-info',
  412. 'dts-offset',
  413. 'exact-manifest-timings'
  414. ].forEach(function(name) {
  415. stateEls[name].addEventListener('change', function(event) {
  416. saveState();
  417. stateEls.minified.dispatchEvent(newEvent('change'));
  418. });
  419. });
  420. [
  421. 'llhls'
  422. ].forEach(function(name) {
  423. stateEls[name].checked = true;
  424. });
  425. [
  426. 'exact-manifest-timings',
  427. 'pixel-diff-selector',
  428. 'buffer-water'
  429. ].forEach(function(name) {
  430. stateEls[name].checked = false;
  431. });
  432. stateEls.debug.addEventListener('change', function(event) {
  433. saveState();
  434. window.videojs.log.level(event.target.checked ? 'debug' : 'info');
  435. });
  436. stateEls.minified.addEventListener('change', function(event) {
  437. var urls = [
  438. 'node_modules/video.js/dist/alt/video.core',
  439. 'node_modules/videojs-contrib-eme/dist/videojs-contrib-eme',
  440. 'node_modules/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels',
  441. 'node_modules/videojs-http-source-selector/dist/videojs-http-source-selector'
  442. ].map(function(url) {
  443. return url + (event.target.checked ? '.min' : '') + '.js';
  444. });
  445. if (stateEls['sync-workers'].checked) {
  446. urls.push('dist/videojs-http-streaming-sync-workers.js');
  447. } else {
  448. urls.push('dist/videojs-http-streaming' + (event.target.checked ? '.min' : '') + '.js');
  449. }
  450. saveState();
  451. if (window.player) {
  452. window.player.dispose();
  453. delete window.player;
  454. }
  455. if (window.videojs) {
  456. delete window.videojs;
  457. }
  458. reloadScripts(urls, function() {
  459. var player;
  460. var fixture = document.getElementById('player-fixture');
  461. var videoEl = document.createElement('video-js');
  462. videoEl.setAttribute('controls', '');
  463. videoEl.setAttribute('preload', stateEls.preload.options[stateEls.preload.selectedIndex].value || 'auto');
  464. videoEl.className = 'vjs-default-skin';
  465. fixture.appendChild(videoEl);
  466. var mirrorSource = getInputValue(stateEls['mirror-source']);
  467. player = window.player = window.videojs(videoEl, {
  468. plugins: {
  469. httpSourceSelector: {
  470. default: 'auto'
  471. }
  472. },
  473. liveui: stateEls.liveui.checked,
  474. enableSourceset: mirrorSource,
  475. html5: {
  476. vhs: {
  477. overrideNative: getInputValue(stateEls['override-native']),
  478. bufferBasedABR: getInputValue(stateEls['buffer-water']),
  479. llhls: getInputValue(stateEls.llhls),
  480. exactManifestTimings: getInputValue(stateEls['exact-manifest-timings']),
  481. leastPixelDiffSelector: getInputValue(stateEls['pixel-diff-selector']),
  482. useNetworkInformationApi: getInputValue(stateEls['network-info']),
  483. useDtsForTimestampOffset: getInputValue(stateEls['dts-offset'])
  484. }
  485. }
  486. });
  487. setupPlayerStats(player);
  488. setupSegmentMetadata(player);
  489. // save player muted state interation
  490. player.on('volumechange', function() {
  491. if (stateEls.muted.checked !== player.muted()) {
  492. stateEls.muted.checked = player.muted();
  493. saveState();
  494. }
  495. });
  496. player.on('sourceset', function() {
  497. var source = player.currentSource();
  498. if (source.keySystems) {
  499. var copy = JSON.parse(JSON.stringify(source.keySystems));
  500. // have to delete pssh as it will often make keySystems too big
  501. // for a uri
  502. Object.keys(copy).forEach(function(key) {
  503. if (copy[key].hasOwnProperty('pssh')) {
  504. delete copy[key].pssh;
  505. }
  506. });
  507. stateEls.keysystems.value = JSON.stringify(copy, null, 2);
  508. }
  509. if (source.src) {
  510. stateEls.url.value = encodeURI(source.src);
  511. }
  512. if (source.type) {
  513. stateEls.type.value = source.type;
  514. }
  515. saveState();
  516. });
  517. player.width(640);
  518. player.height(264);
  519. // configure videojs-contrib-eme
  520. player.eme();
  521. stateEls.debug.dispatchEvent(newEvent('change'));
  522. stateEls.muted.dispatchEvent(newEvent('change'));
  523. stateEls.fluid.dispatchEvent(newEvent('change'));
  524. stateEls.autoplay.dispatchEvent(newEvent('change'));
  525. // run the load url handler for the intial source
  526. if (stateEls.url.value) {
  527. urlButton.dispatchEvent(newEvent('click'));
  528. } else {
  529. sources.dispatchEvent(newEvent('change'));
  530. }
  531. player.on('loadedmetadata', function() {
  532. if (player.tech_.vhs) {
  533. window.vhs = player.tech_.vhs;
  534. window.pc = player.tech_.vhs.playlistController_;
  535. window.pc.mainPlaylistLoader_.on('mediachange', regenerateRepresentations);
  536. regenerateRepresentations();
  537. } else {
  538. window.vhs = null;
  539. window.pc = null;
  540. }
  541. });
  542. cb(player);
  543. });
  544. });
  545. var urlButtonClick = function(event) {
  546. var ext;
  547. var type = stateEls.type.value;
  548. // reset type if it's a manifest object's type
  549. if (type === 'application/vnd.videojs.vhs+json') {
  550. type = '';
  551. }
  552. if (isManifestObjectType(stateEls.url.value)) {
  553. type = 'application/vnd.videojs.vhs+json';
  554. }
  555. if (!type.trim()) {
  556. ext = getFileExtension(stateEls.url.value);
  557. if (ext === 'mpd') {
  558. type = 'application/dash+xml';
  559. } else if (ext === 'm3u8') {
  560. type = 'application/x-mpegURL';
  561. }
  562. }
  563. saveState();
  564. var source = {
  565. src: stateEls.url.value,
  566. type: type
  567. };
  568. if (stateEls.keysystems.value) {
  569. source.keySystems = JSON.parse(stateEls.keysystems.value);
  570. }
  571. sources.selectedIndex = -1;
  572. Array.prototype.forEach.call(sources.options, function(s, i) {
  573. if (s.value === stateEls.url.value) {
  574. sources.selectedIndex = i;
  575. }
  576. });
  577. window.player.src(source);
  578. };
  579. urlButton.addEventListener('click', urlButtonClick);
  580. urlButton.addEventListener('tap', urlButtonClick);
  581. sources.addEventListener('change', function(event) {
  582. var selectedOption = sources.options[sources.selectedIndex];
  583. if (!selectedOption) {
  584. return;
  585. }
  586. var src = selectedOption.value;
  587. stateEls.url.value = src;
  588. stateEls.type.value = selectedOption.getAttribute('data-mimetype');
  589. stateEls.keysystems.value = selectedOption.getAttribute('data-key-systems');
  590. urlButton.dispatchEvent(newEvent('click'));
  591. });
  592. stateEls.url.addEventListener('keyup', function(event) {
  593. if (event.key === 'Enter') {
  594. urlButton.click();
  595. }
  596. });
  597. stateEls.url.addEventListener('input', function(event) {
  598. if (stateEls.type.value.length) {
  599. stateEls.type.value = '';
  600. }
  601. });
  602. stateEls.type.addEventListener('keyup', function(event) {
  603. if (event.key === 'Enter') {
  604. urlButton.click();
  605. }
  606. });
  607. // run the change handler for the first time
  608. stateEls.minified.dispatchEvent(newEvent('change'));
  609. };
  610. }(window));