Ver Fonte

feat: frame-skip feature

Sv443 há 5 dias atrás
pai
commit
8362f8aa31

+ 9 - 9
assets/translations/README.md

@@ -16,15 +16,15 @@ To submit or edit a translation, please follow [this guide](../../contributing.m
 ### Translation progress:
 |   | Locale | Translated keys | Based on |
 | :----: | ------ | --------------- | :------: |
-|  | [`en-US`](./en-US.json) | `343` (default locale) |  |
-| ✅ | [`de-DE`](./de-DE.json) | `343/343` (100%) | ─ |
-|  | [`en-GB`](./en-GB.json) | `343/343` (100%) | `en-US` |
-| ⚠ | [`es-ES`](./es-ES.json) | `335/343` (97.7%) | ─ |
-| ⚠ | [`fr-FR`](./fr-FR.json) | `335/343` (97.7%) | ─ |
-| ⚠ | [`hi-IN`](./hi-IN.json) | `335/343` (97.7%) | ─ |
-| ⚠ | [`ja-JP`](./ja-JP.json) | `335/343` (97.7%) | ─ |
-| ⚠ | [`pt-BR`](./pt-BR.json) | `335/343` (97.7%) | ─ |
-| ⚠ | [`zh-CN`](./zh-CN.json) | `335/343` (97.7%) | ─ |
+|  | [`en-US`](./en-US.json) | `345` (default locale) |  |
+| ⚠ | [`de-DE`](./de-DE.json) | `343/345` (99.4%) | ─ |
+|  | [`en-GB`](./en-GB.json) | `345/345` (100%) | `en-US` |
+| ⚠ | [`es-ES`](./es-ES.json) | `335/345` (97.1%) | ─ |
+| ⚠ | [`fr-FR`](./fr-FR.json) | `335/345` (97.1%) | ─ |
+| ⚠ | [`hi-IN`](./hi-IN.json) | `335/345` (97.1%) | ─ |
+| ⚠ | [`ja-JP`](./ja-JP.json) | `335/345` (97.1%) | ─ |
+| ⚠ | [`pt-BR`](./pt-BR.json) | `335/345` (97.1%) | ─ |
+| ⚠ | [`zh-CN`](./zh-CN.json) | `335/345` (97.1%) | ─ |
 
 <sub>
 ✅ - Fully translated

+ 4 - 2
assets/translations/en-US.json

@@ -315,8 +315,10 @@
   "feature_desc_arrowKeySupport": "Use arrow keys to skip forwards and backwards in the currently playing song",
   "feature_helptext_arrowKeySupport": "Normally you can only skip forwards and backwards by a fixed 10 second interval with the keys \"H\" and \"L\". This feature allows you to use the arrow keys too.\nTo change the amount of seconds to skip, use the option below.",
   "feature_desc_arrowKeySkipBy": "By how many seconds to skip when using the arrow keys",
-  "feature_desc_switchBetweenSites": "Add a hotkey to switch between the YT and YTM sites on a video / song",
-  "feature_helptext_switchBetweenSites": "Pressing this hotkey will switch to the other site if you are on YouTube or YouTube Music while staying on the same video / song.",
+  "feature_desc_frameSkip": "Use the period and comma keys to skip forwards and backwards by a frame when the video or song is paused",
+  "feature_desc_frameSkipWhilePlaying": "Also allow skipping by a frame while the video or song is still playing",
+  "feature_desc_switchBetweenSites": "Add a hotkey to switch between the YT and YTM sites on a video or song",
+  "feature_helptext_switchBetweenSites": "Pressing this hotkey will switch to the other site if you are on YouTube or YouTube Music while staying on the same video or song.",
   "feature_desc_switchSitesHotkey": "Which hotkey needs to be pressed to switch sites?",
   "feature_desc_anchorImprovements": "Add and improve links all over the page so things can be opened in a new tab easier",
   "feature_helptext_anchorImprovements": "Some elements on the page are only clickable with the left mouse button, which means you can't open them in a new tab by middle-clicking or through the context menu using shift + right-click. This feature adds links to a lot of them or enlarges existing ones to make clicking easier.",

+ 4 - 3
dist/BetterYTM.css

@@ -1960,6 +1960,7 @@ button[disabled].bytm-busy {
 .bytm-cfg-menu-option {
   display: block;
   padding: 8px 0;
+  border-top: 1px solid var(--yt-spec-outline, rgba(255, 255, 255, 0.2));
 }
 
 .bytm-cfg-menu-option-item {
@@ -2309,9 +2310,9 @@ ytmusic-player-queue-item
   button {
   background-color: var(
     --bytm-themesong-bg-accent-col,
-    var(--ts-palette-darkmuted-hex),
-    initial
+    var(--ts-palette-darkmuted-hex, initial)
   );
+  border: unset;
 }
 
 .ytmusic-player-queue .bytm-song-list-item-btn:hover,
@@ -2319,7 +2320,7 @@ ytmusic-player-queue-item
   ytmusic-menu-renderer
   #button-shape.ytmusic-menu-renderer:hover
   button {
-  background-color: rgba(255, 255, 255, 0.2);
+  box-shadow: inset 0 0 1000px rgba(255, 255, 255, 0.2);
 }
 
 /* #region volume slider */

+ 1 - 0
src/config.ts

@@ -139,6 +139,7 @@ export const migrations: DataMigrationsDict = {
   10: (oldData: FeatureConfig) => useNewDefaultIfUnchanged(
     useDefaultConfig(oldData, [
       "aboveQueueBtnsSticky", "autoScrollToActiveSongMode",
+      "frameSkip", "frameSkipWhilePlaying",
     ]), [
       { key: "lyricsCacheMaxSize", oldDefault: 2000 },
     ],

+ 16 - 0
src/features/index.ts

@@ -508,6 +508,22 @@ export const featInfo = {
     reloadRequired: false,
     enable: noop,
   },
+  frameSkip: {
+    type: "toggle",
+    category: "input",
+    default: true,
+    reloadRequired: false,
+    enable: noop,
+  },
+  frameSkipWhilePlaying: {
+    type: "toggle",
+    category: "input",
+    default: false,
+    reloadRequired: false,
+    enable: noop,
+    advanced: true,
+    textAdornment: adornments.advanced,
+  },
   switchBetweenSites: {
     type: "toggle",
     category: "input",

+ 31 - 0
src/features/input.ts

@@ -48,9 +48,40 @@ export async function initArrowKeySkip() {
     if(vidElem && vidElem.readyState > 0)
       vidElem.currentTime = clamp(vidElem.currentTime + skipBy, 0, vidElem.duration);
   });
+
   log("Added arrow key press listener");
 }
 
+//#region frame skip
+
+/** Initializes the feature that lets users skip by a frame with the period and comma keys while the video is paused */
+export async function initFrameSkip() {
+  document.addEventListener("keydown", async (evt) => {
+    if(!getFeature("frameSkip"))
+      return;
+
+    if(!["Comma", "Period"].includes(evt.code))
+      return;
+
+    const vid = getVideoElement();
+    if(!vid || vid.readyState === 0)
+      return warn("Could not find video element or it hasn't loaded yet, so the keypress is ignored");
+
+    if(!getFeature("frameSkipWhilePlaying") && (vid.playbackRate === 0 || !vid.paused))
+      return;
+
+    evt.preventDefault();
+    evt.stopImmediatePropagation();
+
+    const newTime = vid.currentTime + 0.04167 * (evt.code === "Comma" ? -1 : 1);
+    vid.currentTime = clamp(newTime, 0, vid.duration);
+
+    log(`Captured key '${evt.code}' and skipped to ${Math.floor(newTime / 60)}m ${(newTime % 60).toFixed(1)}s (${Math.floor(newTime * 1000 % 1000)}ms)`);
+  });
+
+  log("Added frame skip key press listener");
+}
+
 //#region site switch
 
 /** switch sites only if current video time is greater than this value */

+ 15 - 13
src/index.ts

@@ -11,31 +11,31 @@ import { MarkdownDialog } from "./components/MarkdownDialog.js";
 import { getWelcomeDialog } from "./dialogs/welcome.js";
 import { showPrompt } from "./dialogs/prompt.js";
 import {
-  // layout
+  // layout category:
   addWatermark, initRemShareTrackParam,
   fixSpacing, initThumbnailOverlay,
   initHideCursorOnIdle, fixHdrIssues,
   initShowVotes,
-  // volume
+  // volume category:
   initVolumeFeatures,
-  // song lists
+  // song lists category:
   initQueueButtons, initAboveQueueBtns,
-  // behavior
+  // behavior category:
   initBeforeUnloadHook, enableDiscardBeforeUnload,
   initAutoCloseToasts, initRememberSongTime,
   initAutoScrollToActiveSong,
-  // input
-  initArrowKeySkip, initSiteSwitch,
-  addAnchorImprovements, initNumKeysSkip,
-  initAutoLike,
-  // lyrics
+  // input category:
+  initArrowKeySkip, initFrameSkip,
+  initSiteSwitch, addAnchorImprovements,
+  initNumKeysSkip, initAutoLike,
+  // lyrics category:
   addPlayerBarLyricsBtn, initLyricsCache,
-  // integrations
+  // integrations category:
   disableDarkReader, fixSponsorBlock,
   fixPlayerPageTheming, fixThemeSong,
-  // general
+  // general category:
   initVersionCheck,
-  // menu
+  // menu:
   addConfigMenuOptionYT, addConfigMenuOptionYTM,
 } from "./features/index.js";
 // import { getAllDataExImDialog } from "./dialogs/allDataExIm.js";
@@ -222,6 +222,8 @@ async function onDomLoad() {
 
       ftInit.push(["arrowKeySkip", initArrowKeySkip()]);
 
+      ftInit.push(["frameSkip", initFrameSkip()]);
+
       if(feats.anchorImprovements)
         ftInit.push(["anchorImprovements", addAnchorImprovements()]);
 
@@ -248,7 +250,7 @@ async function onDomLoad() {
     //#region (ytm+yt) cfg menu
     try {
       if(domain === "ytm") {
-        addSelectorListener("body", "tp-yt-iron-dropdown #contentWrapper ytd-multi-page-menu-renderer #container.menu-container", {
+        addSelectorListener("popupContainer", "tp-yt-iron-dropdown #contentWrapper ytmusic-multi-page-menu-renderer #container", {
           listener: addConfigMenuOptionYTM,
         });
       }

+ 6 - 2
src/types.ts

@@ -18,7 +18,7 @@ import type { showIconToast, showToast } from "./components/toast.js";
 import resources from "../assets/resources.json" with { type: "json" };
 import locales from "../assets/locales.json" with { type: "json" };
 
-void ["type imports only", resources, locales];
+void ["type imports only:", resources, locales];
 
 //#region other
 
@@ -489,7 +489,7 @@ export type FeatureInfo = Record<
     valueHidden?: boolean;
     /** Transformation function called before the value is rendered in the config menu */
     renderValue?: (value: string) => string | Promise<string>;
-    /** HTML string that is appended to the end of a feature's text description */
+    /** HTML string that is prepended to the feature's text description */
     textAdornment?: () => (Promise<string | undefined> | string | undefined);
 
     /** Whether to only show this feature when advanced mode is activated (default false) */
@@ -587,6 +587,10 @@ export interface FeatureConfig {
   arrowKeySupport: boolean;
   /** By how many seconds to skip when pressing the arrow keys */
   arrowKeySkipBy: number;
+  /** Use . and , keys to skip by a frame while the video is paused */
+  frameSkip: boolean;
+  /** Allow frame skipping while the song is playing */
+  frameSkipWhilePlaying: boolean;
   /** Add a hotkey to switch between the YT and YTM sites on a video / song */
   switchBetweenSites: boolean;
   /** The hotkey that needs to be pressed to initiate the site switch */