- Added features:
- Added a feature to like songs and videos of certain channels (on both sites) automatically.
The button to toggle auto-liking will only show up on channel pages until the next update. Please report any issues you encounter.
- Added the ability to show the approximate amount of likes and dislikes on the currently playing song (powered by ReturnYoutubeDislike)
- Added support for themes set by the ThemeSong extension
- Added a dialog for listing the currently installed and active plugins including some metadata
- Changes:
- Made song/video time remembering enabled by default on YT too
- Made reset button in config menu a feature of type
button
- Welcome menu is now shown on YT too
- Added Ctrl modifier key to every lyrics button to open a lyrics search prompt
- Added Shift and Ctrl modifier keys to the above-queue buttons that will skip prompts or customize their behavior in other ways
- Arrow key and number key skipping works more reliably and now also in the config menu
- Changed default settings for some features.
After updating, if the values were unchanged from their previous default, they will automatically have the new default value:
- Remember Song Time Sites: if set to
YTM only
, it changes to both sites
- Volume Slider Scroll Sensitivity: if set to
10%
, it changes to 4%
- Made some settings require advanced mode that didn't before:
- Fix spacing/layout issues
- Fix HDR issues
- Disable Dark Reader sites
- Remove share tracking parameter sites
- Placement of list/queue buttons
- Removed broken feature "remove upgrade tab"
- Removed unnecessary experimental feature "advancedLyricsFilter" as the API's native search improved a lot
- Made all integration features configurable and gave them their own config category
- Created a prompt dialog to replace the browser's native dialogs, which could accidentally be turned off by the user and would softlock the script
- Fixes:
- Fixed major bug that threw "This document requires 'TrustedHTML' assignment" errors on Chromium browsers
- Adjusted script to UI redesign of playlists
- Fixed song list buttons disappearing when dragging the row around
- Fixed song list buttons not always appearing immediately
- Fixed escape closing all open dialogs instead of one at a time
- Fixed "added to liked songs" toast not being consistently closed
- Fixed messed up time restoration feature on YT because of the
&t
param
- Fixed broken autoplay queue delete button after a redesign
- Fixed transparent player bar background in fullscreen being barely readable with thumbnail overlay active
- Fixed thumbnail overlay not updating in fullscreen mode and in the mini player
- Fixed video time restoring breaking after pausing for a longer time
- Fixed toasts being shown with a 1000x higher duration than intended
- Fixed volume slider features not working anymore when display width shrinks to below 1150px
Click to expand internal and plugin changes
- Internal Changes:
- Updated the UserUtils library to v8.0.2
- Removed
compareVersions()
and compareVersionArrays()
in favor of including the compare-versions
library
- Now using a single query parameter for lyrics lookup
- Added license for plugin-related source code, see license-for-plugins.txt
- Added advanced feature to change the startup timeout (only impacts plugin initialization for now)
- Now using a blue logo is instead of the red BetterYTM logo when the script was compiled in development (preview) mode
- Added Storybook for easier and faster development of components
- Removed the
@updateURL
and @downloadURL
directives because their use is controversial and the script has a built-in update check now
- Migrated to pnpm for faster compilation times
- Moved
NanoEmitter
class over to the UserUtils library (it is still re-exported by the plugin interface as before)
- Made
getThumbnailUrl()
and getBestThumbnailUrl()
use the domain youtube.com
to prevent cross-origin issues
- Added custom error instances
LyricsError
and PluginError
for better error handling using instanceof
- Changed the feature identifier key for
showVotesFormat
to numbersFormat
as it is now generic and available to plugins through the formatNumber()
function
- Feature config keys will now be corrected on each page load (meaning missing keys will be set to their default and extra keys will be removed)
- Plugin Changes:
See the contributing guide for the latest documentation of the plugin interface
- Changed the way plugins are registered by making the
registerPlugin()
function the sole argument passed by the bytm:registerPlugin
event. Call this function synchronously to register your plugin.
- Plugins will now load at an earlier point in BetterYTM's startup sequence. This means that plugins can now be initialized before the script's features are fully initialized and the DOM is ready. Use site events to wait for the right moment to interact with the page.
- Added new components:
createLongBtn()
to create a button with an icon and text (works either as normal or as a toggle button)
The design follows that of the subscribe button on YTM's channel pages, but the consistent class names make it easy to style it differently.
createRipple()
to create a click ripple animation effect on a given element
showToast()
to show a custom toast notification with a message string or element and duration
showIconToast()
to show a custom toast notification with a message string or element, icon and duration
showPrompt()
to show a styled dialog that replaces the confirm()
, alert()
and prompt()
functions
ExImDialog
class for creating a BytmDialog instance that is designed for exporting and importing generic data as a string
- Changed components:
- BytmDialog now has the option
removeListenersOnDestroy
(true by default) to configure removing all event listeners when the dialog is destroyed
- BytmDialog's private members and methods have been changed to protected for easier extension (when using TypeScript)
- Plugin definition changes:
- Some intents were added or moved around in their order. See the new values in
src/types.ts -> enum PluginIntent
- Added interface functions:
setInnerHtml()
to set the innerHTML property of an element to a sanitized string using the Trusted Types API and the library DOMPurify
getAutoLikeData()
to return the current auto-like data (authenticated function)
saveAutoLikeData()
to overwrite the auto-like data (authenticated function)
fetchVideoVotes()
to fetch the approximate like and dislike count of a video from Return Youtube Dislike
getDomain()
returns the current domain ("yt" or "ytm")
waitVideoElementReady()
returns a promise that resolves when the video element is ready
getCurrentMediaType()
(on YTM only) returns the current media type ("video" or "song")
tl()
returns the translation for the provided translation key and provided locale
tlp()
returns the translation for the provided translation key, including pluralization identifier and provided locale
formatNumber()
formats a number according to the configured locale and configured or provided format ("short" or "long")
- SelectorObserver /
addSelectorListener()
changes:
- Added
ytMasthead
instance for the title bar on YT
- Renamed all YT-specific instances to have the
yt
prefix
watchFlexy
renamed to ytWatchFlexy
watchMetadata
renamed to ytWatchMetadata
- Added new SelectorObserver instance
browseResponse
for pages like /channel/{id}
- Event changes:
- Added events
bytm:featureInitStarted
- emitted when the feature initialization process starts
bytm:featureInitialized
- emitted every time a feature has been initialized and is passed the feature's identifier string
bytm:dialogClosed
- emitted when a BytmDialog is closed and gets passed the instance
bytm:dialogClosed:id
- emitted only when the dialog with the given ID is closed and gets passed the instance
bytm:siteEvent:pathChanged
- emitted whenever the URL path (location.pathname
) changes
- Now the event
bytm:siteEvent:fullscreenToggled
is only emitted once per fullscreen change
- Renamed event
bytm:initPlugins
to bytm:registerPlugin
to be more consistent
- Changed
event
property returned by registerPlugin()
from nanoevents Emitter to NanoEmitter instance (see the UserUtils docs)
In practice this changes nothing, but it benefits from plugins having access to the additional methods once()
for immediately unsubscribing from an event after it was emitted once and unsubscribeAll()
to remove all event listeners.
See pull request for more info