9 Commits

11 changed files with 158 additions and 125 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "stream-bypass", "name": "stream-bypass",
"version": "2.1.3", "version": "2.1.5",
"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",

View File

@ -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>'],

View File

@ -4,20 +4,20 @@ 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)

View File

@ -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.3", "version": "2.1.5",
"homepage_url": "https://github.com/ByteDream/stream-bypass", "homepage_url": "https://github.com/ByteDream/stream-bypass",
"browser_specific_settings": { "browser_specific_settings": {
"gecko": { "gecko": {

View File

@ -19,11 +19,12 @@ export abstract class Match {
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.ws',
'dood.wf'
] ]
replace = true replace = true
regex = new RegExp(/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s) regex = new RegExp(/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s)
@ -139,7 +140,7 @@ class Streamtape implements Match {
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'

View File

@ -1,28 +0,0 @@
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

34
src/ui/player/player.scss Normal file
View 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
}
}

View File

@ -8,33 +8,15 @@ function show_message(message: string) {
document.getElementById('video').hidden = true document.getElementById('video').hidden = true
} }
async function play_native(url: string, match: Match) { async function check_loaded(match: Match, check: Promise<boolean>) {
const video = document.getElementById('video') as HTMLVideoElement const loaded = await new Promise((resolve, _) => {
video.controls = true
video.src = url
}
async function play_hls(url: string, match: Match) {
const video = document.getElementById('video') as HTMLVideoElement
video.controls = true
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url
} else if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: false
})
hls.loadSource(url)
hls.attachMedia(video)
const loaded = await new Promise((resolve, reject) => {
setTimeout(() => { setTimeout(() => {
resolve(false) resolve(false)
}, match.reliability * 3000) }, match.reliability * 3000)
hls.on(Hls.Events.MANIFEST_PARSED, () => { check
resolve(true) .then(value => resolve(value))
}) .catch(_ => resolve(false))
}) })
if (!loaded) { if (!loaded) {
@ -56,6 +38,38 @@ async function play_hls(url: string, match: Match) {
} }
show_message(`Could not load video. ${message}`) show_message(`Could not load video. ${message}`)
} }
}
async function play_native(url: string, match: Match) {
const video = document.getElementById('video') as HTMLVideoElement
video.controls = true
video.src = url
const readyState = new Promise<boolean>((resolve, _) => {
video.onloadeddata = () => resolve(true)
})
await check_loaded(match, readyState)
}
async function play_hls(url: string, match: Match) {
const video = document.getElementById('video') as HTMLVideoElement
video.controls = true
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = url
} else if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: false
})
hls.loadSource(url)
hls.attachMedia(video)
const readyState = new Promise<boolean>((resolve, _) => {
video.onloadeddata = () => resolve(true)
})
await check_loaded(match, readyState)
} 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>')
} }

View File

@ -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
View 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;
}

View File

@ -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)) {