Conversation
1b85370 to
884623f
Compare
There was a problem hiding this comment.
Pull request overview
This is a major feature release (v3.1.0) that introduces significant improvements and new functionality to BetterYTM. The PR adds a redesigned config menu with sidenav, exponential volume scaling, hotkeys for search bar interaction, automatic dismissal of the "Are you still there?" dialog, track numbers in playlists, and numerous plugin API enhancements including a new intent-based permission system.
Key Changes:
- New sidenav-based config menu with improved UX and organization
- Plugin system enhancements with intent-based permissions and authenticated APIs
- Exponential volume slider scaling with configurable curves (x^3, x^4, x^5)
- New hotkeys for focusing/clearing search bar and double-press guard for number key seeking
- Automatic "Are you still there?" dialog dismissal feature
- Migration from ES2017 to ES2020 target with UserUtils → CoreUtils transition
Reviewed changes
Copilot reviewed 86 out of 130 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Updates TypeScript target to ES2020 and lib to ES2024 |
| src/utils/xhr.ts | Refactors to use CoreUtils, improves iTunes API handling, increases vote cache TTL |
| src/utils/translations.ts | Adds CoreUtils integration, dev translation tracking, locale direction support |
| src/utils/misc.ts | Major refactoring with new utilities (overflowVal, version session counter, repeat task, resource caching) |
| src/utils/logging.ts | Adds log file export functionality and improved error handling |
| src/utils/dom.ts | Adds sanitizeHtml helper and transplantElement utility |
| src/types.ts | Extensive type additions for new features and better documentation |
| src/tools/*.ts | Build tool improvements with better arg parsing and antifeature directives |
| src/siteEvents.ts | New events and timing improvements with forceEmitSiteEvent workaround |
| src/serializers.ts | New file replacing serializer.ts with full data export support |
| src/observers.ts | Adds searchPage observer for YTM |
| src/interface.ts | Major plugin system overhaul with intent checking and new authenticated APIs |
| src/index.ts | Improved initialization timing with better performance tracking |
| src/features/volume.ts | Implements exponential volume scaling with HTMLMediaElement override |
| src/features/songLists.ts | Adds track numbers and improves list button placement logic |
| src/features/lyricsCache.ts | Migration to debulkified cache format with path-only storage |
| src/features/lyrics.ts | Unicode sanitization and improved URL handling |
| src/features/input.ts | Double-press guard for number key seeking |
| src/features/hotkeys.ts | New search bar focus/clear hotkeys with improved event handling |
| src/features/behavior.ts | "Are you still there?" auto-dismissal with interaction simulation |
| src/menu/menu_old.ts | Complete sidenav redesign with category organization and extra info sections |
| CSS files | Extensive styling updates for new menu layout and component improvements |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 54 out of 527 changed files in this pull request and generated 8 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 55 out of 528 changed files in this pull request and generated 12 comments.
Comments suppressed due to low confidence (1)
.github/workflows/lint.yml:1
- Same as build workflow:
actions/checkout@v6,actions/setup-node@v6, andactions/cache@v5are not known valid major versions (up to 2025-08) and likely cause workflow failures. Use known valid tags (commonly v4) or pin to SHAs.
name: "Lint BetterYTM"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Check below this list to install the latest stable-ish preview version.
initTimeoutwill be changed from8to5seconds.rememberSongTimeDurationwill be changed from60to180seconds.frameSkipAmountwill be changed from0.0417to0.0166seconds.thumbnailOverlayITunesImgReswill be changed from1500to2000pixels.thumbnailOverlayAlbumArtCacheMaxSizewill be changed from2000to10000entries.thumbnailOverlayIndicatorOpacitywill be changed from40to25percent.lyricsCacheMaxSizewill be changed from2000to10000entries.rememberSongTimeMinPlayTimewill be changed from10to5seconds.hideCursorOnIdleDelaywill be changed from2to3seconds.DataStoresinterface.tsand common dependencieswatermarkEnabledis off (closes Inline SVG logo swap doesn't trigger correctly when watermark is disabled #161)Click here to see everything that is postponed to a later update
Click to expand plugin and internal changes
(I did my best to order these by relevance for each section)(also refer to version 3.1.0's API docs)
PluginDefobject'sintentsproperty (which can now also be an array instead of just a bitwise-or'ed number). Read below for a list of functions and their required intents.BytmDialog,ExImDialogorMarkdownDialogclasses directly, switch to the new authenticated functionsgetBytmDialog(),getExImDialog()andgetMarkdownDialog(). Direct access will continue to work until version 4.0.0, but to future-proof your plugin, switch to the new functions as soon as possible, and make sure to add theCreateModalDialogs(32) intent to your plugin definition'sintentsproperty.bytm:readyto reliably wait until all features are initialized, switch tobytm:allReadyinstead.The
bytm:readyevent is still emitted, but it is now only guaranteed to be emitted when the DOM is loaded and all features have started to initialize.NanoEmittersubclasses and the interface-exposedNanoEmitterclass reference now use CoreUtils' newNanoEmitterclass, which grants you access to the powerfulonMulti()method to listen to multiple events at once, with configurable behavior.intentsprop can now be an array ofPluginIntentenum members.Intents are now required to be set in the plugin definition object, though for now they will still all be granted and don't need to be explicitly allowed by the user once after installing yet.
The new intent
FullAccess(512) grants all other intents, though you should only use it if your plugin truly requires all intents.These are the intents that are now required for the respective functions:
getFeatures()-ReadFeatureConfig(1) and optionallySeeHiddenConfigValues(4)saveFeatures()-WriteFeatureConfig(2)setLocale()-WriteTranslations(16)getBytmDialog()-CreateModalDialogs(32)getExImDialog()-CreateModalDialogs(32)getMarkdownDialog()-CreateModalDialogs(32)getAutoLikeData()-ReadAutoLikeData(64)saveAutoLikeData()-WriteAutoLikeData(128)getInternals()-InternalAccess(256)BytmDialog,ExImDialogandMarkdownDialogshould now be gotten using the new authenticatedgetBytmDialog(),getExImDialog()andgetMarkdownDialog()functions, respectively.Using the direct access will work until version 4.0.0, but it is recommended you switch to the new functions as soon as possible.
PluginDefobject'sintentsproperty can now be either an array ofPluginIntentvalues or a single number that is the bitwise OR of the intents.bytm-broadcast), used for inter-tab communication. Events are relayed via the site eventbytm:siteEvent:broadcast- seesrc/utils/broadcast.tsfor a list of events.registerPlugin()now also returns apermissionsobject with theintandarrayproperties, which contain all of the bitwise OR of the plugin's intents and an array of the intents that were actually granted to the plugin. Theintproperty can be used with CoreUtils'bitSetHas()function to check if specific intents were granted.PluginDefobject'shomepage.changelogproperty.InternalAccess(256) (currently only used bygetInternals()) andFullAccess(512) (grants all intents).resourceAsString()- Returns a BYTM resource as a string, some of which are cached cross-session in GM storage for better performance.onSiteEvent()- Adds a site event listener.onceSiteEvent()- Adds a site event listener that is only called once and also returns a Promise for use with the async/await pattern.onMultiSiteEvents()- Adds a listener that triggers after one of, or all of the given site events are dispatched, either continuously or just once, with configurable behavior.getBytmDialog()(requires intentCreateModalDialogs(32)) - Returns a reference to theBytmDialogclass, which can be used to create new generic dialog instances.getExImDialog()(requires intentCreateModalDialogs(32)) - Returns a reference to theExImDialogclass, to export and import serializable data.getMarkdownDialog()(requires intentCreateModalDialogs(32)) - Returns a reference to theMarkdownDialogclass, to render a markdown string in a modal dialog.getInternals()(requires intentInternalAccess(256)) - returns some internal function and object references that can be used by core libraries and deeper reaching plugins.bytm:preInitPlugin(no arguments) - emitted at the earliest possible point in time, even before the DOM is loaded, to allow plugins to do any immediate but superficial initialization.bytm:allReady(no arguments) - emitted when all features have been initialized and the interface is fully ready to use.This triggers much later than
bytm:ready, which is emitted when the DOM is loaded and all features are starting to initialize.For the fastest response times, use
bytm:featureInitializedfor every feature your code depends on.bytm:featureInitialized:id(no arguments) - emitted when a feature with the specified key has been initialized.In TypeScript, use
"bytm:featureInitialized:myFeatureKey" as "bytm:featureInitialized:id"to make the error go away.bytm:artworkCacheEntryAdded- emitted when an album artwork was added to the cache. Gets passed an object with the propertiesartist,albumandentry(object with the propsentry.url: string,entry.videoId: stringandentry.created: number).bytm:siteEvent:cfgMenuMounted(no arguments) - emitted when the config menu is invisibly mounted to the DOM (not opened yet, but modifiable).bytm:siteEvent:configHeaderSelected: (name: LooseUnion<FeatureCategory>)- emitted when a config header is selected in the config menu, with the name of the selected header. This is usually the feature category name, but can also be an info category name (currently just"about"and"changelog").bytm:siteEvent:voteLabelsAdded(no arguments) - emitted after the Return YouTube Dislike vote labels were added to the DOM.bytm:siteEvent:updateVolumeSliderLabel(no arguments) - emitted to make the volume slider label update its text content.searchPage, as the root observer for the YTM search page.@antifeature trackingdirective, to indicate that services temporarily log IP addresses and the currently playing song.@sv443-network/coreutilsas a new core library, accessible on the BYTM API viaBYTM.CoreUtils.@sv443-network/userutilsto v10.x.x to, among other things, fix two bugs related to the template literal placeholder format. This now allows specifying a single placeholder multiple times per translation string.siteEventssystem use CoreUtils' improvedNanoEmitter, so it can now also be used to listen to multiple events using.onMulti().siteEventsinitialization to an earlier point, so that it is no longer initialized alongside features. It is now available to plugins at an earlier point in time, before any feature has started initializing, but still after plugin initialization is already done.events(returned byregisterPlugin()) use CoreUtils' newNanoEmitteras well.bytm:readywill now emit earlier and the new eventbytm:allReadywill emit much later, once all features have been initialized or the configured timeout has been reached.resourceAsString()for even better feature init performance.GM.getResourceUrl()entirely in favor of fetching resources from a CDN.{ name: "John" }for a translation using the new placeholder syntax, e.g."Hello, ${name}!".sanitizeArtists()andsanitizeSong()will now replace some common Unicode punctuation symbols with their ASCII counterparts (e.g.‘->').generalfeature category to the top of the config menu.bytm-ftconf-category-${categoryName}to allow for the sidenav to disable all but one at a time.categoryName(currently just"about"and"changelog").pluginHasPerms()tointerface.ts, which will now check forFullAccessor the given intents before allowing authenticated functions to be called.--bytm-menu-bg-highlight-2(hex, opacity 1) as a secondary level of highlight to--bytm-menu-bg-highlight.--bytm-dialog-height-maxto--bytm-dialog-target-height, but only for the config menu. All BytmDialogs will still use--bytm-dialog-height-max.src/utils/logging.ts(if the last argument is a number that exceeds the range of the enumLogLevel, it will not be interpreted as a log level anymore, but as a number to be logged).Preview Version:
Important
The preview version contains unfinished features, could potentially be unstable, and is likely to mess up your configuration data in the early stages.
This is why I highly recommend you fully remove the script and reinstall it manually once the update is released.
Before installing the preview version you should use the config and auto-liked channels menu's export and import functions to back up all your data.
Note
Developer Modeicon in the bottom left of the config menu.