mirror of
https://github.com/bytedream/stream-bypass.git
synced 2025-06-27 10:30: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
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
3. Turn the developer mode in the top right corner on.
|
||||
4. Click Load unpacked.
|
||||
@ -36,7 +36,7 @@ Install the `.xpi` (firefox addon) file from the [latest release](https://github
|
||||
|
||||
### 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.
|
||||
3. Turn the developer mode in the top right corner on.
|
||||
4. Click Load unpacked.
|
||||
@ -77,7 +77,7 @@ For this, you need [docker](https://www.docker.com/) to be installed.
|
||||
```
|
||||
- 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.
|
||||
|
||||
|
10
SUPPORTED
10
SUPPORTED
@ -1,4 +1,14 @@
|
||||
evoload.io
|
||||
mcloud.to
|
||||
mixdrop.co
|
||||
streamtape.com
|
||||
streamzz.to
|
||||
thevideome.com
|
||||
upstream.to
|
||||
vidlox.me
|
||||
vidstream.pro
|
||||
vidoza.net
|
||||
vivo.st
|
||||
vivo.sx
|
||||
voe.sx
|
||||
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']:
|
||||
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)
|
||||
|
||||
|
||||
@ -55,18 +62,13 @@ def copy_built():
|
||||
subprocess.call(['tsc', '-p', 'src'])
|
||||
|
||||
build_path = Path('build')
|
||||
if build_path.is_dir():
|
||||
for file in build_path.rglob('*'):
|
||||
if file.is_dir():
|
||||
shutil.rmtree(str(file))
|
||||
else:
|
||||
file.unlink()
|
||||
else:
|
||||
if not build_path.is_dir():
|
||||
build_path.mkdir()
|
||||
for file in Path('src').rglob('*'):
|
||||
build_file = build_path.joinpath(str(file)[4:])
|
||||
if file.is_dir():
|
||||
build_file.mkdir(parents=True)
|
||||
if not build_file.exists():
|
||||
build_file.mkdir(parents=True)
|
||||
elif file.suffix == '.sass':
|
||||
css_file = str(file)[:-4] + 'css'
|
||||
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
|
||||
chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
let keys = Object.keys(result)
|
||||
@ -6,16 +10,34 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
}
|
||||
// @ts-ignore
|
||||
for (let match of matches) {
|
||||
if (window.location.href.indexOf(match[0]) !== -1) {
|
||||
if (keys.indexOf('disabled') === -1 || result['disabled'].indexOf(match[0]) === -1) {
|
||||
let domain = match[0] as string
|
||||
if (window.location.href.indexOf(domain) !== -1) {
|
||||
if (keys.indexOf('disabled') === -1 || result['disabled'].indexOf(domain) === -1) {
|
||||
let regex = match[1] as RegExp
|
||||
let matchClass = match[2] as Match
|
||||
let reliability = match[3] as Reliability
|
||||
|
||||
let re
|
||||
if (regex === null) {
|
||||
location.assign(matchClass === null ? document.body.innerHTML : matchClass.match(new RegExp('').exec(document.body.innerHTML)))
|
||||
} else if ((re = regex.exec(document.body.innerHTML)) !== null) {
|
||||
location.assign(matchClass === null ? re[0] : matchClass.match(re))
|
||||
if (regex !== null) {
|
||||
if ((re = document.body.innerHTML.match(regex)) === null) {
|
||||
continue
|
||||
}
|
||||
} 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
|
||||
|
@ -3,26 +3,43 @@
|
||||
"name": "Stream Bypass",
|
||||
"author": "ByteDream",
|
||||
"description": "",
|
||||
"version": "1.0.0",
|
||||
"version": "1.2.0",
|
||||
"homepage_url": "https://github.com/ByteDream/stream-bypass",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "{55dd42e8-3dd9-455a-b4fe-86664881b10c}"
|
||||
}
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"all_frames": true,
|
||||
"matches": [
|
||||
"*://evoload.io/*",
|
||||
"*://mcloud.to/*",
|
||||
"*://mixdrop.co/*",
|
||||
"*://streamtape.com/*",
|
||||
"*://streamzz.to/*",
|
||||
"*://thevideome.com/*",
|
||||
"*://upstream.to/*",
|
||||
"*://vidlox.me/*",
|
||||
"*://vidstream.pro/*",
|
||||
"*://vidoza.net/*",
|
||||
"*://vivo.st/*",
|
||||
"*://vivo.sx/*",
|
||||
"*://voe.sx/*",
|
||||
"*://vupload.com/*"
|
||||
],
|
||||
"js": [
|
||||
"match.js",
|
||||
"index.js"
|
||||
]
|
||||
],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
],
|
||||
"permissions": [
|
||||
"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": {
|
||||
"default_icon": "icons/stream-bypass.png",
|
||||
"default_title": "Stream Bypass",
|
||||
|
108
src/match.ts
108
src/match.ts
@ -1,16 +1,84 @@
|
||||
enum Reliability {
|
||||
LOW = 1,
|
||||
NORMAL,
|
||||
HIGH
|
||||
}
|
||||
|
||||
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 {
|
||||
match(match: RegExpMatchArray): string {
|
||||
async match(match: RegExpMatchArray): Promise<string> {
|
||||
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 {
|
||||
match(match: RegExpMatchArray): string {
|
||||
return this.rot47(decodeURIComponent(match[1]))
|
||||
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)
|
||||
@ -29,15 +97,35 @@ class Vivo 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`
|
||||
}
|
||||
}
|
||||
|
||||
// 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 = [
|
||||
['streamtape.com', new RegExp(/id=\S*(?=')/gm), new Streamtape()],
|
||||
['vidoza.net', new RegExp(/(?<=src:(\s*)?")\S*(?=")/gm), null],
|
||||
['vivo.sx', new RegExp(/source:\s*'(\S+)'/gm), new Vivo()],
|
||||
['vupload.com', new RegExp(/(?<=class\|)\w*/gm), new Vupload()]
|
||||
['evoload.io', null, new Evoload(), Reliability.NORMAL],
|
||||
['mcloud.to', new RegExp(/(?<=')\w+(?=';)/gm), new MCloud(), Reliability.NORMAL],
|
||||
['mixdrop.co', new RegExp(/(?<=\|)\w{2,}/gm), new Mixdrop(), Reliability.HIGH],
|
||||
['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">
|
||||
<title>Title</title>
|
||||
<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>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -2,14 +2,14 @@ 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
|
||||
|
||||
|
||||
a
|
||||
border: 1px solid #281515
|
||||
cursor: pointer
|
||||
@ -24,7 +24,6 @@ a
|
||||
background-color: grey
|
||||
cursor: not-allowed
|
||||
|
||||
|
||||
hr
|
||||
margin: 3px 0
|
||||
|
||||
@ -33,3 +32,16 @@ hr
|
||||
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
|
||||
|
@ -51,12 +51,53 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
let name = document.createElement('td')
|
||||
let nameValue = document.createElement('p')
|
||||
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')
|
||||
buttons.classList.add('buttons')
|
||||
let on = document.createElement('a')
|
||||
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')
|
||||
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')
|
||||
if (allDisabled) {
|
||||
on.classList.add('disabled')
|
||||
@ -85,6 +126,7 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
}
|
||||
|
||||
let allButtons = document.getElementById('all').getElementsByTagName('a')
|
||||
let allOn = allButtons[0]
|
||||
allButtons[0].onclick = function () {
|
||||
if (!allButtons[0].classList.contains('disabled')) {
|
||||
enableAll(true)
|
||||
@ -92,6 +134,15 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
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 () {
|
||||
if (!allButtons[1].classList.contains('disabled')) {
|
||||
enableAll(false)
|
||||
@ -99,5 +150,14 @@ chrome.storage.local.get(['all', 'disabled'], function (result) {
|
||||
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')
|
||||
})
|
||||
|
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": {
|
||||
"module": "commonjs",
|
||||
"target": "es2015",
|
||||
"removeComments": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es5",
|
||||
"scripthost",
|
||||
"es2015.collection"
|
||||
"es2015.collection",
|
||||
"es2015.promise"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
|
Reference in New Issue
Block a user