Extract normal and premium links with Fetch y XHR.
// ==UserScript==
// @name Xexle - Link Extractor
// @namespace http://tampermonkey.net/
// @version 1.0
// @license MIT
// @description Extract normal and premium links with Fetch y XHR.
// @author xness
// @match *://*.xexle.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=xexle.com
// @grant unsafeWindow
// @run-at document-start
// ==/UserScript==
(function() {
'use strict';
const videoDataMap = new Map();
const win = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window;
// fetch interceptor
const originalFetch = win.fetch;
win.fetch = async (...args) => {
const response = await originalFetch(...args);
if (args[0] && args[0].includes('/api/')) {
const clone = response.clone();
clone.json().then(data => processJson(data)).catch(()=>{});
}
return response;
};
// xhr interceptor if has clasic XMLHttpRequest
const originalOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function() {
this.addEventListener('load', function() {
if (this.responseURL.includes('/api/')) {
try {
const data = JSON.parse(this.responseText);
processJson(data);
} catch (e) {}
}
});
return originalOpen.apply(this, arguments);
};
// process data
function processJson(json) {
if (json && json.data && json.data.list) {
json.data.list.forEach(item => {
const link = item.filePath || item.downloadPath;
if (link) {
videoDataMap.set(item.id.toString(), link);
}
});
}
}
// add button for each video
function injectUI() {
// find video containers
const entries = document.querySelectorAll('a.xexleWatchAFullpage');
entries.forEach(entry => {
const id = entry.getAttribute('data-id');
if (id && videoDataMap.has(id)) {
if (entry.querySelector('.force-unlock-btn')) return;
const realUrl = videoDataMap.get(id);
const btn = document.createElement('div');
btn.className = 'force-unlock-btn';
btn.innerHTML = '▶ FULL VIDEO';
btn.style.cssText = `
position: absolute;
top: 5px;
right: 5px;
background: #2ecc71;
color: white;
padding: 6px 10px;
border-radius: 4px;
font-weight: bold;
font-size: 11px;
z-index: 9999;
cursor: pointer;
box-shadow: 0px 2px 5px rgba(0,0,0,0.5);
`;
btn.onclick = (e) => {
e.preventDefault();
e.stopPropagation();
window.open(realUrl, '_blank');
};
entry.style.position = 'relative';
entry.appendChild(btn);
// Opcional: Quitar el blur de la imagen
const img = entry.querySelector('.list_blur');
if (img) {
img.classList.remove('list_blur');
img.style.filter = 'none';
}
}
});
}
// executes each 1.5s
setInterval(injectUI, 1500);
})();