Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/ianz56/spicetify-cli
Browse files Browse the repository at this point in the history
  • Loading branch information
ianz56 committed Feb 4, 2025
2 parents 57a08fe + e01ce58 commit b3107ea
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 35 deletions.
34 changes: 32 additions & 2 deletions Extensions/trashbin.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@
header.innerText = "Local Storage";
content.appendChild(header);

content.appendChild(createButton("Export", "Copy all items in trashbin to clipboard, manually save to a .json file.", exportItems));
content.appendChild(createButton("Copy", "Copy all items in trashbin to clipboard.", copyItems));
content.appendChild(createButton("Export", "Save all items in trashbin to a .json file.", exportItems));
content.appendChild(createButton("Import", "Overwrite all items in trashbin via .json file.", importItems));
content.appendChild(
createButton("Clear ", "Clear all items from trashbin (cannot be reverted).", () => {
Expand Down Expand Up @@ -361,7 +362,7 @@
Spicetify.LocalStorage.set("TrashArtistList", JSON.stringify(trashArtistList));
}

function exportItems() {
function copyItems() {
const data = {
songs: trashSongList,
artists: trashArtistList,
Expand All @@ -370,6 +371,35 @@
Spicetify.showNotification("Copied to clipboard");
}

async function exportItems() {
const data = {
songs: trashSongList,
artists: trashArtistList,
};

try {
const handle = await window.showSaveFilePicker({
suggestedName: "spicetify-trashbin.json",
types: [
{
description: "Spicetify trashbin backup",
accept: {
"application/json": [".json"],
},
},
],
});

const writable = await handle.createWritable();
await writable.write(JSON.stringify(data));
await writable.close();

Spicetify.showNotification("Backup saved succesfully.");
} catch {
Spicetify.showNotification("Failed to save, try copying trashbin contents to clipboard and creating a backup manually.");
}
}

function importItems() {
const input = document.createElement("input");
input.type = "file";
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ go 1.21

require (
github.com/go-ini/ini v1.67.0
github.com/mattn/go-colorable v0.1.13
golang.org/x/net v0.33.0
github.com/mattn/go-colorable v0.1.14
golang.org/x/net v0.34.0
)

require (
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.7.1 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/sys v0.29.0 // indirect
)
18 changes: 9 additions & 9 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
40 changes: 29 additions & 11 deletions jsHelper/expFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,25 +132,41 @@

(function waitForRemoteConfigResolver() {
// Don't show options if hooks aren't patched/loaded
if (!hooksPatched || (!Spicetify.RemoteConfigResolver && !Spicetify.Platform?.RemoteConfiguration)) {
if (!hooksPatched || (!Spicetify.RemoteConfigResolver && !Spicetify.Platform?.RemoteConfigDebugAPI && !Spicetify.Platform?.RemoteConfiguration)) {
setTimeout(waitForRemoteConfigResolver, 500);
return;
}

let remoteConfiguration = Spicetify.RemoteConfigResolver?.value.remoteConfiguration || Spicetify.Platform?.RemoteConfiguration;
let setOverrides = () => {};
const setOverrides = async (overrides) => {
if (Spicetify.Platform?.RemoteConfigDebugAPI) {
for (const [name, value] of Object.entries(overrides)) {
const feature = overrideList[name];
const type = feature.values ? "enum" : typeof value === "number" ? "number" : "boolean";
await Spicetify.Platform.RemoteConfigDebugAPI.setOverride(
{
source: "web",
type,
name,
},
value
);
}
} else if (Spicetify.RemoteConfigResolver?.value?.setOverrides) {
Spicetify.RemoteConfigResolver.value.setOverrides(Spicetify.createInternalMap?.(overrides));
}
};

(function waitForResolver() {
if (!Spicetify.RemoteConfigResolver) {
(async function waitForResolver() {
if (!Spicetify.RemoteConfigResolver && !Spicetify.Platform?.RemoteConfigDebugAPI) {
isFallback = true;
notice.innerText = "⚠️ Using fallback mode. Some features may not work.";
setTimeout(waitForResolver, 500);
return;
}
isFallback = false;
notice.remove();
remoteConfiguration = Spicetify.RemoteConfigResolver.value.remoteConfiguration;
setOverrides = Spicetify.RemoteConfigResolver.value.setOverrides;
remoteConfiguration = Spicetify?.RemoteConfigResolver?.remoteConfiguration ?? (await Spicetify.Platform?.RemoteConfigDebugAPI.getProperties());
})();

for (const key of Object.keys(overrideList)) {
Expand All @@ -165,7 +181,7 @@
localStorage.setItem("spicetify-exp-features", JSON.stringify(overrideList));

featureMap[name] = value;
setOverrides(Spicetify.createInternalMap?.(featureMap));
setOverrides({ [name]: value });
}

function createSlider(name, desc, defaultVal) {
Expand Down Expand Up @@ -254,8 +270,12 @@ ${Spicetify.SVGIcons.search}

for (const name of Object.keys(overrideList)) {
if (!prevSessionOverrideList.includes(name) && remoteConfiguration.values.has(name)) {
changeValue(name, remoteConfiguration.values.get(name));
console.log(name, remoteConfiguration.values.get(name), overrideList[name]);
const currentValue = remoteConfiguration.values.get(name);
overrideList[name].value = currentValue;
localStorage.setItem("spicetify-exp-features", JSON.stringify(overrideList));

featureMap[name] = currentValue;
setOverrides({ [name]: currentValue });
}

const feature = overrideList[name];
Expand All @@ -269,8 +289,6 @@ ${Spicetify.SVGIcons.search}
}

content.appendChild(resetButton);

setOverrides(Spicetify.createInternalMap?.(featureMap));
})();

await new Promise((res) => Spicetify.Events.webpackLoaded.on(res));
Expand Down
2 changes: 1 addition & 1 deletion jsHelper/homeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ SpicetifyHomeConfig = {};
const main = document.querySelector(".main-home-content");
elem = [...main.querySelectorAll("section")];
for (const [index, item] of elem.entries()) {
item.dataset.uri = list[index].uri ?? list[index].item.uri;
item.dataset.uri = list[index]?.uri ?? list[index].item?.uri;
}

function appendItems() {
Expand Down
8 changes: 8 additions & 0 deletions src/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,12 +413,20 @@ func insertExpFeatures(jsPath string, flags Flag) {
return fmt.Sprintf("%s%s=Spicetify.expFeatureOverride(%s);%s", submatches[1], submatches[2], submatches[2], submatches[3])
})

// utils.ReplaceOnce(
// &content,
// `(\w+\.fromJSON)(\s*=\s*function\b[^{]*{[^}]*})`,
// func(submatches ...string) string {
// return fmt.Sprintf("%s=Spicetify.createInternalMap%s", submatches[1], submatches[2])
// })

utils.ReplaceOnce(
&content,
`(([\w$.]+\.fromJSON)\(\w+\)+;)(return ?[\w{}().,]+[\w$]+\.Provider,)(\{value:\{localConfiguration)`,
func(submatches ...string) string {
return fmt.Sprintf("%sSpicetify.createInternalMap=%s;%sSpicetify.RemoteConfigResolver=%s", submatches[1], submatches[2], submatches[3], submatches[4])
})

return content
})
}
Expand Down
6 changes: 3 additions & 3 deletions src/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (
var (
spicetifyFolder = utils.GetSpicetifyFolder()
rawFolder, themedFolder = getExtractFolder()
backupFolder = utils.GetUserFolder("Backup")
userThemesFolder = utils.GetUserFolder("Themes")
backupFolder = utils.GetStateFolder("Backup")
userThemesFolder = utils.GetSubFolder(spicetifyFolder, "Themes")
quiet bool
isAppX = false
spotifyPath string
Expand Down Expand Up @@ -205,7 +205,7 @@ func GetSpotifyPath() string {
}

func getExtractFolder() (string, string) {
dir := utils.GetUserFolder("Extracted")
dir := utils.GetStateFolder("Extracted")

raw := filepath.Join(dir, "Raw")
utils.CheckExistAndCreate(raw)
Expand Down
41 changes: 36 additions & 5 deletions src/utils/path-utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,48 @@ func GetSpicetifyFolder() string {
return result
}

// getUserFolder checks if folder `name` is available in spicetifyFolder,
func GetStateFolder(name string) string {
result, isAvailable := os.LookupEnv("SPICETIFY_STATE")
defer func() { CheckExistAndCreate(result) }()

if isAvailable && len(result) > 0 {
return result
}

if runtime.GOOS == "windows" {
parent := os.Getenv("APPDATA")

result = filepath.Join(parent, "spicetify")
} else if runtime.GOOS == "linux" {
parent, isAvailable := os.LookupEnv("XDG_STATE_HOME")

if !isAvailable || len(parent) == 0 {
parent = filepath.Join(os.Getenv("HOME"), ".local", "state")
CheckExistAndCreate(parent)
}

result = filepath.Join(parent, "spicetify")
} else if runtime.GOOS == "darwin" {
parent := filepath.Join(os.Getenv("HOME"), ".local", "state")
CheckExistAndCreate(parent)

result = filepath.Join(parent, "spicetify")
}

return GetSubFolder(result, name)
}

// GetSubFolder checks if folder `name` is available in specified folder,
// else creates then returns the path.
func GetUserFolder(name string) string {
dir := filepath.Join(GetSpicetifyFolder(), name)
func GetSubFolder(folder string, name string) string {
dir := filepath.Join(folder, name)
CheckExistAndCreate(dir)

return dir
}

var userAppsFolder = GetUserFolder("CustomApps")
var userExtensionsFolder = GetUserFolder("Extensions")
var userAppsFolder = GetSubFolder(GetSpicetifyFolder(), "CustomApps")
var userExtensionsFolder = GetSubFolder(GetSpicetifyFolder(), "Extensions")

func GetCustomAppSubfolderPath(folderPath string) string {
entries, err := os.ReadDir(folderPath)
Expand Down

0 comments on commit b3107ea

Please sign in to comment.