mirror of
https://github.com/bytedream/stream-bypass.git
synced 2025-06-27 18:40:31 +02:00
Compare commits
39 Commits
Author | SHA1 | Date | |
---|---|---|---|
f4cbdd3258 | |||
fa41a8de8e | |||
ce8bc855b9 | |||
03202b2a12 | |||
9f0e1b59ce | |||
d928d25e09 | |||
266771aa13 | |||
d56672d90f | |||
a9ea5fe4b2 | |||
bb3f5384d6 | |||
6989587161 | |||
dd9bf71a5c | |||
6da0050df4 | |||
1a7c22ec0e | |||
175862b098 | |||
fd5a532d0f | |||
8c43eedb23 | |||
e027c2e09e | |||
f9a0656d4d | |||
382d8b1268 | |||
5b8639ce6a | |||
841c824590 | |||
2055a3ea81 | |||
0262d1853c | |||
81da6600e6 | |||
817f5b82f9 | |||
9a17fb0d9b | |||
17f8aab216 | |||
44d4c9cbcf | |||
b34531b982 | |||
e699d3885c | |||
396038a803 | |||
bd64d4ed0b | |||
a207c336b0 | |||
2460657f2a | |||
698ed5ac3c | |||
dc42220f09 | |||
e146649bbf | |||
424e34190c |
23
README.md
23
README.md
@ -68,20 +68,20 @@ Install the addon directly from the [firefox addon store](https://addons.mozilla
|
|||||||
## 📜 Supported sites
|
## 📜 Supported sites
|
||||||
|
|
||||||
| Site | Supported | Note |
|
| Site | Supported | Note |
|
||||||
|-----------------------------------------------------------------------|-----------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-----------------------------------------------------------------------|-----------|--------------------------------------------------------------------------------------------------------------|
|
||||||
| [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | ❌ | URL can be extracted but not played (see [here](https://github.com/ByteDream/stream-bypass/blob/674527ed9c1aa35a30fed135c46017571dd3ce31/src/match/matches.ts#L18) for more information) |
|
| [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | ✔️ | |
|
||||||
| [evoload.io](https://evoload.io) | ✔️ | |
|
| [filemoon.sx](https://filemoon.sx) | ✔ | |
|
||||||
|
| [mcloud.to](https://mcloud.to/) | ❌ | Reverse engineering the site costs too much time ([#5](https://github.com/ByteDream/stream-bypass/issues/5)) |
|
||||||
| [mixdrop.co](https://mixdrop.co) | ✔ ️ | |
|
| [mixdrop.co](https://mixdrop.co) | ✔ ️ | |
|
||||||
| [mp4upload.com](https://mp4upload.com) | ❌ | URL can be extracted but not. Probably the same issue as with doodstream |
|
| [mp4upload.com](https://mp4upload.com) | ✔ | |
|
||||||
| [newgrounds.com](https://newgrounds.com) | ✔ | |
|
| [newgrounds.com](https://newgrounds.com) | ✔ | |
|
||||||
| [streamtape.com](https://streamtape.com) | ✔ | |
|
| [streamtape.com](https://streamtape.com) | ✔ | |
|
||||||
| [streamzz.to](https://streamzz.to) / [streamz.ws](https://streamz.ws) | ✔ | |
|
| [streamzz.to](https://streamzz.to) / [streamz.ws](https://streamz.ws) | ✔ | |
|
||||||
| [upstream.to](https://upstream.to) | ✔ | |
|
| [upstream.to](https://upstream.to) | ✔ | |
|
||||||
| [videovard.sx](https://videovard.sx) | ❌ | Reverse engineering the site costs too much time |
|
| [videovard.sx](https://videovard.sx) | ❌ | Reverse engineering the site costs too much time |
|
||||||
| [vidlox.me](https://vidlox.me) | ⚠ | Website down / Timeout |
|
|
||||||
| [vidoza.net](https://vidoza.net) | ✔ | |
|
| [vidoza.net](https://vidoza.net) | ✔ | |
|
||||||
| [vivo.sx](https://vivo.sx) | ⚠️ | Website down / Timeout |
|
| [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) / [voeunblk.com](https://voeunblk.com) | ✔ | |
|
| [voe.sx](https://voe.sx) | ✔ | |
|
||||||
| [vupload.com](https://vupload.com) | ✔ | |
|
| [vupload.com](https://vupload.com) | ✔ | |
|
||||||
|
|
||||||
- ✔️: Everything ok.
|
- ✔️: Everything ok.
|
||||||
@ -90,6 +90,15 @@ Install the addon directly from the [firefox addon store](https://addons.mozilla
|
|||||||
|
|
||||||
Some sites put much effort in obfuscating their code / how they receive the video stream so that it simply cost too much time for me to reverse engineer it and find out how to bypass the native video player of the site.
|
Some sites put much effort in obfuscating their code / how they receive the video stream so that it simply cost too much time for me to reverse engineer it and find out how to bypass the native video player of the site.
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Hall of dead sites</summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://evoload.io">evoload.io</a> - Down</li>
|
||||||
|
<li><a href="https://vidlox.me">vidlox.me</a> - Reachable but empty</li>
|
||||||
|
<li><a href="https://vivo.sx">vivo.sx</a> - Down</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
## ⚙️ Building
|
## ⚙️ Building
|
||||||
|
|
||||||
If you want to build the addon from source and not using the [installation](#installation) way, follow the instructions.
|
If you want to build the addon from source and not using the [installation](#installation) way, follow the instructions.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "stream-bypass",
|
"name": "stream-bypass",
|
||||||
"version": "2.1.0",
|
"version": "2.1.7",
|
||||||
"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",
|
||||||
"main": "src/index.ts",
|
"main": "src/index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -21,12 +21,12 @@
|
|||||||
"homepage": "https://github.com/ByteDream/stream-bypass#readme",
|
"homepage": "https://github.com/ByteDream/stream-bypass#readme",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-commonjs": "^22.0.0",
|
"@rollup/plugin-commonjs": "^22.0.0",
|
||||||
"@rollup/plugin-node-resolve": "^13.3.0",
|
"@rollup/plugin-node-resolve": "^14.0.1",
|
||||||
"@rollup/plugin-replace": "^4.0.0",
|
"@rollup/plugin-replace": "^4.0.0",
|
||||||
"@rollup/plugin-typescript": "^8.3.3",
|
"@rollup/plugin-typescript": "^8.3.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
"@typescript-eslint/eslint-plugin": "^5.27.1",
|
||||||
"@typescript-eslint/parser": "^5.27.1",
|
"@typescript-eslint/parser": "^5.27.1",
|
||||||
"@types/chrome": "^0.0.190",
|
"@types/chrome": "^0.0.196",
|
||||||
"@types/node-sass": "^4.11.2",
|
"@types/node-sass": "^4.11.2",
|
||||||
"@types/yazl": "^2.4.2",
|
"@types/yazl": "^2.4.2",
|
||||||
"eslint": "^8.17.0",
|
"eslint": "^8.17.0",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {getMatch} from "./match/match";
|
import {getMatch} from "./match/match";
|
||||||
import {storageGet, storageSet} from "./store/store";
|
import {storageDelete, storageGet, storageSet} from "./store/store";
|
||||||
import {Match} from "./match/matches";
|
import {Match} from "./match/matches";
|
||||||
|
|
||||||
chrome.webRequest.onBeforeRedirect.addListener(async details => {
|
chrome.webRequest.onBeforeRedirect.addListener(async details => {
|
||||||
@ -9,6 +9,8 @@ chrome.webRequest.onBeforeRedirect.addListener(async details => {
|
|||||||
if ((match = await getMatch(new URL(details.url).host)) !== undefined) {
|
if ((match = await getMatch(new URL(details.url).host)) !== undefined) {
|
||||||
await storageSet('redirect', match.id)
|
await storageSet('redirect', match.id)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
await storageDelete('redirect')
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
urls: ['<all_urls>'],
|
urls: ['<all_urls>'],
|
||||||
|
22
src/index.ts
22
src/index.ts
@ -4,23 +4,35 @@ import {Match, matches} from "./match/matches";
|
|||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
let match: Match;
|
let match: Match;
|
||||||
|
let redirect = false;
|
||||||
if ((match = await getMatch(window.location.host)) === undefined) {
|
if ((match = await getMatch(window.location.host)) === undefined) {
|
||||||
let id: string
|
let id: string
|
||||||
if ((id = await storageGet('redirect')) !== undefined) {
|
if ((id = await storageGet('redirect')) !== undefined) {
|
||||||
|
redirect = true
|
||||||
match = matches.find(m => m.id === id)
|
match = matches.find(m => m.id === id)
|
||||||
await storageDelete('redirect')
|
|
||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const re = document.body.innerHTML.match(match.regex)
|
const re = document.body.innerHTML.match(match.regex)
|
||||||
if (re === null) {
|
if (re === null) return
|
||||||
return
|
if (redirect) await storageDelete('redirect')
|
||||||
}
|
|
||||||
|
|
||||||
const url = await match.match(re)
|
const url = await match.match(re)
|
||||||
location.assign(chrome.runtime.getURL(`ui/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}`))
|
|
||||||
|
if (match.replace && !url.endsWith('.m3u8')) {
|
||||||
|
const player = document.createElement('video')
|
||||||
|
player.style.width = '100%'
|
||||||
|
player.style.height = '100%'
|
||||||
|
player.controls = true
|
||||||
|
player.src = url
|
||||||
|
|
||||||
|
document.body.innerHTML = ''
|
||||||
|
document.body.append(player)
|
||||||
|
} else {
|
||||||
|
window.location.assign(chrome.runtime.getURL(`ui/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}&domain=${window.location.host}`))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Stream Bypass",
|
"name": "Stream Bypass",
|
||||||
"author": "ByteDream",
|
"author": "ByteDream",
|
||||||
"description": "A multi-browser addon / extension for multiple streaming providers which redirects directly to the source video.",
|
"description": "A multi-browser addon / extension for multiple streaming providers which redirects directly to the source video.",
|
||||||
"version": "2.1.0",
|
"version": "2.1.6",
|
||||||
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export enum Reliability {
|
export enum Reliability {
|
||||||
HIGH = 1,
|
HIGH,
|
||||||
NORMAL,
|
NORMAL,
|
||||||
LOW,
|
LOW,
|
||||||
}
|
}
|
||||||
@ -9,24 +9,24 @@ export abstract class Match {
|
|||||||
id: string
|
id: string
|
||||||
reliability: Reliability
|
reliability: Reliability
|
||||||
domains: string[]
|
domains: string[]
|
||||||
|
replace?: boolean
|
||||||
regex: RegExp
|
regex: RegExp
|
||||||
abstract match(match: RegExpMatchArray): Promise<string>
|
abstract match(match: RegExpMatchArray): Promise<string>
|
||||||
|
|
||||||
notice?: string
|
notice?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
// DOES NOT WORK.
|
|
||||||
// The url can be extracted (sometimes??? wtf) without problems but to receive the actual video, custom request
|
|
||||||
// headers must be set. And because the javascript and browser ecosystem is so fucked up, there is no good way to
|
|
||||||
// do this with media which can be natively played with the browser, like here.
|
|
||||||
class Doodstream implements Match {
|
class Doodstream implements Match {
|
||||||
name = 'Doodstream'
|
name = 'Doodstream'
|
||||||
id = 'doodstream'
|
id = 'doodstream'
|
||||||
reliability = Reliability.HIGH
|
reliability = Reliability.NORMAL
|
||||||
domains = [
|
domains = [
|
||||||
'doodstream.com',
|
'doodstream.com',
|
||||||
'dood.pm'
|
'dood.pm',
|
||||||
|
'dood.ws',
|
||||||
|
'dood.wf'
|
||||||
]
|
]
|
||||||
|
replace = true
|
||||||
regex = new RegExp(/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s)
|
regex = new RegExp(/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
@ -41,57 +41,63 @@ class Doodstream implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Evoload implements Match {
|
class Filemoon implements Match {
|
||||||
name = 'Evoload'
|
name = 'Filemoon'
|
||||||
id = 'evoload'
|
id = 'filemoon'
|
||||||
reliability = Reliability.NORMAL
|
reliability = Reliability.HIGH
|
||||||
domains = [
|
domains = [
|
||||||
'evoload.io'
|
'filemoon.sx'
|
||||||
]
|
]
|
||||||
regex = new RegExp(/.*/gm)
|
regex = new RegExp(/(?<=\|)\w{2,}/gm)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
const code = window.location.pathname.split('/').slice(-1)[0]
|
const start_idx = match.indexOf('moon')
|
||||||
const response = await fetch('https://evoload.io/SecurePlayer', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({code: code})
|
|
||||||
})
|
|
||||||
|
|
||||||
const json = await response.json()
|
const prefix = `${match[start_idx]}-${match[start_idx-1]}-${match[start_idx-2]}-${match[start_idx-3]}`
|
||||||
return json['stream']['src']
|
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]}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Mixdrop implements Match {
|
class Mixdrop implements Match {
|
||||||
name = 'Mixdrop'
|
name = 'Mixdrop'
|
||||||
id = 'mixdrop'
|
id = 'mixdrop'
|
||||||
reliability = Reliability.HIGH
|
reliability = Reliability.NORMAL
|
||||||
domains = [
|
domains = [
|
||||||
'mixdrop.co'
|
'mixdrop.co'
|
||||||
]
|
]
|
||||||
regex = new RegExp(/(?<=\|)\w{2,}/gm)
|
regex = new RegExp(/(?<=\|)\w{2,}/gm)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return `https://a-${match[1]}.${match[4]}.${match[5]}/v/${match[2]}.${match[6]}?s=${match[12]}&e=${match[13]}`
|
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}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*class Mp4Upload implements Match {
|
class Mp4Upload implements Match {
|
||||||
name = 'Mp4Upload'
|
name = 'Mp4Upload'
|
||||||
id = 'mp4upload'
|
id = 'mp4upload'
|
||||||
reliability = Reliability.LOW
|
reliability = Reliability.NORMAL
|
||||||
domains = [
|
domains = [
|
||||||
'mp4upload.com'
|
'mp4upload.com'
|
||||||
]
|
]
|
||||||
|
replace = true
|
||||||
regex = new RegExp(/(?<=\|)\w{2,}/gm)
|
regex = new RegExp(/(?<=\|)\w{2,}/gm)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return `https://${match[34]}.mp4upload.com:${match[89]}/d/${match[88]}/video.mp4`
|
let id = match.slice().reduce((a, b) => a.length >= b.length ? a : b)
|
||||||
|
return `https://www4.mp4upload.com:282/d/${id}/video.mp4`
|
||||||
}
|
}
|
||||||
}*/
|
}
|
||||||
|
|
||||||
class Newgrounds implements Match {
|
class Newgrounds implements Match {
|
||||||
name = 'Newgrounds'
|
name = 'Newgrounds'
|
||||||
@ -121,17 +127,17 @@ class Streamtape implements Match {
|
|||||||
domains = [
|
domains = [
|
||||||
'streamtape.com'
|
'streamtape.com'
|
||||||
]
|
]
|
||||||
regex = new RegExp(/\/get_video\S*(?=')/gm)
|
regex = new RegExp(/id=.*(?=')/gm)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return `https://streamtape.com${match[0]}`
|
return `https://streamtape.com/get_video?${match.reverse()[0]}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Streamzz implements Match {
|
class Streamzz implements Match {
|
||||||
name = 'Streamzz'
|
name = 'Streamzz'
|
||||||
id = 'streamzz'
|
id = 'streamzz'
|
||||||
reliability = Reliability.NORMAL
|
reliability = Reliability.LOW
|
||||||
domains = [
|
domains = [
|
||||||
'streamzz.to',
|
'streamzz.to',
|
||||||
'streamz.ws'
|
'streamz.ws'
|
||||||
@ -157,20 +163,6 @@ class Upstream implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Vidlox implements Match {
|
|
||||||
name = 'Vidlox'
|
|
||||||
id = 'vidlox'
|
|
||||||
reliability = Reliability.LOW
|
|
||||||
domains = [
|
|
||||||
'vidlox.me'
|
|
||||||
]
|
|
||||||
regex = new RegExp(/(?<=\[")\S+?(?=")/gm)
|
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
|
||||||
return match[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Vidoza implements Match {
|
class Vidoza implements Match {
|
||||||
name = 'Vidoza'
|
name = 'Vidoza'
|
||||||
id = 'vidoza'
|
id = 'vidoza'
|
||||||
@ -185,34 +177,6 @@ class Vidoza implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Vivo implements Match {
|
|
||||||
name = 'Vivo'
|
|
||||||
id = 'vivo'
|
|
||||||
reliability = Reliability.LOW
|
|
||||||
domains = [
|
|
||||||
'vivo.sx'
|
|
||||||
]
|
|
||||||
regex = new RegExp(/(?<=source:\s')(\S+)(?=')/gms)
|
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
|
||||||
return this.rot47(decodeURIComponent(match[0]))
|
|
||||||
}
|
|
||||||
|
|
||||||
// decrypts a string with the rot47 algorithm (https://en.wikipedia.org/wiki/ROT13#Variants)
|
|
||||||
rot47(encoded: string): string {
|
|
||||||
const s = []
|
|
||||||
for(let i = 0; i < encoded.length; i++) {
|
|
||||||
const j = encoded.charCodeAt(i)
|
|
||||||
if((j >= 33) && (j <= 126)) {
|
|
||||||
s[i] = String.fromCharCode(33+((j+ 14)%94))
|
|
||||||
} else {
|
|
||||||
s[i] = String.fromCharCode(j)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return s.join('')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Voe implements Match {
|
class Voe implements Match {
|
||||||
name = 'Voe'
|
name = 'Voe'
|
||||||
id = 'voe'
|
id = 'voe'
|
||||||
@ -220,7 +184,7 @@ class Voe implements Match {
|
|||||||
domains = [
|
domains = [
|
||||||
'voe.sx'
|
'voe.sx'
|
||||||
]
|
]
|
||||||
regex = new RegExp(/https?:\/\/\S*m3u8(?=")/gm)
|
regex = new RegExp(/https?:\/\/\S*m3u8.+(?=')/gm)
|
||||||
|
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return match[0]
|
return match[0]
|
||||||
@ -242,15 +206,15 @@ class Vupload implements Match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const matches = [
|
export const matches = [
|
||||||
new Evoload(),
|
new Doodstream(),
|
||||||
|
new Filemoon(),
|
||||||
new Mixdrop(),
|
new Mixdrop(),
|
||||||
|
new Mp4Upload(),
|
||||||
new Newgrounds(),
|
new Newgrounds(),
|
||||||
new Streamtape(),
|
new Streamtape(),
|
||||||
new Streamzz(),
|
new Streamzz(),
|
||||||
new Upstream(),
|
new Upstream(),
|
||||||
new Vidlox(),
|
|
||||||
new Vidoza(),
|
new Vidoza(),
|
||||||
new Vivo(),
|
|
||||||
new Voe(),
|
new Voe(),
|
||||||
new Vupload()
|
new Vupload()
|
||||||
]
|
]
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>HLS</title>
|
<title>Stream Bypass</title>
|
||||||
<link rel="stylesheet" href="player.css">
|
<link rel="stylesheet" href="player.css">
|
||||||
<script src="player.js" defer></script>
|
<script src="player.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<video id="video"></video>
|
<video id="video"></video>
|
||||||
<div id="message-container">
|
<div id="message-container">
|
||||||
<p id="message" hidden></p>
|
<p id="message"></p>
|
||||||
|
<br>
|
||||||
|
<p>Open a new issue <a href="https://github.com/ByteDream/stream-bypass/issues">here</a></p>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
body
|
|
||||||
background-color: #131313
|
|
||||||
|
|
||||||
html, body, video
|
|
||||||
width: 100%
|
|
||||||
height: 100%
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
video
|
|
||||||
position: absolute
|
|
||||||
top: 0
|
|
||||||
left: 0
|
|
||||||
|
|
||||||
#message-container
|
|
||||||
display: flex
|
|
||||||
justify-content: center
|
|
||||||
align-items: center
|
|
||||||
height: 100%
|
|
||||||
|
|
||||||
#message
|
|
||||||
color: white
|
|
||||||
text-align: center
|
|
34
src/ui/player/player.scss
Normal file
34
src/ui/player/player.scss
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
body {
|
||||||
|
background-color: #131313;
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body, video {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#message-container {
|
||||||
|
visibility: hidden;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
color: white;
|
||||||
|
text-align: center;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
& * {
|
||||||
|
visibility: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
& a, & a:visited {
|
||||||
|
color: red
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +1,20 @@
|
|||||||
import {Match, matches, Reliability} from "../../match/matches";
|
import {matches} from "../../match/matches";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import Hls from "hls.js";
|
import Hls from "hls.js";
|
||||||
|
|
||||||
function show_message(message: string) {
|
function show_message(message: string) {
|
||||||
document.getElementById('message').innerText = message
|
document.getElementById('message').innerText = message
|
||||||
document.getElementById('message-container').hidden = false
|
document.getElementById('message-container').style.visibility = 'visible'
|
||||||
document.getElementById('video').hidden = true
|
document.getElementById('video').hidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
async function play_native(url: string, match: Match) {
|
async function play_native(url: string) {
|
||||||
const video = document.getElementById('video') as HTMLVideoElement
|
const video = document.getElementById('video') as HTMLVideoElement
|
||||||
video.controls = true
|
video.controls = true
|
||||||
video.src = url
|
video.src = url
|
||||||
}
|
}
|
||||||
|
|
||||||
async function play_hls(url: string, match: Match) {
|
async function play_hls(url: string) {
|
||||||
const video = document.getElementById('video') as HTMLVideoElement
|
const video = document.getElementById('video') as HTMLVideoElement
|
||||||
video.controls = true
|
video.controls = true
|
||||||
|
|
||||||
@ -26,36 +26,6 @@ async function play_hls(url: string, match: Match) {
|
|||||||
})
|
})
|
||||||
hls.loadSource(url)
|
hls.loadSource(url)
|
||||||
hls.attachMedia(video)
|
hls.attachMedia(video)
|
||||||
|
|
||||||
const loaded = await new Promise((resolve, reject) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
resolve(false)
|
|
||||||
}, match.reliability * 3000)
|
|
||||||
|
|
||||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
|
||||||
resolve(true)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!loaded) {
|
|
||||||
let message: string
|
|
||||||
switch (match.reliability) {
|
|
||||||
case Reliability.LOW:
|
|
||||||
message = `The reliability for this domain is low, errors like this are common.
|
|
||||||
Try to choose another streaming provider (if existent) or deactivate the addon for this provider (${match.name}) and try again`
|
|
||||||
break
|
|
||||||
case Reliability.NORMAL:
|
|
||||||
message = `The reliability for this domain is normal, errors like this can occur but are not very common. Try to refresh the page`
|
|
||||||
break
|
|
||||||
case Reliability.HIGH:
|
|
||||||
message = `The reliability for this domains is high, errors like this are very unlikely to happen.
|
|
||||||
Try to refresh the page and if the error still exists you might want to open a new issue <a href="https://github.com/ByteDream/stream-bypass/issues/new">here</a>.
|
|
||||||
When you're using <a href="https://www.torproject.org/">Tor</a> such errors have a slight chance to occur more often,
|
|
||||||
so if this is the case just try to reload the page and see if it's working then`
|
|
||||||
break
|
|
||||||
}
|
|
||||||
show_message(`Could not load HLS video. ${message}`)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
show_message('Failed to play m3u8 video (hls is not supported). Try again or create a new issue <a href="https://github.com/ByteDream/stream-bypass/issues/new">here</a>')
|
show_message('Failed to play m3u8 video (hls is not supported). Try again or create a new issue <a href="https://github.com/ByteDream/stream-bypass/issues/new">here</a>')
|
||||||
}
|
}
|
||||||
@ -64,16 +34,17 @@ async function play_hls(url: string, match: Match) {
|
|||||||
async function main() {
|
async function main() {
|
||||||
const urlQuery = new URLSearchParams(window.location.search)
|
const urlQuery = new URLSearchParams(window.location.search)
|
||||||
const id = urlQuery.get('id')
|
const id = urlQuery.get('id')
|
||||||
const url = urlQuery.get('url')
|
const url = decodeURIComponent(urlQuery.get('url'))
|
||||||
|
const domain = urlQuery.get('domain')
|
||||||
|
|
||||||
const match = matches.find((m) => m.id === id)
|
const match = matches.find((m) => m.id === id)
|
||||||
if (match === undefined) {
|
if (match === undefined) {
|
||||||
show_message(`Invalid id: ${id}. Please report this <a href="https://github.com/ByteDream/stream-bypass/issues/new">here</a>`)
|
show_message(`Invalid id: ${id}. Please report this <a href="https://github.com/ByteDream/stream-bypass/issues">here</a>`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
document.title = match.name
|
document.title = `Stream Bypass (${domain})`
|
||||||
|
|
||||||
url.endsWith('.m3u8') ? await play_hls(url, match) : await play_native(url, match)
|
new URL(url).pathname.endsWith('.m3u8') ? await play_hls(url) : await play_native(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<table id="sub-container">
|
<table id="sub-container">
|
||||||
</table>
|
</table>
|
||||||
<a id="error" href="https://github.com/ByteDream/stream-bypass/issues/new">Something does not work</a>
|
<a id="error" href="https://github.com/ByteDream/stream-bypass/issues">Something does not work</a>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
body
|
|
||||||
background-color: #2b2a33
|
|
||||||
font-weight: bold
|
|
||||||
max-height: 500px
|
|
||||||
overflow-x: hidden
|
|
||||||
overflow-y: auto
|
|
||||||
|
|
||||||
a, p
|
|
||||||
color: white
|
|
||||||
font-size: 16px
|
|
||||||
margin: 5px 0
|
|
||||||
cursor: default
|
|
||||||
|
|
||||||
a
|
|
||||||
border: 1px solid #281515
|
|
||||||
cursor: pointer
|
|
||||||
font-weight: normal
|
|
||||||
padding: 5px 8px
|
|
||||||
|
|
||||||
&.active
|
|
||||||
background-color: rgba(255, 65, 65, 0.74)
|
|
||||||
cursor: default
|
|
||||||
|
|
||||||
&.disabled
|
|
||||||
background-color: grey
|
|
||||||
cursor: not-allowed
|
|
||||||
|
|
||||||
&#error
|
|
||||||
border: none
|
|
||||||
display: block
|
|
||||||
font-weight: lighter
|
|
||||||
font-size: 0.8rem
|
|
||||||
text-align: center
|
|
||||||
padding: 10px 0 5px 0
|
|
||||||
|
|
||||||
hr
|
|
||||||
margin: 3px 0
|
|
||||||
|
|
||||||
|
|
||||||
#all
|
|
||||||
display: flex
|
|
||||||
justify-content: center
|
|
||||||
margin: 10px 0
|
|
||||||
|
|
||||||
|
|
||||||
.low-reliability
|
|
||||||
text-decoration: underline
|
|
||||||
text-decoration-color: rgb(255, 0, 0)
|
|
||||||
|
|
||||||
.normal-reliability
|
|
||||||
text-decoration: underline
|
|
||||||
text-decoration-color: yellow
|
|
||||||
|
|
||||||
.high-reliability
|
|
||||||
text-decoration: underline
|
|
||||||
text-decoration-color: #00ff00
|
|
66
src/ui/popup/popup.scss
Normal file
66
src/ui/popup/popup.scss
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
body {
|
||||||
|
background-color: #2b2a33;
|
||||||
|
font-weight: bold;
|
||||||
|
max-height: 500px;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
a, p {
|
||||||
|
color: white;
|
||||||
|
font-size: 16px;
|
||||||
|
margin: 5px 0;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
border: 1px solid #281515;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
padding: 5px 8px;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background-color: rgba(255, 65, 65, 0.74);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background-color: grey;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
&#error {
|
||||||
|
border: none;
|
||||||
|
display: block;
|
||||||
|
font-weight: lighter;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px 0 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin: 3px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#all {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 10px 0
|
||||||
|
}
|
||||||
|
|
||||||
|
.low-reliability {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: rgb(255, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.normal-reliability {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: yellow;
|
||||||
|
}
|
||||||
|
|
||||||
|
.high-reliability {
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: #00ff00;
|
||||||
|
}
|
@ -47,8 +47,8 @@ async function buildHtml() {
|
|||||||
|
|
||||||
async function buildCss() {
|
async function buildCss() {
|
||||||
const files = {
|
const files = {
|
||||||
'src/ui/popup/popup.sass': 'build/ui/popup/popup.css',
|
'src/ui/popup/popup.scss': 'build/ui/popup/popup.css',
|
||||||
'src/ui/player/player.sass': 'build/ui/player/player.css'
|
'src/ui/player/player.scss': 'build/ui/player/player.css'
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [src, dst] of Object.entries(files)) {
|
for (const [src, dst] of Object.entries(files)) {
|
||||||
|
Reference in New Issue
Block a user