X (Twitter) 视频画质修复

强制 X (Twitter) 播放最高画质的视频

  1. // ==UserScript==
  2. // @name Video Quality Fixer for X (Twitter)
  3. // @name:zh X (Twitter) 视频画质修复
  4. // @name:zh-CN X (Twitter) 视频画质修复
  5. // @namespace https://github.com/yuhaofe
  6. // @version 0.2.1
  7. // @description Force highest quality playback for X (Twitter) videos.
  8. // @description:zh 强制 X (Twitter) 播放最高画质的视频
  9. // @description:zh-CN 强制 X (Twitter) 播放最高画质的视频
  10. // @author yuhaofe
  11. // @match https://x.com/*
  12. // @match https://mobile.x.com/*
  13. // @match https://twitter.com/*
  14. // @match https://mobile.twitter.com/*
  15. // @grant none
  16. // ==/UserScript==
  17.  
  18. (function() {
  19. 'use strict';
  20. initHijack();
  21. initUI();
  22. function initHijack() {
  23. var realOpen = window.XMLHttpRequest.prototype.open;
  24. window.XMLHttpRequest.prototype.open = hijackedOpen;
  25. function hijackedOpen() {
  26. var url = arguments['1'];
  27. if (isHLSPlaylist(url)) {
  28. this.addEventListener('readystatechange', function(e) {
  29. if (this.readyState === 4) {
  30. var originalText = e.target.responseText;
  31. if(isMasterPlaylist(originalText)) {
  32. var modifiedText = modifyMasterPlaylist(originalText);
  33. Object.defineProperty(this, 'response', {writable: true});
  34. Object.defineProperty(this, 'responseText', {writable: true});
  35. this.response = this.responseText = modifiedText;
  36. }
  37. }
  38. });
  39. }
  40. return realOpen.apply(this, arguments);
  41. };
  42.  
  43. function isHLSPlaylist(url) {
  44. var reg = new RegExp(/^https:\/\/video\.twimg\.com\/.+m3u8?/, 'i') ;
  45. return reg.test(url);
  46. }
  47.  
  48. function isMasterPlaylist(text) {
  49. return text.indexOf('#EXT-X-TARGETDURATION') === -1 && text.indexOf('#EXT-X-STREAM-INF') != -1;
  50. }
  51.  
  52. function modifyMasterPlaylist(text) {
  53. var result = text;
  54. var reg = new RegExp(/^#EXT-X-STREAM-INF:.*BANDWIDTH=(\d+).*\r?\n.*$/, 'gm');
  55. var stream = reg.exec(text);
  56. if (stream) {
  57. var globalTags = text.substring(0, stream.index);
  58.  
  59. // find max bitrate media playlist
  60. var maxBitrateStream = stream;
  61. while((stream = reg.exec(text)) != null){
  62. if (parseInt(stream[1]) > parseInt(maxBitrateStream[1])) {
  63. maxBitrateStream = stream;
  64. }
  65. }
  66. result = globalTags + maxBitrateStream[0];
  67. }
  68. return result;
  69. }
  70. }
  71. function initUI() {
  72. // add a mark helps identify if userscript loaded successfully
  73. var disableHQ = localStorage.getItem('vqfft-disablehq');
  74. if(!disableHQ) {
  75. var mark = document.createElement('button');
  76. mark.innerText = 'HQ';
  77. mark.style = "position: fixed;right: 5px;top: 5px;color: white;border-width: 0px;border-radius: 5px;background-color: gray;opacity: 0.5;";
  78. mark.onclick = function() {
  79. if(confirm('Do not display HQ mark anymore?')){
  80. localStorage.setItem('vqfft-disablehq', 'true');
  81. mark.remove();
  82. }
  83. };
  84. document.body.appendChild(mark);
  85. }
  86. }
  87. })();
  88.  

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址