mirror of
https://github.com/bytedream/stream-bypass.git
synced 2025-06-27 18:40:31 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
0916f1c637 | |||
99d4577d1d | |||
9929c48761 | |||
2e13586ebb | |||
6583b0c15c | |||
038f708b36 | |||
f0f8bc9189 | |||
b45c1410f2 | |||
4907448aa6 | |||
4f08fee7b4 | |||
3624317116 |
@ -24,11 +24,11 @@ The addon was tested on
|
|||||||
|
|
||||||
### Firefox
|
### Firefox
|
||||||
|
|
||||||
Install the `.xpi` (firefox addon) file from the [latest release](https://github.com/ByteDream/vivosx-source-redirector/releases/latest).
|
Install the addon directly from the [firefox addon store](https://addons.mozilla.org/de/firefox/addon/stream-bypass/).
|
||||||
|
|
||||||
### Chromium / Google Chrome
|
### Chromium / Google Chrome
|
||||||
|
|
||||||
1. Download the `stream-bypass-<version>.zip` file from the [latest release](https://github.com/ByteDream/vivosx-source-redirector/releases/latest) and unzip it (with [7zip](https://www.7-zip.org/) or something like that).
|
1. Download the `stream-bypass-<version>.zip` file 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).
|
||||||
2. Go into your browser and type `chrome://extensions` in the address bar.
|
2. Go into your browser and type `chrome://extensions` in the address bar.
|
||||||
3. Turn the developer mode in the top right corner on.
|
3. Turn the developer mode in the top right corner on.
|
||||||
4. Click Load unpacked.
|
4. Click Load unpacked.
|
||||||
@ -36,7 +36,7 @@ Install the `.xpi` (firefox addon) file from the [latest release](https://github
|
|||||||
|
|
||||||
### Opera
|
### Opera
|
||||||
|
|
||||||
1. Download the `stream-bypass-<version>.zip` file from the [latest release](https://github.com/ByteDream/vivosx-source-redirector/releases/latest) and unzip it (with [7zip](https://www.7-zip.org/) or something like that).
|
1. Download the `stream-bypass-<version>.zip` file 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).
|
||||||
2. Go into your browser and type `opera://extensions` in the address bar.
|
2. Go into your browser and type `opera://extensions` in the address bar.
|
||||||
3. Turn the developer mode in the top right corner on.
|
3. Turn the developer mode in the top right corner on.
|
||||||
4. Click Load unpacked.
|
4. Click Load unpacked.
|
||||||
@ -77,7 +77,7 @@ For this, you need [docker](https://www.docker.com/) to be installed.
|
|||||||
```
|
```
|
||||||
- Compile
|
- Compile
|
||||||
```
|
```
|
||||||
$ docker rum --rm -v build:/build stream-bypass
|
$ docker run --rm -v build:/build stream-bypass
|
||||||
```
|
```
|
||||||
The compiled output will remain in a (new created if not existing) `build` directory.
|
The compiled output will remain in a (new created if not existing) `build` directory.
|
||||||
|
|
||||||
|
10
SUPPORTED
10
SUPPORTED
@ -1,4 +1,14 @@
|
|||||||
|
evoload.io
|
||||||
|
mcloud.to
|
||||||
|
mixdrop.co
|
||||||
streamtape.com
|
streamtape.com
|
||||||
|
streamzz.to
|
||||||
|
thevideome.com
|
||||||
|
upstream.to
|
||||||
|
vidlox.me
|
||||||
|
vidstream.pro
|
||||||
vidoza.net
|
vidoza.net
|
||||||
|
vivo.st
|
||||||
vivo.sx
|
vivo.sx
|
||||||
|
voe.sx
|
||||||
vupload.com
|
vupload.com
|
||||||
|
18
build.py
Executable file → Normal file
18
build.py
Executable file → Normal file
@ -35,6 +35,13 @@ def write_manifest():
|
|||||||
for content_script in manifest['content_scripts']:
|
for content_script in manifest['content_scripts']:
|
||||||
content_script['matches'] = [f'*://{match}/*' for match in matches]
|
content_script['matches'] = [f'*://{match}/*' for match in matches]
|
||||||
|
|
||||||
|
domains = []
|
||||||
|
for match in matches:
|
||||||
|
toplevel = match.split('.')[-1]
|
||||||
|
if toplevel not in domains:
|
||||||
|
domains.append(toplevel)
|
||||||
|
manifest['content_security_policy'] = f"script-src 'self' blob: https://cdn.jsdelivr.net https://unpkg.com {' '.join(f'*.{toplevel}' for toplevel in domains)}; object-src 'self'"
|
||||||
|
|
||||||
json.dump(manifest, open('src/manifest.json', 'w'), indent=2)
|
json.dump(manifest, open('src/manifest.json', 'w'), indent=2)
|
||||||
|
|
||||||
|
|
||||||
@ -55,18 +62,13 @@ def copy_built():
|
|||||||
subprocess.call(['tsc', '-p', 'src'])
|
subprocess.call(['tsc', '-p', 'src'])
|
||||||
|
|
||||||
build_path = Path('build')
|
build_path = Path('build')
|
||||||
if build_path.is_dir():
|
if not build_path.is_dir():
|
||||||
for file in build_path.rglob('*'):
|
|
||||||
if file.is_dir():
|
|
||||||
shutil.rmtree(str(file))
|
|
||||||
else:
|
|
||||||
file.unlink()
|
|
||||||
else:
|
|
||||||
build_path.mkdir()
|
build_path.mkdir()
|
||||||
for file in Path('src').rglob('*'):
|
for file in Path('src').rglob('*'):
|
||||||
build_file = build_path.joinpath(str(file)[4:])
|
build_file = build_path.joinpath(str(file)[4:])
|
||||||
if file.is_dir():
|
if file.is_dir():
|
||||||
build_file.mkdir(parents=True)
|
if not build_file.exists():
|
||||||
|
build_file.mkdir(parents=True)
|
||||||
elif file.suffix == '.sass':
|
elif file.suffix == '.sass':
|
||||||
css_file = str(file)[:-4] + 'css'
|
css_file = str(file)[:-4] + 'css'
|
||||||
subprocess.call(['sass', '--no-source-map', file, css_file])
|
subprocess.call(['sass', '--no-source-map', file, css_file])
|
||||||
|
34
src/index.ts
34
src/index.ts
@ -1,3 +1,7 @@
|
|||||||
|
function hasSuffix(content: string, suffix: string) {
|
||||||
|
return content.indexOf(suffix, content.length - suffix.length) !== -1
|
||||||
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
chrome.storage.local.get(['all', 'disabled'], function (result) {
|
chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||||
let keys = Object.keys(result)
|
let keys = Object.keys(result)
|
||||||
@ -6,16 +10,34 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
for (let match of matches) {
|
for (let match of matches) {
|
||||||
if (window.location.href.indexOf(match[0]) !== -1) {
|
let domain = match[0] as string
|
||||||
if (keys.indexOf('disabled') === -1 || result['disabled'].indexOf(match[0]) === -1) {
|
if (window.location.href.indexOf(domain) !== -1) {
|
||||||
|
if (keys.indexOf('disabled') === -1 || result['disabled'].indexOf(domain) === -1) {
|
||||||
let regex = match[1] as RegExp
|
let regex = match[1] as RegExp
|
||||||
let matchClass = match[2] as Match
|
let matchClass = match[2] as Match
|
||||||
|
let reliability = match[3] as Reliability
|
||||||
|
|
||||||
let re
|
let re
|
||||||
if (regex === null) {
|
if (regex !== null) {
|
||||||
location.assign(matchClass === null ? document.body.innerHTML : matchClass.match(new RegExp('').exec(document.body.innerHTML)))
|
if ((re = document.body.innerHTML.match(regex)) === null) {
|
||||||
} else if ((re = regex.exec(document.body.innerHTML)) !== null) {
|
continue
|
||||||
location.assign(matchClass === null ? re[0] : matchClass.match(re))
|
}
|
||||||
|
} else {
|
||||||
|
re = document.body.innerHTML.match(regex)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchClass === null) {
|
||||||
|
if (regex === null) {
|
||||||
|
location.assign(document.body.innerHTML)
|
||||||
|
} else {
|
||||||
|
// @ts-ignore
|
||||||
|
location.assign(hasSuffix(re[0], 'm3u8') ? chrome.runtime.getURL(`res/hls.html?domain=${domain}&reliability=${reliability}#${re[0]}`) : re[0])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matchClass.match(re).then(function (path) {
|
||||||
|
// @ts-ignore
|
||||||
|
location.assign(hasSuffix(path, 'm3u8') ? chrome.runtime.getURL(`res/hls.html?domain=${domain}&reliability=${reliability}#${path}`) : path)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -3,26 +3,43 @@
|
|||||||
"name": "Stream Bypass",
|
"name": "Stream Bypass",
|
||||||
"author": "ByteDream",
|
"author": "ByteDream",
|
||||||
"description": "",
|
"description": "",
|
||||||
"version": "1.0.0",
|
"version": "1.2.0",
|
||||||
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "{55dd42e8-3dd9-455a-b4fe-86664881b10c}"
|
||||||
|
}
|
||||||
|
},
|
||||||
"content_scripts": [
|
"content_scripts": [
|
||||||
{
|
{
|
||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"matches": [
|
"matches": [
|
||||||
|
"*://evoload.io/*",
|
||||||
|
"*://mcloud.to/*",
|
||||||
|
"*://mixdrop.co/*",
|
||||||
"*://streamtape.com/*",
|
"*://streamtape.com/*",
|
||||||
|
"*://streamzz.to/*",
|
||||||
|
"*://thevideome.com/*",
|
||||||
|
"*://upstream.to/*",
|
||||||
|
"*://vidlox.me/*",
|
||||||
|
"*://vidstream.pro/*",
|
||||||
"*://vidoza.net/*",
|
"*://vidoza.net/*",
|
||||||
|
"*://vivo.st/*",
|
||||||
"*://vivo.sx/*",
|
"*://vivo.sx/*",
|
||||||
|
"*://voe.sx/*",
|
||||||
"*://vupload.com/*"
|
"*://vupload.com/*"
|
||||||
],
|
],
|
||||||
"js": [
|
"js": [
|
||||||
"match.js",
|
"match.js",
|
||||||
"index.js"
|
"index.js"
|
||||||
]
|
],
|
||||||
|
"run_at": "document_end"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"storage"
|
"storage"
|
||||||
],
|
],
|
||||||
|
"content_security_policy": "script-src 'self' blob: https://cdn.jsdelivr.net https://unpkg.com *.io *.to *.co *.com *.me *.pro *.net *.st *.sx; object-src 'self'",
|
||||||
"browser_action": {
|
"browser_action": {
|
||||||
"default_icon": "icons/stream-bypass.png",
|
"default_icon": "icons/stream-bypass.png",
|
||||||
"default_title": "Stream Bypass",
|
"default_title": "Stream Bypass",
|
||||||
|
108
src/match.ts
108
src/match.ts
@ -1,16 +1,84 @@
|
|||||||
|
enum Reliability {
|
||||||
|
LOW = 1,
|
||||||
|
NORMAL,
|
||||||
|
HIGH
|
||||||
|
}
|
||||||
|
|
||||||
interface Match {
|
interface Match {
|
||||||
match(match: RegExpMatchArray): string
|
match(match: RegExpMatchArray): Promise<string>
|
||||||
|
}
|
||||||
|
|
||||||
|
class Evoload implements Match {
|
||||||
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
|
const code = window.location.pathname.split('/').slice(-1)[0]
|
||||||
|
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()
|
||||||
|
return json['stream']['src']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MCloud implements Match {
|
||||||
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
|
const code = window.location.pathname.split('/').slice(-1)[0]
|
||||||
|
const response = await fetch(`https://mcloud.to/info/${code}?skey=${match[0]}`, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
referrer: `https://mcloud.to/embed/${code}`
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
return json['media']['sources'][0]['file']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Mixdrop implements Match {
|
||||||
|
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]}`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Streamtape implements Match {
|
class Streamtape implements Match {
|
||||||
match(match: RegExpMatchArray): string {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return `https://streamtape.com/get_video?${match[0]}`
|
return `https://streamtape.com/get_video?${match[0]}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TheVideoMe implements Match {
|
||||||
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
|
return `https://thevideome.com/${match[5]}.mp4`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Upstream implements Match {
|
||||||
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
|
return `https://${match[48]}.upstreamcdn.co/hls/,${match.sort((a, b) => {return b.length - a.length})[0]},.urlset/master.m3u8`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Vidstream implements Match {
|
||||||
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
|
const code = window.location.pathname.split('/').slice(-1)[0]
|
||||||
|
const response = await fetch(`https://vidstream.pro/info/${code}?skey=${match[0]}`, {
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
referrer: `https://vidstream.pro/embed/${code}`
|
||||||
|
})
|
||||||
|
const json = await response.json()
|
||||||
|
return json['media']['sources'][0]['file']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Vivo implements Match {
|
class Vivo implements Match {
|
||||||
match(match: RegExpMatchArray): string {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return this.rot47(decodeURIComponent(match[1]))
|
return this.rot47(decodeURIComponent(match[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
// decrypts a string with the rot47 algorithm (https://en.wikipedia.org/wiki/ROT13#Variants)
|
// decrypts a string with the rot47 algorithm (https://en.wikipedia.org/wiki/ROT13#Variants)
|
||||||
@ -29,15 +97,35 @@ class Vivo implements Match {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Vupload implements Match {
|
class Vupload implements Match {
|
||||||
match(match: RegExpMatchArray): string {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return `https://www3.megaupload.to/${match[0]}/v.mp4`
|
return `https://www3.megaupload.to/${match[0]}/v.mp4`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// every match HAS to be on an separate line
|
// all domains to match. the matches must be structured like this:
|
||||||
|
// [domain, regex match (can be null), class to call after match (can be null), reliability]
|
||||||
|
// => the domain which should be redirected
|
||||||
|
// => the regex gets called if the user visits a site with the given domain and matches the websites document body.
|
||||||
|
// if the regex is null, the complete document body gets handled as one big regex match
|
||||||
|
// => the class to call when the regex was parsed successfully. the class has to implement the `Match` interface.
|
||||||
|
// if the class is null, the user gets redirected to the first regex match element
|
||||||
|
// => the reliability shows how reliable a stream redirect is. for example, vivo.sx works nearly every time whereas
|
||||||
|
// upstream.to works only sometimes because of a security mechanism they're using (CORS) which currently can't be bypassed
|
||||||
|
//
|
||||||
|
// every match HAS to be on an separate line (for automatically manifest generation)
|
||||||
const matches = [
|
const matches = [
|
||||||
['streamtape.com', new RegExp(/id=\S*(?=')/gm), new Streamtape()],
|
['evoload.io', null, new Evoload(), Reliability.NORMAL],
|
||||||
['vidoza.net', new RegExp(/(?<=src:(\s*)?")\S*(?=")/gm), null],
|
['mcloud.to', new RegExp(/(?<=')\w+(?=';)/gm), new MCloud(), Reliability.NORMAL],
|
||||||
['vivo.sx', new RegExp(/source:\s*'(\S+)'/gm), new Vivo()],
|
['mixdrop.co', new RegExp(/(?<=\|)\w{2,}/gm), new Mixdrop(), Reliability.HIGH],
|
||||||
['vupload.com', new RegExp(/(?<=class\|)\w*/gm), new Vupload()]
|
['streamtape.com', new RegExp(/id=\S*(?=')/gm), new Streamtape(), Reliability.NORMAL],
|
||||||
|
['streamzz.to', new RegExp(/https?:\/\/get.streamz.tw\/getlink-\w+\.dll/gm), null, Reliability.NORMAL],
|
||||||
|
['thevideome.com', new RegExp(/(?<=\|)\w{2,}/gm), new TheVideoMe(), Reliability.NORMAL],
|
||||||
|
['upstream.to', new RegExp(/(?<=\|)\w{2,}/gm), new Upstream(), Reliability.LOW],
|
||||||
|
['vidlox.me', new RegExp(/(?<=\[")\S+?(?=")/gm), null, Reliability.NORMAL],
|
||||||
|
['vidstream.pro', new RegExp(/(?<=')\w+(?=';)/gm), new Vidstream(), Reliability.LOW],
|
||||||
|
['vidoza.net', new RegExp(/(?<=src:(\s*)?")\S*(?=")/gm), null, Reliability.NORMAL],
|
||||||
|
['vivo.st', new RegExp(/(?<=source:\s')(\S+)(?=')/gm), new Vivo(), Reliability.HIGH],
|
||||||
|
['vivo.sx', new RegExp(/(?<=source:\s')(\S+)(?=')/gm), new Vivo(), Reliability.HIGH],
|
||||||
|
['voe.sx', new RegExp(/https?:\/\/\S*m3u8(?=")/gm), null, Reliability.HIGH],
|
||||||
|
['vupload.com', new RegExp(/(?<=class\|)\w*/gm), new Vupload(), Reliability.NORMAL]
|
||||||
]
|
]
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Title</title>
|
<title>Title</title>
|
||||||
<link rel="stylesheet" href="popup.css">
|
<link rel="stylesheet" href="popup.css">
|
||||||
|
<script src="https://unpkg.com/@popperjs/core@2"></script>
|
||||||
|
<script src="https://unpkg.com/tippy.js@6"></script>
|
||||||
<script src="../match.js"></script>
|
<script src="../match.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -2,14 +2,14 @@ body
|
|||||||
background-color: #2b2a33
|
background-color: #2b2a33
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
max-height: 500px
|
max-height: 500px
|
||||||
|
overflow-x: hidden
|
||||||
|
overflow-y: auto
|
||||||
|
|
||||||
a, p
|
a, p
|
||||||
color: white
|
color: white
|
||||||
font-size: 16px
|
font-size: 16px
|
||||||
margin: 5px 0
|
margin: 5px 0
|
||||||
|
|
||||||
|
|
||||||
a
|
a
|
||||||
border: 1px solid #281515
|
border: 1px solid #281515
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
@ -24,7 +24,6 @@ a
|
|||||||
background-color: grey
|
background-color: grey
|
||||||
cursor: not-allowed
|
cursor: not-allowed
|
||||||
|
|
||||||
|
|
||||||
hr
|
hr
|
||||||
margin: 3px 0
|
margin: 3px 0
|
||||||
|
|
||||||
@ -33,3 +32,16 @@ hr
|
|||||||
display: flex
|
display: flex
|
||||||
justify-content: center
|
justify-content: center
|
||||||
margin: 10px 0
|
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
|
||||||
|
@ -51,12 +51,53 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
let name = document.createElement('td')
|
let name = document.createElement('td')
|
||||||
let nameValue = document.createElement('p')
|
let nameValue = document.createElement('p')
|
||||||
nameValue.innerText = match[0]
|
nameValue.innerText = match[0]
|
||||||
|
switch (match[3]) {
|
||||||
|
case 1: // low
|
||||||
|
nameValue.classList.add('low-reliability')
|
||||||
|
// @ts-ignore
|
||||||
|
tippy(nameValue, {
|
||||||
|
content: 'Low reliability: Errors may occur often'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 2: // normal
|
||||||
|
nameValue.classList.add('normal-reliability')
|
||||||
|
// @ts-ignore
|
||||||
|
tippy(nameValue, {
|
||||||
|
content: 'Normal reliability: Save to use but errors may occur'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
case 3: //high
|
||||||
|
nameValue.classList.add('high-reliability')
|
||||||
|
// @ts-ignore
|
||||||
|
tippy(nameValue, {
|
||||||
|
content: 'High reliability: Errors are very unlikely to happen'
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
let buttons = document.createElement('td')
|
let buttons = document.createElement('td')
|
||||||
buttons.classList.add('buttons')
|
buttons.classList.add('buttons')
|
||||||
let on = document.createElement('a')
|
let on = document.createElement('a')
|
||||||
on.innerText = 'On'
|
on.innerText = 'On'
|
||||||
|
// @ts-ignore
|
||||||
|
let onTippy = tippy(on, {
|
||||||
|
content: `Enable ${match[0]}`,
|
||||||
|
onMount: () => {
|
||||||
|
if (on.classList.contains('active') || off.classList.contains('disabled')) {
|
||||||
|
onTippy.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
let off = document.createElement('a')
|
let off = document.createElement('a')
|
||||||
off.innerText = 'Off'
|
off.innerText = 'Off'
|
||||||
|
// @ts-ignore
|
||||||
|
let offTippy = tippy(off, {
|
||||||
|
content: `Disable ${match[0]}`,
|
||||||
|
onMount: () => {
|
||||||
|
if (off.classList.contains('active') || off.classList.contains('disabled')) {
|
||||||
|
offTippy.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
disabled.has(match[0]) ? off.classList.add('active') : on.classList.add('active')
|
disabled.has(match[0]) ? off.classList.add('active') : on.classList.add('active')
|
||||||
if (allDisabled) {
|
if (allDisabled) {
|
||||||
on.classList.add('disabled')
|
on.classList.add('disabled')
|
||||||
@ -85,6 +126,7 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let allButtons = document.getElementById('all').getElementsByTagName('a')
|
let allButtons = document.getElementById('all').getElementsByTagName('a')
|
||||||
|
let allOn = allButtons[0]
|
||||||
allButtons[0].onclick = function () {
|
allButtons[0].onclick = function () {
|
||||||
if (!allButtons[0].classList.contains('disabled')) {
|
if (!allButtons[0].classList.contains('disabled')) {
|
||||||
enableAll(true)
|
enableAll(true)
|
||||||
@ -92,6 +134,15 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
allButtons[1].classList.remove('active')
|
allButtons[1].classList.remove('active')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
let allOnTippy = tippy(allOn, {
|
||||||
|
content: 'Enable all websites',
|
||||||
|
onMount: () => {
|
||||||
|
if (allButtons[0].classList.contains('active')) {
|
||||||
|
allOnTippy.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
allButtons[1].onclick = function () {
|
allButtons[1].onclick = function () {
|
||||||
if (!allButtons[1].classList.contains('disabled')) {
|
if (!allButtons[1].classList.contains('disabled')) {
|
||||||
enableAll(false)
|
enableAll(false)
|
||||||
@ -99,5 +150,14 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
allButtons[1].classList.add('active')
|
allButtons[1].classList.add('active')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
let allOffTippy = tippy(allButtons[1], {
|
||||||
|
content: 'Disable all websites',
|
||||||
|
onMount: () => {
|
||||||
|
if (allButtons[1].classList.contains('active')) {
|
||||||
|
allOffTippy.hide()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
allDisabled ? allButtons[1].classList.add('active') : allButtons[0].classList.add('active')
|
allDisabled ? allButtons[1].classList.add('active') : allButtons[0].classList.add('active')
|
||||||
})
|
})
|
||||||
|
13
src/res/hls.html
Normal file
13
src/res/hls.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>m3u8</title>
|
||||||
|
<link rel="stylesheet" href="/res/hls.css">
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video id="video"></video>
|
||||||
|
<p id="message" hidden></p>
|
||||||
|
<script src="/res/hls.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/res/hls.sass
Normal file
9
src/res/hls.sass
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
html, body, video
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
margin: 0
|
||||||
|
|
||||||
|
video
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
60
src/res/hls.ts
Normal file
60
src/res/hls.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
function showMessage(message: string) {
|
||||||
|
let messageElement = document.getElementById('message') as HTMLParagraphElement
|
||||||
|
messageElement.innerHTML = message
|
||||||
|
messageElement.hidden = false
|
||||||
|
document.getElementById('video').hidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadHls() {
|
||||||
|
let url = window.location.hash.substring(1)
|
||||||
|
let video = document.getElementById('video') as HTMLVideoElement;
|
||||||
|
|
||||||
|
video.controls = true
|
||||||
|
if (video.canPlayType('application/vnd.apple.mpegurl')) {
|
||||||
|
video.src = url
|
||||||
|
// @ts-ignore
|
||||||
|
} else if (Hls.isSupported()) {
|
||||||
|
// @ts-ignore
|
||||||
|
let hls = new Hls()
|
||||||
|
hls.loadSource(url)
|
||||||
|
hls.attachMedia(video)
|
||||||
|
|
||||||
|
let searchParams = new URLSearchParams(window.location.search)
|
||||||
|
let rawReliability = parseInt(searchParams.get('reliability'))
|
||||||
|
|
||||||
|
let thirdPartyFallback = setTimeout(() => {
|
||||||
|
let message: string
|
||||||
|
|
||||||
|
switch (rawReliability) {
|
||||||
|
case 1: // low
|
||||||
|
message = `The reliability for this domain is low, so errors like this are common.
|
||||||
|
Try to choose another streaming provider (if existent) or deactivate the addon for this domain (${searchParams.get('domain')}) and try again`
|
||||||
|
break
|
||||||
|
case 2: // 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 3: // 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">here</a>.
|
||||||
|
When your 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 you it's working then`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// shows a message if hls could not be loaded
|
||||||
|
showMessage(`Could not load hls video. ${message}`)
|
||||||
|
}, rawReliability * 3000)
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
clearTimeout(thirdPartyFallback)
|
||||||
|
document.getElementById('video').hidden = false
|
||||||
|
document.getElementById('message').hidden = true
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// shows a message if hls is not supported
|
||||||
|
showMessage(`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">here</a>`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loadHls()
|
@ -2,11 +2,13 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "es2015",
|
"target": "es2015",
|
||||||
|
"removeComments": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"dom",
|
"dom",
|
||||||
"es5",
|
"es5",
|
||||||
"scripthost",
|
"scripthost",
|
||||||
"es2015.collection"
|
"es2015.collection",
|
||||||
|
"es2015.promise"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": [
|
||||||
|
Reference in New Issue
Block a user