♻️ Refactor project

This commit is contained in:
Younes 2022-05-14 18:08:04 +02:00
parent 4384d50abc
commit 05975a4780
24 changed files with 4853 additions and 366 deletions

232
.gitignore vendored Normal file
View File

@ -0,0 +1,232 @@
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,macos,node
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,macos,node
### macOS ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### macOS Patch ###
# iCloud generated files
*.icloud
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
### Node Patch ###
# Serverless Webpack directories
.webpack/
# Optional stylelint cache
# SvelteKit build / generate output
.svelte-kit
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# Support for Project snippet scope
.vscode/*.code-snippets
# Ignore code-workspaces
*.code-workspace
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,macos,node
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)

3
.parcelrc Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "@parcel/config-webextension"
}

3
.prettierrc.json Normal file
View File

@ -0,0 +1,3 @@
{
"arrowParens": "avoid"
}

View File

@ -1,12 +1,59 @@
# TTV.LOL browser extensions
<h1 align="center">
<img src="src/images/icon.png" height="100" width="100" alt="Icon" />
<br />
TTV LOL
<br />
</h1>
This respository contains the browser extensions for [TTV.LOL](https://ttv.lol).
<div align="center">
<a href="https://github.com/younesaassila/ttv-lol/issues">
<img
alt="GitHub issues"
src="https://img.shields.io/github/issues/younesaassila/ttv-lol"
/>
</a>
<a href="https://github.com/younesaassila/ttv-lol/network">
<img
alt="GitHub forks"
src="https://img.shields.io/github/forks/younesaassila/ttv-lol"
/>
</a>
<a href="https://github.com/younesaassila/ttv-lol/stargazers">
<img
alt="GitHub stars"
src="https://img.shields.io/github/stars/younesaassila/ttv-lol"
/>
</a>
</div>
# Chrome webstore
<br />
The extension can be installed via the chrome webstore [here](https://chrome.google.com/webstore/detail/ttv-lol/ofbbahodfeppoklmgjiokgfdgcndngjm).
```text
This is a fork of the original project at https://github.com/TTV-LOL/extensions
```
# Firefox Addon
>
The extension can be installed via the Firefox addons store [here](https://addons.mozilla.org/en-US/firefox/addon/ttv-lol/).
[TTV LOL](https://ttv.lol/) removes livestream ads from [Twitch](https://www.twitch.tv/).
This fork:
- disables TTV LOL for channels you are subscribed to.
## Installation
### Chrome
1. Download the latest version of this extension in the "Releases" section (ZIP file)
1. Unzip the ZIP file you just downloaded
1. Go to `chrome://extensions`
1. Turn on `Developer mode`
1. Click on `Load unpacked`
1. Select the unzipped folder you just created
### Firefox
1. Download the latest version of this extension in the "Releases" section (ZIP file)
1. Go to `about:addons`
1. Click on the gear icon then select "Install Add-on From File…"
1. Select the ZIP file you just downloaded

View File

@ -1,68 +0,0 @@
html {
width: 300px;
height: 100px;
background: #151619;
color: #c9cbcd;
font-family: Open Sans,Segoe UI,sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
.container {
text-align: center;
padding-bottom: 10px;
}
.button-group {
display: flex;
justify-content: center;
}
.button {
border-radius: 6px;
color: #c3c4ca;
font-weight: bold;
padding: 10px 20px;
text-decoration: none;
transition: all 150ms ease-in-out;
}
.button:hover {
background-color: #1d1f23;
}
.button:not(:first-of-type) {
margin-left: 15px;
}
.discord {
overflow: visible;
margin-right: 3px;
display: inline-block;
}
.button-arrow .arrow-icon {
overflow: visible;
margin-left: 3px;
margin-bottom: -2px;
width: 8px;
}
.icon {
margin-bottom: -3px;
}
.buton-text{
margin-bottom: 10px;
}
.button-arrow .arrow-head {
transform: translateX(0);
transition: transform 150ms ease-in-out;
}
.button-arrow .arrow-body {
opacity: 0;
transform: scaleX(1);
transition: transform 150ms ease-in-out, opacity 150ms ease-in-out;
}
.button-arrow:hover .arrow-head {
transform: translateX(3px);
}
.button-arrow:hover .arrow-body {
opacity: 1;
transform: scaleX(2);
}

View File

@ -1,48 +0,0 @@
<html>
<head>
<link rel="stylesheet" href="../css/styles.css" />
</head>
<body>
<div class="container">
<div style="background-color: #202127; border-radius: 8px; margin: 30px;">
<img width="60%" src="../img/ttvlol.png">
</div>
<div class="button-group">
<a href="https://ttv.lol/donate" target="_blank" class="button button-arrow">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" width="16" height="16" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M3.172 5.172a4 4 0 015.656 0L10 6.343l1.172-1.171a4 4 0 115.656 5.656L10 17.657l-6.828-6.829a4 4 0 010-5.656z" clip-rule="evenodd" />
</svg>
Donate
<svg viewBox="0 0 6 9" fill="none" xmlns="http://www.w3.org/2000/svg" class="arrow-icon">
<g class="arrow-head">
<path d="M1 1C4.5 4 5 4.38484 5 4.5C5 4.61516 4.5 5 1 8" stroke="currentColor" stroke-width="2"/>
</g>
<g class="arrow-body">
<path d="M3.5 4.5H0" stroke="currentColor" stroke-width="2"/>
</g>
</svg>
</a>
<a href="https://discord.gg/NAv7AFAyTF" target="_blank" class="button button-arrow">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" style="margin-right: 3px;" width="16" height="16" fill="currentColor" class="bi bi-discord" viewBox="0 0 16 16">
<path d="M6.552 6.712c-.456 0-.816.4-.816.888s.368.888.816.888c.456 0 .816-.4.816-.888.008-.488-.36-.888-.816-.888zm2.92 0c-.456 0-.816.4-.816.888s.368.888.816.888c.456 0 .816-.4.816-.888s-.36-.888-.816-.888z"/>
<path d="M13.36 0H2.64C1.736 0 1 .736 1 1.648v10.816c0 .912.736 1.648 1.64 1.648h9.072l-.424-1.48 1.024.952.968.896L15 16V1.648C15 .736 14.264 0 13.36 0zm-3.088 10.448s-.288-.344-.528-.648c1.048-.296 1.448-.952 1.448-.952-.328.216-.64.368-.92.472-.4.168-.784.28-1.16.344a5.604 5.604 0 0 1-2.072-.008 6.716 6.716 0 0 1-1.176-.344 4.688 4.688 0 0 1-.584-.272c-.024-.016-.048-.024-.072-.04-.016-.008-.024-.016-.032-.024-.144-.08-.224-.136-.224-.136s.384.64 1.4.944c-.24.304-.536.664-.536.664-1.768-.056-2.44-1.216-2.44-1.216 0-2.576 1.152-4.664 1.152-4.664 1.152-.864 2.248-.84 2.248-.84l.08.096c-1.44.416-2.104 1.048-2.104 1.048s.176-.096.472-.232c.856-.376 1.536-.48 1.816-.504.048-.008.088-.016.136-.016a6.521 6.521 0 0 1 4.024.752s-.632-.6-1.992-1.016l.112-.128s1.096-.024 2.248.84c0 0 1.152 2.088 1.152 4.664 0 0-.68 1.16-2.448 1.216z"/>
</svg>
Discord
<svg viewBox="0 0 6 9" fill="none" xmlns="http://www.w3.org/2000/svg" class="arrow-icon">
<g class="arrow-head">
<path d="M1 1C4.5 4 5 4.38484 5 4.5C5 4.61516 4.5 5 1 8" stroke="currentColor" stroke-width="2"/>
</g>
<g class="arrow-body">
<path d="M3.5 4.5H0" stroke="currentColor" stroke-width="2"/>
</g>
</svg>
</a>
</div>
</div>
</body>
</html>

View File

@ -1,57 +0,0 @@
function stripUnusedParams(str, params) {
if (!params) {
params = [ 'token', 'sig' ];
}
var tempUrl = new URL('https://localhost/' + str);
for (var i = 0; i < params.length; i++) {
tempUrl.searchParams.delete(params[i]);
}
return tempUrl.pathname.substring(1) + tempUrl.search;
}
function onPlaylistBeforeRequest(details) {
details.url = stripUnusedParams(details.url, null);
// (hls\/|vod\/)(.+?)$
const match = /(hls|vod)\/(.+?)$/gim.exec(details.url);
if (match !== null && match.length > 1) {
var playlistType = match[1] == "vod" ? "vod" : "playlist";
var req = new XMLHttpRequest();
req.open("GET", `https://api.ttv.lol/ping`, false);
req.send();
// validate that our API is online, if not fallback to standard stream with ads
if (req.status != 200) {
return {
redirectUrl: details.url
};
} else {
return {
redirectUrl: `https://api.ttv.lol/${playlistType}/${encodeURIComponent(match[2])}`,
};
}
}
}
chrome.webRequest.onBeforeRequest.addListener(
onPlaylistBeforeRequest,
{ urls: ["https://usher.ttvnw.net/api/channel/hls/*", "https://usher.ttvnw.net/vod/*"] },
["blocking", "extraHeaders"]
);
function onBeforeSendHeaders(req) {
req.requestHeaders.push({ name: 'X-Donate-To', value: "https://ttv.lol/donate" })
return {
requestHeaders: req.requestHeaders
}
}
chrome.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeaders,
{ urls: ["https://api.ttv.lol/playlist/*", "https://api.ttv.lol/vod/*"] },
["blocking", "requestHeaders"]
);

View File

@ -1,29 +0,0 @@
{
"background": {
"persistent": true,
"scripts": [
"js/background.js"
]
},
"browser_action": {
"default_icon": {
"128": "images/icon.png"
},
"default_popup": "common/html/popup.html",
"default_title": "TTV LOL"
},
"description": "TTV LOL",
"icons": {
"128": "images/icon.png"
},
"manifest_version": 2,
"name": "TTV LOL",
"permissions": [
"webRequest",
"webRequestBlocking",
"https://*.twitch.tv/*",
"https://usher.ttvnw.net/*",
"https://api.ttv.lol/*"
],
"version": "0.0.0.4"
}

View File

@ -1,71 +0,0 @@
html, body {
width: 300px;
}
html {
background: #151619;
color: #c9cbcd;
font-family: Open Sans,Segoe UI,sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
.container {
text-align: center;
padding-bottom: 10px;
}
.button-group {
display: flex;
justify-content: center;
}
.button {
border-radius: 6px;
color: #c3c4ca;
font-weight: bold;
padding: 10px 20px;
text-decoration: none;
transition: all 150ms ease-in-out;
}
.button:hover {
background-color: #1d1f23;
}
.button:not(:first-of-type) {
margin-left: 15px;
}
.discord {
overflow: visible;
margin-right: 3px;
display: inline-block;
}
.button-arrow .arrow-icon {
overflow: visible;
margin-left: 3px;
margin-bottom: -2px;
width: 8px;
}
.icon {
margin-bottom: -3px;
}
.buton-text{
margin-bottom: 10px;
}
.button-arrow .arrow-head {
transform: translateX(0);
transition: transform 150ms ease-in-out;
}
.button-arrow .arrow-body {
opacity: 0;
transform: scaleX(1);
transition: transform 150ms ease-in-out, opacity 150ms ease-in-out;
}
.button-arrow:hover .arrow-head {
transform: translateX(3px);
}
.button-arrow:hover .arrow-body {
opacity: 1;
transform: scaleX(2);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,58 +0,0 @@
function stripUnusedParams(str, params) {
if (!params) {
params = [ 'token', 'sig' ];
}
var tempUrl = new URL('https://localhost/' + str);
for (var i = 0; i < params.length; i++) {
tempUrl.searchParams.delete(params[i]);
}
return tempUrl.pathname.substring(1) + tempUrl.search;
}
function onPlaylistBeforeRequest(details) {
details.url = stripUnusedParams(details.url, null);
// (hls\/|vod\/)(.+?)$
const match = /(hls|vod)\/(.+?)$/gim.exec(details.url);
if (match !== null && match.length > 1) {
var playlistType = match[1] == "vod" ? "vod" : "playlist";
return new Promise(resolve => {
fetch(
'https://api.ttv.lol/ping',
{
method: 'GET',
}).then(r => {
if (r.status == 200) {
resolve({ redirectUrl: `https://api.ttv.lol/${playlistType}/${encodeURIComponent(match[2])}` });
} else {
resolve({});
}
}).catch((error) => {
resolve({});
});
});
}
}
browser.webRequest.onBeforeRequest.addListener(
onPlaylistBeforeRequest,
{ urls: ["https://usher.ttvnw.net/api/channel/hls/*", "https://usher.ttvnw.net/vod/*"] },
["blocking"]
);
function onBeforeSendHeaders(req) {
req.requestHeaders.push({ name: 'X-Donate-To', value: "https://ttv.lol/donate" })
return {
requestHeaders: req.requestHeaders
}
}
browser.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeaders,
{ urls: ["https://api.ttv.lol/playlist/*", "https://api.ttv.lol/vod/*"] },
["blocking", "requestHeaders"]
);

View File

@ -1,29 +0,0 @@
{
"background": {
"persistent": true,
"scripts": [
"js/background.js"
]
},
"browser_action": {
"default_icon": {
"128": "images/icon.png"
},
"default_popup": "common/html/popup.html",
"default_title": "TTV LOL"
},
"description": "TTV LOL",
"icons": {
"128": "images/icon.png"
},
"manifest_version": 2,
"name": "TTV LOL",
"permissions": [
"webRequest",
"webRequestBlocking",
"https://*.twitch.tv/*",
"https://usher.ttvnw.net/*",
"https://api.ttv.lol/*"
],
"version": "0.0.0.4"
}

4364
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

38
package.json Normal file
View File

@ -0,0 +1,38 @@
{
"name": "ttv-lol",
"version": "1.0.0-younesaassila",
"description": "TTV LOL removes livestream ads from twitch.tv",
"targets": {
"webext-dev": {
"sourceMap": {
"inline": true,
"inlineSources": true
}
},
"webext-prod": {}
},
"scripts": {
"dev": "parcel src/manifest.json --host localhost --target webext-dev",
"lint": "prettier --write ./src",
"build": "parcel build src/manifest.json --target webext-prod"
},
"keywords": [
"twitch",
"web-extension",
"adblocker"
],
"author": "TTV-LOL (https://github.com/TTV-LOL)",
"contributors": [
"Younes Aassila (https://github.com/younesaassila)"
],
"license": "UNLICENSED",
"devDependencies": {
"@parcel/config-webextension": "^2.5.0",
"@types/webextension-polyfill": "^0.8.3",
"parcel": "^2.5.0",
"prettier": "^2.6.2",
"typescript": "^4.6.4",
"webextension-polyfill": "^0.9.0"
},
"private": true
}

70
src/common/css/styles.css Normal file
View File

@ -0,0 +1,70 @@
html,
body {
width: 300px;
}
html {
background: #151619;
color: #c9cbcd;
font-family: Open Sans, Segoe UI, sans-serif;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
.container {
text-align: center;
padding-bottom: 10px;
}
.button-group {
display: flex;
justify-content: center;
}
.button {
border-radius: 6px;
color: #c3c4ca;
font-weight: bold;
padding: 10px 20px;
text-decoration: none;
transition: all 150ms ease-in-out;
}
.button:hover {
background-color: #1d1f23;
}
.button:not(:first-of-type) {
margin-left: 15px;
}
.discord {
overflow: visible;
margin-right: 3px;
display: inline-block;
}
.button-arrow .arrow-icon {
overflow: visible;
margin-left: 3px;
margin-bottom: -2px;
width: 8px;
}
.icon {
margin-bottom: -3px;
}
.buton-text {
margin-bottom: 10px;
}
.button-arrow .arrow-head {
transform: translateX(0);
transition: transform 150ms ease-in-out;
}
.button-arrow .arrow-body {
opacity: 0;
transform: scaleX(1);
transition: transform 150ms ease-in-out, opacity 150ms ease-in-out;
}
.button-arrow:hover .arrow-head {
transform: translateX(3px);
}
.button-arrow:hover .arrow-body {
opacity: 1;
transform: scaleX(2);
}

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 52 KiB

View File

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

27
src/manifest.json Normal file
View File

@ -0,0 +1,27 @@
{
"manifest_version": 2,
"name": "TTV LOL (Younes Aassila's Fork)",
"description": "TTV LOL removes livestream ads from twitch.tv",
"version": "1.0.0",
"background": {
"persistent": true,
"scripts": ["ts/background.ts"]
},
"browser_action": {
"default_icon": {
"128": "images/icon.png"
},
"default_title": "TTV LOL",
"default_popup": "common/html/popup.html"
},
"icons": {
"128": "images/icon.png"
},
"permissions": [
"webRequest",
"webRequestBlocking",
"https://*.twitch.tv/*",
"https://usher.ttvnw.net/*",
"https://api.ttv.lol/*"
]
}

59
src/ts/background.ts Normal file
View File

@ -0,0 +1,59 @@
import browser, { WebRequest } from "webextension-polyfill";
import { PlaylistType } from "../types";
function onBeforeRequest(details: WebRequest.OnBeforeRequestDetailsType) {
const match = /(hls|vod)\/(.+?)$/gim.exec(details.url);
if (match == null) return {};
const [_, type, path] = match;
if (type == null || path == null) return {};
const playlistType =
type.toLowerCase() === "vod" ? PlaylistType.VOD : PlaylistType.Playlist;
// Synchronous XMLHttpRequest is required for the plugin to work in Chrome.
const request = new XMLHttpRequest();
request.open("GET", `https://api.ttv.lol/ping`, false);
request.send();
if (request.status === 200) {
console.info("[TTV LOL] Successfully pinged TTV LOL's server.");
return {
redirectUrl: `https://api.ttv.lol/${playlistType}/${encodeURIComponent(
path
)}`,
};
} else {
return {};
}
}
browser.webRequest.onBeforeRequest.addListener(
onBeforeRequest,
{
urls: [
"https://usher.ttvnw.net/api/channel/hls/*",
"https://usher.ttvnw.net/vod/*",
],
},
["blocking"]
);
function onBeforeSendHeaders(
details: WebRequest.OnBeforeSendHeadersDetailsType
) {
console.log(`[TTV LOL] ${details.method} ${details.url}`);
details.requestHeaders.push({
name: "X-Donate-To",
value: "https://ttv.lol/donate",
});
return {
requestHeaders: details.requestHeaders,
};
}
browser.webRequest.onBeforeSendHeaders.addListener(
onBeforeSendHeaders,
{ urls: ["https://api.ttv.lol/playlist/*", "https://api.ttv.lol/vod/*"] },
["blocking", "requestHeaders"]
);

4
src/types.ts Normal file
View File

@ -0,0 +1,4 @@
export enum PlaylistType {
Playlist = "playlist",
VOD = "vod",
}