mirror of
https://github.com/bytedream/stream-bypass.git
synced 2025-05-11 21:25:12 +02:00
Compare commits
36 Commits
Author | SHA1 | Date | |
---|---|---|---|
607326e6d6 | |||
47f6de2de8 | |||
d159fb0aa4 | |||
290733a85a | |||
84eb32ab61 | |||
927a4e3ae3 | |||
5926177920 | |||
9a29316641 | |||
c300125f64 | |||
59f2ffec57 | |||
6dff691c25 | |||
c4085f9ac8 | |||
422702b16f | |||
c3dad3681c | |||
6eb3259ec5 | |||
68e445a738 | |||
e864bc6100 | |||
3ac73ac3b4 | |||
6aaf960c28 | |||
8a13dea681 | |||
8d575241fe | |||
50f400b8b9 | |||
f6fcfd354a | |||
c081127d35 | |||
416fceba88 | |||
a9cf03c176 | |||
8852318483 | |||
7067aaf4a0 | |||
bf723e2ed6 | |||
9c80362a1c | |||
ae738ff32f | |||
16d4f2956a | |||
|
f6c6102436 | ||
|
f1525817b1 | ||
1e1d8cdfa6 | |||
47eed2d12b |
14
.github/workflows/ci.yml
vendored
14
.github/workflows/ci.yml
vendored
@ -9,12 +9,12 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install nodejs
|
- name: Install nodejs
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 22
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -32,12 +32,12 @@ jobs:
|
|||||||
- manifest_version: 3
|
- manifest_version: 3
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install nodejs
|
- name: Install nodejs
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 22
|
||||||
cache: 'npm'
|
cache: 'npm'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@ -49,7 +49,7 @@ jobs:
|
|||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
- name: Upload
|
- name: Upload
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: stream-bypass-mv${{ matrix.manifest_version }}
|
name: stream-bypass-mv${{ matrix.manifest_version }}
|
||||||
path: ./dist
|
path: ./dist
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"useTabs": true,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"printWidth": 100,
|
|
||||||
"plugins": ["prettier-plugin-svelte"],
|
|
||||||
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
|
|
||||||
}
|
|
17
.prettierrc.cjs
Normal file
17
.prettierrc.cjs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// @ts-check
|
||||||
|
|
||||||
|
/** @type {import("prettier").Config} */
|
||||||
|
module.exports = {
|
||||||
|
useTabs: true,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'none',
|
||||||
|
printWidth: 100,
|
||||||
|
plugins: ['prettier-plugin-svelte', '@ianvs/prettier-plugin-sort-imports'],
|
||||||
|
/* prettier-plugin-svelte */
|
||||||
|
overrides: [{ files: '*.svelte', options: { parser: 'svelte' } }],
|
||||||
|
/* @ianvs/prettier-plugin-sort-imports */
|
||||||
|
importOrder: ['^~/(.*)$', '^./(.*)$', ''],
|
||||||
|
importOrderParserPlugins: ['typescript'],
|
||||||
|
importOrderTypeScriptVersion: '5.0.0',
|
||||||
|
importOrderCaseSensitive: false
|
||||||
|
};
|
40
README.md
40
README.md
@ -79,25 +79,27 @@ The best way to install the extension are the official browser extension stores:
|
|||||||
|
|
||||||
## 📜 Supported websites
|
## 📜 Supported websites
|
||||||
|
|
||||||
| Site | Firefox & Firefox for Android | Chrome & Chromium based |
|
| Site | Firefox & Firefox for Android | Chrome & Chromium based |
|
||||||
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
|
| --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
|
||||||
| [dropload.io](https://dropload.io) | ✔ | ✔ |
|
| [dropload.io](https://dropload.io) | ✔ | ✔ |
|
||||||
| [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | ✔️ | ⚠ (redirect probably required) |
|
| [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | ✔ | ⚠ (redirect probably required) |
|
||||||
| [filemoon.to](https://filemoon.to) | ✔ | ✔ |
|
| [filemoon.to](https://filemoon.to) | ✔ | ✔ |
|
||||||
| [goodstream.uno](https://goodstream.uno) | ✔ | ✔ |
|
| [goodstream.uno](https://goodstream.uno) | ✔ | ✔ |
|
||||||
| [mixdrop.co](https://mixdrop.co) | ✔ ️ | ✔ |
|
| [kwik.cx](https://kwik.cx) | ✔ | ✔ |
|
||||||
| [mp4upload.com](https://mp4upload.com) | ✔ | ✔ |
|
| [loadx.ws](https://loadx.ws) | ✔ | ❌ (background request always required) |
|
||||||
| [newgrounds.com](https://newgrounds.com) | ✔ | ✔ |
|
| [luluvdo.com](https://luluvdo.com) | ✔ | ❌ (background request always required) |
|
||||||
| [streama2z.com](https://streama2z.com) | ✔ | ❌ (redirect always required) |
|
| [mixdrop.co](https://mixdrop.co) | ✔ ️ | ✔ |
|
||||||
| [streamtape.com](https://streamtape.com) | ⚠ (correct video url can't always be extract, retrying/reloading the page might fix it) | ⚠ (correct video url can't always be extract, retrying/reloading the page might fix it) |
|
| [mp4upload.com](https://mp4upload.com) | ✔ | ✔ |
|
||||||
| [streamzz.to](https://streamzz.to) / [streamz.ws](https://streamz.ws) | ✔ | ✔ |
|
| [newgrounds.com](https://newgrounds.com) | ✔ | ✔ |
|
||||||
| [supervideo.tv](https://supervideo.tv) | ✔ | ✔ |
|
| [streama2z.com](https://streama2z.com) | ✔ | ❌ (redirect always required) |
|
||||||
| [upstream.to](https://upstream.to) | ✔ | ✔ |
|
| [streamtape.com](https://streamtape.com) | ⚠ (correct video url can't always be extract, retrying/reloading the page might fix it) | ⚠ (correct video url can't always be extract, retrying/reloading the page might fix it) |
|
||||||
| [vidmoly.to](https://vidmoly.me) | ✔ | ✔ |
|
| [streamzz.to](https://streamzz.to) / [streamz.ws](https://streamz.ws) | ✔ | ✔ |
|
||||||
| [vidoza.net](https://vidoza.net) | ⚠ (doesn't always work the first time, retrying/reloading the page one or two times fixes it) | ⚠ (doesn't always work the first time, retrying/reloading the page one or two times fixes it) |
|
| [supervideo.tv](https://supervideo.tv) | ✔ | ✔ |
|
||||||
| [voe.sx](https://voe.sx) | ✔ | ❌ (redirect always required) |
|
| [upstream.to](https://upstream.to) | ✔ | ✔ |
|
||||||
| [vupload.com](https://vupload.com) | ✔ | ✔ |
|
| [vidmoly.to](https://vidmoly.me) | ✔ | ✔ |
|
||||||
| [kwik.cx](https://kwik.cx) | ✔ | ✔ |
|
| [vidoza.net](https://vidoza.net) | ✔ | ✔ |
|
||||||
|
| [voe.sx](https://voe.sx) | ✔ | ❌ (redirect always required) |
|
||||||
|
| [vupload.com](https://vupload.com) | ✔ | ✔ |
|
||||||
|
|
||||||
- ✔️: Everything ok.
|
- ✔️: Everything ok.
|
||||||
- ⚠: Works with limitations.
|
- ⚠: Works with limitations.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import prettier from 'eslint-config-prettier';
|
|
||||||
import js from '@eslint/js';
|
import js from '@eslint/js';
|
||||||
|
import prettier from 'eslint-config-prettier';
|
||||||
import svelte from 'eslint-plugin-svelte';
|
import svelte from 'eslint-plugin-svelte';
|
||||||
import ts from 'typescript-eslint';
|
import ts from 'typescript-eslint';
|
||||||
|
|
||||||
|
3221
package-lock.json
generated
3221
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
37
package.json
37
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stream-bypass",
|
"name": "stream-bypass",
|
||||||
"version": "3.1.1",
|
"version": "3.1.6",
|
||||||
"displayName": "Stream Bypass",
|
"displayName": "Stream Bypass",
|
||||||
"author": "bytedream",
|
"author": "bytedream",
|
||||||
"description": "Multi-browser addon for multiple streaming providers which redirects directly to the source video",
|
"description": "Multi-browser addon for multiple streaming providers which redirects directly to the source video",
|
||||||
@ -11,8 +11,8 @@
|
|||||||
"serve:firefox": "web-ext run --start-url \"about:debugging#/runtime/this-firefox\" --source-dir ./dist/",
|
"serve:firefox": "web-ext run --start-url \"about:debugging#/runtime/this-firefox\" --source-dir ./dist/",
|
||||||
"serve:chrome": "web-ext run -t chromium --start-url \"https://example.com\" --source-dir ./dist/",
|
"serve:chrome": "web-ext run -t chromium --start-url \"https://example.com\" --source-dir ./dist/",
|
||||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||||
"lint": "prettier --check --plugin prettier-plugin-svelte . && eslint .",
|
"lint": "prettier --check . && eslint .",
|
||||||
"format": "prettier --write --plugin prettier-plugin-svelte .",
|
"format": "prettier --write .",
|
||||||
"release:firefox": "MANIFEST_VERSION=2 vite build --outDir release/firefox",
|
"release:firefox": "MANIFEST_VERSION=2 vite build --outDir release/firefox",
|
||||||
"release:chrome": "MANIFEST_VERSION=3 vite build --outDir release/chrome"
|
"release:chrome": "MANIFEST_VERSION=3 vite build --outDir release/chrome"
|
||||||
},
|
},
|
||||||
@ -25,26 +25,27 @@
|
|||||||
"url": "https://github.com/bytedream/stream-bypass/issues"
|
"url": "https://github.com/bytedream/stream-bypass/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||||
"@samrum/vite-plugin-web-extension": "^5.1.1",
|
"@samrum/vite-plugin-web-extension": "^5.1.1",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.2",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tsconfig/svelte": "^5.0.4",
|
"@tsconfig/svelte": "^5.0.4",
|
||||||
"@types/chrome": "^0.0.287",
|
"@types/chrome": "^0.0.320",
|
||||||
"@types/firefox-webext-browser": "^120.0.4",
|
"@types/firefox-webext-browser": "^120.0.4",
|
||||||
"eslint": "^9.17.0",
|
"eslint": "^9.26.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^10.1.3",
|
||||||
"eslint-plugin-svelte": "^2.46.1",
|
"eslint-plugin-svelte": "^3.5.1",
|
||||||
"hls.js": "^1.5.17",
|
"hls.js": "^1.6.2",
|
||||||
"prettier": "^3.4.2",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-svelte": "^3.3.2",
|
"prettier-plugin-svelte": "^3.3.3",
|
||||||
"sass": "^1.83.0",
|
"sass": "^1.87.0",
|
||||||
"svelte": "^5.14.0",
|
"svelte": "^5.28.2",
|
||||||
"svelte-check": "^4.1.1",
|
"svelte-check": "^4.1.7",
|
||||||
"svelte-preprocess": "^6.0.3",
|
"svelte-preprocess": "^6.0.3",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.8.3",
|
||||||
"typescript-eslint": "^8.18.0",
|
"typescript-eslint": "^8.32.0",
|
||||||
"vite": "^6.0.3",
|
"vite": "^6.3.5",
|
||||||
"web-ext": "^8.3.0"
|
"web-ext": "^8.6.0"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"type": "module"
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import './shared';
|
import './shared';
|
||||||
|
|
||||||
import type { Match } from '~/lib/match';
|
import { getMatch, type Match } from '~/lib/match';
|
||||||
import { Redirect, UrlReferer } from '~/lib/settings';
|
import { Redirect, UrlReferer } from '~/lib/settings';
|
||||||
import { getMatch } from '~/lib/match';
|
|
||||||
|
|
||||||
chrome.webRequest.onBeforeSendHeaders.addListener(
|
chrome.webRequest.onBeforeSendHeaders.addListener(
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import type { Match } from '~/lib/match';
|
import { getMatch, MatchMediaType, type Match } from '~/lib/match';
|
||||||
import { getMatch } from '~/lib/match';
|
|
||||||
import { Other, Redirect } from '~/lib/settings';
|
import { Other, Redirect } from '~/lib/settings';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@ -35,13 +34,28 @@ async function main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let url: string | null;
|
let url: string | null;
|
||||||
|
let urlType: MatchMediaType | null;
|
||||||
try {
|
try {
|
||||||
url = await match.match(re);
|
const matchResult = await match.match(re);
|
||||||
|
if (matchResult && typeof matchResult === 'string') {
|
||||||
|
url = matchResult;
|
||||||
|
urlType = url.includes('.m3u8') ? MatchMediaType.Hls : MatchMediaType.Native;
|
||||||
|
} else if (matchResult && typeof matchResult === 'object') {
|
||||||
|
if (MatchMediaType.Hls in matchResult) {
|
||||||
|
url = matchResult[MatchMediaType.Hls];
|
||||||
|
urlType = MatchMediaType.Hls;
|
||||||
|
} else if (MatchMediaType.Native in matchResult) {
|
||||||
|
url = matchResult[MatchMediaType.Native];
|
||||||
|
urlType = MatchMediaType.Native;
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!url) {
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
if (!url || !urlType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +64,7 @@ async function main() {
|
|||||||
await chrome.runtime.sendMessage({ action: 'ff2mpv', url: url });
|
await chrome.runtime.sendMessage({ action: 'ff2mpv', url: url });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match.replace && !url.includes('.m3u8')) {
|
if (match.replace && urlType != MatchMediaType.Hls) {
|
||||||
// this destroys all intervals that may spawn popups or events
|
// this destroys all intervals that may spawn popups or events
|
||||||
let intervalId = window.setInterval(() => {}, 0);
|
let intervalId = window.setInterval(() => {}, 0);
|
||||||
while (intervalId--) {
|
while (intervalId--) {
|
||||||
@ -81,7 +95,7 @@ async function main() {
|
|||||||
chrome.runtime.getURL(
|
chrome.runtime.getURL(
|
||||||
`src/entries/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}&domain=${
|
`src/entries/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}&domain=${
|
||||||
window.location.hostname
|
window.location.hostname
|
||||||
}`
|
}&type=${urlType}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { play } from '~/entries/player/player';
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
import { play } from '~/entries/player/player';
|
||||||
|
|
||||||
let errorMessage: string | null = $state(null);
|
let errorMessage: string | null = $state(null);
|
||||||
|
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import Player from '~/entries/player/Player.svelte';
|
|
||||||
import { mount } from 'svelte';
|
import { mount } from 'svelte';
|
||||||
|
import Player from '~/entries/player/Player.svelte';
|
||||||
|
|
||||||
mount(Player, {
|
mount(Player, {
|
||||||
target: document.body
|
target: document.body
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { matches } from '~/lib/match';
|
|
||||||
import Hls from 'hls.js';
|
import Hls from 'hls.js';
|
||||||
|
import { matches, MatchMediaType } from '~/lib/match';
|
||||||
import { UrlReferer } from '~/lib/settings';
|
import { UrlReferer } from '~/lib/settings';
|
||||||
|
|
||||||
async function playNative(url: string, domain: string, videoElem: HTMLVideoElement) {
|
async function playNative(url: string, domain: string, videoElem: HTMLVideoElement) {
|
||||||
@ -31,6 +31,7 @@ export async function play(videoElem: HTMLVideoElement) {
|
|||||||
const id = urlQuery.get('id') as string;
|
const id = urlQuery.get('id') as string;
|
||||||
const url = decodeURIComponent(urlQuery.get('url') as string);
|
const url = decodeURIComponent(urlQuery.get('url') as string);
|
||||||
const domain = urlQuery.get('domain') as string;
|
const domain = urlQuery.get('domain') as string;
|
||||||
|
const type = urlQuery.get('type') as MatchMediaType;
|
||||||
|
|
||||||
const match = matches[id];
|
const match = matches[id];
|
||||||
if (match === undefined) {
|
if (match === undefined) {
|
||||||
@ -38,9 +39,9 @@ export async function play(videoElem: HTMLVideoElement) {
|
|||||||
}
|
}
|
||||||
document.title = `Stream Bypass (${domain})`;
|
document.title = `Stream Bypass (${domain})`;
|
||||||
|
|
||||||
if (new URL(url).pathname.endsWith('.m3u8')) {
|
if (type === MatchMediaType.Hls) {
|
||||||
await playHls(url, domain, videoElem);
|
await playHls(url, domain, videoElem);
|
||||||
} else {
|
} else if (type === MatchMediaType.Native) {
|
||||||
await playNative(url, domain, videoElem);
|
await playNative(url, domain, videoElem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { type Match, matches } from '~/lib/match';
|
import { matches, type Match } from '~/lib/match';
|
||||||
import { Hosters, Other } from '~/lib/settings';
|
import { Hosters, Other } from '~/lib/settings';
|
||||||
import Toggle from './toggle.svelte';
|
import Toggle from './toggle.svelte';
|
||||||
|
|
||||||
@ -43,7 +43,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
{#each hosters as hoster, i}
|
{#each hosters as hoster, i (hoster.id)}
|
||||||
<label for="hoster-{i}" style="cursor: {hostersEnabled ? 'pointer' : 'default'}"
|
<label for="hoster-{i}" style="cursor: {hostersEnabled ? 'pointer' : 'default'}"
|
||||||
>{hoster.name}</label
|
>{hoster.name}</label
|
||||||
>
|
>
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body style="overflow-y: scroll">
|
<body style="overflow-y: scroll">
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import Popup from '~/entries/popup/Popup.svelte';
|
|
||||||
import { mount } from 'svelte';
|
import { mount } from 'svelte';
|
||||||
|
import Popup from '~/entries/popup/Popup.svelte';
|
||||||
|
|
||||||
mount(Popup, {
|
mount(Popup, {
|
||||||
target: document.body
|
target: document.body
|
||||||
|
178
src/lib/match.ts
178
src/lib/match.ts
@ -1,5 +1,6 @@
|
|||||||
import { unpack } from './utils';
|
|
||||||
import { Hosters, Redirect, TmpHost } from './settings';
|
import { Hosters, Redirect, TmpHost } from './settings';
|
||||||
|
import { lastPathSegment } from './util/extract';
|
||||||
|
import { unpack } from './util/userspace';
|
||||||
|
|
||||||
export interface Match {
|
export interface Match {
|
||||||
name: string;
|
name: string;
|
||||||
@ -9,7 +10,19 @@ export interface Match {
|
|||||||
regex: RegExp[];
|
regex: RegExp[];
|
||||||
notice?: string;
|
notice?: string;
|
||||||
|
|
||||||
match(match: RegExpMatchArray): Promise<string | null>;
|
match(
|
||||||
|
match: RegExpMatchArray
|
||||||
|
): Promise<
|
||||||
|
string | { [MatchMediaType.Hls]: string } | { [MatchMediaType.Native]: string } | null
|
||||||
|
>;
|
||||||
|
|
||||||
|
// allow other properties that may be implemented by the objects that use this interface declaration
|
||||||
|
[other: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum MatchMediaType {
|
||||||
|
Hls = 'hls',
|
||||||
|
Native = 'native'
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Doodstream: Match = {
|
export const Doodstream: Match = {
|
||||||
@ -23,6 +36,7 @@ export const Doodstream: Match = {
|
|||||||
'dood.cx',
|
'dood.cx',
|
||||||
'dood.sh',
|
'dood.sh',
|
||||||
'dood.watch',
|
'dood.watch',
|
||||||
|
'dood.work',
|
||||||
'dood.to',
|
'dood.to',
|
||||||
'dood.so',
|
'dood.so',
|
||||||
'dood.la',
|
'dood.la',
|
||||||
@ -37,7 +51,7 @@ export const Doodstream: Match = {
|
|||||||
replace: true,
|
replace: true,
|
||||||
regex: [/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s],
|
regex: [/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const response = await fetch(`https://${window.location.host}${match[1]}`, {
|
const response = await fetch(`https://${window.location.host}${match[1]}`, {
|
||||||
headers: {
|
headers: {
|
||||||
Range: 'bytes=0-'
|
Range: 'bytes=0-'
|
||||||
@ -53,10 +67,10 @@ export const Doodstream: Match = {
|
|||||||
export const DropLoad: Match = {
|
export const DropLoad: Match = {
|
||||||
name: 'Dropload',
|
name: 'Dropload',
|
||||||
id: 'dropload',
|
id: 'dropload',
|
||||||
domains: ['dropload.ui'],
|
domains: ['dropload.io'],
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
||||||
}
|
}
|
||||||
@ -69,7 +83,7 @@ export const Filemoon: Match = {
|
|||||||
regex: [/(?<=<iframe\s*src=")\S*(?=")/s, /eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/(?<=<iframe\s*src=")\S*(?=")/s, /eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
replace: true,
|
replace: true,
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
if (window.location.host.startsWith('filemoon')) {
|
if (window.location.host.startsWith('filemoon')) {
|
||||||
await TmpHost.set(new URL(match[0]).host, Filemoon);
|
await TmpHost.set(new URL(match[0]).host, Filemoon);
|
||||||
return null;
|
return null;
|
||||||
@ -88,7 +102,7 @@ export const GoodStream: Match = {
|
|||||||
domains: ['goodstream.uno'],
|
domains: ['goodstream.uno'],
|
||||||
regex: [/(?<=file:\s+").*(?=")/g],
|
regex: [/(?<=file:\s+").*(?=")/g],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return match[0];
|
return match[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -99,19 +113,78 @@ export const Kwik: Match = {
|
|||||||
domains: ['kwik.cx'],
|
domains: ['kwik.cx'],
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
return unpacked.match(/(?<=source=').*(?=')/)![0];
|
return unpacked.match(/(?<=source=').*(?=')/)![0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const LoadX: Match = {
|
||||||
|
name: 'LoadX',
|
||||||
|
id: 'loadx',
|
||||||
|
domains: ['loadx.ws'],
|
||||||
|
regex: [/./gm],
|
||||||
|
|
||||||
|
match: async () => {
|
||||||
|
const hash = encodeURIComponent(lastPathSegment(window.location.href));
|
||||||
|
const response = await fetch(
|
||||||
|
`https://${window.location.host}/player/index.php?data=${hash}&do=getVideo`,
|
||||||
|
{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const responseJson = await response.json();
|
||||||
|
const videoSource: string = responseJson['videoSource'];
|
||||||
|
|
||||||
|
// extension of extracted url is '.txt', so we have to manually specify that it's a hls
|
||||||
|
return { [MatchMediaType.Hls]: videoSource.replace('\\/', '/') };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Luluvdo: Match = {
|
||||||
|
name: 'Luluvdo',
|
||||||
|
id: 'luluvdo',
|
||||||
|
domains: ['luluvdo.com'],
|
||||||
|
regex: [/./gm],
|
||||||
|
|
||||||
|
match: async () => {
|
||||||
|
const requestBody = new FormData();
|
||||||
|
requestBody.set('op', 'embed');
|
||||||
|
requestBody.set('file_code', lastPathSegment(window.location.href));
|
||||||
|
const response = await fetch(`https://${window.location.host}/dl`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: requestBody,
|
||||||
|
referrer: window.location.href
|
||||||
|
});
|
||||||
|
|
||||||
|
let unpacked;
|
||||||
|
|
||||||
|
const responseText = await response.text();
|
||||||
|
const evalMatch = responseText.match(/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms)!;
|
||||||
|
// sometimes is packed, sometimes it's not. looks like someone forgets to obfuscate the code when pushing to
|
||||||
|
// production
|
||||||
|
if (evalMatch) {
|
||||||
|
unpacked = await unpack(evalMatch[0]);
|
||||||
|
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
||||||
|
} else {
|
||||||
|
unpacked = responseText;
|
||||||
|
}
|
||||||
|
|
||||||
|
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const Mixdrop: Match = {
|
export const Mixdrop: Match = {
|
||||||
name: 'Mixdrop',
|
name: 'Mixdrop',
|
||||||
id: 'mixdrop',
|
id: 'mixdrop',
|
||||||
domains: ['mixdrop.co', 'mixdrop.to', 'mixdrop.ch', 'mixdrop.bz', 'mixdrop.gl'],
|
domains: ['mixdrop.bz', 'mixdrop.ch', 'mixdrop.co', 'mixdrop.gl', 'mixdrop.my', 'mixdrop.to'],
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
const url = unpacked.match(/(?<=MDCore.wurl=").*(?=")/)![0];
|
const url = unpacked.match(/(?<=MDCore.wurl=").*(?=")/)![0];
|
||||||
return `https:${url}`;
|
return `https:${url}`;
|
||||||
@ -125,7 +198,7 @@ export const Mp4Upload: Match = {
|
|||||||
replace: true,
|
replace: true,
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
return unpacked.match(/(?<=player.src\(").*(?=")/)![0];
|
return unpacked.match(/(?<=player.src\(").*(?=")/)![0];
|
||||||
}
|
}
|
||||||
@ -155,7 +228,7 @@ export const StreamA2z: Match = {
|
|||||||
domains: ['streama2z.com', 'streama2z.xyz'],
|
domains: ['streama2z.com', 'streama2z.xyz'],
|
||||||
regex: [/https?:\/\/\S*m3u8.+(?=['"])/gm],
|
regex: [/https?:\/\/\S*m3u8.+(?=['"])/gm],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
if (StreamA2z.domains.indexOf(window.location.hostname) !== -1) {
|
if (StreamA2z.domains.indexOf(window.location.hostname) !== -1) {
|
||||||
await Redirect.set(StreamA2z);
|
await Redirect.set(StreamA2z);
|
||||||
return null;
|
return null;
|
||||||
@ -170,7 +243,7 @@ export const Streamtape: Match = {
|
|||||||
domains: ['streamtape.com', 'streamtape.net', 'shavetape.cash'],
|
domains: ['streamtape.com', 'streamtape.net', 'shavetape.cash'],
|
||||||
regex: [/id=.*(?=')/gm],
|
regex: [/id=.*(?=')/gm],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
while (i < match.length) {
|
while (i < match.length) {
|
||||||
if (match[++i - 1] == match[i]) {
|
if (match[++i - 1] == match[i]) {
|
||||||
@ -189,7 +262,7 @@ export const Streamzz: Match = {
|
|||||||
domains: ['streamzz.to', 'streamz.ws'],
|
domains: ['streamzz.to', 'streamz.ws'],
|
||||||
regex: [/(?<=\|)\w{2,}/gm],
|
regex: [/(?<=\|)\w{2,}/gm],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return `https://get.${location.hostname.split('.')[0]}.tw/getlink-${
|
return `https://get.${location.hostname.split('.')[0]}.tw/getlink-${
|
||||||
match.sort((a, b) => b.length - a.length)[0]
|
match.sort((a, b) => b.length - a.length)[0]
|
||||||
}.dll`;
|
}.dll`;
|
||||||
@ -199,10 +272,10 @@ export const Streamzz: Match = {
|
|||||||
export const SuperVideo: Match = {
|
export const SuperVideo: Match = {
|
||||||
name: 'Supervideo',
|
name: 'Supervideo',
|
||||||
id: 'supervideo',
|
id: 'supervideo',
|
||||||
domains: ['supervideo.tv'],
|
domains: ['supervideo.cc', 'supervideo.tv'],
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
||||||
}
|
}
|
||||||
@ -214,7 +287,7 @@ export const Upstream: Match = {
|
|||||||
domains: ['upstream.to'],
|
domains: ['upstream.to'],
|
||||||
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
regex: [/eval\(function\(p,a,c,k,e,d\).*?(?=<\/script>)/gms],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
const unpacked = await unpack(match[0]);
|
const unpacked = await unpack(match[0]);
|
||||||
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
return unpacked.match(/(?<=file:").*(?=")/)![0];
|
||||||
}
|
}
|
||||||
@ -227,7 +300,7 @@ export const Vidmoly: Match = {
|
|||||||
regex: [/(?<=file:").+\.m3u8/gm],
|
regex: [/(?<=file:").+\.m3u8/gm],
|
||||||
replace: true,
|
replace: true,
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return match[0];
|
return match[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -239,7 +312,7 @@ export const Vidoza: Match = {
|
|||||||
regex: [/(?<=src:\s?").+?(?=")/gm],
|
regex: [/(?<=src:\s?").+?(?=")/gm],
|
||||||
replace: true,
|
replace: true,
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return match[0];
|
return match[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -248,10 +321,67 @@ export const Voe: Match = {
|
|||||||
name: 'Voe',
|
name: 'Voe',
|
||||||
id: 'voe',
|
id: 'voe',
|
||||||
domains: ['voe.sx'],
|
domains: ['voe.sx'],
|
||||||
regex: [/(?<='hls':\s*')\S*(?=')/gm],
|
regex: [
|
||||||
|
// voe.sx
|
||||||
|
/(?<=window\.location\.href\s=\s')\S*(?=')/gm,
|
||||||
|
// whatever site voe.sx redirects to
|
||||||
|
/(?<=<script type="application\/json">).*(?=<\/script>)/m
|
||||||
|
],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return atob(match[0]);
|
if (window.location.host === 'voe.sx') {
|
||||||
|
const redirectUrl = new URL(match[0]);
|
||||||
|
await TmpHost.set(redirectUrl.host, Voe);
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
let json = match[0];
|
||||||
|
json = JSON.parse(json);
|
||||||
|
|
||||||
|
let deobfuscated = json[0];
|
||||||
|
deobfuscated = this.rot13(deobfuscated);
|
||||||
|
deobfuscated = this.removeSpecialSequences(deobfuscated);
|
||||||
|
deobfuscated = atob(deobfuscated);
|
||||||
|
deobfuscated = this.shiftString(deobfuscated);
|
||||||
|
deobfuscated = deobfuscated.split('').reverse().join('');
|
||||||
|
deobfuscated = atob(deobfuscated);
|
||||||
|
|
||||||
|
const payload = JSON.parse(deobfuscated);
|
||||||
|
|
||||||
|
return payload['source'];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
rot13: function (encrypted: string) {
|
||||||
|
let decrypted = '';
|
||||||
|
for (let i = 0; i < encrypted.length; i++) {
|
||||||
|
let char = encrypted.charCodeAt(i);
|
||||||
|
if (char >= 65 && char <= 90) {
|
||||||
|
char = ((char - 65 + 13) % 26) + 65;
|
||||||
|
} else if (char >= 97 && char <= 122) {
|
||||||
|
char = ((char - 97 + 13) % 26) + 97;
|
||||||
|
}
|
||||||
|
decrypted += String.fromCharCode(char);
|
||||||
|
}
|
||||||
|
return decrypted;
|
||||||
|
},
|
||||||
|
removeSpecialSequences: function (input: string) {
|
||||||
|
return input
|
||||||
|
.replaceAll(/@\$/g, '')
|
||||||
|
.replaceAll(/\^\^/g, '')
|
||||||
|
.replaceAll(/~@/g, '')
|
||||||
|
.replaceAll(/%\?/g, '')
|
||||||
|
.replaceAll(/\*~/g, '')
|
||||||
|
.replaceAll(/!!/g, '')
|
||||||
|
.replaceAll(/#&/g, '');
|
||||||
|
},
|
||||||
|
shiftString: function (input: string) {
|
||||||
|
let shifted = '';
|
||||||
|
for (let i = 0; i < input.length; i++) {
|
||||||
|
const char = input.charCodeAt(i);
|
||||||
|
const shiftedChar = char - 3;
|
||||||
|
shifted += String.fromCharCode(shiftedChar);
|
||||||
|
}
|
||||||
|
return shifted;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -261,7 +391,7 @@ export const Vupload: Match = {
|
|||||||
domains: ['vupload.com'],
|
domains: ['vupload.com'],
|
||||||
regex: [/(?<=src:\s?").+?(?=")/gm],
|
regex: [/(?<=src:\s?").+?(?=")/gm],
|
||||||
|
|
||||||
match: async (match: RegExpMatchArray) => {
|
match: async function (match: RegExpMatchArray) {
|
||||||
return match[0];
|
return match[0];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -272,6 +402,8 @@ export const matches = {
|
|||||||
[Filemoon.id]: Filemoon,
|
[Filemoon.id]: Filemoon,
|
||||||
[GoodStream.id]: GoodStream,
|
[GoodStream.id]: GoodStream,
|
||||||
[Kwik.id]: Kwik,
|
[Kwik.id]: Kwik,
|
||||||
|
[LoadX.id]: LoadX,
|
||||||
|
[Luluvdo.id]: Luluvdo,
|
||||||
[Mixdrop.id]: Mixdrop,
|
[Mixdrop.id]: Mixdrop,
|
||||||
[Mp4Upload.id]: Mp4Upload,
|
[Mp4Upload.id]: Mp4Upload,
|
||||||
[Newgrounds.id]: Newgrounds,
|
[Newgrounds.id]: Newgrounds,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import type { Match } from './match';
|
import { matches, type Match } from './match';
|
||||||
import { matches } from './match';
|
|
||||||
|
|
||||||
export const Hosters = {
|
export const Hosters = {
|
||||||
getDisabled: async () => {
|
getDisabled: async () => {
|
||||||
|
6
src/lib/util/extract.ts
Normal file
6
src/lib/util/extract.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
export function lastPathSegment(path: string): string {
|
||||||
|
while (path.endsWith('/')) {
|
||||||
|
path = path.slice(0, -1);
|
||||||
|
}
|
||||||
|
return path.substring(path.lastIndexOf('/') + 1);
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"target": "es2019",
|
"target": "es2021",
|
||||||
"module": "esnext",
|
"module": "esnext",
|
||||||
"useDefineForClassFields": true,
|
"useDefineForClassFields": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { defineConfig, loadEnv } from 'vite';
|
import { fileURLToPath } from 'url';
|
||||||
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
||||||
import webExtension from '@samrum/vite-plugin-web-extension';
|
import webExtension from '@samrum/vite-plugin-web-extension';
|
||||||
import path from 'path';
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
||||||
import { getManifest } from './src/manifest';
|
import { defineConfig, loadEnv, type PluginOption } from 'vite';
|
||||||
import { matches } from './src/lib/match';
|
import { matches } from './src/lib/match';
|
||||||
|
import { getManifest } from './src/manifest';
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig(({ mode }) => {
|
export default defineConfig(({ mode }) => {
|
||||||
@ -11,7 +11,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
plugins: [
|
plugins: [
|
||||||
svelte(),
|
svelte() as PluginOption,
|
||||||
webExtension({
|
webExtension({
|
||||||
manifest: getManifest(Number(env.MANIFEST_VERSION)),
|
manifest: getManifest(Number(env.MANIFEST_VERSION)),
|
||||||
additionalInputs: {
|
additionalInputs: {
|
||||||
@ -27,12 +27,10 @@ export default defineConfig(({ mode }) => {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
}) as unknown as PluginOption
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: [{ find: '~', replacement: fileURLToPath(new URL('./src', import.meta.url)) }]
|
||||||
'~': path.resolve(__dirname, './src')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user