23 Commits

Author SHA1 Message Date
44d4c9cbcf Update supported websites 2022-07-20 11:56:08 +02:00
b34531b982 Bump version to 2.1.1 2022-07-20 11:55:57 +02:00
e699d3885c Change mp4upload reliability 2022-07-19 11:53:14 +02:00
396038a803 Fix replace video player height 2022-07-19 11:28:11 +02:00
bd64d4ed0b Add doodstream domain 2022-07-19 11:27:03 +02:00
a207c336b0 Add mp4upload support 2022-07-19 11:09:09 +02:00
2460657f2a Remove doodstream comment 2022-07-19 11:06:56 +02:00
698ed5ac3c Add support for doodstream 2022-07-19 11:03:16 +02:00
dc42220f09 Fix streamtape 2022-07-19 10:07:21 +02:00
e146649bbf Use window.location instead of location 2022-07-16 02:34:22 +02:00
424e34190c Rework title of built-in player 2022-07-16 02:32:23 +02:00
c5f4f8b246 Version to 2.1.0 2022-07-13 18:39:26 +02:00
e2b8d884af Fix streamtape regex 2022-07-13 18:21:03 +02:00
b07d0b4be6 Update supported sites table 2022-07-13 18:04:55 +02:00
2d0441997c Add doodstream stubs 2022-07-13 18:04:44 +02:00
53e040db46 Fix addon cannot be disabled via ui 2022-07-13 01:00:33 +02:00
6d1ff3fbea Fix player not working in non firefox browsers 2022-07-13 00:46:40 +02:00
4cf76eb62a Add functions to bypass websites that are redirected to (looking at you voe) 2022-07-13 00:45:52 +02:00
672b920f31 Rename match.ts to matches.ts 2022-07-12 22:51:37 +02:00
1e166b5ecc Add new voe domain (un-block-voe.net) 2022-07-04 12:27:14 +02:00
213b996755 Add new voe domain (voeun-block.net) 2022-06-26 14:08:56 +02:00
de0d8d5a41 Fix typo 2022-06-20 16:22:34 +02:00
1f34f74e11 Fix typo 2022-06-20 10:49:34 +02:00
12 changed files with 343 additions and 315 deletions

View File

@ -27,7 +27,7 @@ A multi-browser addon / extension for multiple streaming providers which redirec
<a href="#-supported-sites">Supported Sites 📜</a> <a href="#-supported-sites">Supported Sites 📜</a>
<a href="#%EF%B8%8F-compiling">Compiling ⚙️</a> <a href="#%EF%B8%8F-building">Building ⚙️</a>
<a href="#-license">License ⚖</a> <a href="#-license">License ⚖</a>
</p> </p>
@ -69,10 +69,10 @@ Install the addon directly from the [firefox addon store](https://addons.mozilla
| Site | Supported | Note | | Site | Supported | Note |
|-----------------------------------------------------------------------|-----------|--------------------------------------------------| |-----------------------------------------------------------------------|-----------|--------------------------------------------------|
| [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | | Reverse engineering the site costs too much time | | [doodstream.com](doodstream.com) / [dood.pm](https://dood.pm) | ✔️ | |
| [evoload.io](https://evoload.io) | ✔️ | | | [evoload.io](https://evoload.io) | ✔️ | |
| [mixdrop.co](https://mixdrop.co) | ✔ | | | [mixdrop.co](https://mixdrop.co) | ✔ | |
| [mp4upload.com](https://mp4upload.com) | | URL can be extracted but not played | | [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) | ✔ | |
@ -90,9 +90,9 @@ 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.
## ⚙️ Compiling ## ⚙️ Building
If you want to compile 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.
Requirements: Requirements:
- `npm` installed. - `npm` installed.

View File

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

16
src/background.ts Normal file
View File

@ -0,0 +1,16 @@
import {getMatch} from "./match/match";
import {storageGet, storageSet} from "./store/store";
import {Match} from "./match/matches";
chrome.webRequest.onBeforeRedirect.addListener(async details => {
// check if redirects origins from a previous redirect
if (await storageGet('redirect') === undefined) {
let match: Match
if ((match = await getMatch(new URL(details.url).host)) !== undefined) {
await storageSet('redirect', match.id)
}
}
}, {
urls: ['<all_urls>'],
types: ['main_frame', 'sub_frame']
})

View File

@ -1,23 +1,38 @@
import {matches} from "./match/match"; import {getMatch} from "./match/match";
import {getAllDisabled, getDisabled} from "./store/store"; import {storageDelete, storageGet} from "./store/store";
import {Match, matches} from "./match/matches";
import play = chrome.cast.media.timeout.play;
async function main() { async function main() {
if (await getAllDisabled()) { let match: Match;
if ((match = await getMatch(window.location.host)) === undefined) {
let id: string
if ((id = await storageGet('redirect')) !== undefined) {
match = matches.find(m => m.id === id)
await storageDelete('redirect')
} else {
return
}
}
const re = document.body.innerHTML.match(match.regex)
if (re === null) {
return return
} }
for (const match of matches) { const url = await match.match(re)
if (!match.domains.some((v) => window.location.host.indexOf(v) !== -1) || ((await getDisabled()).some((v) => v === match))) {
continue
}
const re = document.body.innerHTML.match(match.regex) if (match.replace && !url.endsWith('.m3u8')) {
if (re === null) { const player = document.createElement('video')
continue player.style.width = '100%'
} player.style.height = '100%'
player.controls = true
player.src = url
const url = await match.match(re) document.body.innerHTML = ''
location.assign(chrome.runtime.getURL(`ui/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}`)) document.body.append(player)
} else {
window.location.assign(chrome.runtime.getURL(`ui/player/player.html?id=${match.id}&url=${encodeURIComponent(url)}&domains=${window.location.host}`))
} }
} }

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.0.0", "version": "2.1.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": {
@ -14,19 +14,7 @@
{ {
"all_frames": true, "all_frames": true,
"matches": [ "matches": [
"*://*.evoload.io/*", "<all_urls>"
"*://*.mixdrop.co/*",
"*://*.newgrounds.com/*",
"*://*.streamtape.com/*",
"*://*.streamzz.to/*",
"*://*.streamz.ws/*",
"*://*.upstream.to/*",
"*://*.vidlox.me/*",
"*://*.vidoza.net/*",
"*://*.vivo.sx/*",
"*://*.voe.sx/*",
"*://*.voeunblk.com/*",
"*://*.vupload.com/*"
], ],
"js": [ "js": [
"index.js" "index.js"
@ -34,8 +22,18 @@
"run_at": "document_end" "run_at": "document_end"
} }
], ],
"background": {
"scripts": [
"background.js"
]
},
"permissions": [ "permissions": [
"storage" "storage",
"webRequest",
"<all_urls>"
],
"web_accessible_resources": [
"ui/player/*"
], ],
"browser_action": { "browser_action": {
"default_icon": { "default_icon": {

View File

@ -1,231 +1,14 @@
export enum Reliability { import {Match, matches} from "./matches";
HIGH = 1, import {getAllDisabled, getDisabled} from "../store/store";
NORMAL,
LOW,
}
export abstract class Match { export async function getMatch(host: string): Promise<Match | undefined> {
name: string if (await getAllDisabled()) {
id: string return undefined
reliability: Reliability
domains: string[]
regex: RegExp
abstract match(match: RegExpMatchArray): Promise<string>
notice?: string
}
class Evoload implements Match {
name = 'Evoload'
id = 'evoload'
reliability = Reliability.NORMAL
domains = [
'evoload.io'
]
regex = new RegExp(/.*/gm)
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 Mixdrop implements Match {
name = 'Mixdrop'
id = 'mixdrop'
reliability = Reliability.HIGH
domains = [
'mixdrop.co'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
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 Mp4Upload implements Match {
name = 'Mp4Upload'
id = 'mp4upload'
reliability = Reliability.LOW
domains = [
'mp4upload.com'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://${match[34]}.mp4upload.com:${match[89]}/d/${match[88]}/video.mp4`
}
}*/
class Newgrounds implements Match {
name = 'Newgrounds'
id = 'newgrounds'
reliability = Reliability.HIGH
domains = [
'newgrounds.com'
]
regex = new RegExp(/.*/gm)
async match(match: RegExpMatchArray): Promise<string> {
let id = window.location.pathname.split('/').slice(-1)[0]
let response = await fetch(`https://www.newgrounds.com/portal/video/${id}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
let json = await response.json()
return decodeURI(json['sources'][Object.keys(json['sources'])[0]][0]['src'])
}
}
class Streamtape implements Match {
name = 'Streamtape'
id = 'streamtape'
reliability = Reliability.NORMAL
domains = [
'streamtape.com'
]
regex = new RegExp(/id=\S*(?=')/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://streamtape.com/get_video?${match[0]}`
}
}
class Streamzz implements Match {
name = 'Streamzz'
id = 'streamzz'
reliability = Reliability.NORMAL
domains = [
'streamzz.to',
'streamz.ws'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://get.${document.domain.split('.')[0]}.tw/getlink-${match.sort((a, b) => b.length - a.length)[0]}.dll`
}
}
class Upstream implements Match {
name = 'Upstream'
id = 'upstream'
reliability = Reliability.NORMAL
domains = [
'upstream.to'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://${match[49]}.upstreamcdn.co/hls/${match[148]}/master.m3u8`
}
}
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 {
name = 'Vidoza'
id = 'vidoza'
reliability = Reliability.HIGH
domains = [
'vidoza.net'
]
regex = new RegExp(/(?<=src:\s?").+?(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
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) for (const match of matches) {
rot47(encoded: string): string { if (match.domains.some(v => host.indexOf(v) !== -1) && !((await getDisabled()).some(v => v === match))) {
const s = [] return match
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 {
name = 'Voe'
id = 'voe'
reliability = Reliability.HIGH
domains = [
'voe.sx',
'voeunblk.com'
]
regex = new RegExp(/https?:\/\/\S*m3u8(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
class Vupload implements Match {
name = 'Vupload'
id = 'vupload'
reliability = Reliability.HIGH
domains = [
'vupload.com'
]
regex = new RegExp(/(?<=src:\s?").+?(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
export const matches = [
new Evoload(),
new Mixdrop(),
new Newgrounds(),
new Streamtape(),
new Streamzz(),
new Upstream(),
new Vidlox(),
new Vidoza(),
new Vivo(),
new Voe(),
new Vupload()
]

258
src/match/matches.ts Normal file
View File

@ -0,0 +1,258 @@
export enum Reliability {
HIGH = 1,
NORMAL,
LOW,
}
export abstract class Match {
name: string
id: string
reliability: Reliability
domains: string[]
replace?: boolean
regex: RegExp
abstract match(match: RegExpMatchArray): Promise<string>
notice?: string
}
class Doodstream implements Match {
name = 'Doodstream'
id = 'doodstream'
reliability = Reliability.HIGH
domains = [
'doodstream.com',
'dood.pm',
'dood.ws'
]
replace = true
regex = new RegExp(/(\/pass_md5\/.*?)'.*(\?token=.*?expiry=)/s)
async match(match: RegExpMatchArray): Promise<string> {
const response = await fetch(`https://${window.location.host}${match[1]}`, {
headers: {
'Range': 'bytes=0-'
},
referrer: `https://${window.location.host}/e/${window.location.pathname.split('/').slice(-1)[0]}`,
});
return `${await response.text()}1234567890${match[2]}${Date.now()}`
}
}
class Evoload implements Match {
name = 'Evoload'
id = 'evoload'
reliability = Reliability.NORMAL
domains = [
'evoload.io'
]
regex = new RegExp(/.*/gm)
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 Mixdrop implements Match {
name = 'Mixdrop'
id = 'mixdrop'
reliability = Reliability.HIGH
domains = [
'mixdrop.co'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
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 Mp4Upload implements Match {
name = 'Mp4Upload'
id = 'mp4upload'
reliability = Reliability.NORMAL
domains = [
'mp4upload.com'
]
replace = true
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://${match[34]}.mp4upload.com:${match[89]}/d/${match[88]}/video.mp4`
}
}
class Newgrounds implements Match {
name = 'Newgrounds'
id = 'newgrounds'
reliability = Reliability.HIGH
domains = [
'newgrounds.com'
]
regex = new RegExp(/.*/gm)
async match(match: RegExpMatchArray): Promise<string> {
let id = window.location.pathname.split('/').slice(-1)[0]
let response = await fetch(`https://www.newgrounds.com/portal/video/${id}`, {
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
let json = await response.json()
return decodeURI(json['sources'][Object.keys(json['sources'])[0]][0]['src'])
}
}
class Streamtape implements Match {
name = 'Streamtape'
id = 'streamtape'
reliability = Reliability.NORMAL
domains = [
'streamtape.com'
]
regex = new RegExp(/id=.*(?=')/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://streamtape.com/get_video?${match.reverse()[0]}`
}
}
class Streamzz implements Match {
name = 'Streamzz'
id = 'streamzz'
reliability = Reliability.NORMAL
domains = [
'streamzz.to',
'streamz.ws'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://get.${document.domain.split('.')[0]}.tw/getlink-${match.sort((a, b) => b.length - a.length)[0]}.dll`
}
}
class Upstream implements Match {
name = 'Upstream'
id = 'upstream'
reliability = Reliability.NORMAL
domains = [
'upstream.to'
]
regex = new RegExp(/(?<=\|)\w{2,}/gm)
async match(match: RegExpMatchArray): Promise<string> {
return `https://${match[49]}.upstreamcdn.co/hls/${match[148]}/master.m3u8`
}
}
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 {
name = 'Vidoza'
id = 'vidoza'
reliability = Reliability.HIGH
domains = [
'vidoza.net'
]
regex = new RegExp(/(?<=src:\s?").+?(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
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 {
name = 'Voe'
id = 'voe'
reliability = Reliability.HIGH
domains = [
'voe.sx'
]
regex = new RegExp(/https?:\/\/\S*m3u8(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
class Vupload implements Match {
name = 'Vupload'
id = 'vupload'
reliability = Reliability.HIGH
domains = [
'vupload.com'
]
regex = new RegExp(/(?<=src:\s?").+?(?=")/gm)
async match(match: RegExpMatchArray): Promise<string> {
return match[0]
}
}
export const matches = [
new Doodstream(),
new Evoload(),
new Mixdrop(),
new Mp4Upload(),
new Newgrounds(),
new Streamtape(),
new Streamzz(),
new Upstream(),
new Vidlox(),
new Vidoza(),
new Vivo(),
new Voe(),
new Vupload()
]

View File

@ -1,6 +1,6 @@
import {Match, matches} from "../match/match"; import {Match, matches} from "../match/matches";
async function storageGet(key: string): Promise<any> { export async function storageGet(key: string): Promise<any> {
return new Promise((resolve) => { return new Promise((resolve) => {
chrome.storage.local.get(key, (value) => { chrome.storage.local.get(key, (value) => {
resolve(value[key]) resolve(value[key])
@ -8,12 +8,16 @@ async function storageGet(key: string): Promise<any> {
}) })
} }
async function storageSet(key: string, value: any) { export async function storageSet(key: string, value: any) {
const obj = {} const obj = {}
obj[key] = value obj[key] = value
await chrome.storage.local.set(obj) await chrome.storage.local.set(obj)
} }
export async function storageDelete(key: string) {
await chrome.storage.local.remove(key)
}
export async function getDisabled(): Promise<Match[]> { export async function getDisabled(): Promise<Match[]> {
const localMatches = [] const localMatches = []
@ -29,7 +33,7 @@ export async function getDisabled(): Promise<Match[]> {
export async function getAllDisabled(): Promise<boolean> { export async function getAllDisabled(): Promise<boolean> {
const value = await storageGet('all') const value = await storageGet('all')
return value !== undefined ? value as unknown as boolean : false return value !== undefined ? String(value).toLowerCase() === 'true' : false
} }
export async function enableAll() { export async function enableAll() {

View File

@ -2,7 +2,7 @@
<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>

View File

@ -1,4 +1,4 @@
import {Match, matches, Reliability} from "../../match/match"; import {Match, matches, Reliability} from "../../match/matches";
// @ts-ignore // @ts-ignore
import Hls from "hls.js"; import Hls from "hls.js";
@ -65,13 +65,14 @@ 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 = 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/new">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) url.endsWith('.m3u8') ? await play_hls(url, match) : await play_native(url, match)
} }

View File

@ -1,5 +1,5 @@
import {getDisabled, disable, enable, getAllDisabled, enableAll, disableAll} from "../../store/store"; import {getDisabled, disable, enable, getAllDisabled, enableAll, disableAll} from "../../store/store";
import {matches, Reliability} from "../../match/match"; import {matches, Reliability} from "../../match/matches";
async function main() { async function main() {
const disabled = await getDisabled() const disabled = await getDisabled()

View File

@ -9,59 +9,11 @@ const sass = require('node-sass')
const sassPluginNodeImport = require('node-sass-package-importer') const sassPluginNodeImport = require('node-sass-package-importer')
const typescript = require('typescript') const typescript = require('typescript')
function getDomains() {
// because nodejs is nodejs, the simple commented out code below cannot be used.
// thus, the following bloated regexes must be used
/*const manifestMatches = []
for (const m of matches) {
for (const domain of m.domains) {
manifestMatches.push(`*://*.${domain}/*`)
}
}
manifest['content_scripts']['matches'] = manifestMatches*/
let domains = []
const matchesRegex = new RegExp(/export\s+const\s+matches\s+=\s+(?<matches>\[.*?])/gms)
const matchesClassesRegex = new RegExp(/(?<!\/\/\s*)new\s+(?<class>\w+)\(\)/gms)
const matchTs = fs.readFileSync('src/match/match.ts')
const jsMatches = matchesRegex.exec(matchTs).groups.matches
let m
while ((m = matchesClassesRegex.exec(jsMatches))) {
if (m.index === matchesClassesRegex.lastIndex) {
matchesClassesRegex.lastIndex++
}
if (m.groups.class !== undefined) {
const classDomainsRegex = new RegExp('class\\s+' + m.groups.class + '.*?domains\\s*=\\s*(?<domains>\\[.*?])', 'gms')
let mm
while ((mm = classDomainsRegex.exec(matchTs))) {
if (mm.index === classDomainsRegex.lastIndex) {
classDomainsRegex.lastIndex++
}
if (mm.groups.domains !== undefined) {
const matches = []
for (const domain of JSON.parse(mm.groups.domains.replace(/'/g, '"', -1))) {
matches.push(domain)
}
domains = domains.concat(matches)
}
}
}
}
return domains
}
async function buildManifest() { async function buildManifest() {
const manifest = JSON.parse(fs.readFileSync('src/manifest.json')) const manifest = JSON.parse(fs.readFileSync('src/manifest.json'))
manifest['version'] = process.env.npm_package_version manifest['version'] = process.env.npm_package_version
manifest['content_scripts'][0]['matches'] = getDomains().map((domain) => {return `*://*.${domain}/*`})
fs.writeFileSync('src/manifest.json', JSON.stringify(manifest, null, 2)) fs.writeFileSync('src/manifest.json', JSON.stringify(manifest, null, 2))
} }
@ -115,6 +67,7 @@ async function buildJs() {
'src/ui/player/player.ts': 'build/ui/player/player.js', 'src/ui/player/player.ts': 'build/ui/player/player.js',
'src/index.ts': 'build/index.js', 'src/index.ts': 'build/index.js',
'src/background.ts': 'build/background.js'
} }
for (const [src, dst] of Object.entries(files)) { for (const [src, dst] of Object.entries(files)) {