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 | |
---|---|---|---|
55eac3c010 | |||
d93a5ea784 | |||
e41bc2b8ef | |||
052c0d1e78 | |||
1e7b9b3d8d | |||
fbb9a1d67b | |||
126aeee1f7 | |||
0916f1c637 | |||
99d4577d1d | |||
9929c48761 | |||
2e13586ebb |
35
README.md
35
README.md
@ -6,9 +6,31 @@ This addon replaces the video player from this sides with the native player buil
|
|||||||
This has the advantage, that no advertising or popups are shown when trying to interact with the video (playing, skipping, ...) or some sites are showing them even if you do nothing.
|
This has the advantage, that no advertising or popups are shown when trying to interact with the video (playing, skipping, ...) or some sites are showing them even if you do nothing.
|
||||||
Additionally this enables you to download the video by right-clicking it and just choose the download option.
|
Additionally this enables you to download the video by right-clicking it and just choose the download option.
|
||||||
|
|
||||||
Supported streaming providers (for a complete list of all supported websites, see [here](SUPPORTED)):
|
Supported streaming providers (for a complete list of all supported websites, see [here](SUPPORTED) or in [show all](#all-supported-websites) below):
|
||||||
- [streamtape.com](https://streamtape.com/)
|
- [streamtape.com](https://streamtape.com)
|
||||||
- [vidoza.net](https://vidoza.net/)
|
- [vivo.sx](https://vivo.sx)
|
||||||
|
- [voe.sx](https://voe.sx)
|
||||||
|
|
||||||
|
<details id="all-supported-websites">
|
||||||
|
<summary><b>Show all</b></summary>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://evoload.io">evoload.io</a></li>
|
||||||
|
<li><a href="https://mcloud.to">mcloud.to</a></li>
|
||||||
|
<li><a href="https://mixdrop.co">mixdrop.co</a></li>
|
||||||
|
<li><a href="https://streamtape.com">streamtape.com</a></li>
|
||||||
|
<li><a href="https://streamzz.to">streamzz.to</a></li>
|
||||||
|
<li><a href="https://thevideome.com">thevideome.com</a></li>
|
||||||
|
<li><a href="https://upstream.to">upstream.to</a></li>
|
||||||
|
<li><a href="https://vidlox.me">vidlox.me</a></li>
|
||||||
|
<li><a href="https://vidstream.pro">vidstream.pro</a></li>
|
||||||
|
<li><a href="https://vidoza.net">vidoza.net</a></li>
|
||||||
|
<li><a href="https://vivo.st">vivo.st</a></li>
|
||||||
|
<li><a href="https://vivo.sx">vivo.sx</a></li>
|
||||||
|
<li><a href="https://voe.sx">voe.sx</a></li>
|
||||||
|
<li><a href="https://vupload.com">vupload.com</a></li></ul>
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
<details id="example">
|
<details id="example">
|
||||||
<summary><b>How it's working</b></summary>
|
<summary><b>How it's working</b></summary>
|
||||||
@ -16,9 +38,10 @@ Supported streaming providers (for a complete list of all supported websites, se
|
|||||||
</details>
|
</details>
|
||||||
|
|
||||||
The addon was tested on
|
The addon was tested on
|
||||||
- Firefox (92.0)
|
- Firefox (95.0b8)
|
||||||
- Chromium (92.0)
|
- Ungoogled Chromium (94.0)
|
||||||
- Opera (78.0)
|
- Vivaldi (4.3)
|
||||||
|
- Opera (81.0)
|
||||||
|
|
||||||
## Installing
|
## Installing
|
||||||
|
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
evoload.io
|
evoload.io
|
||||||
|
mcloud.to
|
||||||
mixdrop.co
|
mixdrop.co
|
||||||
streamtape.com
|
streamtape.com
|
||||||
streamzz.to
|
streamzz.to
|
||||||
thevideome.com
|
thevideome.com
|
||||||
|
upstream.to
|
||||||
vidlox.me
|
vidlox.me
|
||||||
|
vidstream.pro
|
||||||
vidoza.net
|
vidoza.net
|
||||||
vivo.st
|
vivo.st
|
||||||
vivo.sx
|
vivo.sx
|
||||||
|
57
build.py
57
build.py
@ -1,8 +1,11 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import io
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
|
import urllib.request
|
||||||
|
import zipfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
@ -42,6 +45,42 @@ def write_supported():
|
|||||||
open('SUPPORTED', 'w').writelines([f'{match}\n' for match in load_matches()])
|
open('SUPPORTED', 'w').writelines([f'{match}\n' for match in load_matches()])
|
||||||
|
|
||||||
|
|
||||||
|
def write_readme():
|
||||||
|
firefox_pattern = re.compile(r'Mozilla Firefox (?P<version>.+)')
|
||||||
|
chromium_pattern = re.compile(r'(?P<version>\d+\.\d+)')
|
||||||
|
tested = {}
|
||||||
|
|
||||||
|
stdout, stderr = subprocess.Popen(['firefox', '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||||
|
if stderr == b'':
|
||||||
|
tested['Firefox'] = re.search(firefox_pattern, stdout.decode('utf-8').replace('\n', '')).group('version')
|
||||||
|
|
||||||
|
for command, name in {'chromium': 'Ungoogled Chromium', 'vivaldi-stable': 'Vivaldi', 'opera': 'Opera'}.items():
|
||||||
|
stdout, stderr = subprocess.Popen([command, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
|
||||||
|
if stderr == b'':
|
||||||
|
tested[name] = re.search(chromium_pattern, stdout.decode('utf-8').replace('\n', '')).group('version')
|
||||||
|
|
||||||
|
# it this the right syntax if i want to read and write to a file? * dreams in python3.10 *
|
||||||
|
with open('README.md', 'r') as read_file:
|
||||||
|
readme = read_file.read()
|
||||||
|
|
||||||
|
# adds all available websites
|
||||||
|
all_providers_regex = r'(?<=<ul>\n)(.+?)(?=</ul>)'
|
||||||
|
domains = filter(lambda domain: domain != '', open('SUPPORTED', 'r').read().split('\n'))
|
||||||
|
all_providers = '\n'.join(f'\t\t<li><a href="https://{supported}">{supported}</a></li>' for supported in domains)
|
||||||
|
readme = re.sub(all_providers_regex, all_providers, readme, flags=re.DOTALL)
|
||||||
|
|
||||||
|
# adds all installed browsers to the tested browser section. i'm just to lazy to seek out all browser versions manually
|
||||||
|
tested_browsers_regex = r'(?<=The addon was tested on\n)(.+?)(?=\n*## Installing)'
|
||||||
|
tested_browsers = '\n'.join(f'- {name} ({version})' for name, version in tested.items())
|
||||||
|
readme = re.sub(tested_browsers_regex, tested_browsers, readme, flags=re.DOTALL)
|
||||||
|
|
||||||
|
# rewrite the readme
|
||||||
|
with open('README.md', 'w') as write_file:
|
||||||
|
write_file.write(readme)
|
||||||
|
write_file.close()
|
||||||
|
read_file.close()
|
||||||
|
|
||||||
|
|
||||||
def copy_built():
|
def copy_built():
|
||||||
if not shutil.which('tsc'):
|
if not shutil.which('tsc'):
|
||||||
sys.stderr.write('The typescript compiler `tsc` could not be found')
|
sys.stderr.write('The typescript compiler `tsc` could not be found')
|
||||||
@ -71,6 +110,21 @@ def copy_built():
|
|||||||
elif file.suffix != '.ts':
|
elif file.suffix != '.ts':
|
||||||
shutil.copy(str(file), str(build_file))
|
shutil.copy(str(file), str(build_file))
|
||||||
|
|
||||||
|
ext_path = Path('build', 'ext')
|
||||||
|
if not ext_path.is_dir():
|
||||||
|
ext_path.mkdir()
|
||||||
|
|
||||||
|
# download hls.js (version 1.1.1)
|
||||||
|
with zipfile.ZipFile(io.BytesIO(urllib.request.urlopen('https://github.com/video-dev/hls.js/releases/download/v1.1.1/release.zip').read())) as z:
|
||||||
|
open(ext_path.joinpath('hls.light.min.js'), 'wb').write(z.read('dist/hls.light.min.js'))
|
||||||
|
z.close()
|
||||||
|
|
||||||
|
# download popperjs core (version 2.10.2)
|
||||||
|
open(ext_path.joinpath('popper.min.js'), 'wb').write(urllib.request.urlopen('https://unpkg.com/@popperjs/core@2.10.2/dist/umd/popper.min.js').read())
|
||||||
|
|
||||||
|
# download tippy.js (version 6.3.7)
|
||||||
|
open(ext_path.joinpath('tippy-bundle.umd.min.js'), 'wb').write(urllib.request.urlopen('https://unpkg.com/tippy.js@6.3.7/dist/tippy-bundle.umd.min.js').read())
|
||||||
|
|
||||||
|
|
||||||
def clean_build():
|
def clean_build():
|
||||||
for file in Path('src').rglob('*'):
|
for file in Path('src').rglob('*'):
|
||||||
@ -81,6 +135,7 @@ def clean_build():
|
|||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('-m', '--manifest', action='store_true', help='Builds the manifest.json file for addon information in ./src')
|
parser.add_argument('-m', '--manifest', action='store_true', help='Builds the manifest.json file for addon information in ./src')
|
||||||
|
parser.add_argument('-r', '--readme', action='store_true', help='Updates the README.md with the currently installed ')
|
||||||
parser.add_argument('-s', '--supported', action='store_true', help='Builds the SUPPORTED file with all supported domains in the current directory')
|
parser.add_argument('-s', '--supported', action='store_true', help='Builds the SUPPORTED file with all supported domains in the current directory')
|
||||||
parser.add_argument('-b', '--build', action='store_true', help='Creates a ./build folder and builds all typescript / sass files')
|
parser.add_argument('-b', '--build', action='store_true', help='Creates a ./build folder and builds all typescript / sass files')
|
||||||
parser.add_argument('-c', '--clean', action='store_true', help='Cleans the ./src folder from .js, .css and .map files')
|
parser.add_argument('-c', '--clean', action='store_true', help='Cleans the ./src folder from .js, .css and .map files')
|
||||||
@ -89,6 +144,8 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
if parsed.manifest:
|
if parsed.manifest:
|
||||||
write_manifest()
|
write_manifest()
|
||||||
|
if parsed.readme:
|
||||||
|
write_readme()
|
||||||
if parsed.supported:
|
if parsed.supported:
|
||||||
write_supported()
|
write_supported()
|
||||||
if parsed.build:
|
if parsed.build:
|
||||||
|
12
src/index.ts
12
src/index.ts
@ -10,10 +10,12 @@ 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) {
|
||||||
@ -28,11 +30,13 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
|||||||
if (regex === null) {
|
if (regex === null) {
|
||||||
location.assign(document.body.innerHTML)
|
location.assign(document.body.innerHTML)
|
||||||
} else {
|
} else {
|
||||||
location.assign(hasSuffix(re[0], 'm3u8') ? `https://bharadwajpro.github.io/m3u8-player/player/#${re[0]}`: re[0])
|
// @ts-ignore
|
||||||
|
location.assign(hasSuffix(re[0], 'm3u8') ? chrome.runtime.getURL(`res/hls.html?domain=${domain}&reliability=${reliability}#${re[0]}`) : re[0])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
matchClass.match(re).then(function (path) {
|
matchClass.match(re).then(function (path) {
|
||||||
location.assign(hasSuffix(path, 'm3u8') ? `https://bharadwajpro.github.io/m3u8-player/player/#${path}`: path)
|
// @ts-ignore
|
||||||
|
location.assign(hasSuffix(path, 'm3u8') ? chrome.runtime.getURL(`res/hls.html?domain=${domain}&reliability=${reliability}#${path}`) : path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"name": "Stream Bypass",
|
"name": "Stream Bypass",
|
||||||
"author": "ByteDream",
|
"author": "ByteDream",
|
||||||
"description": "",
|
"description": "A multi-browser addon / extension for multiple streaming providers which redirects directly to the source video.",
|
||||||
"version": "1.1.4",
|
"version": "1.4.0",
|
||||||
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
||||||
"browser_specific_settings": {
|
"browser_specific_settings": {
|
||||||
"gecko": {
|
"gecko": {
|
||||||
@ -15,11 +15,14 @@
|
|||||||
"all_frames": true,
|
"all_frames": true,
|
||||||
"matches": [
|
"matches": [
|
||||||
"*://evoload.io/*",
|
"*://evoload.io/*",
|
||||||
|
"*://mcloud.to/*",
|
||||||
"*://mixdrop.co/*",
|
"*://mixdrop.co/*",
|
||||||
"*://streamtape.com/*",
|
"*://streamtape.com/*",
|
||||||
"*://streamzz.to/*",
|
"*://streamzz.to/*",
|
||||||
"*://thevideome.com/*",
|
"*://thevideome.com/*",
|
||||||
|
"*://upstream.to/*",
|
||||||
"*://vidlox.me/*",
|
"*://vidlox.me/*",
|
||||||
|
"*://vidstream.pro/*",
|
||||||
"*://vidoza.net/*",
|
"*://vidoza.net/*",
|
||||||
"*://vivo.st/*",
|
"*://vivo.st/*",
|
||||||
"*://vivo.sx/*",
|
"*://vivo.sx/*",
|
||||||
@ -29,12 +32,14 @@
|
|||||||
"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:; 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",
|
||||||
|
77
src/match.ts
77
src/match.ts
@ -1,3 +1,9 @@
|
|||||||
|
enum Reliability {
|
||||||
|
LOW = 1,
|
||||||
|
NORMAL,
|
||||||
|
HIGH
|
||||||
|
}
|
||||||
|
|
||||||
interface Match {
|
interface Match {
|
||||||
match(match: RegExpMatchArray): Promise<string>
|
match(match: RegExpMatchArray): Promise<string>
|
||||||
}
|
}
|
||||||
@ -18,6 +24,20 @@ class Evoload implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
class Mixdrop implements Match {
|
||||||
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]}`
|
return `https://a-${match[1]}.${match[4]}.${match[5]}/v/${match[2]}.${match[6]}?s=${match[12]}&e=${match[13]}`
|
||||||
@ -36,6 +56,26 @@ class TheVideoMe implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
async match(match: RegExpMatchArray): Promise<string> {
|
async match(match: RegExpMatchArray): Promise<string> {
|
||||||
return this.rot47(decodeURIComponent(match[0]))
|
return this.rot47(decodeURIComponent(match[0]))
|
||||||
@ -62,17 +102,30 @@ class Vupload implements Match {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 = [
|
||||||
['evoload.io', null, new Evoload()],
|
['evoload.io', null, new Evoload(), Reliability.NORMAL],
|
||||||
['mixdrop.co', new RegExp(/(?<=\|)\w{2,}/gm), new Mixdrop()],
|
['mcloud.to', new RegExp(/(?<=')\w+(?=';)/gm), new MCloud(), Reliability.NORMAL],
|
||||||
['streamtape.com', new RegExp(/id=\S*(?=')/gm), new Streamtape()],
|
['mixdrop.co', new RegExp(/(?<=\|)\w{2,}/gm), new Mixdrop(), Reliability.HIGH],
|
||||||
['streamzz.to', new RegExp(/https?:\/\/get.streamz.tw\/getlink-\w+\.dll/gm), null],
|
['streamtape.com', new RegExp(/id=\S*(?=')/gm), new Streamtape(), Reliability.NORMAL],
|
||||||
['thevideome.com', new RegExp(/(?<=\|)\w{2,}/gm), new TheVideoMe()],
|
['streamzz.to', new RegExp(/https?:\/\/get.streamz.tw\/getlink-\w+\.dll/gm), null, Reliability.NORMAL],
|
||||||
['vidlox.me', new RegExp(/(?<=\[")\S+?(?=")/gm), null],
|
['thevideome.com', new RegExp(/(?<=\|)\w{2,}/gm), new TheVideoMe(), Reliability.NORMAL],
|
||||||
['vidoza.net', new RegExp(/(?<=src:(\s*)?")\S*(?=")/gm), null],
|
['upstream.to', new RegExp(/(?<=\|)\w{2,}/gm), new Upstream(), Reliability.LOW],
|
||||||
['vivo.st', new RegExp(/(?<=source:\s')(\S+)(?=')/gm), new Vivo()],
|
['vidlox.me', new RegExp(/(?<=\[")\S+?(?=")/gm), null, Reliability.NORMAL],
|
||||||
['vivo.sx', new RegExp(/(?<=source:\s')(\S+)(?=')/gm), new Vivo()],
|
['vidstream.pro', new RegExp(/(?<=')\w+(?=';)/gm), new Vidstream(), Reliability.LOW],
|
||||||
['voe.sx', new RegExp(/https?:\/\/\S*m3u8(?=")/gm), null],
|
['vidoza.net', new RegExp(/(?<=src:(\s*)?")\S*(?=")/gm), null, Reliability.NORMAL],
|
||||||
['vupload.com', new RegExp(/(?<=class\|)\w*/gm), new Vupload()]
|
['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="../ext/popper.min.js"></script>
|
||||||
|
<script src="../ext/tippy-bundle.umd.min.js"></script>
|
||||||
<script src="../match.js"></script>
|
<script src="../match.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
@ -5,13 +5,11 @@ body
|
|||||||
overflow-x: hidden
|
overflow-x: hidden
|
||||||
overflow-y: auto
|
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
|
||||||
@ -26,7 +24,6 @@ a
|
|||||||
background-color: grey
|
background-color: grey
|
||||||
cursor: not-allowed
|
cursor: not-allowed
|
||||||
|
|
||||||
|
|
||||||
hr
|
hr
|
||||||
margin: 3px 0
|
margin: 3px 0
|
||||||
|
|
||||||
@ -35,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="/ext/hls.light.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<video id="video"></video>
|
||||||
|
<p id="message" hidden></p>
|
||||||
|
<script src="/res/hls.light.min.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.innerText = 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