您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically download HLS streams from Privacy
当前为
// ==UserScript== // @name Privacy HLS Stream Downloader // @namespace http://tampermonkey.net/ // @license GPL-3.0 // @version 2024-10-16.4 // @description Automatically download HLS streams from Privacy // @author Rvnsxmwvrx // @match https://privacy.com.br/* // @icon https://www.google.com/s2/favicons?sz=64&domain=privacy.com.br // @grant none // ==/UserScript== (function () { "use strict"; function filterHLS(urlBegin, text) { let rtn = []; for (let line of text.split("\n")) { if (line.startsWith("#")) continue; rtn.push(urlBegin + line); } let fhd = rtn.filter((e) => e.includes("1080p")); if (fhd) return fhd; let hd = rtn.filter((e) => e.includes("720p")); if (hd) return hd; return rtn[0]; return rtn; } async function downloadFiles(button, urls) { for (let url of urls) { let start = url.lastIndexOf("/"); let filename = url.substring(start); let split = url.indexOf("hls/") + 4; let urlBegin = url.substring(0, split); await fetch(url) .then((response) => response.text()) .then(async (text) => { const fileContent = text; let video = filterHLS(urlBegin, text); await helper(button, urlBegin, video); }) .catch((err) => console.error("Error downloading file:", err)); } } async function helper(button, beginUrl, url) { fetch(url) .then((response) => response.text()) .then(async (text) => { console.log(text); let tsFiles = filterHLS(beginUrl, text); await downloadVideos(button, tsFiles); }) .catch((err) => console.error("Error downloading file:", err)); } async function downloadVideos(button, tsFiles) { const combinedBuffers = []; const end = tsFiles[0].indexOf("--") const name = tsFiles[0].substring(0, end) for (const tsFile of tsFiles) { const response = await fetch(tsFile); if (!response.ok) { throw new Error(`Failed to fetch ${tsFile}: ${response.statusText}`); } const arrayBuffer = await response.arrayBuffer(); combinedBuffers.push(arrayBuffer); let percent = (combinedBuffers.length / tsFiles.length) * 100 button.innerText = "Downloading (" + percent.toPrecision(2) + "%)" } button.innerText = "Download Videos" console.log(combinedBuffers.length); const videoBlob = new Blob(combinedBuffers, { type: "video/mp2t" }); const url = URL.createObjectURL(videoBlob); const downloadLink = document.createElement("a"); downloadLink.href = url; downloadLink.download = name + ".ts"; downloadLink.textContent = "Download Combined Video"; document.body.appendChild(downloadLink); downloadLink.click(); URL.revokeObjectURL(url); } let allVideos = new Set(); function find_docs() { let elements = document.querySelectorAll("privacy-web-mediahub-carousel"); for (let element of elements) { let mediasStr = element.getAttribute("medias"); let medias = collectObjects(mediasStr); let videos = medias .filter((e) => e.url && e.url.endsWith(".m3u8") && !allVideos.has(e.url)) .map((e) => e.url); videos.forEach((e) => allVideos.add(e)); if (videos.length < 1) continue; let start = videos[0].indexOf("hls/") + 4 let end = videos[0].indexOf("--") let buttonId = videos[0].substring(start, end) console.log(buttonId) let button = document.createElement("button"); button.innerText = "Download Videos"; button.setAttribute("id", buttonId) button.addEventListener("click", function () { downloadFiles(button, videos); }); element.shadowRoot.appendChild(button); } } function collectObjects(mediasStr) { let start = 0; let offset = 0; let objects = []; for (let i = 0; i < mediasStr.length; i++) { let char = mediasStr[i]; if (char == "{") { start = i; } else if (char == "}") { let objStr = mediasStr.substring(start, start + offset + 1); objects.push(JSON.parse(objStr)); offset = 0; } else { offset += 1; } } return objects; } setInterval(() => find_docs(), 1000); })();