This commit is contained in:
2023-11-11 21:07:44 +01:00
parent 0054f5da0e
commit 6e7410b088
60 changed files with 8809 additions and 1314 deletions

277
src/lib/match.ts Normal file
View File

@@ -0,0 +1,277 @@
import { unpack } from '~/lib/utils';
import { Hosters } from '~/lib/settings';
export enum Reliability {
HIGH,
NORMAL,
LOW
}
export interface Match {
name: string;
id: string;
reliability: Reliability;
domains: string[];
replace?: boolean;
regex: RegExp;
notice?: string;
match(match: RegExpMatchArray): Promise<string>;
}
export const Doodstream: Match = {
name: 'Doodstream',
id: 'doodstream',
reliability: Reliability.NORMAL,
domains: [
'doodstream.com',
'dood.pm',
'dood.ws',
'dood.wf',
'dood.cx',
'dood.sh',
'dood.watch',
'dood.to',
'dood.so',
'dood.la',
'dood.re',
'dood.yt',
'ds2play.com',
'dooood.com'
],
replace: true,
regex: /(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s,
match: async (match: RegExpMatchArray) => {
const response = await fetch(`https://${window.location.host}${match[1]}`, {
headers: {
Range: 'bytes=0-'
},
referrer: `https://${window.location.host}/e/${
window.location.pathname.split('/').slice(-1)[0]
}`
});
return `${await response.text()}1234567890${match[2]}${Date.now()}`;
}
};
export const DropLoad: Match = {
name: 'Dropload',
id: 'dropload',
reliability: Reliability.HIGH,
domains: ['dropload.ui'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
return unpacked.match(/(?<=file:").*(?=")/)[0];
}
};
export const Filemoon: Match = {
name: 'Filemoon',
id: 'filemoon',
reliability: Reliability.HIGH,
domains: ['filemoon.sx', 'filemoon.in'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
const unpacked = await unpack(match[0]);
return unpacked.match(/(?<=file:").*(?=")/)[0];
}
};
export const GoodStream: Match = {
name: 'Goodstream',
id: 'goodstream',
reliability: Reliability.NORMAL,
domains: ['goodstream.uno'],
regex: /(?<=file:\s+").*(?=")/g,
match: async (match: RegExpMatchArray) => {
return match[0];
}
};
export const Kwik: Match = {
name: 'Kwik',
id: 'kwik',
reliability: Reliability.HIGH,
domains: ['kwik.cx'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
return unpacked.match(/(?<=source=').*(?=')/)[0];
}
};
export const Mixdrop: Match = {
name: 'Mixdrop',
id: 'mixdrop',
reliability: Reliability.HIGH,
domains: ['mixdrop.co', 'mixdrop.to', 'mixdrop.ch', 'mixdrop.bz', 'mixdrop.gl'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
let url = unpacked.match(/(?<=MDCore.wurl=").*(?=")/)[0];
return `https:${url}`;
}
};
export const Mp4Upload: Match = {
name: 'Mp4Upload',
id: 'mp4upload',
reliability: Reliability.HIGH,
domains: ['mp4upload.com'],
replace: true,
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
return unpacked.match(/(?<=player.src\(").*(?=")/)[0];
}
};
export const Newgrounds: Match = {
name: 'Newgrounds',
id: 'newgrounds',
reliability: Reliability.HIGH,
domains: ['newgrounds.com'],
regex: /.*/gm,
match: async (match: RegExpMatchArray) => {
let id = window.location.pathname.split('/').slice(-1)[0];
let response = await fetch(`https://www.newgrounds.com/portal/video/${id}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
});
let json = await response.json();
return decodeURI(json['sources'][Object.keys(json['sources'])[0]][0]['src']);
}
};
export const Streamtape: Match = {
name: 'Streamtape',
id: 'streamtape',
reliability: Reliability.NORMAL,
domains: ['streamtape.com', 'streamtape.net', 'shavetape.cash'],
regex: /id=.*(?=')/gm,
match: async (match: RegExpMatchArray) => {
return `https://streamtape.com/get_video?${match.reverse()[0]}`;
}
};
export const Streamzz: Match = {
name: 'Streamzz',
id: 'streamzz',
reliability: Reliability.LOW,
domains: ['streamzz.to', 'streamz.ws'],
regex: /(?<=\|)\w{2,}/gm,
match: async (match: RegExpMatchArray) => {
return `https://get.${location.hostname.split('.')[0]}.tw/getlink-${
match.sort((a, b) => b.length - a.length)[0]
}.dll`;
}
};
export const SuperVideo: Match = {
name: 'Supervideo',
id: 'supervideo',
reliability: Reliability.HIGH,
domains: ['supervideo.tv'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
return unpacked.match(/(?<=file:").*(?=")/)[0];
}
};
export const Upstream: Match = {
name: 'Upstream',
id: 'upstream',
reliability: Reliability.HIGH,
domains: ['upstream.to'],
regex: /eval\(function\(p,a,c,k,e,d\).*?(?=\<\/script\>)/gms,
match: async (match: RegExpMatchArray) => {
let unpacked = await unpack(match[0]);
return unpacked.match(/(?<=file:").*(?=")/)[0];
}
};
export const Vidoza: Match = {
name: 'Vidoza',
id: 'vidoza',
reliability: Reliability.HIGH,
domains: ['vidoza.net'],
regex: /(?<=src:\s?").+?(?=")/gm,
match: async (match: RegExpMatchArray) => {
return match[0];
}
};
export const Voe: Match = {
name: 'Voe',
id: 'voe',
reliability: Reliability.HIGH,
domains: ['voe.sx'],
regex: /https?:\/\/\S*m3u8.+(?=')/gm,
match: async (match: RegExpMatchArray) => {
return match[0];
}
};
export const Vupload: Match = {
name: 'Vupload',
id: 'vupload',
reliability: Reliability.HIGH,
domains: ['vupload.com'],
regex: /(?<=src:\s?").+?(?=")/gm,
match: async (match: RegExpMatchArray) => {
return match[0];
}
};
export const matches = {
[Doodstream.id]: Doodstream,
[DropLoad.id]: DropLoad,
[Filemoon.id]: Filemoon,
[GoodStream.id]: GoodStream,
[Kwik.id]: Kwik,
[Mixdrop.id]: Mixdrop,
[Mp4Upload.id]: Mp4Upload,
[Newgrounds.id]: Newgrounds,
[Streamtape.id]: Streamtape,
[Streamzz.id]: Streamzz,
[SuperVideo.id]: SuperVideo,
[Upstream.id]: Upstream,
[Vidoza.id]: Vidoza,
[Voe.id]: Voe,
[Vupload.id]: Vupload
};
export async function getMatch(domain: string): Promise<Match | null> {
if (await Hosters.getAllDisabled()) {
return null;
}
for (const match of Object.values(matches)) {
if (
match.domains.indexOf(domain) !== -1 &&
!(await Hosters.getDisabled().then((d) => d.find((p) => p.id == match.id)))
) {
return match;
}
}
return null;
}

73
src/lib/settings.ts Normal file
View File

@@ -0,0 +1,73 @@
import browser from 'webextension-polyfill';
import type { Match } from '~/lib/match';
import { matches } from '~/lib/match';
export const Hosters = {
getDisabled: async () => {
const disabled = await storageGet<string[]>('hosters.disabled', []);
return disabled.map((id) => matches[id]).filter((m) => m !== undefined);
},
disable: async (match: Match) => {
const disabled = await storageGet('hosters.disabled', []);
const index = disabled.indexOf(match.id);
if (index === -1) {
disabled.push(match.id);
await storageSet('hosters.disabled', disabled);
}
},
enable: async (match: Match) => {
let disabled = await storageGet('hosters.disabled', []);
const index = disabled.indexOf(match.id);
if (index !== -1) {
disabled.splice(index, 1);
await storageSet('hosters.disabled', disabled);
}
},
getAllDisabled: async () => {
return await storageGet<boolean>('hosters.allDisabled', false);
},
disableAll: async () => {
await storageSet('hosters.allDisabled', true);
},
enableAll: async () => {
await storageSet('hosters.allDisabled', false);
}
};
export const Redirect = {
get: async (): Promise<Match | null> => {
return matches[await storageGet<string>('redirect')] || null;
},
set: async (match: Match) => {
await storageSet('redirect', match.id);
},
delete: async () => {
await storageDelete('redirect');
}
};
export const Other = {
getFf2mpv: async () => {
return await storageGet('other.ff2mpv', true);
},
setFf2mpv: async (enable: boolean) => {
await storageSet('other.ff2mpv', enable);
}
};
export async function storageGet<T>(key: string, defaultValue?: T): Promise<T | undefined> {
const entry = await browser.storage.local.get(key);
const value = entry[key];
return value === undefined ? defaultValue : value;
}
export async function storageSet<T>(key: string, value: T) {
const obj = {
[key]: value
};
await browser.storage.local.set(obj);
}
export async function storageDelete(key: string) {
await browser.storage.local.remove(key);
}

94
src/lib/utils.ts Normal file
View File

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