Skip to content

Commit

Permalink
fix: arrow key skip (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sv443 committed Sep 19, 2023
1 parent a8a38e1 commit 99fdc4d
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 11 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ Configurable layout and UX improvements for YouTube Music
<br>

### Features:
All of these features can be toggled and configured!
- Input:
- Use arrow keys to skip forward or backward by 10 seconds
- Switch between YouTube and YouTube Music on a video by pressing a hotkey (F9 by default)
- Switch between YouTube and YouTube Music on a video by pressing a hotkey (F9 by default) <!-- TODO: make configurable -->
- TODO: Automatically dismiss "are you still there" popup
- Layout:
- Open any song's lyrics on genius.com which generally has higher quality than YouTube's providers
- TODO: Quick actions on songs in a queue, to open their lyrics or remove them from the queue
- Remove the "Upgrade to YT Music Premium" tab in the title bar
- Set a custom size and step resolution for the volume slider
- Quickly open any song's lyrics on genius.com
- TODO: Improvements to clickability of song titles and thumbnails (to open them in a new tab better)

... and more!

Expand Down
32 changes: 32 additions & 0 deletions dev/ytForceShowVideoTime.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// caveats:
// only works once for some reason (should be enough tho)

const player = document.querySelector("#movie_player");
player.dispatchEvent(new MouseEvent("mouseenter", {
view: window,
bubbles: true,
cancelable: false,
}));

const { x, y, width, height } = player.getBoundingClientRect();
const screenY = Math.round(y + height / 2);
const screenX = x + Math.min(50, Math.round(width / 3));

player.dispatchEvent(new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: false,
screenY,
screenX,
movementX: 5,
movementY: 0
}));
console.log("x:", screenX, "y:", screenY);

setTimeout(() => {
player.dispatchEvent(new MouseEvent("mouseleave", {
view: window,
bubbles: true,
cancelable: false,
}));
}, 4000);
2 changes: 1 addition & 1 deletion dist/BetterYTM.user.js

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@
"type": "module",
"scripts": {
"test": "npm run node-ts -- ./test.ts",
"build": "webpack",
"build": "tsc && webpack",
"post-build": "npm run node-ts -- ./src/tools/post-build.ts",
"serve": "npm run node-ts -- ./src/tools/serve.ts",
"serve-old": "http-server -s -c 5 -p 8710 .",
"watch": "nodemon --exec \"npm run build && npm run serve\"",
"lint": "tsc --noEmit && eslint .",
"node-ts": "node --no-warnings=ExperimentalWarning --enable-source-maps --loader ts-node/esm"
Expand Down
1 change: 1 addition & 0 deletions src/features/input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ function onKeyDown(evt: KeyboardEvent) {
cancelable: true,
isTrusted: true,
repeat: false,
view: window,
};

let invalidKey = false;
Expand Down
3 changes: 2 additions & 1 deletion src/features/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export function setVolSliderStep() {
export function initQueueButtons() {
siteEvents.on("queueChanged", (evt) => {
for(const queueItm of ((evt.data as HTMLElement).childNodes as NodeListOf<HTMLElement>)) {
if(!queueItm.dataset["bytm-has-queue-btns"])
if(!queueItm.classList.contains("bytm-has-queue-btns"))
addQueueButtons(queueItm);
}
});
Expand Down Expand Up @@ -141,4 +141,5 @@ function addQueueButtons(queueItem: HTMLElement) {

const songInfo = queueItem.querySelector(".song-info")!;
songInfo.appendChild(queueBtnsCont);
queueItem.classList.add("bytm-has-queue-btns");
}
64 changes: 59 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,37 @@ export function getDomain(): Domain {
}

/**
* TODO: this is entirely broken now
* Returns the current video time in seconds
* @param force Set to true to dispatch mouse movement events in case the video time can't be estimated
* @returns Returns null if the video time is unavailable
*/
export function getVideoTime() {
export function getVideoTime(force = false) {
const domain = getDomain();

try {
if(domain === "ytm") {
const pbEl = document.querySelector("#progress-bar") as HTMLProgressElement;
return pbEl.value ?? null;
return !isNaN(Number(pbEl.value)) ? Number(pbEl.value) : null;
}
else if(domain === "yt") {
// YT doesn't update the progress bar when it's hidden (YTM doesn't hide it) so TODO: come up with some solution here

// Possible solution:
// - Use MutationObserver to detect when attributes of progress bar (selector `div.ytp-progress-bar[role="slider"]`) change
// - Wait until the attribute increments, then save the value of `aria-valuenow` and the current system time to memory
// - When site switch hotkey is pressed, take saved `aria-valuenow` value and add the difference between saved system time and current system time
// - If no value is present, use the script from `dev/ytForceShowVideoTime.js` to simulate mouse movement to force the element to update
// - Subtract one or two seconds to make up for rounding errors
// - profit

// if(!ytCurrentVideoTime) {
// ytForceShowVideoTime();
// const videoTime = document.querySelector("#TODO")?.getAttribute("aria-valuenow") ?? null;
// }
void [ force, ytForceShowVideoTime ];

return null;
}
else if(domain === "yt") // YT doesn't update the progress bar when it's hidden (YTM doesn't hide it) so TODO: come up with some solution here
return 0;

return null;
}
Expand All @@ -43,6 +60,43 @@ export function getVideoTime() {
}
}

/** Sends events that force the video controls to become visible for about 3 seconds */
function ytForceShowVideoTime() {
const player = document.querySelector("#movie_player");
if(!player)
return false;

player.dispatchEvent(new MouseEvent("mouseenter", {
view: window,
bubbles: true,
cancelable: false,
}));

const { x, y, width, height } = player.getBoundingClientRect();
const screenY = Math.round(y + height / 2);
const screenX = x + Math.min(50, Math.round(width / 3));

player.dispatchEvent(new MouseEvent("mousemove", {
view: window,
bubbles: true,
cancelable: false,
screenY,
screenX,
movementX: 5,
movementY: 0
}));

setTimeout(() => {
player.dispatchEvent(new MouseEvent("mouseleave", {
view: window,
bubbles: true,
cancelable: false,
}));
}, 4000);

return true;
}

//#SECTION DOM

/**
Expand Down

0 comments on commit 99fdc4d

Please sign in to comment.