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 enums), 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, as long as you clicked the “track external edits” button.
Configure this behavior in the nodemonConfig object in package.json and src/tools/serve.ts.
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!
npm i -g pnpm)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 pitfallpackage.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 will by default automatically calculate the SRI hash for the asset and append it to the URL in the metadata block, unless explicitly set to false.resources.json file.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 is true in assets/resources.json, making the plugin 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) or the .vscode/settings.json file to automatically format your code on manual saves:
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
},
Alternatively if you want a manual keybind for this, press F1, enter Preferences: Open Keyboard Shortcuts, search for @command:eslint.executeAutofix and bind it to a key of your choice.
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.