Force highest quality playback for X (Twitter). Fixed UI layout shifts.
// ==UserScript==
// @name Video Quality Controller for X (Twitter) (Chromium browsers only)
// @version 1.0.0
// @description Force highest quality playback for X (Twitter). Fixed UI layout shifts.
// @match https://x.com/*
// @match https://mobile.x.com/*
// @match https://pro.x.com/*
// @match https://twitter.com/*
// @match https://mobile.twitter.com/*
// @match https://pro.twitter.com/*
// @exclude https://x.com/i/cards-frame/*
// @exclude https://*.x.com/i/cards-frame/*
// @exclude https://twitter.com/i/cards-frame/*
// @exclude https://*.twitter.com/i/cards-frame/*
// @grant none
// @run-at document-start
// @namespace https://greasyfork.org/users/1474347
// ==/UserScript==
(function () {
'use strict';
if (window.__VQFFT) return; window.__VQFFT = 1;
// --- CONFIGURATION ---
const KEYS = { QUALITY: 'vqfft_settings_quality_v31', MIN: 'vqfft_settings_min_v31' };
const LEVELS = { 'Auto': 'Auto', 'Best': 'Highest', '1080P': '1080p', '720P': '720p', 'Worst': 'Saver' };
const ORDER = ['Best', '1080P', '720P', 'Auto'];
// Helper
const store = {
get: k => localStorage.getItem(k),
set: (k, v) => localStorage.setItem(k, v)
};
// --- M3U8 LOGIC (Nearest Neighbor) ---
const HLS = {
isPl: (u, t) => u.includes('.m3u8') || t.includes('#EXT-X-STREAM-INF'),
proc: (txt, q) => {
if (q === 'Auto') return txt;
const lines = txt.split(/\r?\n/);
const vars = [];
let header = "";
let found = false;
for (let i = 0; i < lines.length; i++) {
const line = lines[i].trim();
if (!line) continue;
if (line.startsWith('#EXT-X-STREAM-INF:')) {
found = true;
const url = lines[i + 1]?.trim();
if (url) {
const res = /RESOLUTION=(\d+)x(\d+)/.exec(line);
const bw = /BANDWIDTH=(\d+)/.exec(line);
vars.push({
def: line, url,
p: res ? res[1] * res[2] : 0,
h: res ? +res[2] : 0,
bw: bw ? +bw[1] : 0
});
i++;
}
} else if (!found) header += line + '\n';
}
if (!vars.length) return txt;
vars.sort((a, b) => b.p - a.p || b.bw - a.bw);
let sel;
if (q === 'Best') sel = vars[0];
else if (q === 'Worst') sel = vars[vars.length - 1];
else {
const target = parseInt(q, 10);
sel = isNaN(target) ? vars[0] : vars.reduce((prev, curr) =>
Math.abs(curr.h - target) < Math.abs(prev.h - target) ? curr : prev
);
}
return `${header}${sel.def}\n${sel.url}`;
}
};
// --- NETWORK INTERCEPTOR ---
class Interceptor {
constructor(mgr) { this.mgr = mgr; this.reg = /^https:\/\/video\.twimg\.com\/.*\.m3u8/i; }
enable() {
const self = this;
// XHR Interceptor
const XHR = window.XMLHttpRequest;
const origOpen = XHR.prototype.open;
XHR.prototype.open = function (m, u) {
if (typeof u === 'string' && self.reg.test(u)) {
this.addEventListener('readystatechange', function () {
if (this.readyState === 4 && this.status === 200 && (!this.responseType || this.responseType === 'text')) {
if (HLS.isPl(u, this.responseText)) {
const mod = HLS.proc(this.responseText, self.mgr.q);
Object.defineProperties(this, { response: { value: mod }, responseText: { value: mod } });
self.mgr.notify();
}
}
});
}
return origOpen.apply(this, arguments);
};
// Fetch Interceptor
const origFetch = window.fetch;
window.fetch = function (...args) {
const url = (args[0] instanceof Request) ? args[0].url : args[0];
if (typeof url === 'string' && self.reg.test(url)) {
return (async () => {
try {
const res = await origFetch.apply(this, args);
if (res.ok && (url.includes('.m3u8') || (res.headers.get('Content-Type') ?? '').includes('mpegurl'))) {
const txt = await res.clone().text();
if (HLS.isPl(url, txt)) {
self.mgr.notify();
const mod = HLS.proc(txt, self.mgr.q);
const h = new Headers(res.headers);
h.delete('Content-Encoding'); h.delete('Content-Length');
return new Response(mod, { status: res.status, statusText: res.statusText, headers: h });
}
}
return res;
} catch (e) { return origFetch.apply(this, args); }
})();
}
return origFetch.apply(this, args);
};
}
}
// --- UI (CSS) ---
class UI {
constructor(mgr) { this.mgr = mgr; this.mini = store.get(KEYS.MIN) === '1'; }
render() {
if (!document.getElementById('vqfft-style')) {
//
const css = `.vqfft-box,.vqfft-box *{box-sizing:border-box}.vqfft-box{--bg:rgba(0,0,0,0.85);--txt:#e7e9ea;--acc:#1d9bf0;position:fixed;top:85px;right:20px;z-index:2147483647;background:var(--bg);backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.15);border-radius:16px;box-shadow:0 4px 24px rgba(0,0,0,0.5);color:var(--txt);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;line-height:1.3;width:230px;user-select:none;transition:opacity .2s;opacity:.5}.vqfft-box:hover{opacity:1}.vqfft-box.mini{width:44px;height:44px;border-radius:50%;cursor:pointer;overflow:hidden;border:none}.vqfft-box.mini .bd,.vqfft-box.mini .tl{display:none}.vqfft-box.mini .hd{padding:0;justify-content:center;height:100%}.vqfft-box.mini::after{content:'';position:absolute;top:10px;right:10px;width:6px;height:6px;border-radius:50%;background:var(--acc);opacity:0}.vqfft-box.mini.locked::after{opacity:1}.hd{display:flex;align-items:center;padding:14px 18px;cursor:pointer}.hd:hover{background:rgba(255,255,255,.1)}.ic{width:20px;height:20px;color:#71767b;margin-right:12px;flex-shrink:0}.tl{font-weight:800;font-size:17px;flex:1}.it{display:flex;justify-content:space-between;align-items:center;padding:12px 18px;cursor:pointer;font-size:15px;font-weight:500;transition:.15s}.it:hover{background:rgba(255,255,255,.1)}.ck,.sp{width:18px;height:18px;display:none}.it.active .ck{display:block;fill:var(--acc)}.it.active span{color:var(--acc);font-weight:700}.sp{border:2px solid rgba(29,155,240,.3);border-top-color:var(--acc);border-radius:50%;animation:s .6s linear infinite}.it.loading .ck{display:none}.it.loading .sp{display:block}@keyframes s{to{transform:rotate(360deg)}}.vqfft-t{position:fixed;bottom:40px;left:50%;transform:translate(-50%);background:var(--acc);color:#fff;padding:10px 20px;border-radius:99px;font-weight:700;animation:p .35s cubic-bezier(.21,1.02,.73,1)}@keyframes p{from{opacity:0;transform:translate(-50%,20px) scale(.9)}to{opacity:1;transform:translate(-50%,0)}}`;
const s = document.createElement('style'); s.id = 'vqfft-style'; s.textContent = css;
(document.head || document.documentElement).appendChild(s);
}
const div = document.createElement('div');
this.el = div;
this.updClass();
div.innerHTML = `
<div class="hd"><svg class="ic" viewBox="0 0 24 24"><path fill="currentColor" d="M10.54 1.75h2.92l.85 2.85c.98.34 1.9.84 2.73 1.48l2.84-1 .85 2.85-2.28 2.05c.1.51.15 1.04.15 1.57s-.05 1.06-.15 1.57l2.28 2.05-.85 2.85-2.84-1c-.83.64-1.75 1.14-2.73 1.48l-.85 2.85h-2.92l-.85-2.85c-.98-.34-1.9-.84-2.73-1.48l-2.84 1-.85-2.85 2.28-2.05c-.1-.51-.15-1.04-.15-1.57s.05-1.06.15-1.57L2.42 8.93l.85-2.85 2.84 1c.83-.64 1.75-1.14 2.73-1.48l.85-2.85zM12 16c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4z"/></svg><span class="tl">Quality</span></div>
<div class="bd">${Object.entries(LEVELS).map(([k, v]) => `<div class="it" data-v="${k}"><span>${v}</span><svg class="ck" viewBox="0 0 24 24"><path d="M9 20.42L2.79 14.21 5.62 11.38 9 14.77 18.88 4.88 21.71 7.71z"/></svg><div class="sp"></div></div>`).join('')}</div>
`;
document.body.appendChild(div);
div.addEventListener('click', e => {
e.stopPropagation();
if (e.target.closest('.hd') || (this.mini && !e.target.closest('.it'))) {
this.mini = !this.mini; store.set(KEYS.MIN, this.mini ? '1' : '0'); this.updClass();
} else if (e.target.closest('.it')) {
const it = e.target.closest('.it');
div.querySelectorAll('.it').forEach(i => i.classList.remove('loading'));
it.classList.add('loading');
this.mgr.set(it.dataset.v);
}
});
this.updState();
}
updClass() { this.el.className = `vqfft-box ${this.mini?'mini':''} ${this.mgr.q!=='Auto'?'locked':''}`; }
updState() {
if(!this.el) return;
this.el.querySelectorAll('.it').forEach(i => i.classList.toggle('active', i.dataset.v === this.mgr.q));
this.updClass();
}
toast(msg) {
const t = document.createElement('div'); t.className = 'vqfft-t'; t.textContent = msg;
document.body.appendChild(t); setTimeout(() => t.remove(), 2500);
}
}
// --- MANAGER ---
class Manager {
constructor() {
this.q = store.get(KEYS.QUALITY) ?? 'Best';
this.ui = new UI(this);
this.net = new Interceptor(this);
}
start() {
this.net.enable();
document.addEventListener('keydown', e => { if (e.altKey && e.key.toLowerCase() === 'q') { e.preventDefault(); this.cycle(); } });
const init = () => window.requestAnimationFrame(() => this.ui.render());
document.readyState === 'complete' ? init() : window.addEventListener('DOMContentLoaded', init, { once: true });
}
cycle() {
const n = ORDER[(ORDER.indexOf(this.q) + 1) % ORDER.length];
this.ui.toast(`Switching: ${n}`); this.set(n);
}
set(v) {
if (this.q !== v) { this.q = v; store.set(KEYS.QUALITY, v); setTimeout(() => location.reload(), 50); }
}
notify() {
if (this.q !== 'Auto' && !this.n) { this.ui.toast(`${this.q} Locked`); this.n = 1; }
}
}
new Manager().start();
})();