U-NEXT Max Resolution

Force streaming video at maximum resolution on U-NEXT.

  1. // ==UserScript==
  2. // @name U-NEXT Max Resolution
  3. // @name:zh-CN U-NEXT 强制最高画质
  4. // @name:ja U-NEXT 最高画質固定
  5. // @namespace http://tampermonkey.net/
  6. // @match https://*.unext.jp/*
  7. // @grant none
  8. // @version 1.0
  9. // @author DiruSec
  10. // @license MIT
  11. // @icon https://www.google.com/s2/favicons?sz=64&domain=unext.jp
  12. // @description Force streaming video at maximum resolution on U-NEXT.
  13. // @description:zh-CN 强制 U-NEXT 使用最高分辨率进行播放
  14. // @description:ja U-NEXTの再生画質を最高画質に固定させる
  15. // ==/UserScript==
  16.  
  17. (function() {
  18. 'use strict';
  19.  
  20. // Function to remove all <Representation> elements except the one with the largest bandwidth
  21. function filterRepresentations(xmlString) {
  22. const parser = new DOMParser();
  23. const xmlDoc = parser.parseFromString(xmlString, "application/xml");
  24.  
  25. const adaptationSets = xmlDoc.getElementsByTagNameNS("*", "AdaptationSet");
  26.  
  27. for (let i = 0; i < adaptationSets.length; i++) {
  28. const adaptationSet = adaptationSets[i];
  29. const representations = adaptationSet.getElementsByTagNameNS("*", "Representation");
  30.  
  31. let maxBandwidth = -1;
  32. let maxRepresentation = null;
  33.  
  34. for (let j = 0; j < representations.length; j++) {
  35. const representation = representations[j];
  36. const bandwidth = parseInt(representation.getAttribute("bandwidth"), 10);
  37.  
  38. if (bandwidth > maxBandwidth) {
  39. maxBandwidth = bandwidth;
  40. maxRepresentation = representation;
  41. }
  42. }
  43.  
  44. // Remove all <Representation> elements except the one with the largest bandwidth
  45. for (let j = representations.length - 1; j >= 0; j--) {
  46. const representation = representations[j];
  47. if (representation !== maxRepresentation) {
  48. adaptationSet.removeChild(representation);
  49. }
  50. }
  51. }
  52.  
  53. // Serialize the DOM object back to a string
  54. const serializer = new XMLSerializer();
  55. return serializer.serializeToString(xmlDoc);
  56. }
  57.  
  58. // Save the original fetch function
  59. const originalFetch = window.fetch;
  60.  
  61. // Override the fetch function
  62. window.fetch = async function(...args) {
  63. const url = args[0];
  64.  
  65. // Check if the URL matches the pattern
  66. const regex = /https:\/\/playlist\.unext\.jp\/playlist\/v00001\/dash\/get\/.*?\.mpd.*/;
  67.  
  68. if (regex.test(url)) {
  69.  
  70. // Perform the fetch request
  71. const response = await originalFetch(...args);
  72.  
  73. // Clone the response so that we can modify it
  74. const responseClone = await response.clone().text();
  75.  
  76. // Modify the XML response
  77. const modifiedXml = filterRepresentations(responseClone);
  78.  
  79. // Return a new Response object with the modified XML
  80. return new Response(modifiedXml, {
  81. status: response.status,
  82. statusText: response.statusText,
  83. headers: response.headers
  84. });
  85. }
  86.  
  87. // If the URL doesn't match, return the original fetch call
  88. return originalFetch(...args);
  89. };
  90. })();