ppvm_player.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. // @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later
  2. function setup_playback(description) {
  3. document.getElementById("no-script").classList.remove("noscript");
  4. document.getElementById("controls").classList.add("javascript");
  5. video_manifest = description;
  6. console.log(description);
  7. player = document.getElementById("player");
  8. player.addEventListener("pause", (event) => playStateChanged(false));
  9. player.addEventListener("playing", (event) => playStateChanged(true));
  10. filteredOptions = description.entries.filter(o => shouldOfferStream(o, description.entries));
  11. if(filteredOptions.length == 0){
  12. player.src = "invalid://invalid";
  13. document.getElementById("unplayable-modal").showModal();
  14. return;
  15. }
  16. player.src = filteredOptions[0].path;
  17. qualitySelector = document.getElementById("quality-selector");
  18. filteredOptions.forEach(option => {
  19. opt = document.createElement("option")
  20. opt.value = option.path;
  21. opt.innerHTML = option.label;
  22. qualitySelector.appendChild(opt);
  23. });
  24. startRes = findOptimalOptionForScreen(filteredOptions);
  25. qualitySelector.value = startRes.path
  26. qualitySelected();
  27. doSpeedTest(startRes, filteredOptions);
  28. // Initialize custom video controls
  29. if (typeof CustomVideoControls !== 'undefined') {
  30. CustomVideoControls.init();
  31. }
  32. }
  33. function qualitySelected() {
  34. qualitySelector = document.getElementById("quality-selector");
  35. player = document.getElementById("player");
  36. paused = player.paused;
  37. time = player.currentTime;
  38. player.src = qualitySelector.value;
  39. player.load();
  40. player.currentTime = time;
  41. if(!paused) {
  42. player.play();
  43. }
  44. }
  45. function canPlayStream(stream) {
  46. if(stream.type !== "video") {
  47. return false;
  48. }
  49. player = document.getElementById("player");
  50. return player.canPlayType(`${stream.mimetype}; codecs="${stream.metadata.codecs}"`);
  51. }
  52. function shouldOfferStream(stream, streams) {
  53. if(!canPlayStream(stream)) {
  54. return false;
  55. }
  56. if(stream.metadata.alternative_to == undefined) {
  57. return true;
  58. }
  59. return !hasHigherUsableAlternative(stream, streams);
  60. }
  61. function hasHigherUsableAlternative(stream, streams) {
  62. if(stream.metadata.alternative_to == undefined) {
  63. return false;
  64. }
  65. parent = streams.find(s => s.label == stream.metadata.alternative_to);
  66. if(canPlayStream(parent)) {
  67. return true;
  68. }
  69. return hasHigherUsableAlternative(parent, streams);
  70. }
  71. function findOptimalOptionForScreen(options) {
  72. screenSize = Math.max(window.screen.width, window.screen.height);
  73. screenSize = screenSize * window.devicePixelRatio
  74. filtered = options.filter(o => o.type === "video" && Math.max(o.metadata.size.split("x")[0], o.metadata.size.split("x")[1]) <= screenSize);
  75. console.log(filtered);
  76. if(filtered.length == 0){
  77. return options[options.length - 1];
  78. }
  79. return filtered[0];
  80. }
  81. function downloadVideo() {
  82. document.getElementById("download-modal").showModal();
  83. }
  84. function showInfo() {
  85. document.getElementById("info-modal").showModal();
  86. }
  87. function shareVideo() {
  88. document.getElementById("share-modal").showModal();
  89. }
  90. function playStateChanged(playing) {
  91. controls = document.getElementById("controls")
  92. if(playing) {
  93. controls.classList.remove("paused")
  94. }
  95. else {
  96. controls.classList.add("paused")
  97. }
  98. // Update custom controls if available
  99. if (typeof CustomVideoControls !== 'undefined' && CustomVideoControls.video) {
  100. CustomVideoControls.updatePlayPauseButton();
  101. }
  102. }
  103. function doSpeedTest(currentOption, options) {
  104. startTime = window.performance.now();
  105. request = new XMLHttpRequest();
  106. request.onreadystatechange = function() {
  107. if(request.readyState === 2) {
  108. // Reset start time, headers received.
  109. startTime = window.performance.now();
  110. }
  111. if(request.readyState === 4 && (request.status === 200 || request.status === 206)) {
  112. endTime = window.performance.now();
  113. size = request.response.size;
  114. rate = size / ((endTime - startTime) / 1000)
  115. console.log(`Detected connection rate: ${rate} bytes/sec`);
  116. filtered = options.filter(o => o.type === "video" && o.byterate < rate);
  117. if(filtered.length == 0) {
  118. filtered = [options[options.length - 1]];
  119. }
  120. optimal = findOptimalOptionForScreen(filtered);
  121. if(optimal !== currentOption) {
  122. qualitySelector.value = optimal.path
  123. console.log("Switched res");
  124. qualitySelected();
  125. }
  126. else {
  127. console.log("Got it right first try B)");
  128. }
  129. }
  130. }
  131. requestSize = Math.min(options[0].filesize, Math.round(options[0].byterate));
  132. request.open("GET", options[0].path);
  133. request.responseType = "blob";
  134. request.setRequestHeader("Range", `bytes=0-${requestSize}`);
  135. request.send();
  136. }
  137. // @license-end