Add Kwik and improve reliabilty for several other hosters (#12)

* add Kwik, use unpacker to improve reliabilty

* use packer for filemoon

* use packer for upstream

* Update README.md

* Revert "Update README.md"

This reverts commit affb6000968beb798423a5403508215b7f6e4670.

* add kwik to hosters in readme

* unpack without using eval
This commit is contained in:
sdaqo 2023-04-28 18:19:01 +02:00 committed by GitHub
parent 7d8d8b6614
commit a920832945
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 133 additions and 30 deletions

View File

@ -83,6 +83,7 @@ Install the addon directly from the [firefox addon store](https://addons.mozilla
| [vidstream.pro](https://vidstream.pro) | ❌ | Reverse engineering the site costs too much time ([#5](https://github.com/ByteDream/stream-bypass/issues/5)) |
| [voe.sx](https://voe.sx) | ✔ | |
| [vupload.com](https://vupload.com) | ✔ | |
| [kwik.cx](https://kwik.cx) | ✔ | |
- ✔️: Everything ok.
- ⚠: Included in the addon but will probably not work. See `Note` in this case, an explanation why will stand there in the most cases.

View File

@ -2,6 +2,7 @@ import {getMatch} from "./match/match";
import {storageDelete, storageGet, storageSet} from "./store/store";
import {Match} from "./match/matches";
chrome.webRequest.onBeforeRedirect.addListener(async details => {
// check if redirects origins from a previous redirect
if (await storageGet('redirect') === undefined) {

View File

@ -21,7 +21,7 @@ async function main() {
const url = await match.match(re)
if (match.replace && !url.endsWith('.m3u8')) {
if (match.replace && !url.includes('.m3u8')) {
const player = document.createElement('video')
player.style.width = '100%'
player.style.height = '100%'

View File

@ -3,7 +3,7 @@
"name": "Stream Bypass",
"author": "ByteDream",
"description": "A multi-browser addon / extension for multiple streaming providers which redirects directly to the source video.",
"version": "2.1.6",
"version": "2.1.7",
"homepage_url": "https://github.com/ByteDream/stream-bypass",
"browser_specific_settings": {
"gecko": {

View File

@ -1,3 +1,5 @@
import {unPack} from "./unpack";
export enum Reliability {
HIGH,
NORMAL,
@ -55,57 +57,51 @@ class Filemoon implements Match {
domains = [
'filemoon.sx'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
regex = new RegExp(/eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms)
async match(match: RegExpMatchArray): Promise<string> {
const start_idx = match.indexOf('moon')
const prefix = `${match[start_idx]}-${match[start_idx-1]}-${match[start_idx-2]}-${match[start_idx-3]}`
const time = match.find(m => m.length === 10 && !isNaN(parseInt(m)))
const offset = !isNaN(parseInt(match[start_idx-12])) && parseInt(match[start_idx-12]).toString().length == match[start_idx-12].length ? 0 : -1
return `https://${prefix}.filemoon.${match[start_idx-4]}/${match[start_idx-5]}/${match[start_idx-6]}/${match[start_idx-7]}/${match[start_idx-8]}/master.m3u8?t=${match[start_idx-11]}${offset != 0 ? `-${match[start_idx-12]}` : ''}&s=${time}&e=${match[start_idx + offset - 12]}&sp=${match[start_idx + offset - 18]}`
let unpacked = await unPack(match[0])
let url = unpacked.match(/(?<=file:").*(?=")/)[0]
console.log(url)
return url
}
}
class Mixdrop implements Match {
name = 'Mixdrop'
id = 'mixdrop'
reliability = Reliability.NORMAL
reliability = Reliability.HIGH
domains = [
'mixdrop.co',
'mixdrop.to',
'mixdrop.ch',
'mixdrop.bz'
'mixdrop.bz',
'mixdrop.gl'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
regex = new RegExp(/eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms)
async match(match: RegExpMatchArray): Promise<string> {
const prefix = /(?<=\/\/)[a|s](?=-)/.exec(document.body.innerHTML)[0]
const subdomain = match[1].length < match[2].length ? match[1] : match[2]
const domain = match.slice().sort((a, b) => b.length - a.length).find(m => /^[a-z]+$/.test(m))
const id = match[1].length > match[2].length ? match[1] : match[2]
const tld = match.find(m => ['net', 'io', 'to', 'sx', 'com'].indexOf(m) !== -1)
const s = match.slice().sort((a, b) => b.length - a.length).slice(1)[0]
const e_t = match.find(m => m.length === 10 && !isNaN(parseInt(m)))
return `https://${prefix}-${subdomain}.${domain}.${tld}/v/${id}.mp4?s=${s}&e=${e_t}&_t=${e_t}`
let unpacked = await unPack(match[0])
let url = unpacked.match(/(?<=MDCore.wurl=").*(?=")/)[0]
return `https:${url}`
}
}
class Mp4Upload implements Match {
name = 'Mp4Upload'
id = 'mp4upload'
reliability = Reliability.NORMAL
reliability = Reliability.HIGH
domains = [
'mp4upload.com'
]
replace = true
regex = new RegExp(/(?<=\|)\w{2,}/gm)
regex = new RegExp(/eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms)
async match(match: RegExpMatchArray): Promise<string> {
let id = match.slice().reduce((a, b) => a.length >= b.length ? a : b)
return `https://www4.mp4upload.com:282/d/${id}/video.mp4`
let unpacked = await unPack(match[0])
console.log(unpacked)
let url = unpacked.match(/(?<=player.src\(").*(?=")/)[0]
return url
}
}
@ -162,14 +158,16 @@ class Streamzz implements Match {
class Upstream implements Match {
name = 'Upstream'
id = 'upstream'
reliability = Reliability.NORMAL
reliability = Reliability.HIGH
domains = [
'upstream.to'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
regex = new RegExp(/eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms)
async match(match: RegExpMatchArray): Promise<string> {
return `https://${match[49]}.upstreamcdn.co/hls/${match[148]}/master.m3u8`
let unpacked = await unPack(match[0])
let url = unpacked.match(/(?<=file:").*(?=")/)[0]
return url
}
}
@ -215,6 +213,24 @@ class Vupload implements Match {
}
}
class Kwik implements Match {
name = 'Kwik'
id = 'kwik'
reliability = Reliability.HIGH
domains = [
'kwik.cx'
]
regex = new RegExp(/eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms)
async match(match: RegExpMatchArray): Promise<string> {
console.log(match[0]);
let unpacked = await unPack(match[0])
let url = unpacked.match(/(?<=source=').*(?=')/)[0]
console.log(url)
return url
}
}
export const matches = [
new Doodstream(),
new Filemoon(),
@ -226,5 +242,6 @@ export const matches = [
new Upstream(),
new Vidoza(),
new Voe(),
new Vupload()
new Vupload(),
new Kwik()
]

84
src/match/unpack.ts Normal file
View File

@ -0,0 +1,84 @@
function runInPageContext(to_execute: string) {
// Adapted from: https://github.com/arikw/extension-page-context
const doc = document;
// test that we are running with the allow-scripts permission
try { window.sessionStorage; } catch (ignore) { return null; }
// returned value container
const resultMessageId = parseInt('' + Math.floor((Math.random() * 100) + 1) + ((new Date()).getTime()));
// prepare script container
let scriptElm = doc.createElement('script');
scriptElm.setAttribute("type", "application/javascript");
const code = `
(
async function () {
const response = {
id: ${resultMessageId}
};
try {
response.result = JSON.stringify(await (${to_execute})() ); // run script
} catch(err) {
response.error = JSON.stringify(err);
}
window.postMessage(response, '*');
}
)();
`;
// inject the script
scriptElm.textContent = code;
// run the script
doc.documentElement.appendChild(scriptElm);
// clean up script element
scriptElm.remove();
// create a "flat" promise
let resolve, reject;
const promise = new Promise((res, rej) => { resolve = res; reject = rej; });
// resolve on result
function onResult(event) {
const data = Object(event.data);
if (data.id === resultMessageId) {
window.removeEventListener('message', onResult);
if (data.error !== undefined) {
return reject(JSON.parse(data.error));
}
return resolve((data.result !== undefined) ? JSON.parse(data.result) : undefined);
}
}
window.addEventListener('message', onResult);
return promise;
}
export const unPack = async (packed: String): Promise<string> => {
// Adapted from http://matthewfl.com/unPacker.html by matthew@matthewfl.com
let context = `
{
eval: function (c) {
packed = c;
},
window: {},
document: {}
}
`
const to_execute = `function() { let packed = ""; with(${context}) { ` + packed + '}; return packed; }'
const res = await runInPageContext(to_execute);
return (res+"").replace(/;/g, ";\n").replace(/{/g, "\n{\n").replace(/}/g, "\n}\n").replace(/\n;\n/g, ";\n").replace(/\n\\n/g, "\n");
}