Skip to content

Instantly share code, notes, and snippets.

@re7BahWREsbrAY
Created July 12, 2022 01:36
  • Select an option

Select an option

vids.io download helper
// ==UserScript==
// @name vids.io download helper
// @match https://vids.io/videos/*
// @match https://*.vids.io/videos/*
// @grant none
// @version 1.0
// ==/UserScript==
//this userscript will do most of the work when you want to dl a video from vids.io
//all you have to do is download the m3u8 data through something like ffmpeg (youtube-dl didn't work for me), e.g. using the command shown below the DL button
async function main(){
const videoIframe = document.querySelector(".sproutvideo-player");
if(!videoIframe)
return;
const videoIframeHtml = await (await fetch(videoIframe.src)).text();
const videoIframeDoc = new DOMParser().parseFromString(videoIframeHtml, "text/html");
const videoDataElement = [...videoIframeDoc.head.childNodes].find(e => e.innerText?.startsWith("var dat = 'ey"));
const videoDataBase64 = videoDataElement.innerText.match(/var dat = '([a-zA-Z0-9\+\/\=]+)';/)[1];
const videoData = JSON.parse(atob(videoDataBase64));
const indexM3u8 = `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/index.m3u8?Policy=${videoData.signatures.m["CloudFront-Policy"]}&Signature=${videoData.signatures.m["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.m["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`;
const qualities = (await (await fetch(indexM3u8)).text()).match(/[0-9]+.m3u8/g);
const bestQuality = qualities[qualities.length - 1];
const videoM3u8 = `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/${bestQuality}?Policy=${videoData.signatures.m["CloudFront-Policy"]}&Signature=${videoData.signatures.m["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.m["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`;
let videoM3u8Data = (await (await fetch(videoM3u8)).text());
//replace key with full url
videoM3u8Data = videoM3u8Data.replace(/URI=\"[0-9]+.key\"/, `URI=\"https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/${bestQuality.replace(".m3u8", ".key")}?Policy=${videoData.signatures.k["CloudFront-Policy"]}&Signature=${videoData.signatures.k["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.k["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}\"`);
//replace .ts files with full url
videoM3u8Data = videoM3u8Data.replace(/[0-9]+_[0-9]+.ts/g, `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/$&?Policy=${videoData.signatures.t["CloudFront-Policy"]}&Signature=${videoData.signatures.t["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.t["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`);
const filename = document.querySelector(".video-title h1").innerText.replace(/[^a-z0-9]/gi, "_");
const dlElement = document.createElement("a");
dlElement.href = window.URL.createObjectURL(new Blob([videoM3u8Data], {type: "application/x-mpegURL"}));
dlElement.download = `${filename}.m3u8`;
dlElement.innerText = "Click to download";
dlElement.style = "display: flex;justify-content: center;height: 40px;font-weight: bold;background: #9234f0;width: 200px;color: white;align-items: center;margin: auto;margin-bottom: 20px;";
document.querySelector(".video-info").appendChild(dlElement);
const infoElement = document.createElement("div");
infoElement.style = "display: flex;justify-content: center;";
const infoTextElement = document.createElement("span");
infoTextElement.innerHTML = "What to do next:<br><br>" +
"DL m3u8 using ffmpeg:<br>" +
`<b style=\"font-weight: bold;\">ffmpeg -protocol_whitelist file,http,https,tcp,tls,crypto -i "${filename}.m3u8" "${filename}.mp4"<b>`;
infoElement.appendChild(infoTextElement);
document.querySelector(".video-info").appendChild(infoElement);
}
main();
@johnwick1127
Copy link
Copy Markdown

How to use it ?

@amoliski
Copy link
Copy Markdown

amoliski commented Aug 28, 2025

Update to fix recent changes:

// ==UserScript==
// @name        vids.io download helper
// @match       https://vids.io/videos/*
// @match       https://*.vids.io/videos/*
// @grant       none
// @version     1.0
// ==/UserScript==

//this userscript will do most of the work when you want to dl a video from vids.io
//all you have to do is download the m3u8 data through something like ffmpeg (youtube-dl didn't work for me), e.g. using the command shown below the DL button

async function main(){
  const videoIframe = document.querySelector(".sproutvideo-player");

  if(!videoIframe) { return }

  const videoIframeHtml = await (await fetch(videoIframe.src)).text();

  const videoIframeDoc = new DOMParser().parseFromString(videoIframeHtml, "text/html");

  const videoDataElement = [...videoIframeDoc.head.childNodes].find(e => e.innerText?.startsWith("const videoInfo ="));
  const videoDataBase64 = videoDataElement.innerText.match(/const videoInfo = '([a-zA-Z0-9\+\/\=]+)';/)[1];
  const videoData = JSON.parse(atob(videoDataBase64));

  const indexM3u8 = `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/index.m3u8?Policy=${videoData.signatures.m["CloudFront-Policy"]}&Signature=${videoData.signatures.m["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.m["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`;

  const qualities = (await (await fetch(indexM3u8)).text()).match(/[0-9]+.m3u8/g);
  const bestQuality = qualities[qualities.length - 1];

  const videoM3u8 = `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/${bestQuality}?Policy=${videoData.signatures.m["CloudFront-Policy"]}&Signature=${videoData.signatures.m["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.m["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`;
  let videoM3u8Data = (await (await fetch(videoM3u8)).text());
  //replace key with full url
  videoM3u8Data = videoM3u8Data.replace(/URI=\"[0-9]+.key\"/, `URI=\"https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/${bestQuality.replace(".m3u8", ".key")}?Policy=${videoData.signatures.k["CloudFront-Policy"]}&Signature=${videoData.signatures.k["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.k["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}\"`);
  //replace .ts files with full url
  videoM3u8Data = videoM3u8Data.replace(/[0-9]+_[0-9]+.ts/g, `https://hls2.videos.sproutvideo.com/${videoData.s3_user_hash}/${videoData.s3_video_hash}/video/$&?Policy=${videoData.signatures.t["CloudFront-Policy"]}&Signature=${videoData.signatures.t["CloudFront-Signature"]}&Key-Pair-Id=${videoData.signatures.t["CloudFront-Key-Pair-Id"]}&sessionID=${videoData.sessionID}`);

  const filename = document.querySelector(".video-title h2").innerText.replace(/[^a-z0-9]/gi, "_");
  const dlElement = document.createElement("a");
  dlElement.href = window.URL.createObjectURL(new Blob([videoM3u8Data], {type: "application/x-mpegURL"}));
  dlElement.download = `${filename}.m3u8`;
  dlElement.innerText = "Click to download";
  dlElement.style = "display: flex;justify-content: center;height: 40px;font-weight: bold;background: #9234f0;width: 200px;color: white;align-items: center;margin: auto;margin-bottom: 20px;";
  document.querySelector(".video-info").appendChild(dlElement);
  const infoElement = document.createElement("div");
  infoElement.style = "display: flex;justify-content: center;";
  const infoTextElement = document.createElement("span");
  infoTextElement.innerHTML = "What to do next:<br><br>" +
    "DL m3u8 using ffmpeg:<br>" +
    `<b style=\"font-weight: bold;\">ffmpeg -protocol_whitelist file,http,https,tcp,tls,crypto -i "${filename}.m3u8" "${filename}.mp4"<b>`;
  infoElement.appendChild(infoTextElement);
  document.querySelector(".video-info").appendChild(infoElement);
}

main();

@KHs231243532
Copy link
Copy Markdown

KHs231243532 commented Nov 23, 2025

It worked for a while and now it stopped. Any update?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment