Skip to content

Commit

Permalink
πŸ”– Release version 1.9.3 (#148)
Browse files Browse the repository at this point in the history
* ⬆️ Bump version number to 1.9.3

* ⬆️ Upgrade dependencies

* πŸ› Fix #145 (#146)

* πŸ› Fix options UI (#147)

* 🏷️ Add type assertion to exported options

* πŸ› Fix list bugs

* πŸ› Fix v2 proxy server check

* πŸ› Fix default servers editing

* πŸ› Fix import of unknown settings

* πŸ”§ Add `tsconfig.json` for IntelliSense

* πŸ’¬ Add message to explain Chrome warnings

* πŸ—‘οΈ Add deprecation warning for "Reset player on midroll"

* πŸ’„ Tweak deprecation warning style

* ✨ Add "Copy debug info" button to popup
  • Loading branch information
younesaassila authored Jun 2, 2023
1 parent 4c9cf69 commit 9f36e8b
Show file tree
Hide file tree
Showing 11 changed files with 903 additions and 2,851 deletions.
3,513 changes: 714 additions & 2,799 deletions package-lock.json

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ttv-lol-pro",
"version": "1.9.2",
"version": "1.9.3",
"description": "TTV LOL PRO removes livestream ads from Twitch",
"@parcel/bundler-default": {
"minBundles": 10000000,
Expand Down Expand Up @@ -34,15 +34,16 @@
],
"license": "GPL-3.0",
"dependencies": {
"bowser": "^2.11.0",
"semver-compare": "^1.0.0"
},
"devDependencies": {
"@parcel/config-webextension": "^2.8.3",
"@types/react": "^18.2.6",
"@parcel/config-webextension": "^2.9.0",
"@types/react": "^18.2.7",
"@types/semver-compare": "^1.0.1",
"@types/webextension-polyfill": "^0.10.0",
"amazon-ivs-player": "^1.18.0",
"parcel": "^2.8.3",
"amazon-ivs-player": "^1.19.0",
"parcel": "^2.9.0",
"postcss": "^8.4.23",
"prettier": "^2.8.8",
"prettier-plugin-css-order": "^1.3.0",
Expand Down
15 changes: 15 additions & 0 deletions src/background/background.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,31 @@
import browser from "webextension-polyfill";
import isChrome from "../common/ts/isChrome";
import onApiHeadersReceived from "./handlers/onApiHeadersReceived";
import onBeforeManifestRequest from "./handlers/onBeforeManifestRequest";
import onBeforeSendApiHeaders from "./handlers/onBeforeSendApiHeaders";
import onInstalledResetUpdateFlag from "./handlers/onInstalledResetUpdateFlag";
import onStartupStoreCleanup from "./handlers/onStartupStoreCleanup";
import onStartupUpdateCheck from "./handlers/onStartupUpdateCheck";

if (isChrome) {
// Chrome shows two warnings when loading the extension:
// 1. Unrecognized manifest key 'browser_specific_settings'.
// 2. Manifest version 2 is deprecated.
console.warn(
"⬆️ THE TWO WARNINGS ABOVE ARE EXPECTED ⬆️ No need to report them."
);
}

// Cleanup the session-related data in the store on startup.
browser.runtime.onStartup.addListener(onStartupStoreCleanup);

// Check for updates on startup.
browser.runtime.onStartup.addListener(onStartupUpdateCheck);

// Reset the `isUpdateAvailable` flag on update, since the update check is only
// performed at browser startup.
browser.runtime.onInstalled.addListener(onInstalledResetUpdateFlag);

// Redirect the HLS master manifest request to TTV LOL's API.
browser.webRequest.onBeforeRequest.addListener(
onBeforeManifestRequest,
Expand Down
15 changes: 15 additions & 0 deletions src/background/handlers/onInstalledResetUpdateFlag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Runtime } from "webextension-polyfill";
import store from "../../store";

export default function onInstalledResetUpdateFlag(
details: Runtime.OnInstalledDetailsType
) {
if (details.reason !== "update") return;
// Wait for the store to be ready (it may not be ready at extension startup).
if (store.readyState !== "complete")
return store.addEventListener("load", () =>
onInstalledResetUpdateFlag(details)
);

store.state.isUpdateAvailable = false;
}
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "TTV LOL PRO",
"description": "TTV LOL PRO removes livestream ads from Twitch.",
"version": "1.9.2",
"version": "1.9.3",
"background": {
"persistent": true,
"scripts": ["background/background.ts"]
Expand Down
121 changes: 75 additions & 46 deletions src/options/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import readFile from "../common/ts/readFile";
import saveFile from "../common/ts/saveFile";
import store from "../store";
import getDefaultState from "../store/getDefaultState";
import { State } from "../store/types";
import type { KeyOfType } from "../types";

//#region Types
Expand Down Expand Up @@ -35,7 +36,7 @@ const whitelistedChannelsListElement = $(
"#whitelisted-channels-list"
) as HTMLUListElement;
$;
// Proxies
// Server list
const serversListElement = $("#servers-list") as HTMLOListElement;
// Privacy
const disableVodRedirectCheckboxElement = $(
Expand All @@ -51,18 +52,19 @@ const importButtonElement = $("#import-button") as HTMLButtonElement;
const resetButtonElement = $("#reset-button") as HTMLButtonElement;
//#endregion

const DEFAULT_SERVERS = getDefaultState().servers;
const DEFAULT_LIST_OPTIONS: ListOptions = Object.freeze({
const DEFAULT_STATE_KEYS = Object.freeze(Object.keys(getDefaultState()));
const DEFAULT_SERVERS = Object.freeze(getDefaultState().servers);
const DEFAULT_LIST_OPTIONS = Object.freeze({
getAlreadyExistsAlertMessage: text => `'${text}' is already in the list`,
getItemPlaceholder: text => `Leave empty to remove '${text}' from the list`,
getPromptPlaceholder: () => "Enter text to create a new item…",
isAddAllowed: () => [true] as AllowedResult,
isEditAllowed: () => [true] as AllowedResult,
focusPrompt: false, // Is set to true once the user has added an item.
focusPrompt: false, // Is set to `true` once the user has added an item.
hidePromptMarker: false,
insertMode: "append",
spellcheck: false,
});
} as ListOptions);

if (store.readyState === "complete") main();
else store.addEventListener("load", main);
Expand Down Expand Up @@ -111,23 +113,31 @@ function main() {
}
});
// Server list
const isServerUrlValid = (url: string): AllowedResult => {
if (DEFAULT_SERVERS.includes(url))
return [false, `'${url}' is a default server URL`];
let Url: URL | undefined;
try {
Url = new URL(url);
} catch {}
if (!Url) return [false, `'${url}' is not a valid URL`];
if (
Url.protocol.endsWith(".ttvlolpro.perfprod.com:") ||
Url.hostname.endsWith(".ttvlolpro.perfprod.com")
) {
return [false, `'${url}' is a proxy server for TTV LOL PRO v2`];
}
if (Url.protocol !== "https:")
return [false, `'${url}' is not a valid HTTPS URL`];
return [true];
};
listInit(serversListElement, "servers", store.state.servers, {
getPromptPlaceholder: insertMode => {
if (insertMode == "prepend") return "Enter a server URL… (Primary)";
return "Enter a server URL… (Fallback)";
},
isAddAllowed(url) {
try {
new URL(url);
return [true];
} catch {
return [false, `'${url}' is not a valid URL`];
}
},
isEditAllowed: url => [
!DEFAULT_SERVERS.includes(url),
"Cannot edit or remove default servers",
],
isAddAllowed: isServerUrlValid,
isEditAllowed: isServerUrlValid,
hidePromptMarker: true,
insertMode: "both",
});
Expand Down Expand Up @@ -193,6 +203,7 @@ function _listAppend(
const listItem = document.createElement("li");
const textInput = document.createElement("input");
textInput.type = "text";

const [allowed] = options.isEditAllowed(text);
if (!allowed) textInput.disabled = true;

Expand All @@ -201,31 +212,41 @@ function _listAppend(
textInput.value = text;

// Highlight text when focused.
textInput.addEventListener("focus", textInput.select);
textInput.addEventListener("focus", textInput.select.bind(textInput));

// Update store when text is changed.
textInput.addEventListener("change", e => {
// Get index of item in array.
const itemIndex = store.state[storeKey].findIndex(
item => item.toLowerCase() === text.toLowerCase()
);
if (itemIndex === -1)
return console.error(`Item '${text}' not found in '${storeKey}' array`);

const textInput = e.target as HTMLInputElement;
const [allowed, errorMessage] = options.isEditAllowed(text);
if (!allowed) {
alert(errorMessage || "You cannot edit this item");
textInput.value = text;
return;
}
const newText = textInput.value.trim();
const index = store.state[storeKey].findIndex(
str => str.toLowerCase() === text.toLowerCase()
);
if (index === -1) return;
// Remove item if text field is left empty.
// Remove item if text is empty.
if (newText === "") {
store.state[storeKey].splice(index, 1);
store.state[storeKey].splice(itemIndex, 1);
listItem.remove();
} else {
store.state[storeKey][index] = newText;
return;
}
// Check if text is valid.
const [allowed, error] = options.isEditAllowed(newText);
if (!allowed) {
alert(error || "You cannot edit this item");
textInput.value = text;
return;
}
// Update item in array.
store.state[storeKey][itemIndex] = newText;
textInput.placeholder = options.getItemPlaceholder(newText);
textInput.value = newText; // Update text in case it was trimmed.
text = newText; // Update current text variable.
});
// Append list item to list.

listItem.append(textInput);

if (options.insertMode === "prepend") listElement.prepend(listItem);
else listElement.append(listItem);
}
Expand Down Expand Up @@ -253,39 +274,43 @@ function _listPrompt(
promptInput.addEventListener("change", e => {
const promptInput = e.target as HTMLInputElement;
const text = promptInput.value.trim();
// Do nothing if text is empty.
if (text === "") return;
const [allowed, errorMessage] = options.isAddAllowed(text);
// Check if text is valid.
const [allowed, error] = options.isAddAllowed(text);
if (!allowed) {
alert(errorMessage || "You cannot add this item");
alert(error || "You cannot add this item");
promptInput.value = "";
return;
}
// Check if item already exists.
const alreadyExists = store.state[storeKey].some(
str => str.toLowerCase() === text.toLowerCase()
item => item.toLowerCase() === text.toLowerCase()
);
if (alreadyExists) {
alert(options.getAlreadyExistsAlertMessage(text));
promptInput.value = "";
return;
}
// Add item to store.
const list = store.state[storeKey]; // Store a reference to the array for the proxy to work.
if (options.insertMode === "prepend") list.unshift(text);
else list.push(text);
store.state[storeKey] = list;
// Add item to array.
const newArray = store.state[storeKey];
if (options.insertMode === "prepend") newArray.unshift(text);
else newArray.push(text);
store.state[storeKey] = newArray;

listItem.remove(); // This will also remove the prompt.
listItem.remove();
_listAppend(listElement, storeKey, text, options);
_listPrompt(listElement, storeKey, {
...options,
focusPrompt: true,
});
});
// Append prompt to list.

listItem.append(promptInput);

if (options.insertMode === "prepend") listElement.prepend(listItem);
else listElement.append(listItem);
// Focus prompt if specified.

if (options.focusPrompt) promptInput.focus();
}

Expand All @@ -299,7 +324,7 @@ exportButtonElement.addEventListener("click", () => {
resetPlayerOnMidroll: store.state.resetPlayerOnMidroll,
servers: store.state.servers,
whitelistedChannels: store.state.whitelistedChannels,
}),
} as Partial<State>),
"application/json;charset=utf-8"
);
});
Expand All @@ -309,11 +334,15 @@ importButtonElement.addEventListener("click", async () => {
const data = await readFile("application/json;charset=utf-8");
const state = JSON.parse(data);
for (const [key, value] of Object.entries(state)) {
if (!DEFAULT_STATE_KEYS.includes(key)) {
console.warn(`Unknown key '${key}' in imported settings`);
continue;
}
store.state[key] = value;
}
window.location.reload(); // Reload page to update UI.
} catch (error) {
alert(`Error: ${error}}`);
alert(`An error occurred while importing settings: ${error}`);
}
});

Expand Down
1 change: 1 addition & 0 deletions src/options/page.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ <h2>General</h2>
<label for="reset-player-on-midroll-checkbox">
Reset the player when a midroll ad is detected
</label>
<span class="tag">Deprecated</span>
<br />
<small>
Player resets may show a momentary black screen. This feature is
Expand Down
35 changes: 35 additions & 0 deletions src/popup/menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,41 @@ <h3 class="list-item-title">Discord</h3>
</a>
</li>
</ol>

<!-- Debug info -->
<ol class="list">
<li>
<button id="copy-debug-info-button" class="list-item">
<div class="list-item-icon">
<!-- https://icons.getbootstrap.com/icons/clipboard2-pulse-fill/ -->
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
class="bi bi-clipboard2-pulse-fill"
viewBox="0 0 16 16"
>
<path
d="M10 .5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5.5.5 0 0 1-.5.5.5.5 0 0 0-.5.5V2a.5.5 0 0 0 .5.5h5A.5.5 0 0 0 11 2v-.5a.5.5 0 0 0-.5-.5.5.5 0 0 1-.5-.5Z"
/>
<path
d="M4.085 1H3.5A1.5 1.5 0 0 0 2 2.5v12A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-12A1.5 1.5 0 0 0 12.5 1h-.585c.055.156.085.325.085.5V2a1.5 1.5 0 0 1-1.5 1.5h-5A1.5 1.5 0 0 1 4 2v-.5c0-.175.03-.344.085-.5ZM9.98 5.356 11.372 10h.128a.5.5 0 0 1 0 1H11a.5.5 0 0 1-.479-.356l-.94-3.135-1.092 5.096a.5.5 0 0 1-.968.039L6.383 8.85l-.936 1.873A.5.5 0 0 1 5 11h-.5a.5.5 0 0 1 0-1h.191l1.362-2.724a.5.5 0 0 1 .926.08l.94 3.135 1.092-5.096a.5.5 0 0 1 .968-.039Z"
/>
</svg>
</div>
<div class="list-item-text">
<h3 class="list-item-title">Copy debug info</h3>
<p
id="copy-debug-info-button-description"
class="list-item-description"
>
Copy debug info to clipboard.
</p>
</div>
</button>
</li>
</ol>
</main>

<script type="module" src="./popup.ts"></script>
Expand Down
Loading

0 comments on commit 9f36e8b

Please sign in to comment.