애니플러스 스트리밍 문제해결
- Tampermonkey 설치: https://tampermonkey.net/
- 문제해결 스크립트 설치: https://gist.github.com/saschanaz/a5e00b559da591b1a4bd59361778b9fa/raw/aniplus-patch.user.js
애니플러스 스트리밍 문제해결
| // ==UserScript== | |
| // @name ANIPLUS HLS fix | |
| // @namespace https://saschanaz.github.io/ | |
| // @version 0.2.4 | |
| // @description Fix bandwidth to match the actual maximum observed bitrate 95726 kbps | |
| // @author Kagami Sascha Rosylight | |
| // @match http://www.aniplustv.com/tv/program_player_html5.asp?* | |
| // @grant none | |
| // @run-at document-start | |
| // ==/UserScript== | |
| /* jshint esversion: 6 */ | |
| "use strict"; | |
| (() => { | |
| console.log("Starting ANIPLUS autoSetup fix"); | |
| const o = new MutationObserver(mutations => { | |
| for (const mutation of mutations) { | |
| for (const node of Array.from(mutation.addedNodes)) { | |
| if (node.nodeType === 1 && node.id === "aniplusVideo" && node.tagName === "VIDEO") { | |
| console.log("Removing data-setup to prevent videojs autoSetup(), which may cause race condition with ANIPLUS ajax success handler and then HLS error."); | |
| node.removeAttribute("data-setup"); | |
| } | |
| } | |
| } | |
| }); | |
| o.observe(document.documentElement, { childList: true, subtree: true }); | |
| })(); | |
| (async () => { | |
| if (!document.createElement("video").canPlayType('application/x-mpegURL')) { | |
| console.log("Skipping ANIPLUS bandwidth fix as this browser doesn't have native HLS support"); | |
| return; | |
| } | |
| console.log("Starting ANIPLUS bandwidth fix"); | |
| const threshold = 128 * 1024 ** 2; | |
| if (!await tryModification()) { | |
| startMutationObserver(); | |
| } | |
| async function tryModification() { | |
| if (!window.aniplusVideo_html5_api) { | |
| return false; | |
| } | |
| return fixVideo(aniplusVideo_html5_api); | |
| } | |
| function startMutationObserver() { | |
| const observer = new MutationObserver(async (mutations) => { | |
| for (const mutation of mutations) { | |
| for (const node of Array.from(mutation.addedNodes)) { | |
| if (node.nodeType === 1 && node.id === "aniplusVideo_html5_api") { | |
| await fixVideo(node); | |
| } | |
| } | |
| } | |
| }); | |
| observer.observe(document.documentElement, { | |
| subtree: true, | |
| childList: true | |
| }); | |
| return observer; | |
| } | |
| async function fixVideo(video) { | |
| const source = video.getElementsByTagName("source")[0]; | |
| if (!source.src.includes("playlist.m3u8")) { | |
| return false; | |
| } | |
| video.src = URL.createObjectURL(await fixPlaylist(source.src)); | |
| video.setAttribute("x-aniplus-fix", true); | |
| } | |
| async function fixPlaylist(path) { | |
| const directory = path.match(/^.*\//); | |
| const response = await fetch(path); | |
| const text = await response.text(); | |
| console.log(`ANIPLUS HLS original:\n\n${text}`); | |
| const fixed = text | |
| .replace(/BANDWIDTH=([0-9]+)/, ($0, $1) => `BANDWIDTH=${Math.max(+$1, threshold)}`) | |
| .replace("chunklist", `${directory}chunklist`); | |
| console.log(`ANIPLUS HLS fix:\n\n${fixed}`); | |
| return new Blob([fixed], { type: "application/vnd.apple.mpegurl" }); | |
| } | |
| })().catch(console.error); |