Template for creating a plugin using BetterYTM's API to further improve YouTube and YouTube Music
WTFPL License
BetterYTM is a UserScript that enhances the YouTube and YouTube Music experience by adding features and fixing bugs. It has a plugin system that allows you to create your own plugins to further customize the experience and make use of its API. This template is perfect for anyone who wants to create a plugin for BetterYTM but doesn't want to deal with the hassle of setting up a working development environment.
BetterYTM (BYTM for short) is included as a Git submodule to ensure that both projects' versions stay compatible until you decide to update your plugin.
This also conveniently allows you to inspect BetterYTM's code for finding specific details about the API and even more conveniently, allows you to navigate through to the BYTM API by ctrl+clicking on imported members.
Just make sure to read the plugin sublicense to find out which parts you are allowed to include in your plugin's bundle in dist/
.
If you only import with the type
keyword (or without, when importing enum
s), you should be fine.
The plugin will be built with Vite and pnpm and written in TypeScript to provide a modern and lightning fast development experience. You may also import plain JavaScript files (with the extension .mjs) if you prefer that instead.
It is also set up to be easily hosted on a local server for testing and to be built for production with a single command.
If you use a UserScript manager extension such as Violentmonkey, you can easily test the plugin by opening the local server URL in your browser.
The extension will keep updating the userscript automatically when any changes are made.
Configure this behavior in the nodemonConfig
object in package.json
.
The library UserUtils is also included to provide a plethora of useful functions and classes for UserScripts.
I highly recommend checking it out! It is included on the BYTM API via unsafeWindow.BYTM.UserUtils
.
[!NOTE] If your plugin is published, send me a quick E-Mail or message on Discord so I can add it to the BetterYTM Plugin List. You can also contact me for questions and help or to request features to be exposed on the API.
Have fun creating your plugin!
git submodule update --init --recursive
to clone the BetterYTM submodule..env.template
to .env
and modify it to your needs.pnpm i
to install dependencies.pnpm run dev
to build the plugin and host it on a local server for testing.Refer to the commands section for more information on the available commands.
@root/
) contains the following:
.env.template
is an example file for an environment configuration..env
and modify it to your needs to change the behavior of the build process..gitmodules
contains the submodule configuration, where the BetterYTM repository is linked. Only modify this via terminal commands.changelog.md
documents all changes between your plugin's versions. It is recommended to keep this up to date.eslint.config.mjs
contains the ESLint configuration in the new v9 format. Feel free to modify this to your liking.@typescript-eslint/no-empty-object-type
is turned off, which means you can use the type {}
, but be careful since this doesn't mean "empty object" and is a common pitfall
package.json
is the single source of truth for lots of your plugin's metadata, like the name, version, description, etc.tsconfig.json
contains the TypeScript configuration. Feel free to modify this to your needs.vite.config.ts
contains the Vite build configuration. This is where your userscript metadata and some default values are defined.src/
folder contains the source code of the plugin (import prefix: @/
).
index.ts
is the main file that will be compiled into the userscript. In there, hook all the functions you want to run when the plugin is loaded.types.ts
makes sure that the BYTM API is available in your code by providing its global types.interface WindowEventMap
by following the format of the other entries and cross-referencing the BYTM API documentation.example/
contains example code to show you how to interact with the BYTM API.utils/
contains utility functions for better organization of your code (import prefix: @utils/
).
constants.ts
contains constants that are used throughout the plugin.vite.config.ts
.logging.ts
has shorthand functions for logging stuff to the console. This has the benefit of adding a common prefix to all log messages and in here you can hook your own functions to improve the logging system.plugin.ts
contains the plugin definition object, the plugin registration logic and constants exposed by the registration (token and event emitter instance).assets/
folder contains all the assets that are used in the plugin, think image, audio, video files, HTML, CSS, markdown, whatever.@resource
directive by editing the vite.config.ts
file, where you can then use GM.getResourceUrl()
to get the URL of the asset, which you can then fetch()
or point to in an img, video, audio, etc. tag.
resources.json
is where you define the @resource
directives for your plugin, which can then be fetched with GM.getResourceUrl()
and GM.getResourceText()
.assets/
folder.path
(follows the same logic as above) and an optional integrity
key, which can be set to true
to automatically calculate the SRI hash for the asset and append it to the URL in the metadata block.bytm
folder contains BetterYTM's entire repository as a submodule (import prefix: @bytm/
).main
is the latest release version, develop
is the latest in-dev version.dist/
folder, the final build of your userscript will be created by vite..js
. This is deliberate, because it is the latest ES module format. Just think of it as if you are trying to import the file that will exist after TypeScript has compiled it..vscode/settings.json
).
@
), which are defined in the tsconfig.json
file.with { type: "json" }
, which too is the latest ES module standard.@resource
directives is supported out of the box by this template.integrity
property to true
in assets/resources.json
, the plugin will automatically calculate the SRI hash and add it to the asset's URL.console.log()
that is called on each page load.dbaeumer.vscode-eslint
.User Settings (JSON)
to automatically format your code on manual saves:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
},
Alternatively if you want a keybind for this, bind the ESLint: Fix all auto-fixable Problems
command to a hotkey (press F1, enter the command name, click the gear icon on it).pnpm run dev
- Builds the plugin using the build-dev
command and hosts it on a local server for testing using the serve
command on default settings (or whatever is set in .env
).http://localhost:8767/betterytm-plugin-template.user.js
(file name is created from userscriptName
in package.json
).pnpm run build
- Builds the plugin for production into the dist
folder.pnpm run build-dev
- Builds the plugin for development into the dist
folder.vite.config.ts
.pnpm run serve
- Serves a few folders including dist
and assets
on a locally hosted HTTP server.--port=n
to specify a different port (8767 by default) and --auto-exit-time=n
to auto-shutdown the server after n seconds.pnpm run lint
- Lints the code with ESLint..eslint.config.mjs
to your liking.pnpm run format
- Formats all auto-fixable problems in the code with ESLint, according to the config.pnpm run node-ts path/to/file.ts
- Runs the given TS file using the normal Node.js binary and the ts-node ESM loader. This is basically like running node file.js
but with TypeScript & ESM and it allows you to use arguments intrinsic to Node.This project (minus Git submodules) is licensed under the WTFPL - do whatever you want with it. It is based on BetterYTM, which itself is licensed under the AGPL-3.0 license.
Make sure to include this in your plugin's readme to comply with BetterYTM's plugin sublicense.