Skip to content

Commit d615064

Browse files
committed
Queue
- Queue finally functional - DOM queue - Video end transitions to next in queue
1 parent 3b332b4 commit d615064

8 files changed

Lines changed: 215 additions & 47 deletions

File tree

README.DE.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ Die neuesten Veröffentlichungen sind [hier](https://github.com/cpiber/NebulaEnh
2020

2121
# Features
2222

23+
**Seite**
24+
- Queue: Füge Videos einfach zu einer Warteschlange hinzu
25+
26+
**Videospieler**
2327
- Standard Abspielgeschwindigkeit: Erlaubt es, standardmäßig Videos mit anderer Geschwindigkeit abzuspielen
2428
- "Quick dial" für Abspielgeschwindigkeit: Ein neuer Knopf im Videospieler erlaubt es per Mausrad die Geschwindigkeit bequem und schnell zu verändern
2529
- Zielqualitäten: Erlaubt es, bevorzugte Videoqualität(en) zu setzen
@@ -44,7 +48,7 @@ Optionen Seite:
4448

4549
Stellen Sie bitte sicher, dass Sie [NodeJS](https://nodejs.org/) und dessen package manager [npm](https://www.npmjs.com/) installiert haben.
4650

47-
- pnpm installieren: `npm install -g pnpm`
51+
- [pnpm](https://github.com/pnpm/pnpm) installieren: `npm install -g pnpm`
4852
- Abhängigkeiten installieren: `pnpm install`
4953
- Entwickeln: In Firefox `pnpm run start:firefox` / In Chromium `pnpm run start:chromium`
5054
- Builden: `pnpm run build`

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ The most recent releases are available [here](https://github.com/cpiber/NebulaEn
2121

2222
# Features
2323

24+
**Page**
25+
- Queue: Add videos to watch queue
26+
27+
**Player**
2428
- Default playback speed
2529
- Quick dial to set speed: New button in player allows to increase/decrease speed by scrolling
2630
- Target qualities: Set the preferred video quality or qualities
@@ -45,7 +49,7 @@ Options page:
4549

4650
Please make sure you have [NodeJS](https://nodejs.org/) and it's package manager [npm](https://www.npmjs.com/) installed.
4751

48-
- Install pnpm: `npm install -g pnpm`
52+
- Install [pnpm](https://github.com/pnpm/pnpm): `npm install -g pnpm`
4953
- Install dependencies: `pnpm install`
5054
- Develop: In Firefox `pnpm run start:firefox` / In Chromium `pnpm run start:chromium`
5155
- Build: `pnpm run build`

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nebulaenhance",
3-
"version": "0.0.3",
3+
"version": "0.1.0",
44
"description": "Enhancer for Nebula. Adds some quality of life features to the nebula player.",
55
"main": "index.js",
66
"scripts": {

rollup.config.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22

33
import 'rollup';
44
import typescript from '@rollup/plugin-typescript';
5-
import { string } from "rollup-plugin-string";;
5+
import { string } from 'rollup-plugin-string';
66
import nodeResolve from '@rollup/plugin-node-resolve';
7-
import { terser } from "rollup-plugin-terser";
7+
import { terser } from 'rollup-plugin-terser';
88
import glob from 'glob';
99

1010
export default glob.sync('src/**/*.ts', { ignore: [ 'src/**/_*.ts', 'src/**/*.d.ts' ] }).map(e => {

src/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"manifest_version": 2,
33
"name": "__MSG_title__",
44
"description": "__MSG_extensionDescription__",
5-
"version": "0.0.3",
5+
"version": "0.1.0",
66
"icons": {
77
"128": "icons/icon_128.png",
88
"64": "icons/icon_64.png"

src/scripts/pages/watchnebula/_nebula.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const videoselector = 'a[href^="/videos/"]';
22
import svg from "./../../../icons/watchlater.svg";
3-
import { addToStore, enqueue, enqueueNow, gotoNextInQueue, init } from "./_queue";
3+
import { addToStore, enqueue, enqueueNow, gotoNextInQueue, init, isEmptyQueue } from "./_queue";
44

55
export const nebula = () => {
66
document.body.addEventListener('mouseover', hover);
@@ -35,15 +35,22 @@ const hover = (e: MouseEvent) => {
3535
const click = (e: MouseEvent) => {
3636
const target = e.target as HTMLElement;
3737
const later = target.closest('.enhancer-queueButton');
38-
const link = target.closest(videoselector) as HTMLAnchorElement;
38+
const link: HTMLAnchorElement = target.closest(videoselector);
3939
if (link === null)
4040
return;
41-
const img = link.querySelector('img') as HTMLImageElement;
42-
// always prevent going to video
43-
e.preventDefault();
41+
const img: HTMLImageElement = link.querySelector('img');
4442
const name = link.getAttribute('href').substr(8);
4543
// extract and store information on video
46-
addToStore(name, img.nextElementSibling?.lastChild.textContent, img.src, link.lastElementChild?.children[1]?.textContent, link.lastElementChild?.lastElementChild?.firstElementChild?.textContent);
44+
addToStore(name,
45+
img.nextElementSibling?.lastChild.textContent,
46+
img.src,
47+
link.lastElementChild?.children[1]?.textContent,
48+
link.lastElementChild?.lastElementChild?.firstElementChild?.textContent);
49+
// no queue and video clicked
50+
if (isEmptyQueue() && later === null)
51+
return;
52+
// always prevent going to video
53+
e.preventDefault();
4754
if (later !== null) {
4855
// queue button clicked
4956
enqueue(name);

src/scripts/pages/watchnebula/_queue.ts

Lines changed: 90 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ export type video = {
99

1010
const store: { [key: string]: video } = {};
1111
const queue: string[] = [];
12-
let queuepos = 0;
12+
let queuepos = -1;
13+
let popupel: HTMLElement = null;
1314
let queueel: HTMLElement = null;
15+
let titleel: HTMLElement = null;
16+
let quenoel: HTMLElement = null;
1417

1518
export async function addToStore(name: string, length: string, thumbnail: string, title: string, creator: string): Promise<void>;
1619
export async function addToStore(name: string): Promise<void>;
@@ -20,83 +23,143 @@ export async function addToStore(name: string, ...args: any[]) {
2023
const [ length, thumbnail, title, creator ] = args.length === 4 ? args : await requestData(name);
2124
store[name] = { length, thumbnail, title, creator };
2225
}
26+
export const isEmptyQueue = () => queue.length === 0;
2327
export const enqueue = (name: string, pos?: number) => {
2428
if (!store[name])
2529
throw "Not in store!";
2630
if (pos !== undefined)
2731
queue.splice(pos, 0, name);
2832
else
2933
queue.splice(queue.length, 0, name);
30-
console.log(queue);
34+
popupel.classList.remove('hidden');
35+
calcBottom(popupel.classList.contains('down'));
3136
};
3237
export const enqueueNow = (name: string) => {
3338
if (!name)
3439
throw "Not in store!";
35-
queue.splice(queuepos + 1, 0, name);
36-
console.log(queue);
40+
if (queue[queuepos] !== name && queue[queuepos + 1] !== name)
41+
enqueue(name, queuepos + 1);
3742
}
3843
export const removeFromQueue = (index: number) => {
44+
console.log(index, queuepos, queue);
45+
if (index < 0 || index >= queue.length) return;
46+
if (queue.length === 1) return clearQueue();
3947
queue.splice(index, 1);
40-
console.log(queue);
48+
if (queuepos >= 0 && index <= queuepos) {
49+
--queuepos;
50+
updateText();
51+
}
4152
}
42-
export const gotoQueue = (index: number) => {
53+
export const gotoQueue = (index: number, go=true) => {
54+
console.log(index, queue);
55+
if (index < 0 || index >= queue.length) return;
4356
queueel?.children[queuepos]?.classList.remove('playing');
4457
queuepos = index;
45-
const url = `/videos/${queue[index]}`;
46-
// trick router into accepting my url without reloading page
47-
window.history.pushState(null, null, url);
48-
window.history.pushState(null, null, url);
49-
window.history.back();
58+
if (go) {
59+
const url = `/videos/${queue[index]}`;
60+
// trick router into accepting my url without reloading page
61+
// if previously tricked, need to undo that (to avoid broken history)
62+
if (history.state?.fake === true)
63+
window.history.back();
64+
setTimeout(() => {
65+
window.history.pushState({ fake: true }, null, url);
66+
window.dispatchEvent(new PopStateEvent("popstate"));
67+
}, 0);
68+
}
5069
queueel?.children[index]?.classList.add('playing');
51-
console.log(queuepos);
70+
updateText();
5271
}
5372
export const gotoNextInQueue = () => gotoQueue(queuepos + 1);
73+
export const clearQueue = () => {
74+
queuepos = -1;
75+
queue.splice(0, queue.length);
76+
clearText();
77+
popupel.classList.add('hidden');
78+
setTimeout(() => popupel.classList.remove('down'), 0);
79+
};
80+
export const toggleQueue = () => calcBottom(popupel.classList.toggle('down'));
5481

5582

5683
export const init = () => {
5784
// remove existing elements from extension reload
58-
Array.from(document.querySelectorAll('.enhancer-queue')).forEach(e => e.remove());
85+
Array.from(document.querySelectorAll('.enhancer-queue')).forEach(n => n.remove());
5986

6087
const q = document.createElement('div');
61-
q.className = 'enhancer-queue';
88+
popupel = q;
89+
q.className = 'enhancer-queue hidden';
6290
q.innerHTML = `
63-
<div class="top"></div>
64-
<div class="elements"></div>
91+
<div class="enhancer-queue-inner">
92+
<div class="top">
93+
<div class="current"><span class="title">Nothing to play</span><span class="no">-</span> / <span class="of">0</span></div>
94+
<div class="close">&times;</div>
95+
</div>
96+
<div class="elements"></div>
97+
</div>
6598
`;
66-
const e = q.querySelector('.elements') as HTMLElement;
99+
const e: HTMLElement = q.querySelector('.elements');
67100
queueel = e;
68-
document.body.appendChild(q);
101+
const o: HTMLElement = q.querySelector('.of');
102+
titleel = q.querySelector('.title');
103+
quenoel = q.querySelector('.no');
104+
document.body.append(q);
69105

70106
queue.splice = (start: number, count: number, ...elements: string[]) => {
71107
start = start < 0 ? queue.length - start : start;
72108
start = start < 0 ? 0 : start > queue.length ? queue.length : start;
73109
const end = start + count > queue.length ? queue.length : start + count;
74110
let s = start > 0 ? e.children[start-1] : null;
75-
for (let i = start; i < end; i++)
111+
for (let i = end - 1; i >= start; i--)
76112
e.children[i].remove();
77113
for (let el of elements) {
78114
const node = insertChild(el);
79-
s = s === null ? e.appendChild(node) : (s.after(node), node);
115+
s === null ? e.firstChild === null ? e.append(node) : e.firstChild.before(node) : s.after(node);
116+
s = node;
80117
}
81-
return Array.prototype.splice.call(queue, start, count, ...elements);
118+
const del = Array.prototype.splice.call(queue, start, count, ...elements);
119+
o.textContent = `${queue.length}`;
120+
return del;
82121
};
83122
e.addEventListener('click', clickElements);
123+
q.querySelector('.top').addEventListener('click', toggleQueue);
124+
q.querySelector('.close').addEventListener('click', clearQueue);
84125
window.addEventListener('message', msg);
85126
};
86127
const clickElements = (e: MouseEvent) => {
87128
const el = (e.target as HTMLElement).closest('.element');
88129
if (el === null)
89130
return;
90131
e.preventDefault();
91-
const i = Array.from(el.parentElement.children).findIndex(e => e.isSameNode(el));
92-
gotoQueue(i);
132+
const i = Array.from(el.parentElement.children).findIndex(n => n.isSameNode(el));
133+
if (i === -1)
134+
return;
135+
const r = (e.target as HTMLElement).closest('.r');
136+
if (r === null)
137+
gotoQueue(i);
138+
else
139+
removeFromQueue(i);
93140
};
94141
const msg = (e: MessageEvent) => {
95142
if (e.origin !== "https://player.zype.com" && e.origin !== "http://player.zype.com")
96143
return;
97-
const m = JSON.parse(e.data);
98-
if (m.event === "zype:complete") gotoNextInQueue();
99-
}
144+
try {
145+
const m = JSON.parse(e.data);
146+
if (m.event === "zype:complete") gotoNextInQueue();
147+
} catch {}
148+
};
149+
const updateText = () => {
150+
titleel.textContent = store[queue[queuepos]]?.title;
151+
quenoel.textContent = queuepos >= 0 ? `${queuepos + 1}` : '-';
152+
};
153+
const clearText = () => {
154+
titleel.textContent = 'Nothing to play';
155+
quenoel.textContent = '-';
156+
};
157+
const calcBottom = (down: boolean) => {
158+
if (down)
159+
popupel.style.bottom = `-${queueel.getBoundingClientRect().height}px`;
160+
else
161+
popupel.style.bottom = '';
162+
};
100163

101164

102165
type thumb = {
@@ -144,6 +207,7 @@ const insertChild = (name: string): HTMLElement => {
144207
<span class="title">${store[name].title}</span>
145208
<span class="creator">${store[name].creator}${store[name].length}</span>
146209
</div>
210+
<div class="remove"><span class="r">&#128465;</span></div>
147211
`;
148212
return n;
149213
};

0 commit comments

Comments
 (0)