13 Commits

Author SHA1 Message Date
c57cd03407 Fix vidmoly & add it to README 2024-05-20 15:40:38 +02:00
64cf565da3 Update dependencies and version 2024-05-20 15:37:46 +02:00
bf8a7eb602 Remove reliability 2024-05-20 14:11:09 +02:00
c643a39e2d Add new doodstream domain 2024-04-24 01:18:01 +02:00
fcfbc41fdb Fix voe.sx 2024-04-24 00:46:32 +02:00
1251f079f5 Remove discord link 2023-12-10 19:51:35 +01:00
ccfc77167b Add vidmoly.me 2023-12-08 15:50:19 +01:00
a10066458f Add chrome web store link 2023-11-20 12:20:32 +01:00
6a8c705b06 Fix mv2 chrome namespace apis 2023-11-17 16:25:40 +01:00
76a5bac7fd Fix chromium popup height 2023-11-17 16:25:29 +01:00
3aca863a4b Fix invalid release name 2023-11-17 15:06:17 +01:00
fe14edc0ef Make mv3 compatible 2023-11-17 15:06:09 +01:00
fffe23638c Update build instructions 2023-11-11 22:05:39 +01:00
14 changed files with 1794 additions and 702 deletions

View File

@ -12,12 +12,12 @@ A multi-browser addon / extension for multiple streaming providers which redirec
<a href="https://addons.mozilla.org/de/firefox/addon/stream-bypass/">
<img src="https://img.shields.io/amo/stars/stream-bypass?label=Firefox%20Store%20Stars&style=flat-square" alt="Firefox Addon Stars">
</a>
<a href="https://chromewebstore.google.com/detail/ddfpfjomnakfckhmilacnbokdaknamdb">
<img src="https://img.shields.io/chrome-web-store/users/ddfpfjomnakfckhmilacnbokdaknamdb?style=flat-square&label=Chrome%20Users" alt="Chrome Users">
</a>
<a href="https://github.com/ByteDream/stream-bypass/releases/latest">
<img src="https://img.shields.io/github/downloads/ByteDream/stream-bypass/total?label=GitHub%20Downloads&style=flat-square" alt="GitHub Downloads">
</a>
<a href="https://discord.gg/gUWwekeNNg">
<img src="https://img.shields.io/discord/915659846836162561?label=Discord&style=flat-square" alt="Discord">
</a>
</p>
<p align="center">
@ -52,6 +52,7 @@ Additionally, this enables you to download the video by right-clicking it and ju
The best way to install the extension are the official browser extension stores:
- [Firefox Addon Store](https://addons.mozilla.org/de/firefox/addon/stream-bypass/)
- [Chrome Web Store](https://chromewebstore.google.com/detail/ddfpfjomnakfckhmilacnbokdaknamdb)
### Manual installation
@ -61,7 +62,7 @@ The best way to install the extension are the official browser extension stores:
- Click the `Load Temporary Add-on...` button and choose the `manifest.json` file in the unzipped directory
- Chromium / Google Chrome
> As nearly every browser other than Firefox is based on Chromium, this should be the same for most of them
- Download `enhance-crunchyroll-<version>-mv3.zip` from the [latest release](https://github.com/ByteDream/stream-bypass/releases/latest) and unzip it (with [7zip](https://www.7-zip.org/) or something like that)
- Download `stream-bypass-<version>-mv3.zip` from the [latest release](https://github.com/ByteDream/stream-bypass/releases/latest) and unzip it (with [7zip](https://www.7-zip.org/) or something like that)
- Go into your browser and type `chrome://extensions` in the address bar
- Turn on the developer mode by checking the switch in the top right corner
- Click `Load unpacked` and choose the unzipped directory
@ -80,6 +81,7 @@ The best way to install the extension are the official browser extension stores:
| [streamzz.to](https://streamzz.to) / [streamz.ws](https://streamz.ws) | ✔ | |
| [upstream.to](https://upstream.to) | ✔ | |
| [videovard.sx](https://videovard.sx) | ❌ | Reverse engineering the site costs too much time |
| [vidmoly.me](https://vidmoly.me) | ✔ | |
| [vidoza.net](https://vidoza.net) | ✔ | |
| [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) | ✔ | |
@ -119,16 +121,16 @@ If the requirements are satisfied, you can continue with the following commands:
# install all dependencies
$ npm install
# build the extension source to a build/ directory
# build the extension source to the dist/ directory
$ npm run build
# same as build + create a bundle zipfile at dist/
$ npm run bundle
# same as build + more optimizations and browser specific settings at release/
$ npm run release:firefox # or "release:chrome" to create a release for chromium based browsers
```
##### Install
If you want to use the addon in Chromium or any browser which is based on it (almost every other, Google Chrome, Opera, ...), follow the steps in [installation](#-installation).
If you want to use the addon in Chromium or any browser which is based on it, follow the steps in [installation](#-installation).
When using firefox, use the following:
1. Type `about:debugging` in the browser's address bar.

2270
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "stream-bypass",
"version": "3.0.0",
"version": "3.0.1",
"displayName": "Stream Bypass",
"author": "ByteDream",
"description": "Multi-browser addon for multiple streaming providers which redirects directly to the source video",
@ -25,28 +25,26 @@
"url": "https://github.com/ByteDream/stream-bypass/issues"
},
"devDependencies": {
"@samrum/vite-plugin-web-extension": "^5.0.0",
"@sveltejs/vite-plugin-svelte": "^2.1.1",
"@tsconfig/svelte": "^4.0.1",
"@types/chrome": "^0.0.228",
"@types/webextension-polyfill": "^0.10.0",
"@typescript-eslint/eslint-plugin": "^6.10.0",
"@typescript-eslint/parser": "^6.10.0",
"eslint": "^8.53.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-svelte": "^2.35.0",
"hls.js": "^1.4.12",
"prettier": "^3.0.3",
"prettier-plugin-svelte": "^3.1.0",
"sass": "^1.69.5",
"svelte": "^3.58.0",
"svelte-check": "^3.2.0",
"svelte-preprocess": "^5.0.3",
"tslib": "^2.5.0",
"typescript": "^5.0.4",
"vite": "~4.3.3",
"web-ext": "^7.6.2",
"webextension-polyfill": "^0.10.0"
"@samrum/vite-plugin-web-extension": "^5.1.0",
"@sveltejs/vite-plugin-svelte": "^2.5.3",
"@tsconfig/svelte": "^5.0.4",
"@types/chrome": "^0.0.268",
"@typescript-eslint/eslint-plugin": "^7.9.0",
"@typescript-eslint/parser": "^7.9.0",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.39.0",
"hls.js": "^1.5.8",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.3",
"sass": "^1.77.2",
"svelte": "^4.2.17",
"svelte-check": "^3.7.1",
"svelte-preprocess": "^5.1.4",
"tslib": "^2.6.2",
"typescript": "^5.4.5",
"vite": "^4.5.3",
"web-ext": "^7.11.0"
},
"type": "module"
}

View File

@ -1,12 +1,26 @@
import './shared';
import type { Match } from '~/lib/match';
import { storageDelete, storageGet, storageSet } from '~/lib/settings';
import { getMatch } from '~/lib/match';
chrome.runtime.onMessage.addListener(async (message) => {
if (message.action == 'ff2mpv') {
await chrome.runtime.sendNativeMessage('ff2mpv', { url: message.url });
}
});
chrome.webRequest.onBeforeSendHeaders.addListener(
async (details) => {
const referer: { domain: string } | undefined = await storageGet('referer');
if (referer === undefined) return;
details.requestHeaders.push({
name: 'Referer',
value: `https://${referer.domain}/`
});
await storageDelete('referer');
return { requestHeaders: details.requestHeaders };
},
{ urls: ['<all_urls>'], types: ['xmlhttprequest'] },
['blocking', 'requestHeaders']
);
chrome.webRequest.onBeforeRedirect.addListener(
async (details) => {

View File

@ -0,0 +1 @@
import './shared';

View File

@ -0,0 +1,5 @@
chrome.runtime.onMessage.addListener(async (message) => {
if (message.action == 'ff2mpv') {
await chrome.runtime.sendNativeMessage('ff2mpv', { url: message.url });
}
});

View File

@ -1,7 +1,6 @@
import type { Match } from '~/lib/match';
import { getMatch } from '~/lib/match';
import { Other, Redirect } from '~/lib/settings';
import browser from 'webextension-polyfill';
async function main() {
let match: Match;
@ -25,7 +24,7 @@ async function main() {
// send the url to the ff2mpv (https://github.com/woodruffw/ff2mpv) application
if (await Other.getFf2mpv()) {
await browser.runtime.sendMessage({ action: 'ff2mpv', url: url });
await chrome.runtime.sendMessage({ action: 'ff2mpv', url: url });
}
if (match.replace && !url.includes('.m3u8')) {
@ -39,7 +38,7 @@ async function main() {
document.body.append(player);
} else {
window.location.assign(
browser.runtime.getURL(
chrome.runtime.getURL(
`src/entries/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}&domain=${
window.location.hostname
}`

View File

@ -1,5 +1,6 @@
import { matches } from '~/lib/match';
import Hls from 'hls.js';
import { storageSet } from '~/lib/settings';
async function playNative(url: string, videoElem: HTMLVideoElement) {
videoElem.src = url;
@ -31,6 +32,8 @@ export async function play(videoElem: HTMLVideoElement) {
}
document.title = `Stream Bypass (${domain})`;
await storageSet('referer', { domain: domain });
if (new URL(url).pathname.endsWith('.m3u8')) {
await playHls(url, videoElem);
} else {

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { matches, Reliability } from '~/lib/match';
import { matches } from '~/lib/match';
import { Hosters, Other } from '~/lib/settings';
let hostersEnabled: boolean;
@ -52,13 +52,7 @@
{#each hosters as hoster}
<tr>
<td class="setting-name">
<p
class:reliability-low={hoster.reliability === Reliability.LOW}
class:reliability-normal={hoster.reliability === Reliability.NORMAL}
class:reliability-high={hoster.reliability === Reliability.HIGH}
>
{hoster.name}
</p>
<p>{hoster.name}</p>
</td>
<td class="buttons">
<button
@ -127,8 +121,8 @@
background-color: #2b2a33;
color: white;
font-weight: bold;
overflow-x: hidden;
overflow-y: auto;
margin: 0;
padding: 0 8px;
}
#bug-notice {
@ -202,17 +196,4 @@
margin-bottom: 10px;
}
}
.reliability-low {
text-decoration: underline;
text-decoration-color: red;
}
.reliability-normal {
text-decoration: underline;
text-decoration-color: yellow;
}
.reliability-high {
text-decoration: underline;
text-decoration-color: #00ff00;
}
</style>

View File

@ -1,10 +1,10 @@
<!doctype html>
<html lang="en">
<html style="width: fit-content; height: 500px; overflow-y: hidden" lang="en">
<head>
<meta charset="UTF-8" />
<title>Stream Bypass</title>
</head>
<body style="width: fit-content; height: 500px">
<body style="width: fit-content; height: 500px; overflow-y: scroll">
<script type="module">
import Popup from '~/entries/popup/Popup.svelte';

View File

@ -1,16 +1,9 @@
import { unpack } from '~/lib/utils';
import { Hosters } from '~/lib/settings';
export enum Reliability {
HIGH,
NORMAL,
LOW
}
import { unpack } from './utils';
import { Hosters } from './settings';
export interface Match {
name: string;
id: string;
reliability: Reliability;
domains: string[];
replace?: boolean;
regex: RegExp;
@ -22,7 +15,6 @@ export interface Match {
export const Doodstream: Match = {
name: 'Doodstream',
id: 'doodstream',
reliability: Reliability.NORMAL,
domains: [
'doodstream.com',
'dood.pm',
@ -36,6 +28,7 @@ export const Doodstream: Match = {
'dood.la',
'dood.re',
'dood.yt',
'doods.pro',
'ds2play.com',
'dooood.com'
],
@ -58,7 +51,6 @@ export const Doodstream: Match = {
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,
@ -71,7 +63,6 @@ export const DropLoad: Match = {
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,
@ -84,7 +75,6 @@ export const Filemoon: Match = {
export const GoodStream: Match = {
name: 'Goodstream',
id: 'goodstream',
reliability: Reliability.NORMAL,
domains: ['goodstream.uno'],
regex: /(?<=file:\s+").*(?=")/g,
@ -96,7 +86,6 @@ export const GoodStream: Match = {
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,
@ -109,7 +98,6 @@ export const Kwik: Match = {
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,
@ -123,7 +111,6 @@ export const Mixdrop: Match = {
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,
@ -137,7 +124,6 @@ export const Mp4Upload: Match = {
export const Newgrounds: Match = {
name: 'Newgrounds',
id: 'newgrounds',
reliability: Reliability.HIGH,
domains: ['newgrounds.com'],
regex: /.*/gm,
@ -156,7 +142,6 @@ export const Newgrounds: Match = {
export const Streamtape: Match = {
name: 'Streamtape',
id: 'streamtape',
reliability: Reliability.HIGH,
domains: ['streamtape.com', 'streamtape.net', 'shavetape.cash'],
regex: /id=.*(?=')/gm,
@ -176,7 +161,6 @@ export const Streamtape: Match = {
export const Streamzz: Match = {
name: 'Streamzz',
id: 'streamzz',
reliability: Reliability.LOW,
domains: ['streamzz.to', 'streamz.ws'],
regex: /(?<=\|)\w{2,}/gm,
@ -190,7 +174,6 @@ export const Streamzz: Match = {
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,
@ -203,7 +186,6 @@ export const SuperVideo: Match = {
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,
@ -213,10 +195,21 @@ export const Upstream: Match = {
}
};
export const Vidmoly: Match = {
name: 'Vidmoly',
id: 'vidmoly',
domains: ['vidmoly.me', 'vidmoly.to'],
regex: /(?<=file:").+\.m3u8/gm,
match: async (match: RegExpMatchArray) => {
alert('a');
return match[0];
}
};
export const Vidoza: Match = {
name: 'Vidoza',
id: 'vidoza',
reliability: Reliability.HIGH,
domains: ['vidoza.net'],
regex: /(?<=src:\s?").+?(?=")/gm,
@ -228,9 +221,8 @@ export const Vidoza: Match = {
export const Voe: Match = {
name: 'Voe',
id: 'voe',
reliability: Reliability.HIGH,
domains: ['voe.sx'],
regex: /https?:\/\/\S*m3u8.+(?=')/gm,
regex: /https?:\/\/\S*m3u8.+(?=['"])/gm,
match: async (match: RegExpMatchArray) => {
return match[0];
@ -240,7 +232,6 @@ export const Voe: Match = {
export const Vupload: Match = {
name: 'Vupload',
id: 'vupload',
reliability: Reliability.HIGH,
domains: ['vupload.com'],
regex: /(?<=src:\s?").+?(?=")/gm,
@ -262,6 +253,7 @@ export const matches = {
[Streamzz.id]: Streamzz,
[SuperVideo.id]: SuperVideo,
[Upstream.id]: Upstream,
[Vidmoly.id]: Vidmoly,
[Vidoza.id]: Vidoza,
[Voe.id]: Voe,
[Vupload.id]: Vupload

View File

@ -1,6 +1,5 @@
import browser from 'webextension-polyfill';
import type { Match } from '~/lib/match';
import { matches } from '~/lib/match';
import type { Match } from './match';
import { matches } from './match';
export const Hosters = {
getDisabled: async () => {
@ -56,18 +55,34 @@ export const Other = {
};
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;
let resolve: (value: T | undefined) => void;
const promise = new Promise<T | undefined>((r) => (resolve = r));
chrome.storage.local.get(key, (entry) => {
const value = entry[key];
resolve(value === undefined ? defaultValue : value);
});
return promise;
}
export async function storageSet<T>(key: string, value: T) {
let resolve: () => void;
const promise = new Promise<void>((r) => (resolve = r));
const obj = {
[key]: value
};
await browser.storage.local.set(obj);
chrome.storage.local.set(obj, () => resolve());
return promise;
}
export async function storageDelete(key: string) {
await browser.storage.local.remove(key);
let resolve: () => void;
const promise = new Promise<void>((r) => (resolve = r));
chrome.storage.local.remove(key, () => resolve());
return promise;
}

View File

@ -1,4 +1,5 @@
import pkg from '../package.json';
import { matches } from './lib/match';
const sharedManifest: Partial<chrome.runtime.ManifestBase> = {
browser_specific_settings: {
@ -9,7 +10,7 @@ const sharedManifest: Partial<chrome.runtime.ManifestBase> = {
content_scripts: [
{
all_frames: true,
matches: ['<all_urls>'],
matches: Object.values(matches).flatMap((m) => m.domains.map((d) => `*://${d}/*`)),
js: ['src/entries/contentScript/main.ts'],
run_at: 'document_end'
}
@ -21,7 +22,7 @@ const sharedManifest: Partial<chrome.runtime.ManifestBase> = {
96: 'icons/stream-bypass@96px.png',
128: 'icons/stream-bypass@128px.png'
},
permissions: ['storage', 'webRequest', 'nativeMessaging', '<all_urls>']
permissions: ['storage', 'nativeMessaging']
};
const browserAction = {
@ -35,18 +36,19 @@ const browserAction = {
const ManifestV2 = {
...sharedManifest,
background: {
scripts: ['src/entries/background/main.ts'],
scripts: ['src/entries/background/mv2.ts'],
persistent: true
},
content_scripts: [{ ...sharedManifest.content_scripts[0], matches: ['<all_urls>'] }],
browser_action: browserAction,
permissions: [...sharedManifest.permissions]
permissions: [...sharedManifest.permissions, 'webRequest', 'webRequestBlocking', '<all_urls>']
};
const ManifestV3 = {
...sharedManifest,
action: browserAction,
background: {
service_worker: 'src/entries/background/main.ts'
service_worker: 'src/entries/background/mv3.ts'
}
};
@ -71,6 +73,9 @@ export function getManifest(
if (manifestVersion === 3) {
return {
...manifest,
// just like all the adblockers which are unable to fully work under MV3, we need access to every website
// the user enters in order to work correctly, which is forbidden when using MV3
name: `${manifest.name} Lite`,
...ManifestV3,
manifest_version: manifestVersion
};

View File

@ -3,6 +3,7 @@ import { svelte } from '@sveltejs/vite-plugin-svelte';
import webExtension from '@samrum/vite-plugin-web-extension';
import path from 'path';
import { getManifest } from './src/manifest';
import { matches } from './src/lib/match';
// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
@ -18,8 +19,10 @@ export default defineConfig(({ mode }) => {
{
fileName: 'src/entries/player/player.html',
webAccessible: {
matches: ['<all_urls>'],
excludeEntryFile: true
matches:
Number(env.MANIFEST_VERSION) === 3
? Object.values(matches).flatMap((m) => m.domains.map((d) => `*://${d}/*`))
: ['<all_urls>']
}
}
]