├── .github
└── workflows
│ ├── algolia_crawler.yml
│ └── compress_images.yml
├── .gitignore
├── .husky
├── .gitignore
└── pre-commit
├── LICENSE
├── README.md
├── biome.json
├── blog
├── 2021-12-14-first-blog-post.md
├── 2022-01-02-your-first-extension.md
├── 2022-04-11-spicetify-org.md
└── authors.yml
├── docs
├── advanced-usage
│ ├── command-line-interface.md
│ ├── custom-apps.md
│ ├── extensions.md
│ ├── index.md
│ ├── installation.md
│ ├── themes.md
│ └── uninstallation.md
├── development
│ ├── api-wrapper
│ │ ├── classes
│ │ │ ├── context-menu.md
│ │ │ ├── menu.md
│ │ │ ├── playbar.md
│ │ │ └── topbar.md
│ │ ├── functions
│ │ │ ├── add-to-queue.md
│ │ │ ├── color-extractor.md
│ │ │ ├── get-audio-data.md
│ │ │ ├── get-font-style.md
│ │ │ ├── remove-from-queue.md
│ │ │ └── show-notification.md
│ │ ├── index.md
│ │ ├── methods
│ │ │ ├── app-title.md
│ │ │ ├── cosmos-async.md
│ │ │ ├── graphql.md
│ │ │ ├── keyboard.md
│ │ │ ├── local-storage.md
│ │ │ ├── panel.md
│ │ │ ├── platform.md
│ │ │ ├── player.md
│ │ │ ├── popup-modal.md
│ │ │ └── uri.md
│ │ ├── modules.md
│ │ ├── properties
│ │ │ ├── config.md
│ │ │ ├── queue.md
│ │ │ ├── react-components.md
│ │ │ ├── react-hook.md
│ │ │ ├── svgicons.md
│ │ │ └── tippy-props.md
│ │ └── types
│ │ │ ├── context-menu
│ │ │ ├── onclick-callback.md
│ │ │ └── should-add-callback.md
│ │ │ ├── context-option.md
│ │ │ ├── context-track.md
│ │ │ ├── cosmos-async
│ │ │ ├── body.md
│ │ │ ├── error.md
│ │ │ ├── headers.md
│ │ │ ├── method.md
│ │ │ └── response.md
│ │ │ ├── graphql
│ │ │ └── query.md
│ │ │ ├── keyboard
│ │ │ ├── keysdefine.md
│ │ │ └── validkey.md
│ │ │ ├── metadata.md
│ │ │ ├── panel
│ │ │ └── panel-props.md
│ │ │ ├── player-state.md
│ │ │ ├── provided-track.md
│ │ │ ├── react-component
│ │ │ ├── confirm-dialog-props.md
│ │ │ ├── context-menu-props.md
│ │ │ ├── icon-component-props.md
│ │ │ ├── menu-item-props.md
│ │ │ ├── menu-props.md
│ │ │ ├── panel-content-props.md
│ │ │ ├── panel-header-props.md
│ │ │ ├── panel-skeleton-props.md
│ │ │ ├── slider-props.md
│ │ │ ├── text-component-props.md
│ │ │ ├── toggle-props.md
│ │ │ └── tooltip-props.md
│ │ │ ├── semantic-color.md
│ │ │ ├── svgicon.md
│ │ │ ├── uri
│ │ │ ├── type.md
│ │ │ └── validation-functions.md
│ │ │ └── variant.md
│ ├── compiling.md
│ ├── custom-apps.md
│ ├── index.md
│ ├── js-modules.md
│ ├── react-devtools.md
│ ├── spicetify-creator
│ │ ├── building-and-testing.md
│ │ ├── create-custom-apps.md
│ │ ├── create-extensions.md
│ │ └── the-basics.md
│ ├── spotify-cli-flags.md
│ └── themes.md
├── faq.md
└── getting-started.md
├── docusaurus.config.js
├── package.json
├── pnpm-lock.yaml
├── sidebars.js
├── src
├── components
│ ├── HomepageFeatures.module.css
│ ├── HomepageFeatures.tsx
│ └── SwiperCarousel.tsx
├── css
│ └── custom.css
└── pages
│ ├── index.module.css
│ └── index.tsx
├── static
├── .nojekyll
└── images
│ ├── anthems.svg
│ ├── app.png
│ ├── extension.png
│ ├── favicon.ico
│ ├── homepage-carousel
│ ├── 1.png
│ ├── 2.png
│ ├── 3.png
│ ├── 4.png
│ ├── 5.png
│ ├── 6.png
│ └── 7.png
│ ├── logo.png
│ ├── powered-by-vercel.svg
│ ├── spicetify-full-link.png
│ ├── spicetify-full.png
│ ├── spicetify-square.png
│ ├── spicetify-svg-examples.png
│ ├── spicetify.png
│ └── theme.png
└── tsconfig.json
/.github/workflows/algolia_crawler.yml:
--------------------------------------------------------------------------------
1 | name: Trigger Algolia Crawler (Push)
2 | on:
3 | push:
4 | branches: [main]
5 |
6 | jobs:
7 | algolia_recrawl:
8 | name: Algolia Recrawl
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout Repo
12 | uses: actions/checkout@v2
13 |
14 | - name: Trigger Algolia Crawler
15 | uses: algolia/algoliasearch-crawler-github-actions@v1.1.0
16 | with:
17 | crawler-user-id: ${{ secrets.CRAWLER_USER_ID }}
18 | crawler-api-key: ${{ secrets.CRAWLER_API_KEY }}
19 | algolia-app-id: ${{ secrets.ALGOLIA_APP_ID }}
20 | algolia-api-key: ${{ secrets.ALGOLIA_API_KEY }}
21 | crawler-name: spicetify
22 | site-url: "https://spicetify.app/"
23 |
--------------------------------------------------------------------------------
/.github/workflows/compress_images.yml:
--------------------------------------------------------------------------------
1 | name: Compress Images
2 | on:
3 | pull_request:
4 | # Run Image Actions when JPG, JPEG, PNG or WebP files are added or changed.
5 | # See https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#onpushpull_requestpaths for reference.
6 | paths:
7 | - '**.jpg'
8 | - '**.jpeg'
9 | - '**.png'
10 | - '**.webp'
11 | jobs:
12 | build:
13 | # Only run on Pull Requests within the same repository, and not from forks.
14 | if: github.event.pull_request.head.repo.full_name == github.repository
15 | name: calibreapp/image-actions
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout Repo
19 | uses: actions/checkout@v2
20 |
21 | - name: Compress Images
22 | uses: calibreapp/image-actions@main
23 | with:
24 | jpegQuality: '70'
25 | jpegProgressive: false
26 | pngQuality: '70'
27 | webpQuality: '70'
28 | githubToken: ${{ secrets.GITHUB_TOKEN }}
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Docusaurus
2 | .docusaurus
3 | build
4 |
5 | # Logs
6 | logs
7 | *.log
8 | npm-debug.log*
9 | yarn-debug.log*
10 | yarn-error.log*
11 | lerna-debug.log*
12 |
13 | # Diagnostic reports (https://nodejs.org/api/report.html)
14 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
15 |
16 | # Runtime data
17 | pids
18 | *.pid
19 | *.seed
20 | *.pid.lock
21 |
22 | # Directory for instrumented libs generated by jscoverage/JSCover
23 | lib-cov
24 |
25 | # Coverage directory used by tools like istanbul
26 | coverage
27 | *.lcov
28 |
29 | # nyc test coverage
30 | .nyc_output
31 |
32 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
33 | .grunt
34 |
35 | # Bower dependency directory (https://bower.io/)
36 | bower_components
37 |
38 | # node-waf configuration
39 | .lock-wscript
40 |
41 | # Compiled binary addons (https://nodejs.org/api/addons.html)
42 | build/Release
43 |
44 | # Dependency directories
45 | node_modules/
46 | jspm_packages/
47 |
48 | # TypeScript v1 declaration files
49 | typings/
50 |
51 | # TypeScript cache
52 | *.tsbuildinfo
53 |
54 | # Optional npm cache directory
55 | .npm
56 |
57 | # Optional eslint cache
58 | .eslintcache
59 |
60 | # Microbundle cache
61 | .rpt2_cache/
62 | .rts2_cache_cjs/
63 | .rts2_cache_es/
64 | .rts2_cache_umd/
65 |
66 | # Optional REPL history
67 | .node_repl_history
68 |
69 | # Output of 'npm pack'
70 | *.tgz
71 |
72 | # Yarn Integrity file
73 | .yarn-integrity
74 |
75 | # dotenv environment variables file
76 | .env
77 | .env.test
78 |
79 | # parcel-bundler cache (https://parceljs.org/)
80 | .cache
81 |
82 | # Next.js build output
83 | .next
84 |
85 | # Nuxt.js build / generate output
86 | .nuxt
87 | dist
88 |
89 | # Gatsby files
90 | .cache/
91 | # Comment in the public line in if your project uses Gatsby and *not* Next.js
92 | # https://nextjs.org/blog/next-9-1#public-directory-support
93 | # public
94 |
95 | # vuepress build output
96 | .vuepress/dist
97 |
98 | # Serverless directories
99 | .serverless/
100 |
101 | # FuseBox cache
102 | .fusebox/
103 |
104 | # DynamoDB Local files
105 | .dynamodb/
106 |
107 | # TernJS port file
108 | .tern-port
109 |
110 | # MacOS directory
111 | .DS_Store
--------------------------------------------------------------------------------
/.husky/.gitignore:
--------------------------------------------------------------------------------
1 | _
2 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | bun lint-staged
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spicetify Docs
2 |
3 | This repository holds the documentation for Spicetify, which can be found [here](https://spicetify.app).
4 |
5 | ## Contributing
6 |
7 | If you feel like you can contribute, please do so by opening an issue or pull request. We are always open to expand our documentation and add new features.
8 |
--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3 | "organizeImports": {
4 | "enabled": true
5 | },
6 | "linter": {
7 | "enabled": true,
8 | "rules": {
9 | "recommended": true
10 | }
11 | },
12 | "vcs": {
13 | "enabled": true,
14 | "clientKind": "git",
15 | "useIgnoreFile": true
16 | },
17 | "formatter": {
18 | "enabled": true,
19 | "indentStyle": "space",
20 | "indentWidth": 2
21 | },
22 | "javascript": {
23 | "formatter": {
24 | "quoteStyle": "single",
25 | "jsxQuoteStyle": "double"
26 | }
27 | },
28 | "json": {
29 | "parser": {
30 | "allowComments": true
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/blog/2021-12-14-first-blog-post.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: first-blog-post
3 | title: First Blog Post
4 | authors: [afonsojramos]
5 | tags: [spicetify, documentation, community]
6 | ---
7 |
8 | Greetings Spicetifiers! 🔥🎶
9 |
10 | First and foremost, thank you all very much for your continued support of this project! The community that we have gathered on Discord over the past months has been amazing, and I would like to thank every single one of you that made this possible.
11 |
12 | Let's get our hands dirty now. Over the last few months, we've had a few issues with Spotify and a few of their breaking changes. To add to the fire, during all of this turmoil, the _Spicetify Developer Community_ was weak, we had very little support outside of the theming community, and there was an overwhelming amount of duplicated issues on GitHub because of this.
13 |
14 | Let's be honest, our wiki was not the most up-to-date, but at the same time, we also did not have the right tools to enable the community to contribute to it, as it was hosted as a GitHub integrated wiki. As such, we have decided to create this little documentation website that, we hope, will facilitate its maintainability and give power to the community in how they want the project to present itself to the world.
15 |
16 | Hope you can join us in this journey and thank you for coming on the ride! 🚀
17 |
18 | ---
19 |
20 | **PS:** Yes, this design is not final, please do contribute and help make it more appealing!
21 |
22 | 
23 |
--------------------------------------------------------------------------------
/blog/2022-01-02-your-first-extension.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: your-first-extension
3 | title: Your First Extension
4 | authors: [charlies1103]
5 | tags: [spicetify, documentation, community, development]
6 | ---
7 |
8 | ## So you want to make an extension....
9 |
10 | ### First step:
11 |
12 | Start out by setting up your environment:
13 | In terminal or powershell, run `spicetify enable-devtools`
14 | If at any point devtools stops working, simply run this command again.
15 | Ensure that you have a text editor or IDE ready.
16 |
17 | ### Second step:
18 |
19 | Firstly, run `spicetify config-dir`, this should open up your default file manager. Secondly, open the `Extensions` folder and create a file titled `extension.js`, or whichever title you choose, for this tutorial we will be using extension.js for consistency purposes. Finally, open this file, and paste the following code:
20 |
21 | ```js
22 | // The async modifier allows for the user of await, which converts a promise into an object, when not using await, async is not necessary.
23 | (async function extension() {
24 | // The following code segment waits for platform to load before running the code, this is important to avoid errors. When using things such as Player or URI, it is necessary to add those as well.
25 | const { Platform } = Spicetify;
26 | if (!Platform) {
27 | setTimeout(extension, 300);
28 | return;
29 | }
30 | console.log('Hello world!');
31 | })();
32 | ```
33 |
34 | Next, run `spicetify config extensions extension.js`, and follow with `spicetify apply`.
35 | Open up the Spotify console, which can be done via right clicking anywhere on the page, however, there are some places that Spotify overrides this right click; if that is the case, right click somewhere else. Then, click `Inspect Element`, and open the console tab in the window that just popped up. You should see your new "Hello World" displayed!
36 |
37 | ### Third Step:
38 |
39 | Let's finish up this blog post by creating a message that welcomes the user on load. For that, you can paste the following code segment in place of the `console.log("Hello world!"); `statement:
40 |
41 | ```js
42 | const user = await Spicetify.Platform.UserAPI.getUser();
43 | Spicetify.showNotification(`Hello ` + user.displayName);
44 | ```
45 |
--------------------------------------------------------------------------------
/blog/2022-04-11-spicetify-org.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: spicetify-org
3 | title: Spicetify's GitHub Organization
4 | authors: [afonsojramos]
5 | tags: [spicetify, documentation, community]
6 | ---
7 |
8 | Greetings Spicetifiers! 🔥🎶
9 |
10 | Our community has been growing a lot lately and some of the growing pains that we've had has been the information segmentation. This documentation website already tried to tackle that, as well as our Discord server. However, we've expanded through other projects other than the CLI, and, as such, we are ***happy*** to announce that **we are now officially a [Spicetify Organization](https://github.com/spicetify) on GitHub! 🎉**
11 |
12 | Essentially, this will not affect any of the inner workings of the community or Spicetify, but it will make it easier for you to get in touch with the community and to help us grow. 🙌 You can find all our projects under this new GitHub organization, and we will be adding more projects as we go along.
13 |
14 | > We hope that Spicetify will continue to be a great tool for everyone, and we are looking forward to enhancing it with new features and improvements. 🙌
15 |
16 | Additionally, we've also created an Open Collective page for whoever has the means to and wants to financially help our community. For now, we do not know what will be the adhesion to this, therefore we don't have many plans on how to split these donations, however, helping to pay the domain already helps! What you can be sure of, is that everything will be decided by the community, and all decisions will be as transparent as possible.
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/blog/authors.yml:
--------------------------------------------------------------------------------
1 | khanhas:
2 | name: khanhas
3 | title: Creator of Spicetify
4 | url: https://github.com/khanhas/
5 | image_url: https://github.com/khanhas.png
6 |
7 | afonsojramos:
8 | name: Afonso Jorge Ramos
9 | title: Maintainer of Spicetify
10 | url: https://afonsojramos.me
11 | image_url: https://github.com/afonsojramos.png
12 |
13 | charlies1103:
14 | name: Charlie S
15 | title: Co-Developer of Marketplace & Contributor
16 | url: https://github.com/CharlieS1103
17 | image_url: https://github.com/CharlieS1103.png
18 |
--------------------------------------------------------------------------------
/docs/advanced-usage/command-line-interface.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Command Line Interface (CLI)
3 | description: 👾 Using Spicetify from the command line.
4 | ---
5 |
6 | Run with no command once to generate config file
7 |
8 | ```bash
9 | spicetify
10 | ```
11 |
12 | If you just want to use Custom Apps and Extensions head over to each specific section, if you want to create your own theme, keep reading below.
13 |
14 | Make sure config file is created successfully and there is no error, then run:
15 |
16 | ```bash
17 | spicetify backup apply enable-devtools
18 | ```
19 |
20 | From now, after changing colors in `color.ini` or CSS in `user.css`, you just need to run:
21 |
22 | ```bash
23 | spicetify update
24 | ```
25 |
26 | to update your theme.
27 |
28 | In Spotify, hit CtrlShiftR / CommandShiftR to reload and receive visual update of your theme.
29 |
30 | For other commands and additional flags information, please run:
31 |
32 | ```bash
33 | spicetify --help
34 | ```
35 |
--------------------------------------------------------------------------------
/docs/advanced-usage/custom-apps.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Custom Apps
3 | description: 💥 Manually installing Custom Apps.
4 | ---
5 |
6 | Custom Apps, similar to Extensions, are simply Javascript that will be injected into Spotify, that consists of a page that can be accessed from the sidebar.
7 |
8 | ## Installing
9 |
10 | Custom Apps files can be stored in:
11 |
12 | - `CustomApps` folder in Home directory:
13 |
14 | | Platform | Path |
15 | | ------------------- | -------------------------------------- |
16 | | **Windows** | `%appdata%\spicetify\CustomApps\` |
17 | | **Linux**/**MacOS** | `~/.config/spicetify/CustomApps` |
18 |
19 | - `CustomApps` folder in Spicetify executable directory.
20 |
21 | If there are 2 Custom Apps with the same name, the extension within the Home directory will be prioritized.
22 |
23 | After placing the Custom App file into correct folder, run following command to install it:
24 |
25 | ```bash
26 | spicetify config custom_apps
27 | spicetify apply
28 | ```
29 |
30 | **Note:** Using `config` command to add Custom Apps always append file name to existed extensions list. It does not replace the whole key's value.
31 |
32 | ## Uninstalling
33 |
34 | If you want to remove a custom app from the current list of custom apps you can always append a `-` after the file name:
35 |
36 | ```bash
37 | spicetify config custom_apps -
38 | spicetify apply
39 | ```
40 |
41 | ## Custom Apps
42 |
43 | Inject custom apps to Spotify and access them in left sidebar.
44 | Add your desired custom app folder names in config, separated them by `|` character.
45 | Example:
46 |
47 | ```ini
48 | [AdditionalOptions]
49 | ...
50 | custom_apps = reddit|yourownapp
51 | ```
52 |
53 | App folders can be stored in:
54 |
55 | - `CustomApps` folder in Home directory:
56 |
57 | | Platform | Path |
58 | | ------------------- | -------------------------------------- |
59 | | **Windows** | `%appdata%\spicetify\CustomApps\` |
60 | | **Linux**/**MacOS** | `~/.config/spicetify/CustomApps` |
61 |
62 | - `CustomApps` folder in Spicetify executable directory.
63 |
64 | If there are 2 apps having same name, app in Home directory is prioritized.
65 |
66 | Three apps have been included to demonstrate how to create and inject an app:
67 |
68 | - [Reddit](#reddit)
69 | - [New Releases](#new-releases)
70 | - [Lyrics Plus](#lyrics-plus)
71 |
72 | ### Reddit
73 |
74 | Fetching posts from any Spotify link sharing subreddit. You can add, remove, arrange subreddits and customize post visual in config menu (in Profile menu, top right button with your username).
75 |
76 | 
77 |
78 | To install, run following commands:
79 |
80 | ```
81 | spicetify config custom_apps reddit
82 | spicetify apply
83 | ```
84 |
85 | ### New Releases
86 |
87 | Aggregate all new releases from favorite artists, podcasts. Time range, release type, and other filters can be customized in config menu (in Profile menu, top right button with your username). Date format is based on your locale code (BCP47).
88 |
89 | 
90 |
91 | To install, run following commands:
92 |
93 | ```
94 | spicetify config custom_apps new-releases
95 | spicetify apply
96 | ```
97 |
98 | ### Lyrics Plus
99 |
100 | Get access to the current track's lyrics from various lyrics providers (Musixmatch, Netease, LRCLIB). Learn more [here](https://github.com/spicetify/cli/tree/main/CustomApps/lyrics-plus).
101 |
102 | Colors, lyrics providers can be customized in config menu (in Profile menu, top right button with your username).
103 |
104 | 
105 |
106 | To install, run following commands:
107 |
108 | ```
109 | spicetify config custom_apps lyrics-plus
110 | spicetify apply
111 | ```
112 |
--------------------------------------------------------------------------------
/docs/advanced-usage/extensions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Extensions
3 | description: 🧩 Manually installing Extensions.
4 | ---
5 |
6 | Extensions, in a nutshell, are JavaScript files that will be evaluated along with Spotify main JavaScript.
7 |
8 | ## Installing
9 |
10 | Extension files can be stored in:
11 |
12 | - `Extensions` folder in Home directory:
13 |
14 | | Platform | Path |
15 | | ------------------- | -------------------------------------- |
16 | | **Windows** | `%appdata%\spicetify\Extensions\` |
17 | | **Linux**/**MacOS** | `~/.config/spicetify/Extensions` |
18 |
19 | - `Extensions` folder in Spicetify executable directory.
20 |
21 | If there are 2 extensions with the same name, the extension within the Home directory will be prioritized.
22 |
23 | Some Spotify API endpoints are exposed and can be found in the global object `Spicetify`. Check out `global.d.ts` for API documentation.
24 |
25 | After placing the extension file into correct folder, run following command to install it:
26 |
27 | ```bash
28 | spicetify config extensions
29 | spicetify apply
30 | ```
31 |
32 | **Note:** Using `config` command to add extension always append file name to existed extensions list. It does not replace the whole key's value.
33 |
34 | ## Uninstalling
35 |
36 | If you want to remove an extension from the current list of extensions you can always append a `-` after the file name:
37 |
38 | ```bash
39 | spicetify config extensions -
40 | spicetify apply
41 | ```
42 |
43 | ## Manual Install
44 |
45 | You can always manually edit the config file, add your desired extension filenames in `extensions` key, separated them by `|` character.
46 | Example:
47 |
48 | ```ini
49 | [AdditionalOptions]
50 | ...
51 | extensions = autoSkipExplicit.js|queueAll.js|djMode.js|shuffle+.js|trashbin.js
52 | ```
53 |
54 | Afterwards, you will need to run the following:
55 |
56 | ```
57 | spicetify apply
58 | ```
59 |
60 | ## Extensions
61 |
62 | Below are list of default extensions that come with the distributed package:
63 |
64 | - [Auto Skip Videos](#auto-skip-videos)
65 | - [Bookmark](#bookmark)
66 | - [Christian Spotify](#christian-spotify)
67 | - [Full App Display](#full-app-display)
68 | - [Keyboard Shortcut](#keyboard-shortcut)
69 | - [Loopy Loop](#loopy-loop)
70 | - [Pop-up Lyrics](#pop-up-lyrics)
71 | - [Shuffle+](#shuffle)
72 | - [Trash Bin](#trash-bin)
73 | - [Web Now Playing](#web-now-playing)
74 |
75 | ### Auto Skip Videos
76 |
77 | **Filename:** `autoSkipVideo.js`
78 |
79 | Videos are unable to play in some regions because of Spotify's policy. Instead of jumping to next song in playlist, it just stops playing. And it's kinda annoying to open up the client to manually click next every times it happens. Use this extension to skip them automatically.
80 |
81 | ### Bookmark
82 |
83 | **Filename:** `bookmark.js`
84 |
85 | Easily store and browse pages, play tracks or tracks in specific time. Useful for who wants to check out an artist, album later without following them or writing their name down.
86 |
87 | 
88 |
89 | ### Christian Spotify
90 |
91 | **Filename:** `autoSkipExplicit.js`
92 |
93 | Auto skip explicit tracks. Toggle option is in Profile menu (top right button).
94 |
95 | 
96 |
97 | ### Full App Display
98 |
99 | **Filename:** `fullAppDisplay.js`
100 |
101 | Full App Display: Minimal album cover art display with beautiful blur effect background. Activating button located in top bar. While in display mode, double click anywhere to exit. Right click anywhere to open setting menu.
102 |
103 | 
104 |
105 | ### Keyboard Shortcut
106 |
107 | **Filename:** `keyboardShortcut.js`
108 |
109 | Extends Spotify's default keybinds (toggle help modal with `?`) with vim like shortcuts. Less time touching the mouse.
110 |
111 | - CtrlTab / CtrlShiftTab: Navigate items in left sidebar menu.
112 | - PageUp/PageDown: Force scroll up/down app page only (because mouse focus is sometimes in sidebar region and they scroll sidebar instead of app page).
113 | - J/K: Scroll app page up/down. \*Tips hat to Vim users\*
114 | - G/ShiftG: Scroll to top or bottom
115 | - F: Open up keyboard-driven navigation. Hit correct key sequences to open up place you want to go:
116 |
117 | 
118 |
119 | ### Loopy Loop
120 |
121 | **Filename:** `loopyLoop.js`
122 |
123 | Provide ability to mark start and end points on progress bar and automatically loop over that track portion.
124 |
125 | 
126 |
127 | ### Pop-up Lyrics
128 |
129 | **Filename:** `popupLyrics.js`
130 |
131 | Have easy access to a pop-up window with the current song's lyrics. Click at microphone icon on top bar to open lyrics windows. Right click at the same icon to open config menu to customize looks and lyrics providers priorities.
132 |
133 | 
134 |
135 | ### Shuffle+
136 |
137 | **Filename:** `shuffle+.js`
138 | Shuffles using Fisher–Yates algorithm with zero bias. After installing extensions, right click album/playlist/artist item, there will be an option "Play with Shuffle+". You can also multiple select tracks and choose to "Play with Shuffle+".
139 |
140 | 
141 |
142 | ### Trash Bin
143 |
144 | **Filename:** `trashbin.js`
145 | Throw songs/artists to trash bin and never hear them again (automatically skip). This extension will append a Throw to Trashbin option in tracks and artists link right click menu.
146 |
147 | 
148 |
149 | ### Web Now Playing
150 |
151 | **Filename:** `webnowplaying.js`
152 | For Rainmeter users, establish connection with WebNowPlaying plugin to send track metadata and control players.
153 |
154 | If you just want WebNowPlaying without changing UI color, CSS, run this:
155 |
156 | ```powershell
157 | spicetify config inject_css 0 replace_colors 0
158 | spicetify config extensions webnowplaying.js
159 | spicetify apply
160 | ```
161 |
162 | ## Legacy Extensions
163 |
164 | If you are running Spicetify 1.2.1 or below, and a supported Spotify version, you may also have access to the extensions listed below.
165 |
166 | - [DJ Mode](#dj-mode)
167 | - [New Release](#new-release)
168 | - [Queue All](#queue-all)
169 |
170 | ### DJ Mode
171 |
172 | **Filename:** `djMode.js`
173 |
174 | Easily setting up the client for your friends or audiences to choose, add song to queue but prevent them to control player. Plays button in album track list/playlist are re-purposed to add track to queue, instead of play track directly. Hide Controls option also allow you to hide all control button in player bar, Play/More/Follow buttons in cards.
175 |
176 | 
177 |
178 | ### New Release
179 |
180 | **Filename:** `newRelease.js`
181 |
182 | Aggregate all new releases from favorite artists, podcasts. Setting menu could be opened by right clicking at Bell icon.
183 |
184 | 
185 |
186 | ### Queue All
187 |
188 | **Filename:** `queueAll.js`
189 |
190 | You like using Discover, New Releases page to find new music but adding each one of them to queue takes a lot of effort? If so, activate this extensions and apply. At top of every carousel now has a "Queue All" button to help you add all of them to queue. Note: Not available for playlist carousels. Just songs, albums ones.
191 |
192 | 
193 |
--------------------------------------------------------------------------------
/docs/advanced-usage/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started
3 | ---
4 |
5 | ```mdx-code-block
6 | import DocCardList from '@theme/DocCardList';
7 | import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
8 |
9 |
10 | ```
--------------------------------------------------------------------------------
/docs/advanced-usage/installation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Installation
3 | description: ⚡ An advanced view on how to install Spicetify.
4 | ---
5 |
6 | ## Windows
7 |
8 | ### Powershell (pre-built binary) - Recommended
9 |
10 | ```powershell
11 | iwr -useb https://raw.githubusercontent.com/spicetify/cli/main/install.ps1 | iex
12 | ```
13 |
14 | ### Chocolatey
15 |
16 | Follow this guide: https://chocolatey.org/packages/spicetify-cli
17 |
18 | ### Scoop
19 |
20 | ```powershell
21 | scoop install spicetify-cli
22 | ```
23 |
24 | #### Spotify installed from Scoop
25 |
26 | - To find the location of your Spotify installation, run `scoop prefix spotify`.
27 |
28 | ```console
29 | $ scoop prefix spotify
30 | C:\Users\\scoop\apps\spotify\current
31 | ```
32 |
33 | After you have located it, set `spotify_path` to that directory in Spicetify's config file:
34 |
35 | 
36 |
37 | ### Winget
38 |
39 | ```powershell
40 | winget install Spicetify.Spicetify
41 | ```
42 |
43 | ## Linux and MacOS
44 |
45 | ### Shell (pre-built binary) - Recommended
46 |
47 | ```bash
48 | curl -fsSL https://raw.githubusercontent.com/spicetify/cli/main/install.sh | sh
49 | ```
50 |
51 | ### Homebrew or LinuxBrew
52 |
53 | ```bash
54 | brew install spicetify-cli
55 | ```
56 |
57 | On macOS, you will need to set `spotify_path` to `/Applications/Spotify.app/Contents/Resources` in the `~/.config/spicetify/config-xpui.ini` config file.
58 |
59 | ### AUR
60 |
61 | ```bash
62 | yay -S spicetify-cli
63 | ```
64 |
65 | ### Note for Linux users
66 |
67 | #### Spotify installed from AUR
68 |
69 | Before applying Spicetify, you need to gain write permission on Spotify files, by running command:
70 |
71 | ```bash
72 | sudo chmod a+wr /opt/spotify
73 | sudo chmod a+wr /opt/spotify/Apps -R
74 | ```
75 |
76 | **Note:** Your Spotify client location might be different.
77 |
78 | #### Spotify installed via `spotify-launcher` package (Arch Linux)
79 |
80 | If Spotify is installed through the `spotify-launcher` package, then Spotify won't install to `/opt/spotify` and is instead in this folder: `$HOME/.local/share/spotify-launcher/install/usr/share/spotify/`
81 |
82 | This directory will need to be added to the `spotify-path` section of the config (and you won't need to change any permissions like the AUR method).
83 |
84 | **Note:** `spotify-path` must be an absolute path. Do not use `~` to reference the home folder.
85 |
86 | #### Spotify installed from Snap
87 |
88 | Apps installed from Snap **cannot be modified** so you need to follow these steps to get Spicetify working:
89 |
90 | 1. Uninstall Spotify in Snap or run command `snap remove spotify`
91 | 2. Install Spotify using `apt`:
92 |
93 | ```sh
94 | curl -sS https://download.spotify.com/debian/pubkey_C85668DF69375001.gpg | sudo gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/spotify.gpg
95 | echo "deb http://repository.spotify.com stable non-free" | sudo tee /etc/apt/sources.list.d/spotify.list
96 | sudo apt-get update && sudo apt-get install spotify-client
97 | ```
98 |
99 | 3. After Spotify is installed successfully, you need to gain read write permissions on Spotify files, by running commands:
100 |
101 | ```bash
102 | sudo chmod a+wr /usr/share/spotify
103 | sudo chmod a+wr /usr/share/spotify/Apps -R
104 | ```
105 |
106 | **Note:** Your Spotify client location might be different.
107 |
108 | #### Spotify installed from Flatpak
109 |
110 | - You need to find where Flatpak stores your Spotify client. In Manjaro and Fedora, it is stored in:
111 |
112 | ```
113 | /var/lib/flatpak/app/com.spotify.Client/x86_64/stable/active/files/extra/share/spotify/
114 | ```
115 |
116 | - In some distros it is stored in:
117 | ```
118 | ~/.local/share/flatpak/app/com.spotify.Client/x86_64/stable/active/files/extra/share/spotify/
119 | ```
120 |
121 | - Yours might be different, try these steps:
122 |
123 | 1. Find flatpak installation place with command: `flatpak --installations`
124 | 2. Go to that directory and dig in until you find folder which contain items like these:
125 |
126 | 
127 |
128 | After you have Spotify location, set `spotify_path` in config file to that directory:
129 |
130 | 
131 |
132 | 3. Find your `prefs` file:
133 | It could be either in these two locations:
134 |
135 | - `~/.config/spotify/prefs`
136 | - `~/.var/app/com.spotify.Client/config/spotify/prefs`
137 |
138 | Check both, expand the right one to absolute path and set it to `prefs_path` in config file.
139 |
140 | ```bash
141 | spicetify config prefs_path ~/.var/app/com.spotify.Client/config/spotify/prefs
142 | ```
143 |
144 | 4. Finally in terminal, set read/write permission for it:
145 |
146 | ```bash
147 | sudo chmod a+wr /var/lib/flatpak/app/com.spotify.Client/x86_64/stable/active/files/extra/share/spotify
148 | sudo chmod a+wr -R /var/lib/flatpak/app/com.spotify.Client/x86_64/stable/active/files/extra/share/spotify/Apps
149 | ```
150 |
151 | ## Legacy Installations
152 |
153 | If, for some reason, you are not using the most up to date Spotify client, you may need to install a specific version of Spicetify.
154 | This is not recommended as our prime focus will always be the latest Spotify version.
155 |
156 | As such, you will need to run either of the below commands with the desired version.
157 | If you wish to use old Spotify client v1.1.56 or older, you have to install spicetify v1.2.1.
158 |
159 | **Windows**: In powershell
160 |
161 | ```powershell
162 | $v="1.2.1"; Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/spicetify/cli/main/install.ps1" | Invoke-Expression
163 | ```
164 |
165 | **Linux/MacOS:** In bash
166 |
167 | ```bash
168 | curl -fsSL https://raw.githubusercontent.com/spicetify/cli/main/install.sh -o /tmp/install.sh
169 | sh /tmp/install.sh 1.2.1
170 | ```
171 |
172 | spicetify v1 code is available in branch [`legacy`](https://github.com/spicetify/cli/tree/legacy) if you want to build from source.
173 |
174 | If you want legacy themes, you can find them [here](https://github.com/spicetify/spicetify-themes/tree/legacy).
175 |
--------------------------------------------------------------------------------
/docs/advanced-usage/themes.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Themes
3 | description: ✨ Themes for Spicetify.
4 | ---
5 |
6 | One of the most popular features in Spicetify is theming.
7 | You can customize your Spotify to your **heart's** desire!
8 | **However**, this is a very cumbersome task.
9 |
10 | For this reason, the theming heroes of the Spicetify community have created a huge library of themes which can be found in the following repositories:
11 |
12 | 1. [spicetify/spicetify-themes](https://github.com/spicetify/spicetify-themes) - The official Spicetify themes repository. Feel free to contribute with more themes!
13 | 2. [NYRI4/Comfy-spicetify](https://github.com/NYRI4/Comfy-spicetify)
14 | 3. [williamckha/spicetify-fluent](https://github.com/williamckha/spicetify-fluent)
15 | 4. [Catppuccin/spicetify](https://github.com/catppuccin/spicetify)
16 | 5. [nimsandu/spicetify-bloom](https://github.com/nimsandu/spicetify-bloom)
17 | 6. [Tetrax-10/Nord-Spotify](https://github.com/Tetrax-10/Nord-Spotify) (not maintained)
18 | 7. [JulienMaille/dribbblish-dynamic-theme](https://github.com/JulienMaille/dribbblish-dynamic-theme) (not maintained)
19 | 8. [sanoojes/spicetify-lucid](https://github.com/sanoojes/spicetify-lucid)
20 | 9. [Skaytacium/Gruvify](https://github.com/Skaytacium/Gruvify)
21 | 10. [dracula/spicetify](https://github.com/dracula/spicetify) (not maintained)
22 | 11. [Spotify Dark](https://github.com/SyndiShanX/Spotify-Dark)
23 | 12. [bluedrift/Spicetify-Throwback](https://github.com/bluedrift/Spicetify-Throwback)
24 | 13. [m0squdev/dracula-spicetify-theme](https://github.com/m0squdev/dracula-spicetify-theme)
25 | 14. Insert your theme here!
26 |
--------------------------------------------------------------------------------
/docs/advanced-usage/uninstallation.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Uninstallation
3 | description: 🗑 How to remove Spicetify.
4 | ---
5 |
6 | ## Windows
7 |
8 | ### Powershell
9 | ```cmd
10 | spicetify restore
11 | rmdir -r -fo $env:APPDATA\spicetify
12 | rmdir -r -fo $env:LOCALAPPDATA\spicetify
13 | ```
14 |
15 | ## Linux and MacOS
16 |
17 | :::note
18 |
19 | If you used a package manager to install Spicetify, please use its default methods for removing packages.
20 |
21 | :::
22 |
23 | ### Shell
24 | ```bash
25 | spicetify restore
26 | rm -rf ~/.spicetify
27 | rm -rf ~/.config/spicetify
28 | ```
29 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/classes/context-menu.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ContextMenu
3 | description: Create custom menu item and prepend to right click context menu.
4 | ---
5 |
6 | Create custom menu item and prepend to right click context menu.
7 |
8 | Useful for adding custom actions to context menu (when a user right-clicks on a track, album, artist, etc.)
9 |
10 | ## Classes
11 |
12 | ### Item
13 |
14 | Single context menu item.
15 |
16 |
17 | ```ts
18 | new Spicetify.ContextMenu.Item(
19 | name: string,
20 | onClick: OnClickCallback,
21 | shouldAdd?: ShouldAddCallback,
22 | icon?: SVGIcon | string,
23 | disabled?: boolean,
24 | )
25 | ```
26 |
27 | #### Parameters
28 |
29 | | Parameter | Type | Description |
30 | | :--- | :--- | :--- |
31 | | name | `string` | Name of the menu item. |
32 | | onClick | `OnClickCallback` | Callback function when the menu item is clicked. |
33 | | shouldAdd | `ShouldAddCallback` | Callback function to determine if the menu item should be added. |
34 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the menu item. |
35 | | disabled | `boolean` | Whether the menu item is disabled. |
36 |
37 | #### Properties
38 |
39 | :::tip
40 |
41 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
42 |
43 | :::
44 |
45 | | Name | Type | Description |
46 | | :--- | :--- | :--- |
47 | | iconList | [`readonly SVGIcon[]`](/docs/development/api-wrapper/types/svgicon) | List of icons. |
48 | | name | `string` | Name of the menu item. |
49 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon at the end of the menu item. |
50 | | disabled | `boolean` | Whether the menu item is disabled. |
51 | | shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |
52 | | onClick | [`OnClickCallback`](/docs/development/api-wrapper/types/context-menu/onclick-callback) | Callback function when the menu item is clicked. |
53 |
54 | #### Methods
55 |
56 | ##### `register`
57 |
58 | Register the menu item to context menu.
59 |
60 | ```ts
61 | register(): void
62 | ```
63 |
64 | ##### `deregister`
65 |
66 | Remove the menu item from context menu.
67 |
68 | ```ts
69 | deregister(): void
70 | ```
71 | #### Example
72 |
73 | ```ts
74 | // This function will determine if the selected item is a track
75 | function ifItemIsTrack(uri) {
76 | let uriObj = Spicetify.URI.fromString(uri[0]);
77 | switch (uriObj.type) {
78 | case Type.TRACK:
79 | return true;
80 | }
81 | return false;
82 | }
83 |
84 | // Create a new menu item that only appears when a track is selected
85 | const menuItem = new Spicetify.ContextMenu.Item(
86 | "My Menu Item",
87 | () => {
88 | Spicetify.showNotification("My Menu Item clicked!");
89 | },
90 | ifItemIsTrack,
91 | Spicetify.SVGIcons["play"],
92 | false,
93 | );
94 |
95 | // Register the menu item
96 | menuItem.register();
97 |
98 | // Deregister the menu item
99 | menuItem.deregister();
100 |
101 | // Change the menu item's name
102 | menuItem.name = "My New Menu Item";
103 |
104 | // Change the menu item's icon
105 | menuItem.icon = "pause"
106 | ```
107 |
108 | ### SubMenu
109 |
110 | Create a sub menu to contain `Item`s.
111 |
112 | `Item`s in `subItems` array shouldn't be registered.
113 |
114 |
115 | ```ts
116 | new Spicetify.ContextMenu.SubMenu(
117 | name: string,
118 | subItems: Iterable,
119 | shouldAdd?: ShouldAddCallback,
120 | disabled?: boolean,
121 | )
122 | ```
123 |
124 | #### Parameters
125 |
126 | | Parameter | Type | Description |
127 | | :--- | :--- | :--- |
128 | | name | `string` | Name of the menu item. |
129 | | subItems | [`Iterable`](#item) | Array of `Item`s to be added to the sub menu. |
130 | | shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |
131 | | disabled | `boolean` | Whether the menu item is disabled. |
132 |
133 | #### Properties
134 |
135 | :::tip
136 |
137 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
138 |
139 | :::
140 |
141 | | Name | Type | Description |
142 | | :--- | :--- | :--- |
143 | | name | `string` | Name of the menu item. |
144 | | disabled | `boolean` | Whether the menu item is disabled. |
145 | | shouldAdd | [`ShouldAddCallback`](/docs/development/api-wrapper/types/context-menu/should-add-callback) | Callback function to determine if the menu item should be added. |
146 |
147 | #### Methods
148 |
149 | ##### `addItem`
150 |
151 | Add an `Item` to the sub menu.
152 |
153 | ```ts
154 | addItem(item: Item): void
155 | ```
156 |
157 | | Parameter | Type | Description |
158 | | :--- | :--- | :--- |
159 | | item | [`Item`](#item) | `Item` to be added to the sub menu. |
160 |
161 | ##### `removeItem`
162 |
163 | Remove an `Item` from the sub menu.
164 |
165 | ```ts
166 | removeItem(item: Item): void
167 | ```
168 |
169 | | Parameter | Type | Description |
170 | | :--- | :--- | :--- |
171 | | item | [`Item`](#item) | `Item` to be removed from the sub menu. |
172 |
173 | ##### `register`
174 |
175 | Register the sub menu to context menu.
176 |
177 | ```ts
178 | register(): void
179 | ```
180 |
181 | ##### `deregister`
182 |
183 | Remove the sub menu from context menu.
184 |
185 | ```ts
186 | deregister(): void
187 | ```
188 |
189 | #### Example
190 |
191 | ```ts
192 | // Create a new menu item
193 | const menuItem = new Spicetify.ContextMenu.Item(
194 | "My Menu Item",
195 | () => {
196 | Spicetify.showNotification("My Menu Item clicked!");
197 | },
198 | () => true,
199 | Spicetify.SVGIcons["play"],
200 | false,
201 | );
202 |
203 | // Create a new sub menu
204 | const subMenu = new Spicetify.ContextMenu.SubMenu(
205 | "My Sub Menu",
206 | [menuItem],
207 | () => true,
208 | false,
209 | );
210 |
211 | // Register the sub menu
212 | subMenu.register();
213 |
214 | // Deregister the sub menu
215 | subMenu.deregister();
216 |
217 | // Change the sub menu's name
218 | subMenu.name = "My New Sub Menu";
219 |
220 | // Add a new menu item to the sub menu
221 | subMenu.addItem(new Spicetify.ContextMenu.Item(
222 | "My New Menu Item",
223 | () => {
224 | Spicetify.showNotification("My New Menu Item clicked!");
225 | },
226 | () => true,
227 | Spicetify.SVGIcons["play"],
228 | false,
229 | ));
230 | ```
231 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/classes/menu.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Menu
3 | description: Create and prepend custom menu items in the profile menu.
4 | ---
5 |
6 | Create and prepend custom menu items in the profile menu.
7 |
8 | ## Classes
9 |
10 | ### Item
11 |
12 | Single menu item.
13 |
14 | ```ts
15 | new Spicetify.Menu.Item(
16 | name: string,
17 | isEnabled: boolean,
18 | onClick: (self: Item) => void,
19 | icon?: SVGIcon | string,
20 | )
21 | ```
22 |
23 | #### Parameters
24 |
25 | | Parameter | Type | Description |
26 | | :--- | :--- | :--- |
27 | | name | `string` | Name of the menu item. |
28 | | isEnabled | `boolean` | Whether the menu item is enabled. |
29 | | onClick | `(self: Item) => void` | Callback function when the menu item is clicked. |
30 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the menu item. |
31 |
32 | #### Properties
33 |
34 | :::tip
35 |
36 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
37 |
38 | :::
39 |
40 | | Name | Type | Description |
41 | | :--- | :--- | :--- |
42 | | name | `string` | Name of the menu item. |
43 | | isEnabled | `boolean` | Whether the menu item is enabled. |
44 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the menu item. |
45 |
46 | #### Methods
47 |
48 | ##### setName
49 |
50 | Set the label of the menu item.
51 |
52 | ```ts
53 | setName(name: string): void
54 | ```
55 |
56 | | Parameter | Type | Description |
57 | | :--- | :--- | :--- |
58 | | name | `string` | Name of the menu item. |
59 |
60 | ##### setState
61 |
62 | Set the state of the menu item. The item will have a tick icon next to it if its state is enabled.
63 |
64 | ```ts
65 | setState(isEnabled: boolean): void
66 | ```
67 |
68 | | Parameter | Type | Description |
69 | | :--- | :--- | :--- |
70 | | isEnabled | `boolean` | Whether the menu item is enabled. |
71 |
72 | ##### setIcon
73 |
74 | Set the icon at the end of the menu item.
75 |
76 | ```ts
77 | setIcon(icon: SVGIcon | string): void
78 | ```
79 |
80 | | Parameter | Type | Description |
81 | | :--- | :--- | :--- |
82 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the menu item. |
83 |
84 | ##### register
85 |
86 | Register the menu item to the profile menu.
87 |
88 | ```ts
89 | register(): void
90 | ```
91 |
92 | ##### deregister
93 |
94 | Remove the menu item from the profile menu.
95 |
96 | ```ts
97 | deregister(): void
98 | ```
99 |
100 | #### Example
101 |
102 | ```ts
103 | const item = new Spicetify.Menu.Item("My Item", true, () => {
104 | console.log("My Item is clicked");
105 | });
106 |
107 | item.register();
108 |
109 | // item.name = "My Item (Updated)";
110 | item.setName("My Item (Updated)");
111 |
112 | // item.isEnabled = false;
113 | item.setState(false);
114 |
115 | // item.icon = "heart";
116 | item.setIcon("heart");
117 | ```
118 |
119 | ### SubMenu
120 |
121 | Create a sub menu to contain `Item` toggles.
122 |
123 | `Item`s in `subItems` array shouldn't be registered.
124 |
125 | ```ts
126 | new Spicetify.Menu.SubMenu(
127 | name: string,
128 | subItems: Item[],
129 | )
130 | ```
131 |
132 | #### Parameters
133 |
134 | | Parameter | Type | Description |
135 | | :--- | :--- | :--- |
136 | | name | `string` | Name of the menu item. |
137 | | subItems | [`Item[]`](/docs/development/api-wrapper/classes/menu#item) | Array of sub menu items. |
138 |
139 | #### Properties
140 |
141 | :::tip
142 |
143 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
144 |
145 | :::
146 |
147 | | Name | Type | Description |
148 | | :--- | :--- | :--- |
149 | | name | `string` | Name of the menu item. |
150 |
151 | #### Methods
152 |
153 | ##### setName
154 |
155 | Set the label of the menu item.
156 |
157 | ```ts
158 | setName(name: string): void
159 | ```
160 |
161 | | Parameter | Type | Description |
162 | | :--- | :--- | :--- |
163 | | name | `string` | Name of the menu item. |
164 |
165 | ##### addItem
166 |
167 | Add a sub menu item.
168 |
169 | ```ts
170 | addItem(item: Item): void
171 | ```
172 |
173 | | Parameter | Type | Description |
174 | | :--- | :--- | :--- |
175 | | item | [`Item`](/docs/development/api-wrapper/classes/menu#item) | Sub menu item. |
176 |
177 | ##### removeItem
178 |
179 | Remove a sub menu item.
180 |
181 | ```ts
182 | removeItem(item: Item): void
183 | ```
184 |
185 | | Parameter | Type | Description |
186 | | :--- | :--- | :--- |
187 | | item | [`Item`](/docs/development/api-wrapper/classes/menu#item) | Sub menu item. |
188 |
189 | ##### register
190 |
191 | Register the menu item to profile menu.
192 |
193 | ```ts
194 | register(): void
195 | ```
196 |
197 | ##### deregister
198 |
199 | Remove the menu item from profile menu.
200 |
201 | ```ts
202 | deregister(): void
203 | ```
204 |
205 | #### Example
206 |
207 | ```ts
208 | const item1 = new Spicetify.Menu.Item("My Item 1", true, () => {
209 | console.log("My Item 1 is clicked");
210 | });
211 |
212 | const item2 = new Spicetify.Menu.Item("My Item 2", true, () => {
213 | console.log("My Item 2 is clicked");
214 | });
215 |
216 | const subMenu = new Spicetify.Menu.SubMenu("My Sub Menu", [item1, item2]);
217 |
218 | subMenu.register();
219 |
220 | // subMenu.name = "My Sub Menu (Updated)";
221 | subMenu.setName("My Sub Menu (Updated)");
222 |
223 | // subMenu.addItem(item3);
224 | subMenu.addItem(
225 | new Spicetify.Menu.Item("My Item 3", true, () => {
226 | console.log("My Item 3 is clicked");
227 | })
228 | );
229 | ```
230 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/classes/playbar.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Playbar
3 | description: Create buttons in the player.
4 | ---
5 |
6 | Create buttons in the player.
7 |
8 | ```ts
9 | namespace Playbar {
10 | class Button {
11 | constructor(label: string, icon: SVGIcon | string, onClick: (self: Button) => void, disabled?: boolean, active?: boolean, registerOnCreate?: boolean);
12 | label: string;
13 | icon: string;
14 | onClick: (self: Button) => void;
15 | disabled: boolean;
16 | active: boolean;
17 | element: HTMLButtonElement;
18 | tippy: any;
19 | register: () => void;
20 | deregister: () => void;
21 | }
22 |
23 | class Widget {
24 | constructor(label: string, icon: SVGIcon | string, onClick?: (self: Widget) => void, disabled?: boolean, active?: boolean, registerOnCreate?: boolean);
25 | label: string;
26 | icon: string;
27 | onClick: (self: Widget) => void;
28 | disabled: boolean;
29 | active: boolean;
30 | element: HTMLButtonElement;
31 | tippy: any;
32 | register: () => void;
33 | deregister: () => void;
34 | }
35 | };
36 | ```
37 |
38 | ## `Button`
39 |
40 | Create buttons next to the player extra control buttons (e.g. queue, lyrics, Now Playing View, etc.).
41 |
42 | This is useful for creating buttons whose actions have an impact on or relate to the player, and are generally dynamic/stateful, such as a button that toggles the player's loop mode.
43 |
44 | #### Parameters
45 |
46 | | Parameter | Type | Description |
47 | | :--- | :--- | :--- |
48 | | label | `string` | Label of the button. |
49 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the button. |
50 | | onClick | `(self: Button) => void` | Callback function when the button is clicked. |
51 | | disabled | `boolean` | `undefined` | Whether the button is disabled. |
52 | | active | `boolean` | `undefined` | Whether the button is active. |
53 | | registerOnCreate | `boolean` | `undefined` | Whether the button should be registered to the player on creation. |
54 |
55 | #### Properties
56 |
57 | :::tip
58 |
59 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
60 |
61 | :::
62 |
63 | | Name | Type | Description |
64 | | :--- | :--- | :--- |
65 | | label | `string` | Label of the button. |
66 | | icon | `string` | Icon of the button. |
67 | | disabled | `boolean` | Whether the button is disabled. |
68 | | active | `boolean` | Whether the button is active. |
69 | | onClick | `(self: Button) => void` | Callback function when the button is clicked. |
70 | | element | `HTMLButtonElement` | HTML element of the button. |
71 | | tippy | `any` | Tippy instance of the button. For more information, see [Tippy.js](https://atomiks.github.io/tippyjs/v6/tippy-instance/). |
72 |
73 | #### Methods
74 |
75 | ##### `register`
76 |
77 | Register the button to the player.
78 |
79 | ```ts
80 | register(): void;
81 | ```
82 |
83 | ##### `deregister`
84 |
85 | Deregister the button from the player.
86 |
87 | ```ts
88 | deregister(): void;
89 | ```
90 |
91 | #### Example
92 |
93 | :::caution
94 |
95 | Tippy, `onclick` or any other click events will **not** work if `disabled` is set to `true`. You will need to manually enable the button inside your extension.
96 |
97 | This is due to the limitations of Tippy itself and how HTML elements work.
98 |
99 | :::
100 |
101 | ```ts
102 | // By default, the button will be registered to the player on creation.
103 | // You can disable this by setting registerOnCreate to false.
104 | // Each button comes with a preconfigured Tippy instance that aims to mimic the original Spotify tooltip.
105 | const button = new Spicetify.Playbar.Button(
106 | "My Button",
107 | "play",
108 | (self) => {
109 | // Do something when the button is clicked.
110 | },
111 | false, // Whether the button is disabled.
112 | false, // Whether the button is active.
113 | );
114 |
115 | // You can also register the button to the player later.
116 | button.register();
117 |
118 | // Remove the button from the player when it is no longer needed.
119 | button.deregister();
120 | // If you don't want to remove the button entirely, you can also disable it.
121 | button.disabled = true;
122 |
123 | // Change button properties.
124 | // Changing label will also change the tooltip content.
125 | button.label = "Hello world!";
126 | button.icon = "play";
127 |
128 | // You can also set properties of the HTML element.
129 | button.element.style.color = "red";
130 | button.element.oncontextmenu = () => {
131 | Spicetify.showNotification("You right-clicked me!");
132 | };
133 | button.element.addEventListener("click", () => {
134 | // Do something else.
135 | Spicetify.showNotification("You clicked me!");
136 | });
137 |
138 | // You can also change properties of the Tippy instance. For more information, see https://atomiks.github.io/tippyjs/v6/tippy-instance/.
139 | button.tippy.setContent("Hello world!");
140 |
141 | // Or if you want to use HTML.
142 | button.tippy.setProps({
143 | content: "Hello world!",
144 | allowHTML: true,
145 | });
146 | ```
147 |
148 | ## `Widget`
149 |
150 | Create widgets in the player, next to track information similar to the Heart button.
151 |
152 | This is useful for creating buttons whose actions have an impact on the state of the player and the track being played, such as a button that adds the current track to a playlist.
153 |
154 | #### Parameters
155 |
156 | | Parameter | Type | Description |
157 | | :--- | :--- | :--- |
158 | | label | `string` | Label of the widget. |
159 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the widget. |
160 | | onClick | `(self: Widget) => void` | Callback function when the widget is clicked. |
161 | | disabled | `boolean` | `undefined` | Whether the widget is disabled. |
162 | | active | `boolean` | `undefined` | Whether the widget is active. |
163 | | registerOnCreate | `boolean` | `undefined` | Whether the widget should be registered to the player on creation. |
164 |
165 | #### Properties
166 |
167 | :::tip
168 |
169 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
170 |
171 | :::
172 |
173 | | Name | Type | Description |
174 | | :--- | :--- | :--- |
175 | | label | `string` | Label of the widget. |
176 | | icon | `string` | Icon of the widget. |
177 | | disabled | `boolean` | Whether the widget is disabled. |
178 | | active | `boolean` | Whether the widget is active. |
179 | | onClick | `(self: Widget) => void` | Callback function when the widget is clicked. |
180 | | element | `HTMLButtonElement` | HTML element of the widget. |
181 | | tippy | `any` | Tippy instance of the widget. For more information, see [Tippy.js](https://atomiks.github.io/tippyjs/v6/tippy-instance/). |
182 |
183 | #### Methods
184 |
185 | ##### `register`
186 |
187 | Register the widget to the player.
188 |
189 | ```ts
190 | register(): void;
191 | ```
192 |
193 | ##### `deregister`
194 |
195 | Deregister the widget from the player.
196 |
197 | ```ts
198 | deregister(): void;
199 | ```
200 |
201 | #### Example
202 |
203 | :::caution
204 |
205 | Tippy, `onclick` or any other click events will **not** work if `disabled` is set to `true`. You will need to manually enable the widget inside your extension.
206 |
207 | This is due to the limitations of Tippy itself and how HTML elements work.
208 |
209 | :::
210 |
211 | ```ts
212 | // By default, the widget will be registered to the player on creation.
213 | // You can disable this by setting registerOnCreate to false.
214 | // Each widget comes with a preconfigured Tippy instance that aims to mimic the original Spotify tooltip.
215 | const widget = new Spicetify.Playbar.Widget(
216 | "My Widget",
217 | "play",
218 | (self) => {
219 | // Do something when the widget is clicked.
220 | },
221 | false, // Whether the widget is disabled.
222 | false, // Whether the widget is active.
223 | );
224 |
225 | // You can also register the widget to the player later.
226 | widget.register();
227 |
228 | // Remove the widget from the player when it is no longer needed.
229 | widget.deregister();
230 |
231 | // Change widget properties.
232 | // Changing label will also change the tooltip content.
233 | widget.label = "Hello world!";
234 | widget.icon = "play";
235 |
236 | // You can also set properties of the HTML element.
237 | widget.element.style.color = "red";
238 | widget.element.oncontextmenu = () => {
239 | Spicetify.showNotification("You right-clicked me!");
240 | };
241 | widget.element.addEventListener("click", () => {
242 | // Do something else.
243 | Spicetify.showNotification("You clicked me!");
244 | });
245 |
246 | // You can also change properties of the Tippy instance. For more information, see https://atomiks.github.io/tippyjs/v6/tippy-instance/.
247 | widget.tippy.setContent("Hello world!");
248 |
249 | // Or if you want to use HTML.
250 | widget.tippy.setProps({
251 | content: "Hello world!",
252 | allowHTML: true,
253 | });
254 | ```
255 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/classes/topbar.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Topbar
3 | description: Create buttons in the top bar.
4 | ---
5 |
6 | Create buttons in the top bar, next to the navigation buttons.
7 |
8 | This is useful for creating buttons that are generally static and whose actions have an impact on the whole app, such as a button that opens a settings menu.
9 |
10 | ```ts
11 | namespace Topbar {
12 | class Button {
13 | constructor(label: string, icon: SVGIcon | string, onClick: (self: Button) => void, disabled?: boolean, isRight?: boolean);
14 | label: string;
15 | icon: string;
16 | onClick: (self: Button) => void;
17 | disabled: boolean;
18 | isRight: boolean;
19 | element: HTMLButtonElement;
20 | tippy: any;
21 | }
22 | };
23 | ```
24 |
25 | #### Parameters
26 |
27 | | Parameter | Type | Description |
28 | | :--- | :--- | :--- |
29 | | label | `string` | Label of the button. |
30 | | icon | [`SVGIcon`](/docs/development/api-wrapper/types/svgicon) | `string` | Icon of the button. |
31 | | onClick | `(self: Button) => void` | Callback function when the button is clicked. |
32 | | disabled | `boolean` | Whether the button is disabled. |
33 | | isRight | `boolean` | Whether the button is button placed on the right side. |
34 |
35 | #### Properties
36 |
37 | :::tip
38 |
39 | All of the listed properties are dynamic and can be changed at any time. Look into the example below for more information.
40 |
41 | :::
42 |
43 | | Name | Type | Description |
44 | | :--- | :--- | :--- |
45 | | label | `string` | Label of the button. |
46 | | icon | `string` | Icon of the button. |
47 | | disabled | `boolean` | Whether the button is disabled. |
48 | | onClick | `(self: Button) => void` | Callback function when the button is clicked. |
49 | | element | `HTMLButtonElement` | HTML element of the button. |
50 | | tippy | `any` | Tippy instance of the button. For more information, see [Tippy.js](https://atomiks.github.io/tippyjs/v6/tippy-instance/). |
51 |
52 | #### Example
53 |
54 | :::caution
55 |
56 | Tippy, `onclick` or any other click events will **not** work if `disabled` is set to `true`. You will need to manually enable the button inside your extension.
57 |
58 | This is due to the limitations of Tippy itself and how HTML elements work.
59 |
60 | :::
61 |
62 | ```ts
63 | // Button is automatically added to the top bar when created.
64 | // Each button comes with a preconfigured Tippy instance that aims to mimic the original Spotify tooltip.
65 | const button = new Spicetify.Topbar.Button("Hello", "download", () => {
66 | Spicetify.showNotification("Hello world!");
67 | });
68 |
69 | // Change button properties.
70 | // Changing label will also change the tooltip content.
71 | button.label = "Hello world!";
72 | button.icon = "play";
73 | button.disabled = true;
74 |
75 | // You can also set properties of the HTML element.
76 | button.element.style.color = "red";
77 | button.element.oncontextmenu = () => {
78 | Spicetify.showNotification("You right-clicked me!");
79 | };
80 | button.element.addEventListener("click", () => {
81 | // Do something else.
82 | Spicetify.showNotification("You clicked me!");
83 | });
84 |
85 | // You can also change properties of the Tippy instance. For more information, see https://atomiks.github.io/tippyjs/v6/tippy-instance/.
86 | button.tippy.setContent("Hello world!");
87 |
88 | // Or if you want to use HTML.
89 | button.tippy.setProps({
90 | content: "Hello world!",
91 | allowHTML: true,
92 | });
93 | ```
94 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/add-to-queue.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: addToQueue
3 | description: Adds a track/album or array of tracks/albums to prioritized queue.
4 | ---
5 |
6 | Adds a track or array of tracks to the bottom of the prioritized queue.
7 |
8 | :::tip
9 |
10 | This works similarly to [`Spicetify.Platform.PlayerAPI.addToQueue`](/docs/development/api-wrapper/methods/platform#addtoqueue) but works silently, meaning no notification will be shown.
11 |
12 | If you want default Spotify behavior, use [`Spicetify.Platform.PlayerAPI.addToQueue`](/docs/development/api-wrapper/methods/platform#addtoqueue) instead.
13 |
14 | :::
15 |
16 | ```ts
17 | function addToQueue(uri: ContextTrack[]): Promise;
18 | ```
19 |
20 | #### Parameters
21 |
22 | | Name | Type | Description |
23 | | :--- | :--- | :--- |
24 | | `uri` | [`ContextTrack[]`](/docs/development/api-wrapper/types/context-track) | Array of tracks to add to queue. |
25 |
26 | #### Example
27 |
28 | ```ts
29 | // Add current track to queue
30 | const currentTrack = Spicetify.Player.data.item;
31 |
32 | await Spicetify.addToQueue([currentTrack]);
33 |
34 | // Add a track to queue
35 | const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh";
36 |
37 | await Spicetify.addToQueue([ { uri: trackUri } ]);
38 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/color-extractor.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: colorExtractor
3 | description: Extracts colors from a playlist, track, album, artist, show, etc.
4 | ---
5 |
6 | Extracts colors from a playlist, track, album, artist, show, etc.
7 |
8 | ```ts
9 | function colorExtractor(uri: string): Promise<{
10 | DARK_VIBRANT: string;
11 | DESATURATED: string;
12 | LIGHT_VIBRANT: string;
13 | PROMINENT: string;
14 | VIBRANT: string;
15 | VIBRANT_NON_ALARMING: string;
16 | }>;
17 | ```
18 |
19 | #### Parameters
20 |
21 | | Parameter | Type | Description |
22 | | :--- | :--- | :--- |
23 | | uri | `string` | URI of anything that has artwork (playlist, track, album, artist, show, etc.) |
24 |
25 | #### Returns
26 |
27 | | Name | Type | Description |
28 | | :--- | :--- | :--- |
29 | | DARK_VIBRANT | `string` | Dark vibrant color in hex format. |
30 | | DESATURATED | `string` | Desaturated color in hex format. |
31 | | LIGHT_VIBRANT | `string` | Light vibrant color in hex format. |
32 | | PROMINENT | `string` | Prominent color in hex format. |
33 | | VIBRANT | `string` | Vibrant color in hex format. |
34 | | VIBRANT_NON_ALARMING | `string` | Vibrant non alarming color in hex format. |
35 |
36 | #### Example
37 |
38 | ```ts
39 | // Get color from current track
40 | const currentTrack = Spicetify.Player.data.item;
41 | const colors = await Spicetify.colorExtractor(currentTrack.uri);
42 | ```
43 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/get-audio-data.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: getAudioData
3 | description: Get the audio data from a track.
4 | ---
5 |
6 | Fetch track analyzed audio data.
7 |
8 | Under the hood, it uses the `wg://audio-attributes/v1/audio-analysis/` endpoint, which is identical to Spotify Web API's [Get Track's Audio Analysis](https://developer.spotify.com/documentation/web-api/reference/get-audio-analysis). The only difference is that it doesn't require authentication.
9 |
10 | :::caution
11 |
12 | Beware, not all tracks have audio data.
13 |
14 | :::
15 |
16 | ```ts
17 | function getAudioData(uri?: string): Promise;
18 | ```
19 |
20 | #### Parameters
21 |
22 | | Parameter | Type | Description |
23 | | :--- | :--- | :--- |
24 | | uri | `string` | `undefined` | URI of the track. If not provided, it will use the current track. |
25 |
26 | #### Returns
27 |
28 | An object containing the audio data. See the [Spotify Web API reference](https://developer.spotify.com/documentation/web-api/reference/get-audio-analysis) for more details.
29 |
30 | #### Example
31 |
32 | ```ts
33 | // Get audio data from current track
34 | const audioData = await Spicetify.getAudioData();
35 |
36 | // Get audio data from a specific track
37 | const audioData = await Spicetify.getAudioData("spotify:track:1qDrWA6lyx8cLECdZE7TV7");
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/get-font-style.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: getFontStyle
3 | description: Returns the font style for a given variant.
4 | ---
5 |
6 | Spicetify provides a function that returns the CSS style for a given font variant used in the Spotify app.
7 |
8 | :::tip
9 |
10 | This function is used to provide backwards compatibility for older Spicetify extensions and custom apps that use `main-type-` classes.
11 |
12 | Instead of using this function to get Spotify stylings, you can simply add the `main-type-` class to your element.
13 |
14 | :::
15 |
16 | ```ts
17 | function getFontStyle(font: Variant): string;
18 | ```
19 |
20 | #### Parameters
21 |
22 | | Parameter | Type | Description |
23 | | :--- | :--- | :--- |
24 | | font | [`Variant`](/docs/development/api-wrapper/types/variant) | Font variant |
25 |
26 | #### Returns
27 |
28 | `string` - CSS style for the given font variant.
29 |
30 | #### Example
31 |
32 | ```ts
33 | const style = getFontStyle("forte");
34 |
35 | // Returns "viola" if given an invalid variant
36 | // Equivalent to `getFontStyle("viola");`
37 | const style = getFontStyle("invalid-variant");
38 | ```
39 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/remove-from-queue.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: removeFromQueue
3 | description: Removes a track or array of tracks from prioritized queue.
4 | ---
5 |
6 | :::tip
7 |
8 | This works similarly to [`Spicetify.Platform.PlayerAPI.removeFromQueue`](/docs/development/api-wrapper/methods/platform#removefromqueue).
9 |
10 | :::
11 |
12 | :::caution
13 |
14 | If a `uid` is not provided, all tracks with the same `uri` will be removed.
15 |
16 | :::
17 |
18 | ```ts
19 | function removeFromQueue(uri: ContextTrack[]): Promise;
20 | ```
21 |
22 | #### Parameters
23 |
24 | | Name | Type | Description |
25 | | :--- | :--- | :--- |
26 | | `uri` | [`ContextTrack[]`](/docs/development/api-wrapper/types/context-track) | Array of tracks to remove from queue. |
27 |
28 | #### Example
29 |
30 | ```ts
31 | // Remove current track from queue
32 | const currentTrack = Spicetify.Player.data.item;
33 |
34 | await Spicetify.removeFromQueue([currentTrack]);
35 |
36 | // Remove a track from queue
37 | const trackUri = "spotify:track:4iV5W9uYEdYUVa79Axb7Rh";
38 |
39 | await Spicetify.removeFromQueue([ { uri: trackUri } ]);
40 | ```
41 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/functions/show-notification.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: showNotification
3 | description: Show a toast notification inside Spotify.
4 | ---
5 |
6 | Show a toast notification inside Spotify.
7 |
8 | ```ts
9 | function showNotification(text: string, isError?: boolean, msTimeout?: number): void;
10 | ```
11 |
12 | | Parameter | Type | Description |
13 | | :--- | :--- | :--- |
14 | | text | `string` | Message to display. Can use inline HTML for styling. |
15 | | isError | `boolean` | If true, toast will be red. Defaults to false. |
16 | | msTimeout | `number` | Time in milliseconds to display the toast. Defaults to Spotify's value. |
17 |
18 | #### Example
19 |
20 | ```ts
21 | // Display a notification
22 | Spicetify.showNotification("My Menu Item clicked!");
23 |
24 | // Display a notification with a custom timeout
25 | Spicetify.showNotification("My Menu Item clicked!", false, 1000);
26 |
27 | // Display an error notification
28 | Spicetify.showNotification("Something wrong happened", true);
29 |
30 | // Display a bolded error notification
31 | Spicetify.showNotification("Something wrong happened", true);
32 | ```
33 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: API Wrapper
3 | description: 🧰 Everything you need to know about the Spicetify object and API Wrapper.
4 | ---
5 |
6 | Making an extension from scratch can be a daunting task. Luckily, Spicetify provides a powerful API Wrapper that makes it easy to interact with Spotify's internal APIs as well as provide out-of-the-box methods to help you easily create extensions.
7 |
8 | ## Spicetify Object
9 | You can access the Spicetify object by typing `Spicetify` in the DevTools console, inside your extension, or `window.top.Spicetify` if you're developing an app inside an `iframe`.
10 |
11 | ```ts
12 | Spicetify
13 | ```
14 |
15 | Navigate the sidebar to see all the methods and properties available in the Spicetify object!
16 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/methods/app-title.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: AppTitle
3 | description: Set of API methods to interact with the Spotify client app title.
4 | ---
5 |
6 | Spicetify provides a set of API methods to interact with the Spotify client app title.
7 |
8 | :::note
9 |
10 | These methods only work for the default app title.
11 |
12 | :::
13 |
14 | ```ts
15 | namespace AppTitle {
16 | function set(title: string): Promise<{ clear: () => void }>;
17 | function reset(): Promise;
18 | function get(): Promise;
19 | function sub(callback: (title: string) => void): { clear: () => void };
20 | }
21 | ```
22 |
23 | ## Methods
24 |
25 | ### `set`
26 |
27 | Set the default app title and force it until canceled. This will override any previous forced title.
28 |
29 | :::note
30 |
31 | This will temporarily override the current title if a track is being played until the player changes track or the user interacts with the player.
32 |
33 | :::
34 |
35 | ```ts
36 | function set(title: string): Promise<{ clear: () => void }>;
37 | ```
38 |
39 | #### Parameters
40 |
41 | | Name | Type | Description |
42 | | ------ | -------- | ----------- |
43 | | `title` | `string` | Title to set |
44 |
45 | #### Returns
46 |
47 | Promise that resolves to a function to cancel forced title. This doesn't reset the title.
48 |
49 | #### Example
50 |
51 | ```ts
52 | await Spicetify.AppTitle.set("My Extension");
53 | ```
54 |
55 | ### `reset`
56 |
57 | Reset app title to default.
58 |
59 | ```ts
60 | function reset(): Promise;
61 | ```
62 |
63 | #### Example
64 |
65 | ```ts
66 | await Spicetify.AppTitle.reset(); // Spotify Premium
67 | ```
68 |
69 | ### `get`
70 |
71 | Get current default app title.
72 |
73 | :::note
74 |
75 | This method cannot get the title of the currently played track.
76 |
77 | :::
78 |
79 | ```ts
80 | function get(): Promise;
81 | ```
82 |
83 | #### Returns
84 |
85 | Current default app title.
86 |
87 | #### Example
88 |
89 | ```ts
90 | const title = await Spicetify.AppTitle.get();
91 | console.log(title); // Spotify Premium
92 | ```
93 |
94 | ### `sub`
95 |
96 | Subscribe to title changes.
97 |
98 | :::note
99 |
100 | This event is not fired when the player changes app title.
101 |
102 | :::
103 |
104 | ```ts
105 | function sub(callback: (title: string) => void): { clear: () => void };
106 | ```
107 |
108 | #### Parameters
109 |
110 | | Name | Type | Description |
111 | | ---- | ---- | ----------- |
112 | | `callback` | `(title: string) => void` | Callback to call when title changes |
113 |
114 | #### Returns
115 |
116 | Object with method to unsubscribe.
117 |
118 | #### Example
119 |
120 | ```ts
121 | const { clear } = Spicetify.AppTitle.sub((title) => {
122 | console.log(title);
123 | });
124 |
125 | await Spicetify.AppTitle.set("My Extension"); // Console: My Extension
126 |
127 | clear();
128 | ```
--------------------------------------------------------------------------------
/docs/development/api-wrapper/methods/cosmos-async.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CosmosAsync
3 | description: Asynchronous Cosmos API wrapper used by the Spotify client.
4 | ---
5 |
6 | Asynchronous Cosmos API wrapper used by the Spotify client. It is used to make requests to the Spotify client's internal API as well as external URLs.
7 |
8 | ```ts
9 | Spicetify.CosmosAsync
10 | ```
11 |
12 | It works similarly to `fetch` or `axios` but for each request it will automatically add the required headers and cookies (such as user session token). All responses are parsed as JSON.
13 |
14 | :::caution
15 |
16 | Be mindful of where you're making a request to, especially if you're making a request to an external URL as it *may* compromise the user's account.
17 |
18 | If you're not certain, only use `CosmosAsync` for internal Spotify URLs, or use `fetch` for external URLs.
19 |
20 | :::
21 |
22 | :::tip
23 |
24 | Feel free to reach out to the developers' community on [**Discord**](https://discord.gg/VnevqPp2Rr) if you need help with any of these methods, or if you need a list of all available internal/useful endpoints.
25 |
26 | :::
27 |
28 | ## Methods
29 |
30 | ```ts
31 | namespace CosmosAsync {
32 | function head(url: string, headers?: Headers): Promise;
33 | function get(url: string, body?: Body, headers?: Headers): Promise;
34 | function post(url: string, body?: Body, headers?: Headers): Promise;
35 | function put(url: string, body?: Body, headers?: Headers): Promise;
36 | function del(url: string, body?: Body, headers?: Headers): Promise;
37 | function patch(url: string, body?: Body, headers?: Headers): Promise;
38 | function sub(url: string, callback: ((b: Response["body"]) => void), onError?: ((e: Error) => void), body?: Body, headers?: Headers): Promise;
39 | function postSub(url: string, body: Body | null, callback: ((b: Response["body"]) => void), onError?: ((e: Error) => void)): Promise;
40 | function request(method: Method, url: string, body?: Body, headers?: Headers): Promise;
41 | function resolve(method: Method, url: string, body?: Body, headers?: Headers): Promise;
42 | }
43 | ```
44 |
45 | It is worth noting that you can either make a request using the [`request`](#request) method, or use the shorthand methods for each HTTP method.
46 |
47 | For example, you can fetch the current client version using either of the following:
48 |
49 | ```ts
50 | await Spicetify.CosmosAsync.get("sp://desktop/v1/version");
51 | ```
52 |
53 | or
54 |
55 | ```ts
56 | await Spicetify.CosmosAsync.request("GET", "sp://desktop/v1/version");
57 | ```
58 |
59 | For a complete list of available HTTP methods, see [`Method`](/docs/development/api-wrapper/types/cosmos-async/method).
60 |
61 | You can also use `CosmosAsync` for Spotify Web API endpoints without having to manually add the required headers and cookies.
62 |
63 | ```ts
64 | // All endpoints that uses the `sp`, `wg`, and `hm` protocol are internal Spotify endpoints
65 | await Spicetify.CosmosAsync.get("sp://desktop/v1/version");
66 |
67 | // Spotify Web API endpoints also works
68 | await Spicetify.CosmosAsync.get("https://api.spotify.com/v1/me");
69 |
70 | // Requests to external URLs are NOT safe and may compromise the user's account
71 | // Only use this if you're certain that the URL is safe
72 | // If you need to make a request to an external URL, use `fetch` instead
73 | await fetch("https://example.com");
74 | ```
75 |
76 | ### `head`
77 |
78 | Make a `HEAD` request to the specified URL.
79 |
80 | ```ts
81 | function head(url: string, headers?: Headers): Promise;
82 | ```
83 |
84 | | Parameter | Type | Description |
85 | | --- | --- | --- |
86 | | `url` | `string` | URL to make the request to. |
87 |
88 | ### `get`
89 |
90 | Make a `GET` request to the specified URL.
91 |
92 | ```ts
93 | function get(url: string, body?: Body, headers?: Headers): Promise;
94 | ```
95 |
96 | | Parameter | Type | Description |
97 | | --- | --- | --- |
98 | | `url` | `string` | URL to make the request to. |
99 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
100 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
101 |
102 | Example:
103 |
104 | ```ts
105 | // Get all playlists in user's library
106 | const res = await Spicetify.CosmosAsync.get("sp://core-playlist/v1/rootlist");
107 | const playlists = res.rows.filter((row) => row.type === "playlist");
108 | ```
109 |
110 | ### `post`
111 |
112 | Make a `POST` request to the specified URL.
113 |
114 | ```ts
115 | function post(url: string, body?: Body, headers?: Headers): Promise;
116 | ```
117 |
118 | | Parameter | Type | Description |
119 | | --- | --- | --- |
120 | | `url` | `string` | URL to make the request to. |
121 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
122 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
123 |
124 | Example:
125 |
126 | ```ts
127 | // Skip to the next track in queue
128 | const res = await Spicetify.CosmosAsync.post("sp://player/v2/main/skip_next");
129 | ```
130 |
131 | ### `put`
132 |
133 | Make a `PUT` request to the specified URL.
134 |
135 | ```ts
136 | function put(url: string, body?: Body, headers?: Headers): Promise;
137 | ```
138 |
139 | | Parameter | Type | Description |
140 | | --- | --- | --- |
141 | | `url` | `string` | URL to make the request to. |
142 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
143 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
144 |
145 | Example:
146 |
147 | ```ts
148 | // Enable/disable incognito mode
149 | const res = await Spicetify.CosmosAsync.put("sp://scrobble/v1/incognito", { enabled: boolean });
150 | ```
151 |
152 | ### `del`
153 |
154 | Make a `DELETE` request to the specified URL.
155 |
156 | ```ts
157 | function del(url: string, body?: Body, headers?: Headers): Promise;
158 | ```
159 |
160 | | Parameter | Type | Description |
161 | | --- | --- | --- |
162 | | `url` | `string` | URL to make the request to. |
163 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
164 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
165 |
166 | ### `patch`
167 |
168 | Make a `PATCH` request to the specified URL.
169 |
170 | ```ts
171 | function patch(url: string, body?: Body, headers?: Headers): Promise;
172 | ```
173 |
174 | | Parameter | Type | Description |
175 | | --- | --- | --- |
176 | | `url` | `string` | URL to make the request to. |
177 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
178 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
179 |
180 | ### `sub`
181 |
182 | Make a `SUB` request to the specified URL.
183 |
184 | ```ts
185 | function sub(url: string, callback: ((b: Response["body"]) => void), onError?: ((e: Error) => void), body?: Body, headers?: Headers): Promise;
186 | ```
187 |
188 | | Parameter | Type | Description |
189 | | --- | --- | --- |
190 | | `url` | `string` | URL to make the request to. |
191 | | `callback` | `(b: Response["body"]) => void` | Callback function to run when the request is successful. |
192 | | `onError` | `(e: Error) => void` | Callback function to run when the request fails. |
193 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
194 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
195 |
196 | ### `postSub`
197 |
198 | Make a `POST` request to the specified URL, and subscribe to the response.
199 |
200 | ```ts
201 | function postSub(url: string, body: Body | null, callback: ((b: Response["body"]) => void), onError?: ((e: Error) => void)): Promise;
202 | ```
203 |
204 | | Parameter | Type | Description |
205 | | --- | --- | --- |
206 | | `url` | `string` | URL to make the request to. |
207 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
208 | | `callback` | `(b: Response["body"]) => void` | Callback function to run when the request is successful. |
209 | | `onError` | `(e: Error) => void` | Callback function to run when the request fails. |
210 |
211 | ### `request`
212 |
213 | Make a request to the specified URL.
214 |
215 | ```ts
216 | function request(method: Method, url: string, body?: Body, headers?: Headers): Promise;
217 | ```
218 |
219 | | Parameter | Type | Description |
220 | | --- | --- | --- |
221 | | `method` | [`Method`](/docs/development/api-wrapper/types/cosmos-async/method) | HTTP method to use. |
222 | | `url` | `string` | URL to make the request to. |
223 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
224 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
225 |
226 | ### `resolve`
227 |
228 | Make a request to the specified URL, and resolve the response.
229 |
230 | ```ts
231 | function resolve(method: Method, url: string, body?: Body, headers?: Headers): Promise;
232 | ```
233 |
234 | | Parameter | Type | Description |
235 | | --- | --- | --- |
236 | | `method` | [`Method`](/docs/development/api-wrapper/types/cosmos-async/method) | HTTP method to use. |
237 | | `url` | `string` | URL to make the request to. |
238 | | `body` | [`Body`](/docs/development/api-wrapper/types/cosmos-async/body) | Request body. |
239 | | `headers` | [`Headers`](/docs/development/api-wrapper/types/cosmos-async/headers) | Request headers. |
240 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/methods/keyboard.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Keyboard
3 | description: A wrapper for keyboard shortcuts.
4 | ---
5 |
6 | Spicetify provides its own method for global keyboard shortcuts. You can specify actions for your extension when the user presses a keyboard shortcut.
7 |
8 | :::tip
9 |
10 | `Spicetify.Keyboard` is a wrapper of [`Spicetify.Mousetrap`](/docs/development/api-wrapper/modules#mousetrap) configured to be compatible with legacy Spotify.
11 |
12 | New extensions are advised to use the module instead.
13 |
14 | :::
15 |
16 | :::caution
17 |
18 | All shortcuts registered by `Spicetify.Keyboard` are global. Be mindful of conflicts with other extensions or the Spotify client itself.
19 |
20 | :::
21 |
22 | ```ts
23 | namespace Keyboard {
24 | const KEYS: Record;
25 | function registerShortcut(keys: KeysDefine, callback: (event: KeyboardEvent) => void): void;
26 | function _deregisterShortcut(keys: KeysDefine): void;
27 | function changeShortcut(keys: KeysDefine, newKeys: KeysDefine): void;
28 | };
29 | ```
30 |
31 | ## Properties
32 |
33 | ### `KEYS`
34 |
35 | An object containing a list of valid keys, mapped to their valid names.
36 |
37 | ```ts
38 | const { KEYS } = Spicetify.Keyboard;
39 | ```
40 |
41 | Refer to [this table](/docs/development/api-wrapper/types/keyboard/validkey) for a list of valid keys.
42 |
43 | #### Example
44 |
45 | ```ts
46 | const { KEYS } = Spicetify.Keyboard;
47 | console.log(KEYS["CAPS"]); // "Capslock"
48 | ```
49 |
50 | ## Methods
51 |
52 | ### `registerShortcut`
53 |
54 | Register a global keyboard shortcut.
55 |
56 | ```ts
57 | function registerShortcut(keys: KeysDefine, callback: (event: KeyboardEvent) => void): void;
58 | ```
59 |
60 | #### Parameters
61 |
62 | | Parameter | Type | Description |
63 | | :--- | :--- | :--- |
64 | | keys | [`KeysDefine`](/docs/development/api-wrapper/types/keyboard/keysdefine) | Keyboard shortcut to register. |
65 | | callback | `(event: KeyboardEvent) => void` | Callback function to run when the shortcut is triggered. |
66 |
67 | #### Example
68 |
69 | ```ts
70 | // Equivalent to `Spicetify.Keyboard.registerShortcut({ key: "p", ctrl: true, shift: true }, (event) => { ... })`
71 | Spicetify.Keyboard.registerShortcut("ctrl+shift+p", (event) => {
72 | // Do something with the event
73 | Spicetify.showNotification("Shortcut triggered!");
74 | });
75 | ```
76 |
77 | ### `_deregisterShortcut`
78 |
79 | Deregister a global keyboard shortcut.
80 |
81 | ```ts
82 | function _deregisterShortcut(keys: KeysDefine): void;
83 | ```
84 |
85 | #### Parameters
86 |
87 | | Parameter | Type | Description |
88 | | :--- | :--- | :--- |
89 | | keys | [`KeysDefine`](/docs/development/api-wrapper/types/keyboard/keysdefine) | Keyboard shortcut to deregister. |
90 |
91 | #### Example
92 |
93 | ```ts
94 | Spicetify.Keyboard._deregisterShortcut("ctrl+shift+p");
95 | ```
96 |
97 | ### `changeShortcut`
98 |
99 | Change a global keyboard shortcut to a new shortcut while keeping the callback.
100 |
101 | ```ts
102 | function changeShortcut(keys: KeysDefine, newKeys: KeysDefine): void;
103 | ```
104 |
105 | #### Parameters
106 |
107 | | Parameter | Type | Description |
108 | | :--- | :--- | :--- |
109 | | keys | [`KeysDefine`](/docs/development/api-wrapper/types/keyboard/keysdefine) | Keyboard shortcut to change. |
110 | | newKeys | [`KeysDefine`](/docs/development/api-wrapper/types/keyboard/keysdefine) | New keyboard shortcut to change to. |
111 |
112 | #### Example
113 |
114 | ```ts
115 | Spicetify.Keyboard.changeShortcut("ctrl+shift+p", "ctrl+shift+o");
116 | ```
117 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/methods/local-storage.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: LocalStorage
3 | description: Get and set data in local storage.
4 | ---
5 |
6 | Spicetify provides a wrapper for `localStorage` to make it easier to use.
7 |
8 | :::tip
9 |
10 | All keys created via this method are generic and stored as-is.
11 |
12 | If you wish to store values that are specific for each user account, you can use [`Platform.LocalStorageAPI`](/docs/development/api-wrapper/methods/platform#localstorageapi) instead.
13 |
14 | :::
15 |
16 | ```ts
17 | namespace LocalStorage {
18 | function clear(): void;
19 | function get(key: string): string | null;
20 | function remove(key: string): void;
21 | function set(key: string, value: string): void;
22 | };
23 | ```
24 |
25 | ## Methods
26 |
27 | ### `clear`
28 |
29 | Empties the list associated with the object of all key/value pairs, if there are any.
30 |
31 | :::warning
32 |
33 | This method will remove all data in local storage, not just the data that Spicetify uses. This essentially resets the client to its default state.
34 |
35 | It will also wipe all data stored by extensions and custom apps (e.g. Marketplace, Lyrics Plus, etc.)
36 |
37 | :::
38 |
39 | ```ts
40 | clear(): void
41 | ```
42 |
43 | ### `get`
44 |
45 | Get key value from local storage.
46 |
47 | ```ts
48 | get(key: string): string | null
49 | ```
50 |
51 | | Parameter | Type | Description |
52 | | :--- | :--- | :--- |
53 | | key | `string` | Key to get value from. |
54 |
55 | #### Example
56 |
57 | ```ts
58 | const value = Spicetify.LocalStorage.get("foo");
59 | ```
60 |
61 | ### `remove`
62 |
63 | Delete key from local storage.
64 |
65 | ```ts
66 | remove(key: string): void
67 | ```
68 |
69 | | Parameter | Type | Description |
70 | | :--- | :--- | :--- |
71 | | key | `string` | Key to delete. |
72 |
73 | #### Example
74 |
75 | ```ts
76 | Spicetify.LocalStorage.remove("foo");
77 | ```
78 |
79 | ### `set`
80 |
81 | Set new value for key in local storage.
82 |
83 | ```ts
84 | set(key: string, value: string): void
85 | ```
86 |
87 | | Parameter | Type | Description |
88 | | :--- | :--- | :--- |
89 | | key | `string` | Key to set value for. |
90 | | value | `string` | Value to set. |
91 |
92 | #### Example
93 |
94 | ```ts
95 | Spicetify.LocalStorage.set("foo", "bar");
96 | ```
97 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/methods/popup-modal.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: PopupModal
3 | description: Set of methods to create and control popup modals.
4 | ---
5 |
6 | Spicetify provides a set of methods to create and control popup modals. This will display a modal on top of the client, which can be used to display information or ask for user input.
7 |
8 | ```ts
9 | namespace PopupModal {
10 | interface Content {
11 | title: string;
12 | content: string | Element;
13 | isLarge?: boolean;
14 | }
15 |
16 | function display(content: Content): void;
17 | function hide(): void;
18 | };
19 | ```
20 |
21 | ## Interface
22 |
23 | ### `Content`
24 |
25 | `Content` is an object that contains the information needed to display the modal.
26 |
27 | | Property | Type | Description |
28 | | --- | --- | --- |
29 | | `title` | `string` | Title of the modal. |
30 | | `content` | `string` | Content of the modal. You can specify a string for simple text display or an HTML element for interactive config/setting menu. |
31 | | `isLarge` | `boolean` | `undefined` | Bigger modal. |
32 |
33 | ## Methods
34 |
35 | ### `display`
36 |
37 | Displays a modal on top of the client.
38 |
39 | :::note
40 |
41 | This method will replace the current modal if there is one.
42 |
43 | :::
44 |
45 | | Parameter | Type | Description |
46 | | --- | --- | --- |
47 | | `content` | [`Content`](#content) | Information about the modal. |
48 |
49 | ```ts
50 | Spicetify.PopupModal.display({
51 | title: 'Hello World',
52 | content: 'This is a simple text',
53 | });
54 | ```
55 |
56 | ### `hide`
57 |
58 | Hides the current modal.
59 |
60 | :::note
61 |
62 | This method will hide *any* modal currently displayed via `Spicetify.PopupModal.display`.
63 |
64 | :::
65 |
66 | ```ts
67 | Spicetify.PopupModal.hide();
68 | ```
69 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/modules.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Modules
3 | description: 🧩 Modules exposed via Spicetify object.
4 | ---
5 |
6 | Spicetify exposes some modules via `Spicetify` object.
7 |
8 | You can access them by typing `Spicetify.` in the DevTools console, inside your extension, or `window.top.Spicetify.` if you're developing an app inside an `iframe`.
9 |
10 | Utilizing these modules can help you create more powerful extensions without having to include the whole module in your extension.
11 |
12 | ```js
13 | Spicetify.React;
14 | ```
15 |
16 | For usage of these modules, please refer to their official documentation.
17 |
18 | ### React
19 |
20 | [React](https://reactjs.org/) is a JavaScript library for building user interfaces. It is used by Spotify to build their UI.
21 |
22 | :::note
23 |
24 | Spotify versions *below* 1.2.26 use version **17.0.2**, *after* - **18.2.0**.
25 |
26 | :::
27 |
28 | ```js
29 | Spicetify.React;
30 | ```
31 |
32 | ### ReactDOM
33 |
34 | [ReactDOM](https://reactjs.org/docs/react-dom.html) is a package that provides DOM-specific methods that can be used at the top level of your app and as an escape hatch to get outside of the React model if you need to. It is used by Spotify to render React components to the DOM.
35 |
36 | ```js
37 | Spicetify.ReactDOM;
38 | ```
39 |
40 | ### Tippy.js
41 |
42 | [Tippy.js](https://atomiks.github.io/tippyjs/) is a highly customizable tooltip and popover library powered by Popper.
43 |
44 | ```js
45 | Spicetify.Tippy;
46 | ```
47 |
48 | ### Mousetrap
49 |
50 | [Mousetrap](https://craig.is/killing/mice) is a simple library for handling keyboard shortcuts in JavaScript.
51 |
52 | ```js
53 | Spicetify.Mousetrap;
54 | ```
55 |
56 | ### React Flip Toolkit
57 |
58 | [React Flip Toolkit](https://github.com/aholachek/react-flip-toolkit) is a collection of easy-to-use animation effects and utilities that can be used to enhance your React project.
59 |
60 | ```js
61 | Spicetify.ReactFlipToolkit;
62 | ```
63 |
64 | ### React Query (v3)
65 |
66 | [React Query](https://react-query.tanstack.com/) is a library for managing, caching, syncing, and refetching server state in React.
67 |
68 | :::note
69 |
70 | Spotify uses React Query v3, instead of the current latest version (v4). As such, the API may be different from the official documentation.
71 |
72 | :::
73 |
74 | ```js
75 | Spicetify.ReactQuery;
76 | ```
77 |
78 | ### classnames
79 |
80 | [classnames](https://github.com/JedWatson/classnames) is a simple JavaScript utility for conditionally joining class names together.
81 |
82 | ```js
83 | Spicetify.classnames;
84 | ```
85 |
86 | ### Snackbar
87 |
88 | [Notistack](https://github.com/iamhosseindhv/notistack) is a JavaScript library for creating highly customizable notification snackbars (toasts) that can be stacked on top of each other.
89 |
90 | :::note
91 |
92 | Be aware that only `SnackbarProvider` and `useSnackbar` work as described in the official Notistack documentation.
93 |
94 | :::
95 |
96 | ```js
97 | Spicetify.Snackbar;
98 | ```
99 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/properties/config.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Config
3 | description: 🛠️ Accessing a copy of Spicetify's `config-xpui.ini` file inside your extension.
4 | ---
5 |
6 | To make it easier for you to validate and debug your extensions, Spicetify provides a filtered copy of the user's `config-xpui.ini` in the `Spicetify` object.
7 |
8 | ```ts
9 | interface Config {
10 | version: string;
11 | current_theme: string;
12 | color_scheme: string;
13 | extensions: string[];
14 | custom_apps: string[];
15 | }
16 | ```
17 |
18 | | Property | Type | Description |
19 | | --- | --- | --- |
20 | | `version` | `string` | Spicetify version. |
21 | | `current_theme` | `string` | Current theme name. |
22 | | `color_scheme` | `string` | Current color scheme name. |
23 | | `extensions` | `string[]` | List of enabled extensions. |
24 | | `custom_apps` | `string[]` | List of enabled custom apps. |
25 |
26 | ## Usage
27 |
28 | You can validate if the user currently has a custom app or a theme enabled by checking if the app or theme's name is included in the `custom_apps` or `current_theme` property of the `Config` object.
29 |
30 | ```ts
31 | const { Config } = Spicetify;
32 |
33 | if (Config.custom_apps.includes("lyrics-plus")) {
34 | // Do something
35 | }
36 | ```
37 |
38 | This can ensure that your extension doesn't break if the user doesn't have the required app or theme installed.
39 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/properties/queue.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Queue
3 | description: An object containing information about the current queue.
4 | ---
5 |
6 | :::note
7 |
8 | This type is deducted from Spotify's internal usage. It may not be accurate and may change in the future.
9 |
10 | :::
11 |
12 | The `Queue` object contains a list of queuing tracks, history of played tracks, and current track metadata.
13 |
14 | ```ts
15 | Spicetify.Queue
16 | ```
17 |
18 | ## Return
19 |
20 | ```ts
21 | const Queue: {
22 | nextTracks: ProvidedTrack[];
23 | prevTracks: ProvidedTrack[];
24 | queueRevision: string;
25 | track: ProvidedTrack;
26 | };
27 | ```
28 |
29 | | Property | Type | Description |
30 | | --- | --- | --- |
31 | | `nextTracks` | [`ProvidedTrack[]`](/docs/development/api-wrapper/types/provided-track) | List of next tracks. |
32 | | `prevTracks` | [`ProvidedTrack[]`](/docs/development/api-wrapper/types/provided-track) | List of previous tracks. |
33 | | `queueRevision` | `string` | Queue revision ID used internally by Spotify. |
34 | | `track` | [`ProvidedTrack`](/docs/development/api-wrapper/types/provided-track) | Current track. |
35 |
36 | ## Usage
37 |
38 | If you plan on developing extensions that need to access the current queue, you can use the `Spicetify.Queue` object.
39 |
40 | ```ts
41 | const queue = Spicetify.Queue;
42 | const currentTrack = queue.track;
43 | ```
44 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/properties/react-hook.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ReactHook
3 | description: Set of React hooks used by the Spotify client.
4 | ---
5 |
6 | Spicetify provides a set of React hooks used by the Spotify client. You can use these hooks to create a React component interactive with the client.
7 |
8 | :::note
9 |
10 | It is recommended that you be familiar with [`React`](https://react.dev/) before using these hooks.
11 |
12 | :::
13 |
14 | ```ts
15 | namespace ReactHook {
16 | function DragHandler(
17 | uris?: string[],
18 | label?: string,
19 | contextUri?: string,
20 | sectionIndex?: number,
21 | dropOriginUri?: string
22 | ): (event: React.DragEvent, uris?: string[], label?: string, contextUri?: string, sectionIndex?: number) => void;
23 | function usePanelState(id: number): { toggle: () => void, isActive: boolean };
24 | function useExtractedColor(uri: string, fallbackColor?: string, variant?: "colorRaw" | "colorLight" | "colorDark"): string;
25 | }
26 | ```
27 |
28 | ## Hooks
29 |
30 | ### `DragHandler`
31 |
32 | React Hook to create interactive drag-and-drop element.
33 |
34 | Used to create a draggable element that can be dropped into Spotify's components (e.g. Playlist, Folder, Sidebar, Queue)
35 |
36 | ```ts
37 | function DragHandler(
38 | uris?: string[],
39 | label?: string,
40 | contextUri?: string,
41 | sectionIndex?: number,
42 | dropOriginUri?: string
43 | ): (event: React.DragEvent, uris?: string[], label?: string, contextUri?: string, sectionIndex?: number) => void;
44 | ```
45 |
46 | #### Parameters
47 |
48 | | Parameter | Type | Description |
49 | | :--- | :--- | :--- |
50 | | uris | `string[]` | `undefined` | List of URIs to be dragged. |
51 | | label | `string` | `undefined` | Label to be displayed when dragging. |
52 | | contextUri | `string` | `undefined` | Context URI of the element from which the drag originated (e.g. Playlist URI). |
53 | | sectionIndex | `number` | `undefined` | Index of the section in which the drag originated. |
54 | | dropOriginUri | `string` | `undefined` | URI of the desired drop target. Leave empty to allow drop anywhere. |
55 |
56 | #### Returns
57 |
58 | Function to handle drag event. Should be passed to `onDragStart` prop of the element. All parameters passed onto the hook will be passed onto the handler unless declared otherwise.
59 |
60 | #### Example
61 |
62 | ```tsx
63 | const DraggableComponent = () => {
64 | // Do I Wanna Know? by Arctic Monkeys
65 | const uri = "spotify:track:5FVd6KXrgO9B3JPmC8OPst";
66 | const label = "Do I Wanna Know? - Arctic Monkeys";
67 |
68 | const handleDragStart = Spicetify.ReactHook.DragHandler([uri], label);
69 |
70 | return (
71 |
72 | {label}
73 |
74 | );
75 | }
76 | ```
77 |
78 | ### `usePanelState`
79 |
80 | React Hook to use panel state.
81 |
82 | ```ts
83 | function usePanelState(id: number): { toggle: () => void, isActive: boolean };
84 | ```
85 |
86 | #### Parameters
87 |
88 | | Parameter | Type | Description |
89 | | :--- | :--- | :--- |
90 | | id | `number` | ID of the panel to use. |
91 |
92 | #### Returns
93 |
94 | Object with methods of the panel.
95 |
96 | | Property | Type | Description |
97 | | :--- | :--- | :--- |
98 | | toggle | `() => void` | Toggle the panel. |
99 | | isActive | `boolean` | Whether the panel is active. |
100 |
101 | #### Example
102 |
103 | ```tsx
104 | const PanelComponent = () => {
105 | // The ID can be either Spotify's default panel IDs or your custom panel ID registered via `Spicetify.Panel.registerPanel`
106 | const { toggle, isActive } = Spicetify.ReactHook.usePanelState(5);
107 |
108 | return (
109 |
110 |
113 |
114 | );
115 | }
116 | ```
117 |
118 | ### `useExtractedColor`
119 |
120 | React Hook to use extracted color from GraphQL.
121 |
122 | ```ts
123 | function useExtractedColor(uri: string, fallbackColor?: string, variant?: "colorRaw" | "colorLight" | "colorDark"): string;
124 | ```
125 |
126 | :::note
127 |
128 | This is a wrapper of ReactQuery's `useQuery` hook. The component using this hook must be wrapped in a `QueryClientProvider` component.
129 |
130 | Look into the example below for more information.
131 |
132 | :::
133 |
134 | #### Parameters
135 |
136 | | Parameter | Type | Description |
137 | | :--- | :--- | :--- |
138 | | uri | `string` | URI of the Spotify image to extract color from. |
139 | | fallbackColor | `string` | `undefined` | Fallback color to use if the image is not available. Defaults to `#535353`. |
140 | | variant | `"colorRaw"` | `"colorLight"` | `"colorDark"` | `undefined` | Variant of the color to use. Defaults to `colorRaw`. |
141 |
142 | #### Returns
143 |
144 | Extracted color hex code.
145 |
146 | #### Example
147 |
148 | ```tsx
149 | import { useEffect, useState } from "react";
150 |
151 | const { QueryClient, QueryClientProvider } = Spicetify.ReactQuery;
152 | const { useExtractedColor } = Spicetify.ReactHook;
153 |
154 | const queryClient = new QueryClient();
155 |
156 | const Component = () => {
157 | const [imageUri, setImageUri] = useState(Spicetify.Player.data?.item?.metadata?.image_xlarge_url ?? "");
158 | const color = useExtractedColor(imageUri);
159 |
160 | useEffect(() => {
161 | // Listen to track change
162 | const listener = () => {
163 | setImageUri(Spicetify.Player.data?.item?.metadata?.image_xlarge_url ?? "");
164 | };
165 | Spicetify.Player.addEventListener("songchange", listener);
166 |
167 | return () => Spicetify.Player.removeEventListener("songchange", listener);
168 | }, []);
169 |
170 | return (
171 |
172 | Hello World
173 |
174 | );
175 | }
176 |
177 | const App = () => {
178 | return (
179 |
180 |
181 |
182 | );
183 | }
184 | ```
185 |
--------------------------------------------------------------------------------
/docs/development/api-wrapper/properties/svgicons.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: SVGIcons
3 | description: A set of SVG icons used throughout the Spotify client.
4 | ---
5 |
6 | Spicetify has a predefined set of SVG icons that are used by Spotify throughout the client. These are strings of SVG `innerHTML` that are used to create `