├── .gitignore
├── extractor.psd
├── firefox
├── icons
│ ├── icon32.png
│ ├── icon48.png
│ ├── icon96.png
│ └── icon128.png
├── .web-extension-id
├── manifest.json
├── background.js
└── extractor.js
├── chromium
├── icons
│ ├── icon128.png
│ ├── icon32.png
│ ├── icon48.png
│ └── icon96.png
├── service.js
├── extractor.js
└── manifest.json
├── manifest.json
├── package.json
├── .github
└── workflows
│ └── release.yml
├── RELEASING.md
├── spicetify
├── extractor.js
├── pnpm-lock.yaml
└── globals.d.ts
├── README.md
└── pnpm-lock.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.crx
2 | *.pem
3 | *.xpi
4 | *.zip
5 | node_modules
6 |
--------------------------------------------------------------------------------
/extractor.psd:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/extractor.psd
--------------------------------------------------------------------------------
/firefox/icons/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/firefox/icons/icon32.png
--------------------------------------------------------------------------------
/firefox/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/firefox/icons/icon48.png
--------------------------------------------------------------------------------
/firefox/icons/icon96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/firefox/icons/icon96.png
--------------------------------------------------------------------------------
/chromium/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/chromium/icons/icon128.png
--------------------------------------------------------------------------------
/chromium/icons/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/chromium/icons/icon32.png
--------------------------------------------------------------------------------
/chromium/icons/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/chromium/icons/icon48.png
--------------------------------------------------------------------------------
/chromium/icons/icon96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/chromium/icons/icon96.png
--------------------------------------------------------------------------------
/firefox/icons/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afonsojramos/spotify-details-extractor/HEAD/firefox/icons/icon128.png
--------------------------------------------------------------------------------
/firefox/.web-extension-id:
--------------------------------------------------------------------------------
1 | # This file was created by https://github.com/mozilla/web-ext
2 | # Your auto-generated extension ID for addons.mozilla.org is:
3 | {8301b4fd-b04f-40f7-be18-55f0da220794}
4 |
--------------------------------------------------------------------------------
/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Spotify Details Extractor",
3 | "description": "Spicetify extension to extract Spotify details from an album page in a specific JSON object.",
4 | "preview": "chromium/icons/icon128.png",
5 | "main": "spicetify/extractor.js",
6 | "readme": "README.md"
7 | }
8 |
--------------------------------------------------------------------------------
/chromium/service.js:
--------------------------------------------------------------------------------
1 | chrome.action.onClicked.addListener((tab) => {
2 | if (tab.url.match(/https:\/\/open\.spotify\.com\/\w*\/\w*/)) {
3 | chrome.scripting.executeScript({
4 | target: { tabId: tab.id },
5 | files: ['extractor.js'],
6 | });
7 | }
8 | });
9 |
10 | chrome.tabs.onActivated.addListener((activeInfo) => {
11 | chrome.tabs.get(activeInfo.tabId, async (tab) => {
12 | if (!tab.url.match(/https:\/\/open\.spotify\.com\/\w*\/\w*/)) chrome.action.disable(tab.id);
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/firefox/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Spotify Details Extractor",
3 | "description": "Extract the most important details of an album to the desired JSON.",
4 | "manifest_version": 2,
5 | "version": "2.5.0",
6 | "background": {
7 | "scripts": ["background.js"]
8 | },
9 | "permissions": ["tabs", "*://*.spotify.com/*", "contextMenus"],
10 | "icons": {
11 | "32": "/icons/icon32.png",
12 | "48": "/icons/icon48.png",
13 | "96": "/icons/icon96.png",
14 | "128": "/icons/icon128.png"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/chromium/extractor.js:
--------------------------------------------------------------------------------
1 | artists = [];
2 | document
3 | .querySelectorAll("section > div:first-child > div > div span > a")
4 | .forEach((artist) => artists.push(artist.innerHTML));
5 |
6 | album = {
7 | title: document.querySelector("h1").innerText,
8 | artist:
9 | artists.length === 1
10 | ? artists[0]
11 | : artists.reduce((artist, artistSum) => `${artist}, ${artistSum}`),
12 | image: document.querySelector("section > div > div > div > img").src,
13 | url: window.location.href.match(/https:\/\/open\.spotify\.com\/\w*\/\w*/)[0],
14 | };
15 |
16 | navigator.clipboard.writeText(JSON.stringify(album));
17 |
--------------------------------------------------------------------------------
/chromium/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Spotify Details Extractor",
3 | "action": {},
4 | "description": "Extract the most important details of an album to the desired JSON.",
5 | "version": "2.5.0",
6 | "manifest_version": 3,
7 | "homepage_url": "https://github.com/afonsojramos/spotify-details-extractor",
8 | "background": {
9 | "service_worker": "service.js"
10 | },
11 | "permissions": ["scripting", "tabs"],
12 | "host_permissions": ["*://*.spotify.com/*"],
13 | "icons": {
14 | "32": "/icons/icon32.png",
15 | "48": "/icons/icon48.png",
16 | "96": "/icons/icon96.png",
17 | "128": "/icons/icon128.png"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/firefox/background.js:
--------------------------------------------------------------------------------
1 | browser.contextMenus.create({
2 | id: 'extract-album',
3 | title: 'Extract Album Info',
4 | documentUrlPatterns: ['https://open.spotify.com/*'],
5 | });
6 |
7 | function messageTab(tabs) {
8 | browser.tabs.sendMessage(tabs[0].id, {
9 | replacement: 'Extracting!',
10 | });
11 | }
12 |
13 | function onExecuted() {
14 | let querying = browser.tabs.query({
15 | active: true,
16 | currentWindow: true,
17 | });
18 | querying.then(messageTab);
19 | }
20 |
21 | browser.contextMenus.onClicked.addListener(function (info, _tab) {
22 | if (info.menuItemId == 'extract-album') {
23 | let executing = browser.tabs.executeScript({
24 | file: 'extractor.js',
25 | });
26 | executing.then(onExecuted);
27 | }
28 | });
29 |
--------------------------------------------------------------------------------
/firefox/extractor.js:
--------------------------------------------------------------------------------
1 | extractorReceiver = () => {
2 | artists = [];
3 | document
4 | .querySelectorAll("section > div:first-child > div > div span > a")
5 | .forEach((artist) => artists.push(artist.innerHTML));
6 |
7 | album = {
8 | title: document.querySelector("h1").innerText,
9 | artist:
10 | artists.length === 1
11 | ? artists[0]
12 | : artists.reduce((artist, artistSum) => `${artist}, ${artistSum}`),
13 | image: document.querySelector("section > div > div > div > img").src,
14 | url: window.location.href.match(
15 | /https:\/\/open\.spotify\.com\/\w*\/\w*/
16 | )[0],
17 | };
18 |
19 | navigator.clipboard.writeText(JSON.stringify(album));
20 | };
21 |
22 | browser.runtime.onMessage.addListener(extractorReceiver);
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "chromium:build": "zip -r spotify-details-extractor-chromium.zip ./chromium/",
4 | "firefox:version": "sed -i '' -e 's/\"version\": \".*\"/\"version\": \"$(git describe --tags --abbrev=0)\"/' ./firefox/manifest.json",
5 | "firefox:dev": "web-ext run -s firefox",
6 | "firefox:build": "web-ext build -s firefox --overwrite-dest",
7 | "chromium:version": "sed -i '' -e 's/\"version\": \".*\"/\"version\": \"$(git describe --tags --abbrev=0)\"/' ./chromium/manifest.json",
8 | "firefox:release": "web-ext sign -s firefox --api-key=$JWT_ISSUER --api-secret=$JWT_SECRET",
9 | "spicetify": "spicetify enable-devtools & spicetify watch -le",
10 | "dev": "pnpm watch & pnpm spicetify",
11 | "watch": "onchange 'extractor.js' -- pnpm copy",
12 | "copy": "cp extractor.js ~/.spicetify/Extensions",
13 | "setup": "spicetify config extensions extractor.js",
14 | "upgrade": "pnpm chromium:version && pnpm firefox:version"
15 | },
16 | "dependencies": {
17 | "@types/react": "^18.2.6",
18 | "onchange": "^7.1.0",
19 | "web-ext": "^7.6.2"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [created]
6 |
7 | permissions:
8 | contents: write
9 | pull-requests: write
10 |
11 | jobs:
12 | release:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v3
16 | - uses: actions/setup-node@v3
17 | with:
18 | node-version: 18
19 | - uses: pnpm/action-setup@v2
20 | with:
21 | version: 8
22 | - name: Install dependencies
23 | run: pnpm install
24 |
25 | - name: Build Chromium
26 | run: pnpm run chromium:build
27 |
28 | - name: Build Firefox
29 | run: pnpm run firefox:build
30 |
31 | - name: Release Firefox
32 | run: pnpm run firefox:release
33 | env:
34 | JWT_SECRET: ${{ secrets.JWT_SECRET }}
35 | JWT_ISSUER: ${{ secrets.JWT_ISSUER }}
36 |
37 | - name: Rename files
38 | run: |
39 | mv web-ext-artifacts/spotify_details_extractor-${{ github.ref_name }}.zip spotify-details-extractor-firefox.zip
40 | mv spicetify/extractor.js spotify-details-extractor-spicetify.js
41 |
42 | - name: Upload Linux release assets
43 | env:
44 | GH_TOKEN: ${{ github.token }}
45 | run: |
46 | gh release upload ${{ github.ref_name }} spotify-details-extractor-firefox.zip
47 | gh release upload ${{ github.ref_name }} spotify-details-extractor-spicetify.js
48 | gh release upload ${{ github.ref_name }} spotify-details-extractor-chromium.zip
49 |
--------------------------------------------------------------------------------
/RELEASING.md:
--------------------------------------------------------------------------------
1 |
2 | ## Installation and Compilation
3 |
4 | ## Chromium
5 |
6 | ### Development
7 |
8 | Chromium only requires you to go to `chrome://extensions`, activate **Developer Mode** and `Load Unpacked` by selecting the folder that you have the extension on. No need to zip it or package it in any way. More reference on how to manually install Chrome extensions [here](https://developer.chrome.com/docs/extensions/mv3/getstarted/#manifest).
9 |
10 | ### Release
11 |
12 | In order to release, all you need to do is select `Pack Extension` under `chrome://extensions`, select the folder and that's it! Remember to save the key somewhere safe to generate new versions of the extension.
13 |
14 | Alternatively, you may, using 7-Zip, run `zip -r dist/spotify-details-extractor.zip .\chromium\` (Unix) or `7z a -tzip dist/spotify-details-extractor.zip .\chromium\` (Windows), and then upload the archive to the [Chrome Web Store Dev Console](https://chrome.google.com/webstore/devconsole/). Finally, you will find the `.crx` extension under the Package tab. This one will be signed and will now show any warning when installing.
15 |
16 | ## Firefox
17 |
18 | Firefox add-ons, before generating an installable `.xpi` file, must be digitally signed by Mozilla, which can be a tiny bit tedious.
19 |
20 | First of all, install the `web-ext` tool with the following `npm install -g web-ext`.
21 |
22 | ### Development
23 |
24 | Development is very streamlined with its own self-contained browser session using the following command `web-ext run -s firefox`.
25 |
26 | ### Release
27 |
28 | In order to release, you first need to build the `.zip` file inside a new `/web-ext-artifacts` directory, which can also be loaded as a temporary extension in Firefox through the `about:debugging` page with the following: `web-ext build -s firefox --overwrite-dest`.
29 |
30 | Afterwards, you need to sign the extension. For this you'll need to generate your [addons.mozilla.org credentials](https://addons.mozilla.org/en-GB/developers/addon/api/key/).
31 |
32 | Then, simply run the following command `web-ext sign -s firefox --api-key=JWT_ISSUER --api-secret=JWT_SECRET` with the API key and secret parameters that you generated. The new `.xpi` file can also be found in the `/web-ext-artifacts` directory.
--------------------------------------------------------------------------------
/spicetify/extractor.js:
--------------------------------------------------------------------------------
1 | // @ts-check
2 |
3 | // NAME: Spotify Details Extractor
4 | // AUTHOR: afonsojramos
5 | // DESCRIPTION: Extracts album information from Spotify.
6 |
7 | ///

| 13 | Browser Download 14 | | 15 |16 | Usage Example 17 | | 18 |
|---|---|
|
21 | |
23 |
24 |
25 | |
26 |
|
29 |
30 | |
33 |
34 |
35 | |
36 |
|
39 |
40 | 43 | Spicetify Marketplace or manually. 44 | |
45 |
46 |
47 | |
48 |

83 |
84 | However, the process of extracting the details from the album page is quite tedious as I have to **manually** copy the album's URL, and extract the album's title, artist and image URL. All of this requires the opening of the developer's console and makes the process rather slow.
85 |
86 | Therefore, I decided to create a browser extension that will **extract the details** from the album page, store them in the desired JSON object, and **automatically copy it to the clipboard**.
87 |
88 | ## Implementation
89 |
90 | Initially, I was going to create an extension that would create an in-page button that would trigger the events. I was somewhat successful in this (it works perfectly on Spicetify), but on Spotify's Web App things are a bit more complicated as it meant interacting with the page's DOM, which I preferred not to do as it would be more prone to errors.
91 |
92 | With this in mind, `v2` shifted to a simple context menu on Firefox and the extension button on Chromium, due to the latter not supporting context menus. These proved to be way more reliable and faster than the previous approach.
93 |
94 | ## More
95 | 🌟 Like it? Gimme some love!
96 | [](https://github.com/afonsojramos/spotify-details-extractor/)
97 |
98 | If you find any bugs or places where podcasts are still showing up, please [create a new issue](https://github.com/afonsojramos/spotify-details-extractor/issues/new/choose) on the GitHub repo.
99 | 
100 |
--------------------------------------------------------------------------------
/spicetify/pnpm-lock.yaml:
--------------------------------------------------------------------------------
1 | lockfileVersion: '6.0'
2 |
3 | dependencies:
4 | '@types/react':
5 | specifier: ^18.2.6
6 | version: 18.2.6
7 | onchange:
8 | specifier: ^7.1.0
9 | version: 7.1.0
10 |
11 | packages:
12 |
13 | /@blakeembrey/deque@1.0.5:
14 | resolution: {integrity: sha512-6xnwtvp9DY1EINIKdTfvfeAtCYw4OqBZJhtiqkT3ivjnEfa25VQ3TsKvaFfKm8MyGIEfE95qLe+bNEt3nB0Ylg==}
15 | dev: false
16 |
17 | /@blakeembrey/template@1.1.0:
18 | resolution: {integrity: sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==}
19 | dev: false
20 |
21 | /@types/prop-types@15.7.5:
22 | resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
23 | dev: false
24 |
25 | /@types/react@18.2.6:
26 | resolution: {integrity: sha512-wRZClXn//zxCFW+ye/D2qY65UsYP1Fpex2YXorHc8awoNamkMZSvBxwxdYVInsHOZZd2Ppq8isnSzJL5Mpf8OA==}
27 | dependencies:
28 | '@types/prop-types': 15.7.5
29 | '@types/scheduler': 0.16.3
30 | csstype: 3.1.2
31 | dev: false
32 |
33 | /@types/scheduler@0.16.3:
34 | resolution: {integrity: sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==}
35 | dev: false
36 |
37 | /anymatch@3.1.3:
38 | resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
39 | engines: {node: '>= 8'}
40 | dependencies:
41 | normalize-path: 3.0.0
42 | picomatch: 2.3.1
43 | dev: false
44 |
45 | /arg@4.1.3:
46 | resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
47 | dev: false
48 |
49 | /binary-extensions@2.2.0:
50 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
51 | engines: {node: '>=8'}
52 | dev: false
53 |
54 | /braces@3.0.2:
55 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
56 | engines: {node: '>=8'}
57 | dependencies:
58 | fill-range: 7.0.1
59 | dev: false
60 |
61 | /chokidar@3.5.3:
62 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
63 | engines: {node: '>= 8.10.0'}
64 | dependencies:
65 | anymatch: 3.1.3
66 | braces: 3.0.2
67 | glob-parent: 5.1.2
68 | is-binary-path: 2.1.0
69 | is-glob: 4.0.3
70 | normalize-path: 3.0.0
71 | readdirp: 3.6.0
72 | optionalDependencies:
73 | fsevents: 2.3.2
74 | dev: false
75 |
76 | /cross-spawn@7.0.3:
77 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
78 | engines: {node: '>= 8'}
79 | dependencies:
80 | path-key: 3.1.1
81 | shebang-command: 2.0.0
82 | which: 2.0.2
83 | dev: false
84 |
85 | /csstype@3.1.2:
86 | resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
87 | dev: false
88 |
89 | /fill-range@7.0.1:
90 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
91 | engines: {node: '>=8'}
92 | dependencies:
93 | to-regex-range: 5.0.1
94 | dev: false
95 |
96 | /fsevents@2.3.2:
97 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
98 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
99 | os: [darwin]
100 | requiresBuild: true
101 | dev: false
102 | optional: true
103 |
104 | /glob-parent@5.1.2:
105 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
106 | engines: {node: '>= 6'}
107 | dependencies:
108 | is-glob: 4.0.3
109 | dev: false
110 |
111 | /ignore@5.2.4:
112 | resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
113 | engines: {node: '>= 4'}
114 | dev: false
115 |
116 | /is-binary-path@2.1.0:
117 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
118 | engines: {node: '>=8'}
119 | dependencies:
120 | binary-extensions: 2.2.0
121 | dev: false
122 |
123 | /is-extglob@2.1.1:
124 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
125 | engines: {node: '>=0.10.0'}
126 | dev: false
127 |
128 | /is-glob@4.0.3:
129 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
130 | engines: {node: '>=0.10.0'}
131 | dependencies:
132 | is-extglob: 2.1.1
133 | dev: false
134 |
135 | /is-number@7.0.0:
136 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
137 | engines: {node: '>=0.12.0'}
138 | dev: false
139 |
140 | /isexe@2.0.0:
141 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
142 | dev: false
143 |
144 | /normalize-path@3.0.0:
145 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
146 | engines: {node: '>=0.10.0'}
147 | dev: false
148 |
149 | /onchange@7.1.0:
150 | resolution: {integrity: sha512-ZJcqsPiWUAUpvmnJri5TPBooqJOPmC0ttN65juhN15Q8xA+Nbg3BaxBHXQ45EistKKlKElb0edmbPWnKSBkvMg==}
151 | hasBin: true
152 | dependencies:
153 | '@blakeembrey/deque': 1.0.5
154 | '@blakeembrey/template': 1.1.0
155 | arg: 4.1.3
156 | chokidar: 3.5.3
157 | cross-spawn: 7.0.3
158 | ignore: 5.2.4
159 | tree-kill: 1.2.2
160 | dev: false
161 |
162 | /path-key@3.1.1:
163 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
164 | engines: {node: '>=8'}
165 | dev: false
166 |
167 | /picomatch@2.3.1:
168 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
169 | engines: {node: '>=8.6'}
170 | dev: false
171 |
172 | /readdirp@3.6.0:
173 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
174 | engines: {node: '>=8.10.0'}
175 | dependencies:
176 | picomatch: 2.3.1
177 | dev: false
178 |
179 | /shebang-command@2.0.0:
180 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
181 | engines: {node: '>=8'}
182 | dependencies:
183 | shebang-regex: 3.0.0
184 | dev: false
185 |
186 | /shebang-regex@3.0.0:
187 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
188 | engines: {node: '>=8'}
189 | dev: false
190 |
191 | /to-regex-range@5.0.1:
192 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
193 | engines: {node: '>=8.0'}
194 | dependencies:
195 | is-number: 7.0.0
196 | dev: false
197 |
198 | /tree-kill@1.2.2:
199 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
200 | hasBin: true
201 | dev: false
202 |
203 | /which@2.0.2:
204 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
205 | engines: {node: '>= 8'}
206 | hasBin: true
207 | dependencies:
208 | isexe: 2.0.0
209 | dev: false
210 |
--------------------------------------------------------------------------------
/spicetify/globals.d.ts:
--------------------------------------------------------------------------------
1 | declare namespace Spicetify {
2 | type Icon =
3 | | "album"
4 | | "artist"
5 | | "block"
6 | | "brightness"
7 | | "car"
8 | | "chart-down"
9 | | "chart-up"
10 | | "check"
11 | | "check-alt-fill"
12 | | "chevron-left"
13 | | "chevron-right"
14 | | "chromecast-disconnected"
15 | | "clock"
16 | | "collaborative"
17 | | "computer"
18 | | "copy"
19 | | "download"
20 | | "downloaded"
21 | | "edit"
22 | | "enhance"
23 | | "exclamation-circle"
24 | | "external-link"
25 | | "facebook"
26 | | "follow"
27 | | "fullscreen"
28 | | "gamepad"
29 | | "grid-view"
30 | | "heart"
31 | | "heart-active"
32 | | "instagram"
33 | | "laptop"
34 | | "library"
35 | | "list-view"
36 | | "location"
37 | | "locked"
38 | | "locked-active"
39 | | "lyrics"
40 | | "menu"
41 | | "minimize"
42 | | "minus"
43 | | "more"
44 | | "new-spotify-connect"
45 | | "offline"
46 | | "pause"
47 | | "phone"
48 | | "play"
49 | | "playlist"
50 | | "playlist-folder"
51 | | "plus-alt"
52 | | "plus2px"
53 | | "podcasts"
54 | | "projector"
55 | | "queue"
56 | | "repeat"
57 | | "repeat-once"
58 | | "search"
59 | | "search-active"
60 | | "shuffle"
61 | | "skip-back"
62 | | "skip-back15"
63 | | "skip-forward"
64 | | "skip-forward15"
65 | | "soundbetter"
66 | | "speaker"
67 | | "spotify"
68 | | "subtitles"
69 | | "tablet"
70 | | "ticket"
71 | | "twitter"
72 | | "visualizer"
73 | | "voice"
74 | | "volume"
75 | | "volume-off"
76 | | "volume-one-wave"
77 | | "volume-two-wave"
78 | | "watch"
79 | | "x";
80 | type Variant =
81 | | "bass"
82 | | "forte"
83 | | "brio"
84 | | "altoBrio"
85 | | "alto"
86 | | "canon"
87 | | "celloCanon"
88 | | "cello"
89 | | "ballad"
90 | | "balladBold"
91 | | "viola"
92 | | "violaBold"
93 | | "mesto"
94 | | "mestoBold"
95 | | "metronome"
96 | | "finale"
97 | | "finaleBold"
98 | | "minuet"
99 | | "minuetBold";
100 | type SemanticColor =
101 | | "textBase"
102 | | "textSubdued"
103 | | "textBrightAccent"
104 | | "textNegative"
105 | | "textWarning"
106 | | "textPositive"
107 | | "textAnnouncement"
108 | | "essentialBase"
109 | | "essentialSubdued"
110 | | "essentialBrightAccent"
111 | | "essentialNegative"
112 | | "essentialWarning"
113 | | "essentialPositive"
114 | | "essentialAnnouncement"
115 | | "decorativeBase"
116 | | "decorativeSubdued"
117 | | "backgroundBase"
118 | | "backgroundHighlight"
119 | | "backgroundPress"
120 | | "backgroundElevatedBase"
121 | | "backgroundElevatedHighlight"
122 | | "backgroundElevatedPress"
123 | | "backgroundTintedBase"
124 | | "backgroundTintedHighlight"
125 | | "backgroundTintedPress"
126 | | "backgroundUnsafeForSmallTextBase"
127 | | "backgroundUnsafeForSmallTextHighlight"
128 | | "backgroundUnsafeForSmallTextPress";
129 | type Metadata = Partial