diff --git a/Dribbblish/README.md b/Dribbblish/README.md
index b1c98f4..c5ec7a6 100644
--- a/Dribbblish/README.md
+++ b/Dribbblish/README.md
@@ -57,11 +57,8 @@ Run these commands:
In **Bash**:
```bash
cd "$(dirname "$(spicetify -c)")/Themes/Dribbblish"
-mkdir -p ../../Extensions
-cp dribbblish.js ../../Extensions/.
-spicetify config extensions dribbblish.js
spicetify config current_theme Dribbblish color_scheme base
-spicetify config inject_css 1 replace_colors 1 overwrite_assets 1
+spicetify config inject_css 1 replace_colors 1 overwrite_assets 1 inject_theme_js 1
spicetify apply
```
@@ -69,10 +66,8 @@ spicetify apply
In **Powershell**:
```powershell
cd "$(spicetify -c | Split-Path)\Themes\Dribbblish"
-Copy-Item dribbblish.js ..\..\Extensions
-spicetify config extensions dribbblish.js
spicetify config current_theme Dribbblish color_scheme base
-spicetify config inject_css 1 replace_colors 1 overwrite_assets 1
+spicetify config inject_css 1 replace_colors 1 overwrite_assets 1 inject_theme_js 1
spicetify apply
```
@@ -97,12 +92,9 @@ Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/spicetify/
```
## Manual uninstall
-Remove the dribbblish script with the following commands
+Remove the dribbblish theme with the following commands
```
-spicetify config extensions dribbblish.js-
-```
-And remove Patch lines you added in config file earlier. Finally, run:
-```
+spicetify config current_theme " " color_scheme " "
spicetify apply
```
diff --git a/Dribbblish/install.ps1 b/Dribbblish/install.ps1
index 604ddd3..2d8a626 100644
--- a/Dribbblish/install.ps1
+++ b/Dribbblish/install.ps1
@@ -26,13 +26,9 @@ if (Test-Path $destPath) {
}
Copy-Item $dribPath $destPath -Recurse
-# Copy extension file
-New-Item -ItemType Directory -Force "$spicePath\Extensions"
-Copy-Item "$destPath\dribbblish.js" "$spicePath\Extensions"
-
Write-Host "Configuring:" -ForegroundColor Green
spicetify
-spicetify config inject_css 1 replace_colors 1 overwrite_assets 1 current_theme Dribbblish extensions dribbblish.js
+spicetify config inject_css 1 replace_colors 1 overwrite_assets 1 inject_theme_js 1 current_theme Dribbblish
# Add patch
$configFile = Get-Content "$spicePath\config-xpui.ini"
diff --git a/Dribbblish/dribbblish.js b/Dribbblish/theme.js
similarity index 97%
rename from Dribbblish/dribbblish.js
rename to Dribbblish/theme.js
index 969da73..4cf51e8 100644
--- a/Dribbblish/dribbblish.js
+++ b/Dribbblish/theme.js
@@ -1,266 +1,266 @@
-// Hide popover message
-// document.getElementById("popover-container").style.height = 0;
-const DribbblishShared = {
- configMenu: new Spicetify.Menu.SubMenu("Dribbblish", []),
- rightBigCover: localStorage.getItem("dribs-right-big-cover") === "true",
- setRightBigCover: () => {
- if (DribbblishShared.rightBigCover) {
- document.documentElement.classList.add("right-expanded-cover");
- } else {
- document.documentElement.classList.remove("right-expanded-cover");
- }
- }
-};
-
-// register drib menu item
-DribbblishShared.configMenu.register();
-DribbblishShared.configMenu.addItem(new Spicetify.Menu.Item(
- "Right expanded cover",
- DribbblishShared.rightBigCover,
- (self) => {
- self.isEnabled = !self.isEnabled;
- DribbblishShared.rightBigCover = self.isEnabled;
- localStorage.setItem("dribs-right-big-cover", self.isEnabled);
- DribbblishShared.setRightBigCover();
- }
-));
-DribbblishShared.setRightBigCover();
-
-function waitForElement(els, func, timeout = 100) {
- const queries = els.map(el => document.querySelector(el));
- if (queries.every(a => a)) {
- func(queries);
- } else if (timeout > 0) {
- setTimeout(waitForElement, 300, els, func, --timeout);
- }
-}
-
-waitForElement([
- `ul[tabindex="0"]`,
- `ul[tabindex="0"] .GlueDropTarget--playlists.GlueDropTarget--folders`
-], ([root, firstItem]) => {
- const listElem = firstItem.parentElement;
- root.classList.add("dribs-playlist-list");
-
- /** Replace Playlist name with their pictures */
- function loadPlaylistImage() {
- for (const item of listElem.children) {
- let link = item.querySelector("a");
- if (!link) continue;
-
- let [_, app, uid ] = link.pathname.split("/");
- let uri;
- if (app === "playlist") {
- uri = `spotify:playlist:${uid}`;
- } else if (app === "folder") {
- const base64 = localStorage.getItem("dribbblish:folder-image:" + uid);
- let img = link.querySelector("img");
- if (!img) {
- img = document.createElement("img");
- img.classList.add("playlist-picture");
- link.prepend(img);
- }
- img.src = base64 || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
- continue;
- }
-
- Spicetify.CosmosAsync.get(
- `sp://core-playlist/v1/playlist/${uri}/metadata`,
- { policy: { picture: true } }
- ).then(res => {
- const meta = res.metadata;
- let img = link.querySelector("img");
- if (!img) {
- img = document.createElement("img");
- img.classList.add("playlist-picture");
- link.prepend(img);
- }
- img.src = meta.picture || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
- });
- }
- }
-
- DribbblishShared.loadPlaylistImage = loadPlaylistImage;
- loadPlaylistImage();
-
- new MutationObserver(loadPlaylistImage)
- .observe(listElem, {childList: true});
-});
-
-waitForElement([".Root__top-container"], ([topContainer]) => {
- const shadow = document.createElement("div");
- shadow.id = "dribbblish-back-shadow";
- topContainer.prepend(shadow);
-});
-
-// allow resizing of the navbar
-waitForElement([
- ".Root__nav-bar .LayoutResizer__input, .Root__nav-bar .LayoutResizer__resize-bar input"
-], ([resizer]) => {
- const observer = new MutationObserver(updateVariable);
- observer.observe(resizer, { attributes: true, attributeFilter: ["value"]});
- function updateVariable() {
- let value = resizer.value;
- if (value < 121) {
- value = 72;
- document.documentElement.classList.add("sidebar-hide-text");
- } else {
- document.documentElement.classList.remove("sidebar-hide-text");
- }
- document.documentElement.style.setProperty(
- "--sidebar-width", value + "px");
- }
- updateVariable();
-});
-
-// allow resizing of the buddy feed
-waitForElement([".Root__right-sidebar .LayoutResizer__input, .Root__right-sidebar .LayoutResizer__resize-bar input"], ([resizer]) => {
- const observer = new MutationObserver(updateVariable);
- observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
- function updateVariable() {
- let value = resizer.value;
- if (value == 320) {
- value = 72;
- document.documentElement.classList.add("buddyFeed-hide-text");
- } else {
- document.documentElement.classList.remove("buddyFeed-hide-text");
- }
- }
- updateVariable();
-});
-
-// add fade effect on playlist/folder list
-waitForElement([".main-navBar-navBar .os-viewport.os-viewport-native-scrollbars-invisible"], ([scrollNode]) => {
- scrollNode.setAttribute("fade", "bottom");
- scrollNode.addEventListener("scroll", () => {
- if (scrollNode.scrollTop == 0) {
- scrollNode.setAttribute("fade", "bottom");
- } else if (scrollNode.scrollHeight - scrollNode.clientHeight - scrollNode.scrollTop == 0) {
- scrollNode.setAttribute("fade", "top");
- } else {
- scrollNode.setAttribute("fade", "full");
- }
- });
-});
-
-// improve styles at smaller sizes
-waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) => {
- const observer = new ResizeObserver(updateVariable);
- observer.observe(resizeHost);
- function updateVariable([ event ]) {
- document.documentElement.style.setProperty(
- "--main-view-width", event.contentRect.width + "px");
- if (event.contentRect.width < 700) {
- document.documentElement.classList.add("minimal-player");
- } else {
- document.documentElement.classList.remove("minimal-player");
- }
- if (event.contentRect.width < 550) {
- document.documentElement.classList.add("extra-minimal-player");
- } else {
- document.documentElement.classList.remove("extra-minimal-player");
- }
- }
-});
-
-(function Dribbblish() {
- // dynamic playback time tooltip
- const progBar = document.querySelector(".playback-bar");
- const root = document.querySelector(".Root");
-
- if (!Spicetify.Player.origin || !progBar || !root) {
- setTimeout(Dribbblish, 300);
- return;
- }
-
- const tooltip = document.createElement("div");
- tooltip.className = "prog-tooltip";
- progBar.append(tooltip);
-
- const progKnob = progBar.querySelector(".progress-bar__slider");
-
- function updateProgTime({ data: e }) {
- const offsetX = progKnob.offsetLeft + progKnob.offsetWidth / 2;
- const maxWidth = progBar.offsetWidth;
- const curWidth = Spicetify.Player.getProgressPercent() * maxWidth;
- const ttWidth = tooltip.offsetWidth / 2;
- if (curWidth < ttWidth) {
- tooltip.style.left = String(offsetX) + "px";
- } else if (curWidth > maxWidth - ttWidth) {
- tooltip.style.left = String(offsetX - ttWidth * 2) + "px";
- } else {
- tooltip.style.left = String(offsetX - ttWidth) + "px";
- }
- tooltip.innerText = Spicetify.Player.formatTime(e) + " / " +
- Spicetify.Player.formatTime(Spicetify.Player.getDuration());
- }
- Spicetify.Player.addEventListener("onprogress", updateProgTime);
- updateProgTime({ data: Spicetify.Player.getProgress() });
-
- Spicetify.CosmosAsync.sub("sp://connect/v1", (state) => {
- const isExternal = state.devices.some(a => a.is_active);
- if (isExternal) {
- root.classList.add("is-connectBarVisible");
- } else {
- root.classList.remove("is-connectBarVisible");
- }
- });
-
- // filepicker for custom folder images
- const filePickerForm = document.createElement("form");
- filePickerForm.setAttribute("aria-hidden", true);
- filePickerForm.innerHTML = '';
- document.body.appendChild(filePickerForm);
- /** @type {HTMLInputElement} */
- const filePickerInput = filePickerForm.childNodes[0];
- filePickerInput.accept = [
- "image/jpeg",
- "image/apng",
- "image/avif",
- "image/gif",
- "image/png",
- "image/svg+xml",
- "image/webp"
- ].join(",");
-
- filePickerInput.onchange = () => {
- if (!filePickerInput.files.length) return;
-
- const file = filePickerInput.files[0];
- const reader = new FileReader;
- reader.onload = (event) => {
- const result = event.target.result;
- const id = Spicetify.URI.from(filePickerInput.uri).id;
- try {
- localStorage.setItem(
- "dribbblish:folder-image:" + id,
- result
- );
- } catch {
- Spicetify.showNotification("File too large");
- }
- DribbblishShared.loadPlaylistImage?.call();
- }
- reader.readAsDataURL(file);
- }
-
- // context menu items for custom folder images
- new Spicetify.ContextMenu.Item("Remove folder image",
- ([uri]) => {
- const id = Spicetify.URI.from(uri).id;
- localStorage.removeItem("dribbblish:folder-image:" + id);
- DribbblishShared.loadPlaylistImage?.call();
- },
- ([uri]) => Spicetify.URI.isFolder(uri),
- "x",
- ).register();
- new Spicetify.ContextMenu.Item("Choose folder image",
- ([uri]) => {
- filePickerInput.uri = uri;
- filePickerForm.reset();
- filePickerInput.click();
- },
- ([uri]) => Spicetify.URI.isFolder(uri),
- "edit",
- ).register();
-})();
+// Hide popover message
+// document.getElementById("popover-container").style.height = 0;
+const DribbblishShared = {
+ configMenu: new Spicetify.Menu.SubMenu("Dribbblish", []),
+ rightBigCover: localStorage.getItem("dribs-right-big-cover") === "true",
+ setRightBigCover: () => {
+ if (DribbblishShared.rightBigCover) {
+ document.documentElement.classList.add("right-expanded-cover");
+ } else {
+ document.documentElement.classList.remove("right-expanded-cover");
+ }
+ }
+};
+
+// register drib menu item
+DribbblishShared.configMenu.register();
+DribbblishShared.configMenu.addItem(new Spicetify.Menu.Item(
+ "Right expanded cover",
+ DribbblishShared.rightBigCover,
+ (self) => {
+ self.isEnabled = !self.isEnabled;
+ DribbblishShared.rightBigCover = self.isEnabled;
+ localStorage.setItem("dribs-right-big-cover", self.isEnabled);
+ DribbblishShared.setRightBigCover();
+ }
+));
+DribbblishShared.setRightBigCover();
+
+function waitForElement(els, func, timeout = 100) {
+ const queries = els.map(el => document.querySelector(el));
+ if (queries.every(a => a)) {
+ func(queries);
+ } else if (timeout > 0) {
+ setTimeout(waitForElement, 300, els, func, --timeout);
+ }
+}
+
+waitForElement([
+ `ul[tabindex="0"]`,
+ `ul[tabindex="0"] .GlueDropTarget--playlists.GlueDropTarget--folders`
+], ([root, firstItem]) => {
+ const listElem = firstItem.parentElement;
+ root.classList.add("dribs-playlist-list");
+
+ /** Replace Playlist name with their pictures */
+ function loadPlaylistImage() {
+ for (const item of listElem.children) {
+ let link = item.querySelector("a");
+ if (!link) continue;
+
+ let [_, app, uid ] = link.pathname.split("/");
+ let uri;
+ if (app === "playlist") {
+ uri = `spotify:playlist:${uid}`;
+ } else if (app === "folder") {
+ const base64 = localStorage.getItem("dribbblish:folder-image:" + uid);
+ let img = link.querySelector("img");
+ if (!img) {
+ img = document.createElement("img");
+ img.classList.add("playlist-picture");
+ link.prepend(img);
+ }
+ img.src = base64 || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
+ continue;
+ }
+
+ Spicetify.CosmosAsync.get(
+ `sp://core-playlist/v1/playlist/${uri}/metadata`,
+ { policy: { picture: true } }
+ ).then(res => {
+ const meta = res.metadata;
+ let img = link.querySelector("img");
+ if (!img) {
+ img = document.createElement("img");
+ img.classList.add("playlist-picture");
+ link.prepend(img);
+ }
+ img.src = meta.picture || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
+ });
+ }
+ }
+
+ DribbblishShared.loadPlaylistImage = loadPlaylistImage;
+ loadPlaylistImage();
+
+ new MutationObserver(loadPlaylistImage)
+ .observe(listElem, {childList: true});
+});
+
+waitForElement([".Root__top-container"], ([topContainer]) => {
+ const shadow = document.createElement("div");
+ shadow.id = "dribbblish-back-shadow";
+ topContainer.prepend(shadow);
+});
+
+// allow resizing of the navbar
+waitForElement([
+ ".Root__nav-bar .LayoutResizer__input, .Root__nav-bar .LayoutResizer__resize-bar input"
+], ([resizer]) => {
+ const observer = new MutationObserver(updateVariable);
+ observer.observe(resizer, { attributes: true, attributeFilter: ["value"]});
+ function updateVariable() {
+ let value = resizer.value;
+ if (value < 121) {
+ value = 72;
+ document.documentElement.classList.add("sidebar-hide-text");
+ } else {
+ document.documentElement.classList.remove("sidebar-hide-text");
+ }
+ document.documentElement.style.setProperty(
+ "--sidebar-width", value + "px");
+ }
+ updateVariable();
+});
+
+// allow resizing of the buddy feed
+waitForElement([".Root__right-sidebar .LayoutResizer__input, .Root__right-sidebar .LayoutResizer__resize-bar input"], ([resizer]) => {
+ const observer = new MutationObserver(updateVariable);
+ observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
+ function updateVariable() {
+ let value = resizer.value;
+ if (value == 320) {
+ value = 72;
+ document.documentElement.classList.add("buddyFeed-hide-text");
+ } else {
+ document.documentElement.classList.remove("buddyFeed-hide-text");
+ }
+ }
+ updateVariable();
+});
+
+// add fade effect on playlist/folder list
+waitForElement([".main-navBar-navBar .os-viewport.os-viewport-native-scrollbars-invisible"], ([scrollNode]) => {
+ scrollNode.setAttribute("fade", "bottom");
+ scrollNode.addEventListener("scroll", () => {
+ if (scrollNode.scrollTop == 0) {
+ scrollNode.setAttribute("fade", "bottom");
+ } else if (scrollNode.scrollHeight - scrollNode.clientHeight - scrollNode.scrollTop == 0) {
+ scrollNode.setAttribute("fade", "top");
+ } else {
+ scrollNode.setAttribute("fade", "full");
+ }
+ });
+});
+
+// improve styles at smaller sizes
+waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) => {
+ const observer = new ResizeObserver(updateVariable);
+ observer.observe(resizeHost);
+ function updateVariable([ event ]) {
+ document.documentElement.style.setProperty(
+ "--main-view-width", event.contentRect.width + "px");
+ if (event.contentRect.width < 700) {
+ document.documentElement.classList.add("minimal-player");
+ } else {
+ document.documentElement.classList.remove("minimal-player");
+ }
+ if (event.contentRect.width < 550) {
+ document.documentElement.classList.add("extra-minimal-player");
+ } else {
+ document.documentElement.classList.remove("extra-minimal-player");
+ }
+ }
+});
+
+(function Dribbblish() {
+ // dynamic playback time tooltip
+ const progBar = document.querySelector(".playback-bar");
+ const root = document.querySelector(".Root");
+
+ if (!Spicetify.Player.origin || !progBar || !root) {
+ setTimeout(Dribbblish, 300);
+ return;
+ }
+
+ const tooltip = document.createElement("div");
+ tooltip.className = "prog-tooltip";
+ progBar.append(tooltip);
+
+ const progKnob = progBar.querySelector(".progress-bar__slider");
+
+ function updateProgTime({ data: e }) {
+ const offsetX = progKnob.offsetLeft + progKnob.offsetWidth / 2;
+ const maxWidth = progBar.offsetWidth;
+ const curWidth = Spicetify.Player.getProgressPercent() * maxWidth;
+ const ttWidth = tooltip.offsetWidth / 2;
+ if (curWidth < ttWidth) {
+ tooltip.style.left = String(offsetX) + "px";
+ } else if (curWidth > maxWidth - ttWidth) {
+ tooltip.style.left = String(offsetX - ttWidth * 2) + "px";
+ } else {
+ tooltip.style.left = String(offsetX - ttWidth) + "px";
+ }
+ tooltip.innerText = Spicetify.Player.formatTime(e) + " / " +
+ Spicetify.Player.formatTime(Spicetify.Player.getDuration());
+ }
+ Spicetify.Player.addEventListener("onprogress", updateProgTime);
+ updateProgTime({ data: Spicetify.Player.getProgress() });
+
+ Spicetify.CosmosAsync.sub("sp://connect/v1", (state) => {
+ const isExternal = state.devices.some(a => a.is_active);
+ if (isExternal) {
+ root.classList.add("is-connectBarVisible");
+ } else {
+ root.classList.remove("is-connectBarVisible");
+ }
+ });
+
+ // filepicker for custom folder images
+ const filePickerForm = document.createElement("form");
+ filePickerForm.setAttribute("aria-hidden", true);
+ filePickerForm.innerHTML = '';
+ document.body.appendChild(filePickerForm);
+ /** @type {HTMLInputElement} */
+ const filePickerInput = filePickerForm.childNodes[0];
+ filePickerInput.accept = [
+ "image/jpeg",
+ "image/apng",
+ "image/avif",
+ "image/gif",
+ "image/png",
+ "image/svg+xml",
+ "image/webp"
+ ].join(",");
+
+ filePickerInput.onchange = () => {
+ if (!filePickerInput.files.length) return;
+
+ const file = filePickerInput.files[0];
+ const reader = new FileReader;
+ reader.onload = (event) => {
+ const result = event.target.result;
+ const id = Spicetify.URI.from(filePickerInput.uri).id;
+ try {
+ localStorage.setItem(
+ "dribbblish:folder-image:" + id,
+ result
+ );
+ } catch {
+ Spicetify.showNotification("File too large");
+ }
+ DribbblishShared.loadPlaylistImage?.call();
+ }
+ reader.readAsDataURL(file);
+ }
+
+ // context menu items for custom folder images
+ new Spicetify.ContextMenu.Item("Remove folder image",
+ ([uri]) => {
+ const id = Spicetify.URI.from(uri).id;
+ localStorage.removeItem("dribbblish:folder-image:" + id);
+ DribbblishShared.loadPlaylistImage?.call();
+ },
+ ([uri]) => Spicetify.URI.isFolder(uri),
+ "x",
+ ).register();
+ new Spicetify.ContextMenu.Item("Choose folder image",
+ ([uri]) => {
+ filePickerInput.uri = uri;
+ filePickerForm.reset();
+ filePickerInput.click();
+ },
+ ([uri]) => Spicetify.URI.isFolder(uri),
+ "edit",
+ ).register();
+})();
diff --git a/Dribbblish/uninstall.ps1 b/Dribbblish/uninstall.ps1
index ccf5757..df48c8c 100644
--- a/Dribbblish/uninstall.ps1
+++ b/Dribbblish/uninstall.ps1
@@ -1,4 +1,4 @@
-spicetify config current_theme " " extensions dribbblish.js-
+spicetify config current_theme " "
$configPath = spicetify -c
$configFile = Get-Content $configPath
diff --git a/Turntable/README.md b/Turntable/README.md
index f2e190e..3023bc2 100644
--- a/Turntable/README.md
+++ b/Turntable/README.md
@@ -43,19 +43,18 @@ spicetify config extensions fullAppDisplay.js
spicetify apply
```
-2. put **Turntable** and **turntable.js** into the **.config/spicetify**
+2. put **Turntable** into the **.config/spicetify**
```shell
cd spicetify-themes
cp -r Turntable ~/.config/spicetify/Themes
-cp Turntable/turntable.js ~/.config/spicetify/Extensions
```
-3. select the theme and extension, then apply
+3. select the theme, then apply
```shell
spicetify config current_theme Turntable
-spicetify config extensions turntable.js
+spicetify config inject_theme_js 1
spicetify apply
```
@@ -65,7 +64,6 @@ spicetify apply
```shell
rm -r ~/.config/spicetify/Themes/Turntable
-rm ~/.config/spicetify/Extensions/turntable.js
```
2. config to spicetify default theme
@@ -74,11 +72,10 @@ rm ~/.config/spicetify/Extensions/turntable.js
spicetify config current_theme SpicetifyDefault
```
-3. remove extension - Full App Display and Turntable(optional)
+3. remove extension - Full App Display
```shell
spicetify config extensions fullAppDisplay.js-
-spicetify config extensions turntable.js-
```
4. apply
diff --git a/Turntable/turntable.js b/Turntable/theme.js
similarity index 100%
rename from Turntable/turntable.js
rename to Turntable/theme.js
diff --git a/manifest.json b/manifest.json
index b12f8c8..3d52d16 100644
--- a/manifest.json
+++ b/manifest.json
@@ -49,7 +49,7 @@
"usercss": "Dribbblish/user.css",
"schemes": "Dribbblish/color.ini",
"include": [
- "https://raw.githubusercontent.com/spicetify/spicetify-themes/master/Dribbblish/dribbblish.js"
+ "https://raw.githubusercontent.com/spicetify/spicetify-themes/master/Dribbblish/theme.js"
],
"authors": [
{
@@ -94,7 +94,7 @@
"usercss": "Turntable/user.css",
"schemes": "Turntable/color.ini",
"include": [
- "https://raw.githubusercontent.com/spicetify/spicetify-themes/master/Turntable/turntable.js"
+ "https://raw.githubusercontent.com/spicetify/spicetify-themes/master/Turntable/theme.js"
],
"authors": [
{