Skip to content

Commit

Permalink
save state in controller element
Browse files Browse the repository at this point in the history
  • Loading branch information
nunsez committed Sep 26, 2024
1 parent 6c20f92 commit d46e8b7
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 36 deletions.
4 changes: 2 additions & 2 deletions dist/bookmarklet-video-speed.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 52 additions & 34 deletions main.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
/**
* @file A script to control the speed of html5 video playback in the browser.
* @author Alexander Mandrikov <mad.nunsez@gmail.com>
* @version 2.0.1
* @version 2.1.0
* @license AGPLv3
* @see {@link https://github.com/nunsez/bookmarklet-video-speed GitHub} for further information.
*/

const PREFIX = "nunsez-video-bookmarklet";
const DEFAULT_SPEED = 100;
const SEARCH_TIMEOUT = 500;
const STATE_ID = `${PREFIX}-state`;
const STORAGE_ID = `${PREFIX}-memory`;
const CONTROLLER_ID = `${PREFIX}-controller`;
const TICKMARKS_ID = `${PREFIX}-tickmarks`;
Expand All @@ -25,6 +26,10 @@ const STYLES =
`#${CONTROLLER_ID} .range {width: 100%;}` +
`#${CONTROLLER_ID} .range ~ * {display: none;}`;

interface MyElement extends HTMLDivElement {
[STATE_ID]?: State
}

function addStyles(document: Document) {
if (document.head.querySelector(`#${STYLESHEET_ID}`)) return;

Expand All @@ -38,8 +43,9 @@ class State {
document: Document;
speed: number;
videos: HTMLVideoElement[] = [];
oldController: HTMLDivElement | null;
#controller: Controller | null = null;
controller: Controller;
searchTimeoutId?: number;
observer: MutationObserver;

static getSpeed(): number {
const storageSpeed = Number.parseInt(
Expand Down Expand Up @@ -78,27 +84,43 @@ class State {
constructor(document: Document) {
this.document = document;
this.speed = State.getSpeed();
this.oldController = document.querySelector<HTMLDivElement>(
`#${CONTROLLER_ID}`,

this.observer = new MutationObserver((mutations) =>
this.refresh(mutations)
);

// create controller and his components
this.controller = new Controller(this);
}

initialize(_mutationRecords: MutationRecord[]) {
setTimeout(() => {
initialize() {
this.observer.observe(document.body, { childList: true });

// append controller to body tag
this.controller.appendTo(document.body);
}

refresh(_mutationRecords: MutationRecord[]) {
console.log('_mutationRecords', _mutationRecords)
console.log('refresh', this.searchTimeoutId, this.controller);
clearTimeout(this.searchTimeoutId);

this.searchTimeoutId = setTimeout(() => {
this.videos = State.getVideos(this.document.body);
this.setSpeed(this.speed);
}, SEARCH_TIMEOUT);
}

get controller(): Controller {
return this.#controller!;
}

set controller(controller: Controller) {
this.#controller = controller;
terminate() {
console.log('terminate observer', this.observer)
console.log('terminate oldController', this.controller)
this.observer.disconnect();
this.controller.el.remove();
this.videos.forEach((v) => v.playbackRate = DEFAULT_SPEED / 100);
}

setSpeed(newSpeed: number) {
if (!this.controller) return;
if (Number.isNaN(newSpeed)) return;

// The 0.05x playback rate is not in the supported playback range
Expand All @@ -118,13 +140,14 @@ class State {
this.controller.range.value = speedString;
this.videos.forEach((v) => v.playbackRate = this.speed / 100);

console.log('set speed', this.videos, this.controller);

localStorage.setItem(STORAGE_ID, speedString);
}
}

class Controller {
state: State;
el: HTMLDivElement;
el: MyElement;
subBtn: HTMLButtonElement = document.createElement("button");
value: HTMLDivElement = document.createElement("div");
addBtn: HTMLButtonElement = document.createElement("button");
Expand All @@ -133,11 +156,11 @@ class Controller {
static tickMarks = [10, 50, 100, 150, 200, 250, 300];

constructor(state: State) {
this.state = state;
this.el = document.createElement("div");
this.el[STATE_ID] = state;
}

append(root: HTMLElement): Controller {
appendTo(root: HTMLElement): Controller {
// remove existing controller if exists
root.querySelector(CONTROLLER_ID)?.remove();
this.#build();
Expand All @@ -146,6 +169,10 @@ class Controller {
return this;
}

get state(): State {
return this.el[STATE_ID]!;
}

#addListeners() {
this.range.addEventListener("input", () => {
const speed = Number.parseFloat(this.range.value);
Expand Down Expand Up @@ -231,31 +258,22 @@ class Controller {

function main(window: Window) {
const document = window.document;
const state = new State(document);

const myElement = document.querySelector<MyElement>(`#${CONTROLLER_ID}`);

// remove controller if exist and restore video playback speed / toggle effect
if (state.oldController) {
state.oldController.remove();
const videos = State.getVideos(document.body);
setTimeout(() => {
videos.forEach((v) => v.playbackRate = DEFAULT_SPEED / 100);
}, SEARCH_TIMEOUT + 5);
if (myElement) {
const state = myElement[STATE_ID];
state?.terminate();
myElement.remove();
return;
}

// add stylesheet if not exist
addStyles(document);

// reset reinitialize on body changes
const observer = new MutationObserver((mutations) =>
state.initialize(mutations)
);
observer.observe(document.body, { childList: true });

// create controller and his components
state.controller = new Controller(state);
// append controller to body tag
state.controller.append(state.document.body);
const state = new State(document);
state.initialize();
}

main(window);

0 comments on commit d46e8b7

Please sign in to comment.