SPON Video tag

Enables HTML5 video playback on SPON with disabled JavaScript.

当前为 2020-09-03 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name SPON Video tag
  3. // @namespace https://greasyfork.org/en/users/8981-buzz
  4. // @version 0.2
  5. // @description Enables HTML5 video playback on SPON with disabled JavaScript.
  6. // @license GPLv2
  7. // @noframes
  8. // @author buzz
  9. // @match https://www.spiegel.de/*
  10. // @grant GM.xmlHttpRequest
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. function setSource(videoEl, source) {
  17. videoEl.setAttribute('src', source.file);
  18. videoEl.setAttribute('type', source.type);
  19. }
  20.  
  21. async function addVideoTag(image, sources, c) {
  22. let source = sources.find((s) => s.label === sources[0].label);
  23. if (!source) {
  24. source = sources[0];
  25. }
  26.  
  27. const videoEl = document.createElement('video');
  28. videoEl.setAttribute('autoplay', '');
  29. videoEl.setAttribute('controls', '');
  30. videoEl.setAttribute('poster', image);
  31. videoEl.setAttribute('preload', '');
  32. videoEl.setAttribute('width', sources[0].width);
  33. videoEl.setAttribute('height', sources[0].height);
  34. videoEl.style.maxWidth = '100%';
  35. videoEl.style.minWidth = '100%';
  36. videoEl.style.height = 'auto';
  37.  
  38. const sourceSelEl = document.createElement('div');
  39. if (sources.length > 1) {
  40. sourceSelEl.style.textAlign = 'right';
  41. sourceSelEl.style.paddingTop = '0.2rem';
  42. sources.forEach((s) => {
  43. const aEl = document.createElement('a');
  44. aEl.innerText = s.label;
  45. aEl.setAttribute('href', '');
  46. aEl.style.margin = '0 0.4rem';
  47. if (s === source) {
  48. aEl.style.textDecoration = 'underline';
  49. }
  50. aEl.addEventListener('click', (ev) => {
  51. ev.preventDefault();
  52. setSource(videoEl, s);
  53. for (let i = 0; i < sourceSelEl.children.length; i++) {
  54. const aChild = sourceSelEl.children[i]
  55. if (aChild.innerText === s.label) {
  56. aChild.style.textDecoration = 'underline';
  57. } else {
  58. aChild.style.textDecoration = 'none';
  59. }
  60. }
  61. });
  62. sourceSelEl.append(aEl);
  63. });
  64. }
  65.  
  66. const child = c.firstElementChild;
  67. child.style.backgroundColor = 'transparent';
  68. child.style.paddingTop = '0';
  69. child.innerHTML = '';
  70. child.append(videoEl);
  71. child.append(sourceSelEl);
  72. setSource(videoEl, source);
  73. }
  74.  
  75. function processApiResponse(r, c) {
  76. const playlist = r.playlist[0];
  77. const sources = playlist.sources
  78. .filter((s) => s.type.startsWith('video/'))
  79. .sort((a, b) => b.height - a.height)
  80. addVideoTag(playlist.image, sources, c);
  81. }
  82.  
  83. function processContainer(c) {
  84. const { apiUrl, mediaId } = JSON.parse(c.dataset.settings);
  85. GM.xmlHttpRequest({
  86. method: "GET",
  87. url: `${apiUrl}/v2/media/${mediaId}`,
  88. onload: (r) => processApiResponse(JSON.parse(r.responseText), c),
  89. });
  90. }
  91.  
  92. document.querySelectorAll('[data-settings*=apiUrl]').forEach(processContainer);
  93. })();