☰

Eporner highest quality resolution

Auto selects only highest quality resolution available on eporner videos

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴、Greasemonkey 油猴子 或 Violentmonkey 暴力猴,才能安装此脚本。

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴 或 Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴 或 Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Eporner highest quality resolution
// @namespace    https://violentmonkey.github.io/
// @version      3.1
// @description  Auto selects only highest quality resolution available on eporner videos
// @author       You
// @match        *://*.eporner.com/*
// @grant        none
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // Parses the HLS Master Playlist (.m3u8) and strips out all resolutions except the absolute highest
    function filterHLS(text) {
        if (!text.includes('#EXT-X-STREAM-INF')) return text;

        const lines = text.split('\n');
        const streams = [];
        let currentInfo = null;

        for (let i = 0; i < lines.length; i++) {
            const line = lines[i].trim();
            if (line.startsWith('#EXT-X-STREAM-INF')) {
                currentInfo = line;
            } else if (currentInfo && line && !line.startsWith('#')) {
                streams.push({ info: currentInfo, url: line });
                currentInfo = null;
            }
        }

        if (streams.length === 0) return text;

        let bestStream = streams[0];
        let maxVal = 0;

        streams.forEach(stream => {
            // Check by Resolution tag (e.g., RESOLUTION=1920x1080)
            const resMatch = stream.info.match(/RESOLUTION=\d+x(\d+)/);
            if (resMatch) {
                const height = parseInt(resMatch[1], 10);
                if (height > maxVal) { maxVal = height; bestStream = stream; }
            } else {
                // Fallback to Bandwidth tag if resolution is missing
                const bwMatch = stream.info.match(/BANDWIDTH=(\d+)/);
                if (bwMatch) {
                    const bw = parseInt(bwMatch[1], 10);
                    if (bw > maxVal) { maxVal = bw; bestStream = stream; }
                }
            }
        });

        // Reconstruct the playlist feeding the player ONLY the highest tier
        return `#EXTM3U\n${bestStream.info}\n${bestStream.url}\n`;
    }

    // 1. Intercept Fetch API Requests
    const originalFetch = window.fetch;
    window.fetch = async function() {
        const url = (arguments[0] instanceof Request) ? arguments[0].url : arguments[0];
        const response = await originalFetch.apply(this, arguments);

        if (typeof url === 'string' && url.includes('.m3u8')) {
            const clone = response.clone();
            const text = await clone.text();

            if (text.includes('#EXT-X-STREAM-INF')) {
                const newPlaylist = filterHLS(text);
                return new Response(newPlaylist, {
                    status: response.status,
                    statusText: response.statusText,
                    headers: response.headers
                });
            }
        }
        return response;
    };

    // 2. Intercept XMLHttpRequest (Older HLS.js implementations)
    const originalOpen = XMLHttpRequest.prototype.open;
    const originalSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function(method, url) {
        this._isM3u8 = typeof url === 'string' && url.includes('.m3u8');
        return originalOpen.apply(this, arguments);
    };

    XMLHttpRequest.prototype.send = function() {
        if (this._isM3u8) {
            this.addEventListener('readystatechange', function() {
                // When the playlist arrives, overwrite the response text before the video engine reads it
                if (this.readyState === 4 && this.responseText && this.responseText.includes('#EXT-X-STREAM-INF')) {
                    const filteredText = filterHLS(this.responseText);
                    Object.defineProperty(this, 'responseText', { get: () => filteredText });
                    if (this.responseType === '' || this.responseType === 'text') {
                        Object.defineProperty(this, 'response', { get: () => filteredText });
                    }
                }
            }, false);
        }
        return originalSend.apply(this, arguments);
    };

})();