spicetify added
This commit is contained in:
parent
030529e98c
commit
a9eeb3517a
16 changed files with 6513 additions and 0 deletions
59
.config/spicetify/Extensions/adblock.js
Normal file
59
.config/spicetify/Extensions/adblock.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
//@ts-check
|
||||
|
||||
// NAME: adblock
|
||||
// AUTHOR: CharlieS1103
|
||||
// DESCRIPTION: Block all audio and UI ads on Spotify
|
||||
|
||||
/// <reference path="../../spicetify-cli/globals.d.ts" />
|
||||
|
||||
(function adblock() {
|
||||
const { Platform} = Spicetify;
|
||||
if (!(Platform)) {
|
||||
setTimeout(adblock, 300)
|
||||
return
|
||||
}
|
||||
|
||||
var styleSheet = document.createElement("style")
|
||||
|
||||
styleSheet.innerHTML =
|
||||
`
|
||||
.MnW5SczTcbdFHxLZ_Z8j, .WiPggcPDzbwGxoxwLWFf, .ReyA3uE3K7oEz7PTTnAn, .main-leaderboardComponent-container, .sponsor-container, a.link-subtle.main-navBar-navBarLink.GKnnhbExo0U9l7Jz2rdc{
|
||||
display: none !important;
|
||||
}
|
||||
`
|
||||
document.body.appendChild(styleSheet)
|
||||
delayAds()
|
||||
var billboard = Spicetify.Platform.AdManagers.billboard.displayBillboard;
|
||||
Spicetify.Platform.AdManagers.billboard.displayBillboard = function (arguments) {
|
||||
Spicetify.Platform.AdManagers.billboard.finish()
|
||||
// hook before call
|
||||
var ret = billboard.apply(this, arguments);
|
||||
// hook after call
|
||||
console.log("Adblock.js: Billboard blocked! Leave a star!")
|
||||
Spicetify.Platform.AdManagers.billboard.finish()
|
||||
const observer = new MutationObserver((mutations, obs) => {
|
||||
const billboardAd = document.getElementById('view-billboard-ad');
|
||||
if (billboardAd) {
|
||||
Spicetify.Platform.AdManagers.billboard.finish()
|
||||
obs.disconnect();
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(document, {
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
function delayAds() {
|
||||
console.log("Ads delayed: Adblock.js")
|
||||
Spicetify.Platform.AdManagers.audio.audioApi.cosmosConnector.increaseStreamTime(-100000000000)
|
||||
Spicetify.Platform.AdManagers.billboard.billboardApi.cosmosConnector.increaseStreamTime(-100000000000)
|
||||
}
|
||||
setInterval(delayAds, 720 *10000);
|
||||
|
||||
|
||||
})()
|
||||
|
||||
|
39
.config/spicetify/Extensions/catppuccin-macchiato.js
Normal file
39
.config/spicetify/Extensions/catppuccin-macchiato.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
// Color map
|
||||
let colorPalette = {
|
||||
rosewater: "#f4dbd6",
|
||||
flamingo: "#f0c6c6",
|
||||
pink: "#f5bde6",
|
||||
maroon: "#ee99a0",
|
||||
red: "#ed8796",
|
||||
peach: "#f5a97f",
|
||||
yellow: "#eed49f",
|
||||
green: "#a6da95",
|
||||
teal: "#8bd5ca",
|
||||
blue: "#8aadf4",
|
||||
sky: "#91d7e3",
|
||||
lavender: "#b7bdf8",
|
||||
white: "#d9e0ee"
|
||||
}
|
||||
|
||||
// waitForElement borrowed from:
|
||||
// https://github.com/morpheusthewhite/spicetify-themes/blob/master/Dribbblish/dribbblish.js
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the color label for a given hex color value
|
||||
function getKeyByValue(object, value) {
|
||||
return Object.keys(object).find(key => object[key] === value.trim());
|
||||
}
|
||||
|
||||
// Used to select matching equalizer-animated-COLOR.gif
|
||||
waitForElement([".Root"], (root) => {
|
||||
let spiceEq = getComputedStyle(document.querySelector(":root")).getPropertyValue("--spice-equalizer");
|
||||
let eqColor = getKeyByValue(colorPalette, spiceEq);
|
||||
root[0].classList.add(`catppuccin-eq-${eqColor}`);
|
||||
});
|
654
.config/spicetify/Extensions/copyPlaylist.js
Normal file
654
.config/spicetify/Extensions/copyPlaylist.js
Normal file
|
@ -0,0 +1,654 @@
|
|||
// NAME: Copy Playlists
|
||||
// AUTHOR: einzigartigerName
|
||||
// DESCRIPTION: copy/combine playlist/queue directly in Spotify
|
||||
|
||||
(function CopyPlaylist() {
|
||||
|
||||
const { CosmosAPI, BridgeAPI, LocalStorage, PlaybackControl, ContextMenu, URI } = Spicetify
|
||||
if (!(CosmosAPI || BridgeAPI)) {
|
||||
setTimeout(CopyPlaylist, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
const STORAGE_KEY = "combine_buffer_spicetify"
|
||||
const TOP_BTN_TOOLTIP = "Combine Playlists"
|
||||
const MENU_BTN_CREATE_NEW = "Create Playlist"
|
||||
const MENU_BTN_INSERT_BUFFER = "Copy to Buffer"
|
||||
|
||||
class PlaylistCollection {
|
||||
constructor() {
|
||||
const menu = createMenu()
|
||||
this.container = menu.container
|
||||
this.items = menu.menu
|
||||
this.lastScroll = 0
|
||||
this.container.onclick = () => {
|
||||
this.storeScroll()
|
||||
this.container.remove()
|
||||
}
|
||||
this.pattern
|
||||
this.apply()
|
||||
}
|
||||
|
||||
apply() {
|
||||
this.items.textContent = '' // Remove all childs
|
||||
this.items.append(createMenuItem("Create Playlist", () => highjackCreateDialog(mergePlaylists(this.pattern))))
|
||||
this.items.append(createMenuItem("Clear Buffer", () => LIST.clearStorage()))
|
||||
|
||||
const select = createPatternSelect(this.filter);
|
||||
select.onchange = (event) => {
|
||||
this.pattern = event.srcElement.selectedIndex;
|
||||
}
|
||||
this.items.append(select);
|
||||
|
||||
const collection = this.getStorage();
|
||||
collection.forEach((item) => this.items.append(new CardContainer(item)))
|
||||
}
|
||||
|
||||
getStorage() {
|
||||
const storageRaw = LocalStorage.get(STORAGE_KEY);
|
||||
let storage = [];
|
||||
|
||||
if (storageRaw) {
|
||||
storage = JSON.parse(storageRaw);
|
||||
} else {
|
||||
LocalStorage.set(STORAGE_KEY, "[]")
|
||||
}
|
||||
|
||||
return storage;
|
||||
}
|
||||
|
||||
addToStorage(data) {
|
||||
|
||||
/** @type {Object[]} */
|
||||
const storage = this.getStorage();
|
||||
storage.push(data);
|
||||
|
||||
LocalStorage.set(STORAGE_KEY, JSON.stringify(storage));
|
||||
this.apply()
|
||||
}
|
||||
|
||||
removeFromStorage(id) {
|
||||
const storage = this.getStorage()
|
||||
.filter(item => item.id !== id)
|
||||
|
||||
LocalStorage.set(STORAGE_KEY, JSON.stringify(storage));
|
||||
this.apply()
|
||||
}
|
||||
|
||||
clearStorage() {
|
||||
LocalStorage.set(STORAGE_KEY, "[]");
|
||||
this.apply()
|
||||
}
|
||||
|
||||
moveItem(uri, direction) {
|
||||
var storage = this.getStorage()
|
||||
|
||||
var from;
|
||||
|
||||
for (var i = 0; i < storage.length; i++) {
|
||||
if (storage[i].uri === uri) {
|
||||
from = i
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!from) { return }
|
||||
|
||||
var to = from + direction
|
||||
if (to < 0 || to >= storage.length) { return }
|
||||
|
||||
var tmp = storage[from]
|
||||
storage[from] = storage[to]
|
||||
storage[to] = tmp
|
||||
|
||||
LocalStorage.set(STORAGE_KEY, JSON.stringify(storage));
|
||||
this.apply()
|
||||
}
|
||||
|
||||
changePosition(x, y) {
|
||||
this.items.style.left = x + "px"
|
||||
this.items.style.top = y + 10 + "px"
|
||||
}
|
||||
|
||||
storeScroll() {
|
||||
this.lastScroll = this.items.scrollTop
|
||||
}
|
||||
|
||||
setScroll() {
|
||||
this.items.scrollTop = this.lastScroll
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Displays Stored Playlist
|
||||
* {id, uri, name, tracks, imgUri, owner}
|
||||
*/
|
||||
class CardContainer extends HTMLElement {
|
||||
constructor(info) {
|
||||
super()
|
||||
|
||||
this.innerHTML = `
|
||||
<div class="card card-horizontal card-type-album ${info.imgUri ? "" : "card-hidden-image"}" data-uri="${info.uri}" data-contextmenu="">
|
||||
<div class="card-attention-highlight-box"></div>
|
||||
<div class="card-horizontal-interior-wrapper">
|
||||
${info.imgUri ? `
|
||||
<div class="card-image-wrapper">
|
||||
<div class="card-image-hit-area">
|
||||
<a class="card-image-link" link="${info.uri}">
|
||||
<div class="card-hit-area-counter-scale-left"></div>
|
||||
<div class="card-image-content-wrapper">
|
||||
<div class="card-image" style="background-image: url('${info.imgUri}')"></div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="card-overlay"></div>
|
||||
</div>
|
||||
</div>
|
||||
` : ""}
|
||||
<div class="card-info-wrapper">
|
||||
<div class="order-controls">
|
||||
<div class="order-controls-up">
|
||||
<button class="button button-green button-icon-only spoticon-chevron-up-16" data-tooltip="Move Up"></button>
|
||||
</div>
|
||||
<div class="order-controls-remove">
|
||||
<button class="button button-green button-icon-only spoticon-x-16" data-tooltip="Remove"></button>
|
||||
</div>
|
||||
<div class="order-controls-down">
|
||||
<button class="button button-green button-icon-only spoticon-chevron-down-16" data-tooltip="Move Down"></button>
|
||||
</div>
|
||||
</div>
|
||||
<a class="card-info-link" ${info.uri}>
|
||||
<div class="card-info-content-wrapper">
|
||||
<div class="card-info-title"><span class="card-info-title-text">${info.name}</span></div>
|
||||
<div class="card-info-subtitle-owner"><span>${info.owner}</span></div>
|
||||
<div class="card-info-subtitle-tracks"><span>${info.tracks.length === 1 ? "1 Track" : `${info.tracks.length} Tracks`}</span></div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
|
||||
const up = this.querySelector(".order-controls-up")
|
||||
up.onclick = (event) => {
|
||||
LIST.moveItem(info.uri, -1)
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
const remove = this.querySelector(".order-controls-remove")
|
||||
remove.onclick = (event) => {
|
||||
LIST.removeFromStorage(info.id)
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
const down = this.querySelector(".order-controls-down")
|
||||
down.onclick = (event) => {
|
||||
LIST.moveItem(info.uri, +1)
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
const imageLink = this.querySelector(".card-image-link");
|
||||
const infoLink = this.querySelector(".card-info-link");
|
||||
|
||||
if (imageLink) imageLink.addEventListener("click", ((e) => showPlaylist(e)));
|
||||
|
||||
if (infoLink) infoLink.addEventListener("click", ((e) => showPlaylist(e)));
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("combine-buffer-card-container", CardContainer)
|
||||
|
||||
const LIST = new PlaylistCollection()
|
||||
|
||||
// New Playlist Button
|
||||
const playlistDialogButton = document.querySelector("#new-playlist-button-mount-point > div > button")
|
||||
if (!playlistDialogButton) return;
|
||||
|
||||
document.querySelector("#view-browser-navigation-top-bar")
|
||||
.append(createTopBarButton())
|
||||
|
||||
createPlaylistContextMenu().register()
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
UI Building
|
||||
**************************************************************************/
|
||||
// If Queue Page add Buttons
|
||||
const iframeInterval = setInterval(() => {
|
||||
/** @type {HTMLIFrameElement} */
|
||||
const currentIframe = document.querySelector("iframe.active");
|
||||
if (!currentIframe ||
|
||||
currentIframe.id !== "app-queue"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const headers = currentIframe.contentDocument.querySelectorAll(
|
||||
".glue-page-header__buttons"
|
||||
);
|
||||
|
||||
for (const e of headers) {
|
||||
e.append(createQueueButton(
|
||||
"Save as Playlist",
|
||||
"Save the current Queue as a new Playlist",
|
||||
() => {
|
||||
let tracks = getQueueTracks();
|
||||
highjackCreateDialog(tracks);
|
||||
},
|
||||
));
|
||||
|
||||
e.append(createQueueButton(
|
||||
"Copy into Buffer",
|
||||
"Insert the current Queue into the Buffer",
|
||||
() => { queueToBuffer() },
|
||||
));
|
||||
}
|
||||
|
||||
if (headers.length > 0) clearInterval(iframeInterval);
|
||||
}, 500)
|
||||
|
||||
// Creates the Main Menu
|
||||
function createMenu() {
|
||||
const container = document.createElement("div")
|
||||
container.id = "combine-playlist-spicetify"
|
||||
container.className = "context-menu-container"
|
||||
container.style.zIndex = "1029"
|
||||
|
||||
const style = document.createElement("style")
|
||||
style.textContent = `
|
||||
#combine-menu {
|
||||
display: inline-block;
|
||||
width: 33%;
|
||||
max-height: 70%;
|
||||
overflow: hidden auto;
|
||||
padding: 10px
|
||||
}
|
||||
.combine-pattern {
|
||||
margin-top: 7px;
|
||||
}
|
||||
.order-controls {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
padding: 0 5px 5px 0;
|
||||
z-index: 3
|
||||
}
|
||||
.button.button-icon-only::before {
|
||||
color: var(--modspotify_main_fg);
|
||||
}
|
||||
.order-controls-up {
|
||||
position: relative;
|
||||
top: 100%;
|
||||
}
|
||||
.order-controls-remove {
|
||||
position: relative;
|
||||
top: 50%;
|
||||
}
|
||||
.order-controls-down {
|
||||
position: relative;
|
||||
bottom: 100%;
|
||||
}
|
||||
.card-info-subtitle-owner {
|
||||
color: var(--modspotify_secondary_fg);
|
||||
}
|
||||
.card-info-subtitle-tracks {
|
||||
font-weight: lighter;
|
||||
color: var(--modspotify_secondary_fg);
|
||||
}
|
||||
`
|
||||
|
||||
const menu = document.createElement("ul")
|
||||
menu.id = "combine-menu"
|
||||
menu.className = "context-menu"
|
||||
|
||||
container.append(style, menu)
|
||||
|
||||
return { container, menu }
|
||||
}
|
||||
|
||||
// Creates a Button in the Combine Menu
|
||||
function createMenuItem(name, callback) {
|
||||
const item = document.createElement("div");
|
||||
item.classList.add("item");
|
||||
item.onclick = callback;
|
||||
item.onmouseover = () => item.classList.add("hover");
|
||||
item.onmouseleave = () => item.classList.remove("hover");
|
||||
|
||||
const text = document.createElement("span");
|
||||
text.classList.add("text");
|
||||
text.innerText = name;
|
||||
|
||||
item.append(text);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
// Creates the SubMenu in Playlist Context
|
||||
function createPlaylistContextMenu() {
|
||||
var createFromCurrent = new Spicetify.ContextMenu.Item(
|
||||
MENU_BTN_CREATE_NEW,
|
||||
(uris) => {
|
||||
if (uris.length === 1) {
|
||||
fetchPlaylist(uris[0])
|
||||
.then((buffer) => highjackCreateDialog(buffer.tracks))
|
||||
.catch((err) => Spicetify.showNotification(`${err}`));
|
||||
return;
|
||||
} else {
|
||||
Spicetify.showNotification("Unable to find Playlist URI")
|
||||
}
|
||||
},
|
||||
(_) => true
|
||||
)
|
||||
|
||||
var insertIntoBuffer = new Spicetify.ContextMenu.Item(
|
||||
MENU_BTN_INSERT_BUFFER,
|
||||
(uris) => {
|
||||
|
||||
if (uris.length === 1) {
|
||||
fetchPlaylist(uris[0])
|
||||
.then((buffer) => {LIST.addToStorage(buffer)})
|
||||
.catch((err) => Spicetify.showNotification(`${err}`));
|
||||
return;
|
||||
}
|
||||
},
|
||||
(_) => true
|
||||
)
|
||||
|
||||
return new Spicetify.ContextMenu.SubMenu(
|
||||
"Copy Playlist",
|
||||
[ createFromCurrent, insertIntoBuffer],
|
||||
(uris) => {
|
||||
if (uris.length === 1) {
|
||||
const uriObj = Spicetify.URI.fromString(uris[0]);
|
||||
switch (uriObj.type) {
|
||||
case Spicetify.URI.Type.PLAYLIST:
|
||||
case Spicetify.URI.Type.PLAYLIST_V2:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Multiple Items selected.
|
||||
return false;
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// Creates the Button to View Merge Buffer
|
||||
function createTopBarButton() {
|
||||
const button = document.createElement("button")
|
||||
button.classList.add("button", "spoticon-copy-16", "merge-button")
|
||||
button.setAttribute("data-tooltip", TOP_BTN_TOOLTIP)
|
||||
button.setAttribute("data-contextmenu", "")
|
||||
button.setAttribute("data-uri", "spotify:special:copy")
|
||||
button.onclick = () => {
|
||||
const bound = button.getBoundingClientRect()
|
||||
LIST.changePosition(bound.left, bound.top)
|
||||
document.body.append(LIST.container)
|
||||
LIST.setScroll()
|
||||
}
|
||||
return button
|
||||
}
|
||||
|
||||
// Creates the Dropdown Menu for Merge Pattern
|
||||
function createPatternSelect(defaultOpt = 0) {
|
||||
const select = document.createElement("select");
|
||||
select.className = "GlueDropdown combine-pattern";
|
||||
|
||||
const appendOpt = document.createElement("option");
|
||||
appendOpt.text = "Append";
|
||||
|
||||
const shuffleOpt = document.createElement("option");
|
||||
shuffleOpt.text = "Shuffle";
|
||||
|
||||
const alternateOpt = document.createElement("option");
|
||||
alternateOpt.text = "Alternate";
|
||||
|
||||
select.onclick = (ev) => ev.stopPropagation();
|
||||
select.append(appendOpt, shuffleOpt, alternateOpt);
|
||||
select.options[defaultOpt].selected = true;
|
||||
|
||||
return select;
|
||||
}
|
||||
|
||||
// Queue button
|
||||
function createQueueButton(name, tooltip, callback) {
|
||||
const b = document.createElement("button");
|
||||
b.classList.add("button", "button-green");
|
||||
b.innerText = name;
|
||||
b.setAttribute("data-tooltip", tooltip);
|
||||
b.onclick = callback;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Highjack Spotifies 'New Playlist' Dialog
|
||||
function highjackCreateDialog(tracks) {
|
||||
playlistDialogButton.click()
|
||||
|
||||
var createButton = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__submit-button-container > button")
|
||||
var buttonContainer = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__submit-button-container")
|
||||
|
||||
var highjackedButton = createButton.cloneNode(true)
|
||||
highjackedButton.addEventListener("click", () => onCreateNewPlaylist(tracks))
|
||||
|
||||
window.addEventListener("keypress", (event) => {
|
||||
if (event.code === `Enter`) {
|
||||
// Cancel the default action, if needed
|
||||
event.preventDefault();
|
||||
// Trigger the button element with a click
|
||||
createButton.click();
|
||||
}
|
||||
});
|
||||
|
||||
createButton.remove()
|
||||
buttonContainer.insertAdjacentElement("afterbegin", highjackedButton)
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
OnCLick Functions
|
||||
**************************************************************************/
|
||||
// Create a new Playlist from Inputs
|
||||
function onCreateNewPlaylist(tracks) {
|
||||
var exitButton = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__close-button > button");
|
||||
var nameInput = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__content > div.PlaylistAnnotationModal__playlist-name > input")
|
||||
var descInput = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__content > div.PlaylistAnnotationModal__playlist-description > textarea")
|
||||
var imageInput = document.querySelector("body > div.Modal__portal > div > div > div > div.PlaylistAnnotationModal__content > div.PlaylistAnnotationModal__img-container > div > div.PlaylistAnnotationModal__img-holder > img")
|
||||
|
||||
var name = nameInput.value
|
||||
if (!name) {
|
||||
name = nameInput.getAttribute("placeholder")
|
||||
}
|
||||
|
||||
var desc = descInput.value
|
||||
|
||||
var img;
|
||||
if (imageInput) {
|
||||
img = imageInput.getAttribute("src")
|
||||
}
|
||||
|
||||
createPlaylist(name)
|
||||
.then(res => addTracks(res.uri, tracks))
|
||||
.then((_) => Spicetify.showNotification(`Created Playlist: "${name}"`))
|
||||
.catch((err) => Spicetify.showNotification(`${err}`));
|
||||
|
||||
exitButton.click()
|
||||
|
||||
if (exitButton) {
|
||||
exitButton.click()
|
||||
}
|
||||
}
|
||||
|
||||
// Get All Tracks in Queue and remove delimiter
|
||||
function getQueueTracks() {
|
||||
return Spicetify.Queue.next_tracks
|
||||
.map((t) => t.uri)
|
||||
.filter((t) => { return t != "spotify:delimiter"; })
|
||||
}
|
||||
|
||||
// Copy the Queue to the Combine Buffer
|
||||
function queueToBuffer() {
|
||||
let tracks = getQueueTracks();
|
||||
|
||||
var date = new Date()
|
||||
var year = new Intl.DateTimeFormat('en', { year: 'numeric' }).format(date);
|
||||
var month = new Intl.DateTimeFormat('en', { month: 'short' }).format(date);
|
||||
var day = new Intl.DateTimeFormat('en', { day: '2-digit' }).format(date);
|
||||
|
||||
const timeOptions = { hour: 'numeric', minute: 'numeric', hour12: false};
|
||||
var time = new Intl.DateTimeFormat(`en`, timeOptions).format(date);
|
||||
|
||||
let queue = {
|
||||
id: `spotify:queue-${date}`,
|
||||
uri: `spotify:queue`,
|
||||
name: "Queue",
|
||||
imgUri: undefined,
|
||||
tracks: tracks,
|
||||
owner: `${time} - ${day} ${month} ${year}`,
|
||||
}
|
||||
|
||||
LIST.addToStorage(queue);
|
||||
}
|
||||
|
||||
// Show the clicked Playlist
|
||||
async function showPlaylist(event) {
|
||||
console.log(event)
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
Merge Playlists
|
||||
**************************************************************************/
|
||||
// Merge all Playlists
|
||||
function mergePlaylists(pattern) {
|
||||
var tracks = LIST.getStorage().map((pl) => pl.tracks)
|
||||
|
||||
switch (pattern) {
|
||||
case 1: return shuffle(tracks);
|
||||
case 2: return alternate(tracks);
|
||||
default: return append(tracks);
|
||||
}
|
||||
}
|
||||
|
||||
// Alternate Playlists
|
||||
function alternate(arrays) {
|
||||
var combined = []
|
||||
|
||||
while (arrays.length != 0) {
|
||||
var current = arrays.shift()
|
||||
if (current.length != 0) {
|
||||
combined.push(current.shift())
|
||||
|
||||
if (current.length != 0) {
|
||||
arrays.push(current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combined
|
||||
}
|
||||
|
||||
// Shuffle all tracks using the Durstenfeld Shuffle
|
||||
function shuffle(arrays) {
|
||||
var combined = append(arrays)
|
||||
|
||||
for (var i = combined.length - 1; i > 0; i--) {
|
||||
var j = Math.floor(Math.random() * (i + 1));
|
||||
var temp = combined[i];
|
||||
combined[i] = combined[j];
|
||||
combined[j] = temp;
|
||||
}
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
// Simply Concat all Playlist
|
||||
function append(arrays) {
|
||||
var combined = []
|
||||
arrays.forEach((arr) => combined = combined.concat(arr))
|
||||
|
||||
return combined;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Calls to the CosmosAPI
|
||||
**************************************************************************/
|
||||
// Fetch all Track from Playlist URI
|
||||
async function fetchPlaylist(uri) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
Spicetify.BridgeAPI.cosmosJSON(
|
||||
{
|
||||
method: "GET",
|
||||
uri: `sp://core-playlist/v1/playlist/${uri}/`,
|
||||
body: {
|
||||
policy: {
|
||||
link: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
(error, res) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
let id = `${uri}-${new Date()}`
|
||||
let tracks = res.items.map((track) => track.link)
|
||||
let img = res.playlist.picture
|
||||
let name = res.playlist.name
|
||||
let owner = res.playlist.owner.name
|
||||
|
||||
let playlist = {id: id, uri: uri, name: name, tracks: tracks, imgUri: img, owner: owner}
|
||||
|
||||
resolve(playlist);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// Create a new Playlist
|
||||
async function createPlaylist(name) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
Spicetify.BridgeAPI.cosmosJSON(
|
||||
{
|
||||
method: "POST",
|
||||
uri: `sp://core-playlist/v1/rootlist`,
|
||||
body: {
|
||||
operation: "create",
|
||||
playlist: !0,
|
||||
before: "start",
|
||||
name: name,
|
||||
},
|
||||
},
|
||||
(error, res) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(res);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// add track list to playlist
|
||||
async function addTracks(uri, tracks) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
Spicetify.BridgeAPI.cosmosJSON(
|
||||
{
|
||||
method: "POST",
|
||||
uri: `sp://core-playlist/v1/playlist/${uri}`,
|
||||
body: {
|
||||
operation: "add",
|
||||
uris: tracks,
|
||||
after: "end"
|
||||
}
|
||||
},
|
||||
(error, res) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(res);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
})();
|
3087
.config/spicetify/Extensions/fullScreen.js
Normal file
3087
.config/spicetify/Extensions/fullScreen.js
Normal file
File diff suppressed because it is too large
Load diff
125
.config/spicetify/Extensions/genre.js
Normal file
125
.config/spicetify/Extensions/genre.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
// <reference path="./globals.d.ts" />
|
||||
|
||||
(function Genre() {
|
||||
const { CosmosAsync, Player } = Spicetify;
|
||||
|
||||
/**
|
||||
* Fetch genre from artist
|
||||
*
|
||||
* @param artistURI {string}
|
||||
* @return {Promise<Array>}
|
||||
*/
|
||||
const fetchGenres = async (artistURI) => {
|
||||
const res = await CosmosAsync.get(
|
||||
`https://api.spotify.com/v1/artists/${artistURI}`
|
||||
);
|
||||
// noinspection JSUnresolvedVariable
|
||||
return res.genres.slice(0, 3) // Only keep the first 3 genres
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch playlist from The Sound of Spotify for a given genre
|
||||
* @param {String} genre
|
||||
* @return {String|null}
|
||||
*/
|
||||
const fetchSoundOfSpotifyPlaylist = async (genre) => {
|
||||
const query = encodeURIComponent(`The Sound of ${genre}`);
|
||||
// Check localStorage for playlist
|
||||
const cached = localStorage.getItem(`everynoise:${query}`);
|
||||
if (cached !== null) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// Search for playlist and check results for the everynoise account
|
||||
const re = new RegExp(`^the sound of ${genre.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i');
|
||||
const res = await CosmosAsync.get(`https://api.spotify.com/v1/search?q=${query}&type=playlist`)
|
||||
for (const item of res.playlists.items) {
|
||||
if (item.owner.id === "thesoundsofspotify" && re.test(item.name)) {
|
||||
localStorage.setItem(`everynoise:${genre}`, item.uri);
|
||||
return item.uri
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
// Store the current playback id
|
||||
let playback = null;
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {Node}
|
||||
*/
|
||||
let genreContainer = null;
|
||||
|
||||
let infoContainer = document.querySelector('div.main-trackInfo-container');
|
||||
|
||||
/**
|
||||
* Remove genre injection in the UI
|
||||
*/
|
||||
const cleanInjection = () => {
|
||||
if (genreContainer !== null) {
|
||||
try {
|
||||
infoContainer.removeChild(genreContainer);
|
||||
} catch (e) {}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Inject genres to UI
|
||||
*/
|
||||
const inject = () => {
|
||||
Player.addEventListener('onprogress', async () => {
|
||||
if (Player.data.track.metadata.hasOwnProperty('artist_uri')) {
|
||||
// If the registered song isn't the same as the one currently being played then fetch genres
|
||||
if (playback !== Player.data.playback_id) {
|
||||
// Save the new track
|
||||
playback = Player.data.playback_id;
|
||||
const id = Player.data.track.metadata.artist_uri.split(':')[2];
|
||||
const genres = await fetchGenres(id);
|
||||
|
||||
cleanInjection();
|
||||
|
||||
genreContainer = document.createElement('div');
|
||||
// noinspection JSUndefinedPropertyAssignment
|
||||
genreContainer.className = 'main-trackInfo-genres ellipsis-one-line main-type-finale';
|
||||
// noinspection JSUnresolvedVariable
|
||||
genreContainer.style.color = 'var(--spice-extratext)';
|
||||
|
||||
for (const i in genres) {
|
||||
let element;
|
||||
const uri = await fetchSoundOfSpotifyPlaylist(genres[i]);
|
||||
if (uri !== null) {
|
||||
element = document.createElement('a');
|
||||
element.innerHTML = genres[i];
|
||||
element.href = uri;
|
||||
} else {
|
||||
element = document.createElement('span');
|
||||
}
|
||||
element.innerHTML = genres[i];
|
||||
element.style.fontSize ="11px";
|
||||
genreContainer.appendChild(element);
|
||||
if (i < genres.length-1) {
|
||||
const separator = document.createElement('span');
|
||||
separator.innerHTML = ', ';
|
||||
genreContainer.appendChild(separator);
|
||||
}
|
||||
}
|
||||
|
||||
infoContainer = document.querySelector('div.main-trackInfo-container');
|
||||
if(!infoContainer) cleanInjection();
|
||||
infoContainer.appendChild(genreContainer);
|
||||
|
||||
}
|
||||
} else {
|
||||
cleanInjection();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (!CosmosAsync) {
|
||||
setTimeout(Genre, 500);
|
||||
} else {
|
||||
inject();
|
||||
}
|
||||
})();
|
5
.config/spicetify/Extensions/hidePodcasts.js
Normal file
5
.config/spicetify/Extensions/hidePodcasts.js
Normal file
File diff suppressed because one or more lines are too long
127
.config/spicetify/Extensions/historyShortcut.js
Normal file
127
.config/spicetify/Extensions/historyShortcut.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
// NAME: History Shortcut
|
||||
// AUTHOR: einzigartigerName
|
||||
// DESCRIPTION: Adds a Shortcut to your Listening History to the Sidebar
|
||||
|
||||
(function HistoryShortcut() {
|
||||
|
||||
const { CosmosAPI, Player, LocalStorage, PlaybackControl, ContextMenu, URI } = Spicetify
|
||||
if (!(CosmosAPI && Player && LocalStorage && PlaybackControl && ContextMenu && URI)) {
|
||||
setTimeout(HistoryShortcut, 300)
|
||||
return
|
||||
}
|
||||
|
||||
const ITEM_LABEL = "History"
|
||||
|
||||
const HISTORY_DIV_CLASS = "SidebarListItem"
|
||||
const HISTORY_DIV_CLASS_ACTIVE = "SidebarListItem SidebarListItem--is-active"
|
||||
|
||||
const HISTORY_ANKER_CLASS = "SidebarListItemLink SidebarListItemLink--tall spoticon-time-24"
|
||||
const HISTORY_ANKER_CLASS_ACTIVE = "SidebarListItemLink SidebarListItemLink--is-highlighted SidebarListItemLink--tall spoticon-time-24"
|
||||
|
||||
let historyItem = createHistoyItem()
|
||||
// Get Sidebar Lists
|
||||
var topicList = document.querySelector("#view-navigation-bar > div > div.LeftSidebar__section > div > ul")
|
||||
if (topicList) {
|
||||
// Add to first in list
|
||||
// On default layout this would be the Home/Browse/Radio List
|
||||
topicList.appendChild(historyItem.div)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
const toCheckMutate = document.getElementById('view-content');
|
||||
const config = { attributes: true, childList: true, subtree: true };
|
||||
|
||||
let observerCallback = function(_, _) {
|
||||
appQueue = document.getElementById("app-queue")
|
||||
if (!appQueue){ return }
|
||||
|
||||
if (appQueue.getAttribute("class") === "active"
|
||||
&& appQueue.getAttribute("data-app-uri") === "spotify:app:queue:history"
|
||||
) {
|
||||
onClickHistory()
|
||||
} else {
|
||||
onLeaveHistory()
|
||||
}
|
||||
};
|
||||
|
||||
let observer = new MutationObserver(observerCallback)
|
||||
observer.observe(toCheckMutate, config)
|
||||
|
||||
|
||||
|
||||
// Deactivate Active Status for History Item
|
||||
function onLeaveHistory() {
|
||||
historyItem.div.setAttribute("class",HISTORY_DIV_CLASS)
|
||||
historyItem.anker.setAttribute("class", HISTORY_ANKER_CLASS)
|
||||
}
|
||||
|
||||
// Activate Active Status for History Item
|
||||
function onClickHistory() {
|
||||
historyItem.div.setAttribute("class", HISTORY_DIV_CLASS_ACTIVE)
|
||||
historyItem.anker.setAttribute("class", HISTORY_ANKER_CLASS_ACTIVE)
|
||||
}
|
||||
|
||||
// Construct the List Item
|
||||
function createHistoyItem() {
|
||||
/* List Item
|
||||
* <li class="SidebarListItem">
|
||||
*/
|
||||
let listItem = document.createElement("li")
|
||||
listItem.setAttribute("class", HISTORY_DIV_CLASS)
|
||||
|
||||
/* Outer Div Element
|
||||
* <div class="DropTarget SidebarListItem__drop-target DropTarget--tracks DropTarget--albums DropTarget--artists DropTarget--playlists">
|
||||
*/
|
||||
let outer = document.createElement("div")
|
||||
outer.setAttribute("class", "DropTarget SidebarListItem__drop-target")
|
||||
|
||||
/* Middle Div Element
|
||||
* <div class="SidebarListItem__inner">
|
||||
*/
|
||||
let inner = document.createElement("div")
|
||||
inner.setAttribute("class", "SidebarListItem__inner")
|
||||
|
||||
/* Link Div Element
|
||||
* <div class="SidebarListItem__link">
|
||||
*/
|
||||
let link = document.createElement("div")
|
||||
link.setAttribute("class", "SidebarListItem__link")
|
||||
|
||||
/* Anker
|
||||
* <a class="SidebarListItemLink SidebarListItemLink--tall spoticon-time-24"
|
||||
* draggable="false"
|
||||
* href="spotify:app:queue:history"
|
||||
* data-sidebar-list-item-uri="spotify:app:queue:history"
|
||||
* data-ta-id="sidebar-list-item-link">
|
||||
*/
|
||||
anker = document.createElement("a")
|
||||
anker.setAttribute("class", HISTORY_ANKER_CLASS)
|
||||
anker.setAttribute("draggable", "false")
|
||||
anker.setAttribute("href", "spotify:app:queue:history")
|
||||
anker.setAttribute("data-sidebar-list-item-uri", "spotify:app:queue:history")
|
||||
anker.setAttribute("data-ta-id", "sidebar-list-item-link")
|
||||
|
||||
/* Item Text
|
||||
* <span class="SidebarListItem__label"
|
||||
* dir="auto">
|
||||
* History
|
||||
* </span>
|
||||
*/
|
||||
span = document.createElement("span")
|
||||
span.setAttribute("class", "SidebarListItem__label")
|
||||
span.setAttribute("dir", "auto")
|
||||
span.textContent = ITEM_LABEL
|
||||
|
||||
|
||||
anker.appendChild(span)
|
||||
link.appendChild(anker)
|
||||
inner.appendChild(link)
|
||||
outer.appendChild(inner)
|
||||
listItem.appendChild(outer)
|
||||
|
||||
listItem.addEventListener("click", onClickHistory)
|
||||
|
||||
return {div: listItem, anker: anker}
|
||||
}
|
||||
})();
|
532
.config/spicetify/Extensions/keyboardShortcutMy.js
Normal file
532
.config/spicetify/Extensions/keyboardShortcutMy.js
Normal file
|
@ -0,0 +1,532 @@
|
|||
//@ts-check
|
||||
|
||||
// NAME: Keyboard Shortcut
|
||||
// AUTHOR: dax
|
||||
// DESCRIPTION: Register a few more keybinds to support keyboard-driven navigation in Spotify client.
|
||||
|
||||
/// <reference path="../spicetify-cli/globals.d.ts" />
|
||||
|
||||
(function KeyboardShortcutMy() {
|
||||
if (!Spicetify.Keyboard) {
|
||||
setTimeout(KeyboardShortcutMy, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
const SCROLL_STEP = 50;
|
||||
|
||||
/**
|
||||
* Register your own keybind with function `registerBind`
|
||||
*
|
||||
* Syntax:
|
||||
* registerBind(keyName, ctrl, shift, alt, callback)
|
||||
*
|
||||
* ctrl, shift and alt are boolean, true or false
|
||||
*
|
||||
* Valid keyName:
|
||||
* - BACKSPACE - C - Y - F3
|
||||
* - TAB - D - Z - F4
|
||||
* - ENTER - E - WINDOW_LEFT - F5
|
||||
* - SHIFT - F - WINDOW_RIGHT - F6
|
||||
* - CTRL - G - SELECT - F7
|
||||
* - ALT - H - NUMPAD_0 - F8
|
||||
* - PAUSE/BREAK - I - NUMPAD_1 - F9
|
||||
* - CAPS - J - NUMPAD_2 - F10
|
||||
* - ESCAPE - K - NUMPAD_3 - F11
|
||||
* - SPACE - L - NUMPAD_4 - F12
|
||||
* - PAGE_UP - M - NUMPAD_5 - NUM_LOCK
|
||||
* - PAGE_DOWN - N - NUMPAD_6 - SCROLL_LOCK
|
||||
* - END - O - NUMPAD_7 - ;
|
||||
* - HOME - P - NUMPAD_8 - =
|
||||
* - ARROW_LEFT - Q - NUMPAD_9 - ,
|
||||
* - ARROW_UP - R - MULTIPLY - -
|
||||
* - ARROW_RIGHT - S - ADD - /
|
||||
* - ARROW_DOWN - T - SUBTRACT - `
|
||||
* - INSERT - U - DECIMAL_POINT - [
|
||||
* - DELETE - V - DIVIDE - \
|
||||
* - A - W - F1 - ]
|
||||
* - B - X - F2 - "
|
||||
*
|
||||
* Use one of keyName as a string. If key that you want isn't in that list,
|
||||
* you can also put its keycode number in keyName as a number.
|
||||
*
|
||||
* callback is name of function you want your shortcut to bind to. It also
|
||||
* returns one KeyboardEvent parameter.
|
||||
*
|
||||
* Following are my default keybinds, use them as examples.
|
||||
*/
|
||||
|
||||
|
||||
//My Personal Binds----------------------------------------------
|
||||
|
||||
// Seek to progress percent of song
|
||||
registerBind("NUMPAD_0", false, false, false, ()=>Spicetify.Player.seek(0));
|
||||
registerBind("NUMPAD_1", false, false, false, ()=>Spicetify.Player.seek(.1));
|
||||
registerBind("NUMPAD_2", false, false, false, ()=>Spicetify.Player.seek(.2));
|
||||
registerBind("NUMPAD_3", false, false, false, ()=>Spicetify.Player.seek(.3));
|
||||
registerBind("NUMPAD_4", false, false, false, ()=>Spicetify.Player.seek(.4));
|
||||
registerBind("NUMPAD_5", false, false, false, ()=>Spicetify.Player.seek(.5));
|
||||
registerBind("NUMPAD_6", false, false, false, ()=>Spicetify.Player.seek(.6));
|
||||
registerBind("NUMPAD_7", false, false, false, ()=>Spicetify.Player.seek(.7));
|
||||
registerBind("NUMPAD_8", false, false, false, ()=>Spicetify.Player.seek(.8));
|
||||
registerBind("NUMPAD_9", false, false, false, ()=>Spicetify.Player.seek(.9));
|
||||
|
||||
|
||||
// Q to open Queue page
|
||||
registerBind("Q", false, false, false, clickQueueButton);
|
||||
|
||||
// C to open current playing context, L to open Lyrics, H to open Home Tab , Y to Open the Ypur Library, S to open the Lyrics Plus Custom App
|
||||
registerBind("C", false, false, false, openContext)
|
||||
registerBind("L", false, false, false, toggleLyrics);
|
||||
registerBind("H", false, false, false, openHome);
|
||||
registerBind("Y", false, false, false, openLibrary);
|
||||
registerBind("S", false, false, false, openLyrics);
|
||||
|
||||
// Arrow keys to change volume
|
||||
registerBind("ARROW_DOWN", false, false, false, decreaseVolume);
|
||||
registerBind("ARROW_UP" , false, false, false, increaseVolume);
|
||||
|
||||
// Arrow keys to seek track
|
||||
registerBind("ARROW_RIGHT", false, false, false, seekForward);
|
||||
registerBind("ARROW_LEFT", false, false, false, seekBack);
|
||||
|
||||
|
||||
function sleep (time) {
|
||||
return new Promise((resolve) => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
function clickQueueButton() {
|
||||
document.querySelector('.control-button-wrapper>button[Aria-label="Queue"]').click();
|
||||
}
|
||||
|
||||
function openContext(){
|
||||
big = document.querySelector("#main > div > div.Root__top-container > nav > div.main-navBar-navBar > div:nth-child(3) > div > div > a > div")
|
||||
small = document.querySelector("#main > div > div.Root__top-container > div.Root__now-playing-bar > footer > div > div.main-nowPlayingBar-left > div > div.main-coverSlotCollapsed-container > div > a > div")
|
||||
if(big)
|
||||
big.click();
|
||||
else
|
||||
small.click()
|
||||
}
|
||||
|
||||
function toggleLyrics() {
|
||||
document.querySelector('button[title="Popup Lyrics"]').click()
|
||||
}
|
||||
function openHome(){
|
||||
ele = document.querySelector(`.main-navBar-navBar a[href="/"]`)
|
||||
if(ele)
|
||||
ele.click();
|
||||
}
|
||||
function openLyrics(){
|
||||
ele = document.querySelector(`.main-navBar-navBar a[href="/lyrics-plus"]`)
|
||||
if(ele)
|
||||
ele.click();
|
||||
}
|
||||
function openLibrary(){
|
||||
ele = document.querySelector(`.main-navBar-navBar a[href="/collection"]`)
|
||||
if(ele)
|
||||
ele.click();
|
||||
}
|
||||
function seekForward(){
|
||||
Spicetify.Player.skipForward(5000)
|
||||
}
|
||||
function seekBack(){
|
||||
Spicetify.Player.skipBack(5000)
|
||||
}
|
||||
async function decreaseVolume(){
|
||||
if(!document.querySelector(".main-trackList-selected")){
|
||||
if(Spicetify.Platform?.PlaybackAPI === undefined) Spicetify.Player?.origin?.setVolume(getVolume() - 0.05)
|
||||
else await Spicetify.Platform.PlaybackAPI.setVolume(getVolume() - 0.05)
|
||||
}
|
||||
}
|
||||
async function increaseVolume(){
|
||||
if(!document.querySelector(".main-trackList-selected")){
|
||||
if(Spicetify.Platform?.PlaybackAPI === undefined) Spicetify.Player?.origin?.setVolume(getVolume() + 0.05)
|
||||
else await Spicetify.Platform.PlaybackAPI.setVolume(getVolume() + 0.05)
|
||||
}
|
||||
}
|
||||
function getVolume(){
|
||||
return (Spicetify.Player?.origin?._volume?._volume ?? Spicetify.Platform?.PlaybackAPI?._volume)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// Ctrl + Tab and Ctrl + Shift + Tab to switch sidebar items
|
||||
registerBind("TAB", true, false, false, rotateSidebarDown);
|
||||
registerBind("TAB", true, true, false, rotateSidebarUp);
|
||||
|
||||
// Ctrl + Q to open Queue page
|
||||
// registerBind("Q", true, false, false, clickQueueButton);
|
||||
|
||||
// Shift + H and Shift + L to go back and forward page
|
||||
registerBind("H", false, true, false, clickNavigatingBackButton);
|
||||
registerBind("L", false, true, false, clickNavigatingForwardButton);
|
||||
|
||||
// PageUp, PageDown to focus on iframe app before scrolling
|
||||
registerBind("PAGE_UP", false, true, false, focusOnApp);
|
||||
registerBind("PAGE_DOWN", false, true, false, focusOnApp);
|
||||
|
||||
// J and K to vertically scroll app
|
||||
registerBind("J", false, false, false, appScrollDown);
|
||||
registerBind("K", false, false, false, appScrollUp);
|
||||
|
||||
// G and Shift + G to scroll to top and to bottom
|
||||
registerBind("G", false, false, false, appScrollTop);
|
||||
registerBind("G", false, true, false, appScrollBottom);
|
||||
|
||||
// M to Like/Unlike track
|
||||
registerBind("M", false, false, false, Spicetify.Player.toggleHeart);
|
||||
|
||||
// Forward Slash to open search page
|
||||
registerBind("/", false, false, false, openSearchPage);
|
||||
|
||||
// A to activate Link Follow function
|
||||
const vim = new VimBind();
|
||||
registerBind("A", false, false, false, vim.activate.bind(vim));
|
||||
|
||||
// Esc to cancel Link Follow
|
||||
vim.setCancelKey("ESCAPE")
|
||||
vim.setCancelKey("Z")
|
||||
|
||||
function rotateSidebarDown() {
|
||||
rotateSidebar(1)
|
||||
}
|
||||
|
||||
function rotateSidebarUp() {
|
||||
rotateSidebar(-1)
|
||||
}
|
||||
|
||||
// function clickQueueButton() {
|
||||
// document.querySelector(".control-button-wrapper .spoticon-queue-16").click();
|
||||
// }
|
||||
|
||||
function clickNavigatingBackButton() {
|
||||
document.querySelector(".main-topBar-historyButtons .main-topBar-back").click();
|
||||
}
|
||||
|
||||
function clickNavigatingForwardButton() {
|
||||
document.querySelector(".main-topBar-historyButtons .main-topBar-forward").click();
|
||||
}
|
||||
|
||||
function appScrollDown() {
|
||||
const app = focusOnApp();
|
||||
if (app) {
|
||||
app.scrollBy(0, SCROLL_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
function appScrollUp() {
|
||||
const app = focusOnApp();
|
||||
if (app) {
|
||||
app.scrollBy(0, -SCROLL_STEP);
|
||||
}
|
||||
}
|
||||
|
||||
function appScrollBottom() {
|
||||
const app = focusOnApp();
|
||||
app.scroll(0, app.scrollHeight);
|
||||
}
|
||||
|
||||
function appScrollTop() {
|
||||
const app = focusOnApp();
|
||||
app.scroll(0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
function openSearchPage(event) {
|
||||
const searchInput = document.querySelector(".main-topBar-topbarContentWrapper input");
|
||||
if (searchInput) {
|
||||
searchInput.focus();
|
||||
} else {
|
||||
const sidebarItem = document.querySelector(`.main-navBar-navBar a[href="/search"]`);
|
||||
if (sidebarItem) {
|
||||
sidebarItem.click();
|
||||
}
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Spicetify.Keyboard.ValidKey} keyName
|
||||
* @param {boolean} ctrl
|
||||
* @param {boolean} shift
|
||||
* @param {boolean} alt
|
||||
* @param {(event: KeyboardEvent) => void} callback
|
||||
*/
|
||||
function registerBind(keyName, ctrl, shift, alt, callback) {
|
||||
const key = Spicetify.Keyboard.KEYS[keyName];
|
||||
|
||||
Spicetify.Keyboard.registerShortcut(
|
||||
{
|
||||
key,
|
||||
ctrl,
|
||||
shift,
|
||||
alt,
|
||||
},
|
||||
(event) => {
|
||||
if (!vim.isActive) {
|
||||
callback(event);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function focusOnApp() {
|
||||
return document.querySelector("main .os-viewport");
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
function findActiveIndex(allItems) {
|
||||
const active = document.querySelector(
|
||||
".main-navBar-navBarLinkActive, .main-collectionLinkButton-selected, .main-rootlist-rootlistItemLinkActive"
|
||||
);
|
||||
if (!active) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
for (const item of allItems) {
|
||||
if (item === active) {
|
||||
return index;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {1 | -1} direction
|
||||
*/
|
||||
function rotateSidebar(direction) {
|
||||
const allItems = document.querySelectorAll(
|
||||
".main-navBar-navBarLink, .main-collectionLinkButton-collectionLinkButton, .main-rootlist-rootlistItemLink"
|
||||
);
|
||||
const maxIndex = allItems.length - 1;
|
||||
let index = findActiveIndex(allItems) + direction;
|
||||
|
||||
if (index < 0) index = maxIndex;
|
||||
else if (index > maxIndex) index = 0;
|
||||
|
||||
let toClick = allItems[index];
|
||||
if (!toClick.hasAttribute("href")) {
|
||||
toClick = toClick.querySelector(".main-rootlist-rootlistItemLink");
|
||||
}
|
||||
|
||||
toClick.click();
|
||||
}
|
||||
})();
|
||||
|
||||
function VimBind() {
|
||||
const elementQuery = ["[href]", "button", "td.tl-play", "td.tl-number", "tr.TableRow"].join(",");
|
||||
|
||||
const keyList = "qwertasdfgzxcvyuiophjklbnm".split("");
|
||||
|
||||
const lastKeyIndex = keyList.length - 1;
|
||||
|
||||
this.isActive = false;
|
||||
|
||||
const vimOverlay = document.createElement("div");
|
||||
vimOverlay.id = "vim-overlay";
|
||||
vimOverlay.style.zIndex = "9999";
|
||||
vimOverlay.style.position = "absolute";
|
||||
vimOverlay.style.width = "100%";
|
||||
vimOverlay.style.height = "100%";
|
||||
vimOverlay.style.display = "none";
|
||||
vimOverlay.innerHTML = `<style>
|
||||
.vim-key {
|
||||
position: fixed;
|
||||
padding: 3px 6px;
|
||||
background-color: black;
|
||||
border-radius: 3px;
|
||||
border: solid 2px white;
|
||||
color: white;
|
||||
text-transform: lowercase;
|
||||
line-height: normal;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>`;
|
||||
document.body.append(vimOverlay);
|
||||
|
||||
const mousetrap = new Spicetify.Mousetrap(document);
|
||||
mousetrap.bind(keyList, listenToKeys.bind(this), "keypress");
|
||||
// Pause mousetrap event emitter
|
||||
const orgStopCallback = mousetrap.stopCallback;
|
||||
mousetrap.stopCallback = () => true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
this.activate = function (event) {
|
||||
vimOverlay.style.display = "block";
|
||||
|
||||
const vimkey = getVims();
|
||||
if (vimkey.length > 0) {
|
||||
vimkey.forEach((e) => e.remove());
|
||||
return;
|
||||
}
|
||||
|
||||
let firstKey = 0;
|
||||
let secondKey = 0;
|
||||
|
||||
getLinks().forEach((e) => {
|
||||
if (e.style.display === "none" || e.style.visibility === "hidden" || e.style.opacity === "0") {
|
||||
return;
|
||||
}
|
||||
|
||||
const bound = e.getBoundingClientRect();
|
||||
let owner = document.body;
|
||||
|
||||
let top = bound.top;
|
||||
let left = bound.left;
|
||||
|
||||
if (
|
||||
bound.bottom > owner.clientHeight ||
|
||||
bound.left > owner.clientWidth ||
|
||||
bound.right < 0 ||
|
||||
bound.top < 0 ||
|
||||
bound.width === 0 ||
|
||||
bound.height === 0
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
vimOverlay.append(createKey(e, keyList[firstKey] + keyList[secondKey], top, left));
|
||||
|
||||
secondKey++;
|
||||
if (secondKey > lastKeyIndex) {
|
||||
secondKey = 0;
|
||||
firstKey++;
|
||||
}
|
||||
});
|
||||
|
||||
this.isActive = true;
|
||||
setTimeout(() => (mousetrap.stopCallback = orgStopCallback.bind(mousetrap)), 100);
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
this.deactivate = function (event) {
|
||||
mousetrap.stopCallback = () => true;
|
||||
this.isActive = false;
|
||||
vimOverlay.style.display = "none";
|
||||
getVims().forEach((e) => e.remove());
|
||||
};
|
||||
|
||||
function getLinks() {
|
||||
const elements = Array.from(document.querySelectorAll(elementQuery));
|
||||
return elements;
|
||||
}
|
||||
|
||||
function getVims() {
|
||||
return Array.from(vimOverlay.getElementsByClassName("vim-key"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {KeyboardEvent} event
|
||||
*/
|
||||
function listenToKeys(event) {
|
||||
if (!this.isActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const vimkey = getVims();
|
||||
|
||||
if (vimkey.length === 0) {
|
||||
this.deactivate(event);
|
||||
return;
|
||||
}
|
||||
|
||||
for (const div of vimkey) {
|
||||
const text = div.innerText.toLowerCase();
|
||||
if (text[0] !== event.key) {
|
||||
div.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
const newText = text.slice(1);
|
||||
if (newText.length === 0) {
|
||||
click(div.target);
|
||||
this.deactivate(event);
|
||||
return;
|
||||
}
|
||||
|
||||
div.innerText = newText;
|
||||
}
|
||||
|
||||
if (vimOverlay.childNodes.length === 1) {
|
||||
this.deactivate(event);
|
||||
}
|
||||
}
|
||||
|
||||
function click(element) {
|
||||
if (element.hasAttribute("href") || element.tagName === "BUTTON") {
|
||||
element.click();
|
||||
return;
|
||||
}
|
||||
|
||||
const findButton = element.querySelector(`button[data-ta-id="play-button"]`) || element.querySelector(`button[data-button="play"]`);
|
||||
if (findButton) {
|
||||
findButton.click();
|
||||
return;
|
||||
}
|
||||
alert("Let me know where you found this button, please. I can't click this for you without that information.");
|
||||
return;
|
||||
// TableCell case where play button is hidden
|
||||
// Index number is in first column
|
||||
const index = parseInt(element.firstChild.innerText) - 1;
|
||||
const context = getContextUri();
|
||||
if (index >= 0 && context) {
|
||||
console.log(index);
|
||||
console.log(context);
|
||||
|
||||
//Spicetify.PlaybackControl.playFromResolver(context, { index }, () => {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function createKey(target, key, top, left) {
|
||||
const div = document.createElement("span");
|
||||
div.classList.add("vim-key");
|
||||
div.innerText = key;
|
||||
div.style.top = top + "px";
|
||||
div.style.left = left + "px";
|
||||
div.target = target;
|
||||
return div;
|
||||
}
|
||||
|
||||
function getContextUri() {
|
||||
const username = __spotify.username;
|
||||
const activeApp = localStorage.getItem(username + ":activeApp");
|
||||
if (activeApp) {
|
||||
try {
|
||||
return JSON.parse(activeApp).uri.replace("app:", "");
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Spicetify.Keyboard.ValidKey} key
|
||||
*/
|
||||
this.setCancelKey = function (key) {
|
||||
mousetrap.bind(Spicetify.Keyboard.KEYS[key], this.deactivate.bind(this));
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
3
.config/spicetify/Extensions/playlistIcons.js
Normal file
3
.config/spicetify/Extensions/playlistIcons.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
var playlistDicons=(()=>{var s=Object.create,o=Object.defineProperty,c=Object.getOwnPropertyDescriptor,p=Object.getOwnPropertyNames,d=Object.getPrototypeOf,m=Object.prototype.hasOwnProperty,e=(e=>"undefined"!=typeof require?require:"undefined"!=typeof Proxy?new Proxy(e,{get:(e,t)=>("undefined"!=typeof require?require:e)[t]}):e)(function(e){if("react"===e)return Spicetify.React;if("react-dom"===e)return Spicetify.ReactDOM;if("undefined"!=typeof require)return require.apply(this,arguments);throw new Error('Dynamic require of "'+e+'" is not supported')}),t=(e,t,i)=>{i=null!=e?s(d(e)):{};var a=!t&&e&&e.__esModule?i:o(i,"default",{value:e,enumerable:!0}),n=e,l=void 0,r=void 0;if(n&&"object"==typeof n||"function"==typeof n)for(let e of p(n))m.call(a,e)||e===l||o(a,e,{get:()=>n[e],enumerable:!(r=c(n,e))||r.enumerable});return a},u=t(e("react")),y=t(e("react-dom"));var i=t(e("react"));function g(){return i.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",height:"24px",viewBox:"0 0 24 24",width:"24px",fill:"#FFFFFF"},i.default.createElement("path",{d:"M0 0h24v24H0V0z",fill:"none"}),i.default.createElement("path",{d:"M9.17 6l2 2H20v10H4V6h5.17M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"}))}var f=new Map;async function r(o){const e=await new Promise(t=>{const i=setInterval(()=>{var e=document.querySelectorAll("#spicetify-playlist-list li a");0<e.length&&(clearInterval(i),t(Array.from(e)))},100)});e.forEach(e=>{var t,i;const a=e.href.split("/").at(-1);var n=e.href.split("/").at(-2),l=f.get(a);if(null!=(t=e.parentElement)&&t.classList.add("playlist-item"),l)null!=(t=e.parentElement)&&t.prepend(l);else switch(n){case"playlist":var r=o.find(e=>e.id===a),r=function(e){const t=document.createElement(e?"img":"div");return t.classList.add("playlist-item__img"),e?t.setAttribute("src",e):t.classList.add("no-icon"),t}((null==(r=null==r?void 0:r.images[0])?void 0:r.url)||"");null!=(i=e.parentElement)&&i.prepend(r),f.set(a,r);break;case"folder":{const s=document.createElement("div");s.classList.add("playlist-item__img","folder"),y.default.render(u.default.createElement(g,null),s),null!=(i=e.parentElement)&&i.prepend(s),f.set(a,s);break}default:console.warn("[playlist-icons] playlist list anchor type not recognized: "+n)}})}var v="playlist-icons_big";var a=async function(){for(var e,a;null==Spicetify||!Spicetify.Platform||null==Spicetify||!Spicetify.CosmosAsync;)await new Promise(e=>setTimeout(e,100));const t=null!=(e=JSON.parse(localStorage.getItem(v)))&&e,i=await async function e(t){t=await Spicetify.CosmosAsync.get(t);return[...t.items,...t.next?await e(t.next):[]]}("https://api.spotify.com/v1/me/playlists?limit=50"),n=(a="#spicetify-playlist-list",await new Promise(t=>{const i=setInterval(()=>{var e=document.querySelector(a);e&&(clearInterval(i),t(e))},100)})),l=new MutationObserver(async()=>{l.disconnect(),await r(i),l.observe(n,{childList:!0,subtree:!0})});await r(i),l.observe(n,{childList:!0,subtree:!0}),t&&n.classList.add("big-icons"),new Spicetify.Menu.Item("Big playlist icons",t,e=>{e.setState(!e.isEnabled),localStorage.setItem(v,JSON.stringify(!t)),n.classList.toggle("big-icons")}).register()};(async()=>{await a()})()})();(async()=>{var e;document.getElementById("playlistDicons")||((e=document.createElement("style")).id="playlistDicons",e.textContent=String.raw`
|
||||
:root{---playlist-img-spacing:6px}.playlist-item{padding-top:0;padding-bottom:0;align-items:center}.playlist-item__img{width:1.5em;height:1.5em;border-radius:2px;margin-right:12px;filter:brightness(85%)}.playlist-item__img.folder{background-color:var(--spice-tab-active);display:flex;align-items:center;justify-content:center}.playlist-item__img.folder svg{width:1.1em;height:1.1em}.playlist-item__img.no-icon{background-color:var(--spice-tab-active);height:1.5em}.playlist-item:hover .playlist-item__img{transition:.2s ease-out;filter:brightness(100%)}.big-icons .playlist-item{padding-top:var(---playlist-img-spacing);padding-bottom:var(---playlist-img-spacing)}.big-icons .playlist-item__img{border-radius:4px;width:2em;height:2em}.big-icons .playlist-item__img.folder{padding:4px}.big-icons .playlist-item__img.folder svg{width:1.5em;height:1.5em}.big-icons>div{contain:unset}
|
||||
`.trim(),document.head.appendChild(e))})();
|
1306
.config/spicetify/Extensions/sortByPlayCount.js
Normal file
1306
.config/spicetify/Extensions/sortByPlayCount.js
Normal file
File diff suppressed because it is too large
Load diff
32
.config/spicetify/Extensions/volumePercentage.js
Normal file
32
.config/spicetify/Extensions/volumePercentage.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
// @ts-check
|
||||
|
||||
// NAME: Add Volume Percentage
|
||||
// AUTHOR: daksh2k
|
||||
// DESCRIPTION: Add the Volume Percentage to the Volume Bar
|
||||
|
||||
/// <reference path="../globals.d.ts" />
|
||||
|
||||
(function addVolumep() {
|
||||
const volumeBar = document.querySelector(".volume-bar");
|
||||
if (!(volumeBar && Spicetify.Player)) {
|
||||
setTimeout(addVolumep, 200);
|
||||
return;
|
||||
}
|
||||
const ele = document.createElement("span");
|
||||
ele.classList.add("volume-percent");
|
||||
ele.setAttribute("style", "font-size: 14px; padding-left: 10px; min-width: 45px;");
|
||||
|
||||
volumeBar.append(ele);
|
||||
// @ts-ignore
|
||||
volumeBar.style.flex = "0 1 180px";
|
||||
|
||||
updatePercentage();
|
||||
function updatePercentage() {
|
||||
const currVolume = Math.round((Spicetify.Player?.origin?._volume?._volume ?? Spicetify.Platform?.PlaybackAPI?._volume) * 100);
|
||||
ele.innerText = currVolume == -100 ? `` : `${currVolume}%`;
|
||||
// @ts-ignore
|
||||
document.querySelector(".main-connectBar-connectBar")?.style.setProperty("--triangle-position", "229px");
|
||||
}
|
||||
if (Spicetify.Platform?.PlaybackAPI === undefined) Spicetify.Player.origin._events.addListener("volume", updatePercentage);
|
||||
else Spicetify.Platform.PlaybackAPI._events.addListener("volume", updatePercentage);
|
||||
})();
|
96
.config/spicetify/Extensions/wikify.js
Normal file
96
.config/spicetify/Extensions/wikify.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
//@ts-check
|
||||
|
||||
// NAME: Wikify
|
||||
// AUTHOR: CharlieS1103
|
||||
// DESCRIPTION: View an artists wikipedia page to learn more about them
|
||||
|
||||
/// <reference path="../../spicetify-cli/globals.d.ts" />
|
||||
(function WikiFy() {
|
||||
if (!document.body.classList.contains('wikify-injected')) {
|
||||
var styleSheet = document.createElement("style")
|
||||
|
||||
styleSheet.innerHTML =
|
||||
`body > generic-modal > div > div {
|
||||
background-color: beige !important;
|
||||
color: black !important;
|
||||
} `
|
||||
document.body.appendChild(styleSheet)
|
||||
document.body.classList.add('wikify-injected');
|
||||
}
|
||||
const {
|
||||
CosmosAsync,
|
||||
URI
|
||||
} = Spicetify;
|
||||
if (!(CosmosAsync && URI)) {
|
||||
setTimeout(WikiFy, 10);
|
||||
return;
|
||||
}
|
||||
const lang = Spicetify.Locale._locale;
|
||||
const buttontxt = "View Wiki"
|
||||
//Watch for when the song is changed
|
||||
|
||||
function error() {
|
||||
Spicetify.PopupModal.display({
|
||||
title: "Error",
|
||||
content: "Selected artist does not have a WikiPedia page, Sorry."
|
||||
});
|
||||
}
|
||||
|
||||
async function getWikiText(uris) {
|
||||
|
||||
const rawUri = uris[0];
|
||||
const uri = rawUri.split(":")[2]
|
||||
const artistName = await CosmosAsync.get(`https://api.spotify.com/v1/artists/${uri}`)
|
||||
const artistNameTrimmed = (artistName.name).replace(/\s/g, "%20");
|
||||
|
||||
if (artistName != null) {
|
||||
try {
|
||||
const wikiInfo = await CosmosAsync.get(`https://${lang}.wikipedia.org/w/api.php?action=query&format=json&prop=extracts%7Cdescription&titles=${artistNameTrimmed}`)
|
||||
//TODO: option to choose local language or english / english fallback? / subcontextmenu to choose?
|
||||
//https://en.wikipedia.org/w/api.php?action=query&format=json&uselang=en&list=search&srsearch=${artistNameTrimmed}
|
||||
|
||||
const wikiInfoArr = wikiInfo.query.pages
|
||||
const page = Object.values(wikiInfoArr)[0];
|
||||
if (page != null || page != undefined) {
|
||||
const pageText = page.extract.replace(/<!--[\s\S]*?-->/g, '');
|
||||
if (pageText != "\n") {
|
||||
Spicetify.PopupModal.display({
|
||||
title: "WikiFy",
|
||||
content: page.extract
|
||||
});
|
||||
} else {
|
||||
error();
|
||||
}
|
||||
} else {
|
||||
error();
|
||||
}
|
||||
} catch {
|
||||
Spicetify.PopupModal.display({
|
||||
title: "Error",
|
||||
content: "Request failed",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function shouldDisplayContextMenu(uris) {
|
||||
if (uris.length > 1) {
|
||||
return false;
|
||||
}
|
||||
const uri = uris[0];
|
||||
const uriObj = Spicetify.URI.fromString(uri);
|
||||
if (uriObj.type === Spicetify.URI.Type.TRACK || uriObj.type === Spicetify.URI.Type.ARTIST) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const cntxMenu = new Spicetify.ContextMenu.Item(
|
||||
buttontxt,
|
||||
getWikiText,
|
||||
shouldDisplayContextMenu,
|
||||
);
|
||||
|
||||
cntxMenu.register();
|
||||
|
||||
})();
|
406
.config/spicetify/Themes/Comfy/color.ini
Normal file
406
.config/spicetify/Themes/Comfy/color.ini
Normal file
|
@ -0,0 +1,406 @@
|
|||
[Comfy]
|
||||
text = FFFFFF
|
||||
subtext = B9BBBE
|
||||
main = 23283D
|
||||
main-transition = 1E2233
|
||||
highlight = 45495b
|
||||
highlight-elevated = 32364a
|
||||
sidebar = 1E2233
|
||||
player = 101320
|
||||
card = 191F2E
|
||||
shadow = 1E2233
|
||||
selected-row = F1F1F1
|
||||
button = 7289DA
|
||||
button-active = 5C6FB1
|
||||
button-disabled = 4B588C
|
||||
tab-active = 1E2233
|
||||
notification = 7289DA
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = 7289da
|
||||
play-button-active = 869adf
|
||||
progress-fg = 1ed760
|
||||
progress-bg = 7289da
|
||||
heart = d25050
|
||||
liked-left = 3a62f5
|
||||
liked-right = c4efd9
|
||||
pagelink-active = 5c6eb1
|
||||
radio-btn-active = 7289DA
|
||||
|
||||
[Nord]
|
||||
text = B2BCCC
|
||||
subtext = B2BCCC
|
||||
main = 2E3440
|
||||
main-transition = 262B35
|
||||
highlight = 50555f
|
||||
highlight-elevated = 3d424d
|
||||
sidebar = 262B35
|
||||
player = 363d4c
|
||||
card = 363d4c
|
||||
shadow = 1d2128
|
||||
button = 8A99AF
|
||||
button-active = 718CAD
|
||||
button-disabled = 434C5E
|
||||
tab-active = 363d4c
|
||||
notification = 363d4c
|
||||
notification-error = A9555E
|
||||
misc = FFFFFF
|
||||
play-button = 8A99AF
|
||||
play-button-active = 718CAD
|
||||
progress-fg = 8A99AF
|
||||
progress-bg = 4b566a
|
||||
heart = 718CAD
|
||||
liked-left = 262B35
|
||||
liked-right = B2BCCC
|
||||
pagelink-active = b7c1d5
|
||||
radio-btn-active = 363d4c
|
||||
|
||||
[Lunar]
|
||||
text = f3f3f3
|
||||
subtext = cecece
|
||||
main = 161616
|
||||
main-transition = 101010
|
||||
highlight = 2a2a2a
|
||||
highlight-elevated = 232323
|
||||
sidebar = 202020
|
||||
player = 202020
|
||||
card = 202020
|
||||
shadow = 252525
|
||||
selected-row = cecece
|
||||
button = 3281ea
|
||||
button-active = 0284e8
|
||||
button-disabled = 303030
|
||||
tab-active = ebbcba
|
||||
notification = 3281ea
|
||||
notification-error = b10c0c
|
||||
misc = 252525
|
||||
play-button = ebbcba
|
||||
play-button-active = eba9a7
|
||||
progress-fg = 025ca1
|
||||
progress-bg = 202020
|
||||
heart = ebbcba
|
||||
liked-left = 3a62f5
|
||||
liked-right = c4efd9
|
||||
pagelink-active = ffffff
|
||||
radio-btn-active = 0284e8
|
||||
|
||||
[catppuccin-dark]
|
||||
text = cad3f5
|
||||
subtext = b8c0e0
|
||||
main = 181926
|
||||
main-transition = 181926
|
||||
highlight = 333645
|
||||
highlight-elevated = 232533
|
||||
sidebar = 24273a
|
||||
player = 24273a
|
||||
card = 494d64
|
||||
shadow = 5b6078
|
||||
selected-row = b8c0e0
|
||||
button = 8aadf4
|
||||
button-active = 7dc4e4
|
||||
button-disabled = 494d64
|
||||
tab-active = ed8796
|
||||
notification = 8aadf4
|
||||
notification-error = ed8796
|
||||
misc = 5b6078
|
||||
play-button = f5bde6
|
||||
play-button-active = f0c6c6
|
||||
progress-fg = 91d7e3
|
||||
progress-bg = 494d64
|
||||
heart = f5a97f
|
||||
liked-left = a6da95
|
||||
liked-right = b7bdf8
|
||||
pagelink-active = ffffff
|
||||
radio-btn-active = 7dc4e4
|
||||
|
||||
[catppuccin-light]
|
||||
text = cad3f5
|
||||
subtext = b8c0e0
|
||||
main = 494d64
|
||||
main-transition = 181926
|
||||
highlight = 5c6179
|
||||
highlight-elevated = 545a71
|
||||
sidebar = 24273a
|
||||
player = 24273a
|
||||
card = 494d64
|
||||
shadow = 5b6078
|
||||
selected-row = b8c0e0
|
||||
button = 8aadf4
|
||||
button-active = 7dc4e4
|
||||
button-disabled = 494d64
|
||||
tab-active = ed8796
|
||||
notification = 8aadf4
|
||||
notification-error = ed8796
|
||||
misc = 5b6078
|
||||
play-button = f5bde6
|
||||
play-button-active = f0c6c6
|
||||
progress-fg = 91d7e3
|
||||
progress-bg = 494d64
|
||||
heart = f5a97f
|
||||
liked-left = a6da95
|
||||
liked-right = b7bdf8
|
||||
pagelink-active = ffffff
|
||||
radio-btn-active = 7dc4e4
|
||||
|
||||
[Mono]
|
||||
text = FFFFFF
|
||||
subtext = B9BBBE
|
||||
main = 171717
|
||||
main-transition = FFFFFF
|
||||
highlight = 3b3b3b
|
||||
highlight-elevated = 262626
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = 343434
|
||||
shadow = 595858
|
||||
selected-row = F1F1F1
|
||||
button = FFFFFF
|
||||
button-active = c5c5c5
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = 101010
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = FFFFFF
|
||||
play-button-active = FFFFFF
|
||||
progress-fg = FFFFFF
|
||||
progress-bg = 343434
|
||||
heart = FFFFFF
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = 787878
|
||||
radio-btn-active = 737373
|
||||
|
||||
[Deep]
|
||||
text = 4f9a87
|
||||
subtext = 406560
|
||||
button-text = 4f9a87
|
||||
main = 040614
|
||||
main-transition = 0F111A
|
||||
highlight = 0f1f28
|
||||
highlight-elevated = 09111d
|
||||
sidebar = 0F111A
|
||||
player = 0F111A
|
||||
subbutton-text = 040614
|
||||
card = 0f1118
|
||||
shadow = 0f1118
|
||||
selected-row = 4f9a87
|
||||
sub-button = 4f9a87
|
||||
button = 106165
|
||||
button-active = 4f9a87
|
||||
button-disabled = 0C1C19
|
||||
tab-active = 0a1527
|
||||
notification = 051024
|
||||
notification-error = 051024
|
||||
playback-bar = 4f9a87
|
||||
misc = 406560
|
||||
play-button = 106165
|
||||
play-button-active = 4f9a87
|
||||
progress-fg = 4f9a87
|
||||
progress-bg = 106165
|
||||
heart = d25050
|
||||
liked-left = 3a62f5
|
||||
liked-right = c4efd9
|
||||
pagelink-active = 4f9a87
|
||||
radio-btn-active = 4f9a87
|
||||
|
||||
[Sunset]
|
||||
text = ffce3f
|
||||
subtext = fef3bb
|
||||
main = 171717
|
||||
main-transition = 000000
|
||||
highlight = 3d3c32
|
||||
highlight-elevated = 272722
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = cc9756
|
||||
shadow = e3b47b
|
||||
selected-row = fef3bb
|
||||
button = ffce3f
|
||||
button-active = bf9b30
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = ffffff
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = ffce3f
|
||||
play-button-active = fc9e3a
|
||||
progress-fg = ff8300
|
||||
progress-bg = 343434
|
||||
heart = ff8300
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = fef3bb
|
||||
radio-btn-active = fef3bb
|
||||
|
||||
[Neon]
|
||||
text = 588bae
|
||||
subtext = eaffff
|
||||
main = 171717
|
||||
main-transition = 000000
|
||||
highlight = 3b3b3b
|
||||
highlight-elevated = 262626
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = 7fa1b5
|
||||
shadow = a9c9db
|
||||
selected-row = F1F1F1
|
||||
button = 588bae
|
||||
button-active = 3b5d75
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = FFFFFF
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = 588bae
|
||||
play-button-active = 5085ab
|
||||
progress-fg = 00afdb
|
||||
progress-bg = 343434
|
||||
heart = 00afdb
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = bbe7fe
|
||||
radio-btn-active = eaffff
|
||||
|
||||
[Forest]
|
||||
text = B2C5B3
|
||||
subtext = d5ddde
|
||||
main = 171717
|
||||
main-transition = 000000
|
||||
highlight = 3b3b3b
|
||||
highlight-elevated = 262626
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = 5c6e59
|
||||
shadow = 3c5148
|
||||
selected-row = F1F1F1
|
||||
button = B2C5B3
|
||||
button-active = F1F1F1
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = FFFFFF
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = 3c5148
|
||||
play-button-active = 43705d
|
||||
progress-fg = 3c5148
|
||||
progress-bg = 343434
|
||||
heart = 3c5148
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = 3c5148
|
||||
radio-btn-active = 737373
|
||||
|
||||
[Sakura]
|
||||
text = fcb4ca
|
||||
subtext = ffdcdc
|
||||
main = 171717
|
||||
main-transition = 000000
|
||||
highlight = 3d3838
|
||||
highlight-elevated = 272525
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = d68ba2
|
||||
shadow = fcb4ca
|
||||
selected-row = ffdcdc
|
||||
button = fcb4ca
|
||||
button-active = d48aa0
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = FFFFFF
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = f42c38
|
||||
play-button-active = ba182b
|
||||
progress-fg = Cfeefa
|
||||
progress-bg = 343434
|
||||
heart = f25477
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = f5bcdb
|
||||
radio-btn-active = ffdcdc
|
||||
|
||||
[Vaporwave]
|
||||
text = 01CDFE
|
||||
subtext = eaffff
|
||||
main = 171717
|
||||
main-transition = 000000
|
||||
highlight = 3b3b3b
|
||||
highlight-elevated = 262626
|
||||
sidebar = 101010
|
||||
player = 101010
|
||||
card = 007f9e
|
||||
shadow = 2ec2e6
|
||||
selected-row = F1F1F1
|
||||
button = 01CDFE
|
||||
button-active = 118ba8
|
||||
button-disabled = 4a4949
|
||||
tab-active = 303030
|
||||
notification = FFFFFF
|
||||
notification-error = d25050
|
||||
misc = 000000
|
||||
play-button = ffd300
|
||||
play-button-active = e3c01b
|
||||
progress-fg = f706cf
|
||||
progress-bg = 343434
|
||||
heart = f706cf
|
||||
liked-left = 000000
|
||||
liked-right = ffffff
|
||||
pagelink-active = c0d6fa
|
||||
radio-btn-active = eaffff
|
||||
|
||||
[Velvet]
|
||||
text = AD434E
|
||||
subtext = 762F37
|
||||
main = 1E1E1E
|
||||
main-transition = 161616
|
||||
highlight = 322324
|
||||
highlight-elevated = 272021
|
||||
sidebar = 161616
|
||||
player = 080808
|
||||
card = 0F0F0F
|
||||
shadow = 161616
|
||||
selected-row = 973B45
|
||||
button = 6B2B32
|
||||
button-active = 552328
|
||||
button-disabled = 262626
|
||||
tab-active = 161616
|
||||
notification = 6B2B32
|
||||
notification-error = 60272D
|
||||
misc = 000000
|
||||
play-button = 552328
|
||||
play-button-active = 6B2B32
|
||||
progress-fg = 81333B
|
||||
progress-bg = A23F49
|
||||
heart = 60272D
|
||||
liked-left = 2D2D2D
|
||||
liked-right = 8C3740
|
||||
pagelink-active = 4A1F23
|
||||
radio-btn-active = 6B2B32
|
||||
|
||||
[wal16]
|
||||
text = ${xrdb:color15:FFFFFF}
|
||||
subtext = ${xrdb:color6:B9BBBE}
|
||||
main = ${xrdb:color0:23283D}
|
||||
main-transition = ${xrdb:color0:000000}
|
||||
sidebar = ${xrdb:color8:1E2233}
|
||||
player = ${xrdb:color4:101320}
|
||||
card = ${xrdb:color8:191F2E}
|
||||
shadow = ${xrdb:color0:1E2233}
|
||||
selected-row = ${xrdb:color15:F1F1F1}
|
||||
button = ${xrdb:color6:7289DA}
|
||||
button-active = ${xrdb:color14:5C6FB1}
|
||||
button-disabled = ${xrdb:color8:4B588C}
|
||||
tab-active = ${xrdb:color9:1E2233}
|
||||
notification = FFFFFF
|
||||
notification-error = d25050
|
||||
misc = ${xrdb:color0:000000}
|
||||
play-button = ${xrdb:color11:5C6FB1}
|
||||
play-button-active = ${xrdb:color3:7289DA}
|
||||
progress-fg = ${xrdb:color10:1ed760}
|
||||
progress-bg = ${xrdb:color0:f1f1f1}
|
||||
heart = ${xrdb:color10:d25050}
|
||||
liked-left = ${xrdb:color10:3a62f5}
|
||||
liked-right = ${xrdb:color11:c4efd9}
|
||||
pagelink-active = ${xrdb:color13:5c6eb1}
|
||||
radio-btn-active = ${xrdb:color13:7289DA}
|
9
.config/spicetify/Themes/Comfy/theme.js
Normal file
9
.config/spicetify/Themes/Comfy/theme.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
(() => {
|
||||
const themeScript = document.createElement("SCRIPT");
|
||||
themeScript.setAttribute("type", "text/javascript");
|
||||
themeScript.setAttribute(
|
||||
"src",
|
||||
"https://comfy-themes.github.io/Spicetify/Comfy/theme.script.js"
|
||||
);
|
||||
document.head.appendChild(themeScript);
|
||||
})();
|
1
.config/spicetify/Themes/Comfy/user.css
Normal file
1
.config/spicetify/Themes/Comfy/user.css
Normal file
|
@ -0,0 +1 @@
|
|||
@import url("https://comfy-themes.github.io/Spicetify/Comfy/app.css");
|
32
.config/spicetify/config-xpui.ini
Normal file
32
.config/spicetify/config-xpui.ini
Normal file
|
@ -0,0 +1,32 @@
|
|||
[Preprocesses]
|
||||
disable_ui_logging = 1
|
||||
remove_rtl_rule = 1
|
||||
expose_apis = 1
|
||||
disable_upgrade_check = 1
|
||||
disable_sentry = 1
|
||||
|
||||
[AdditionalOptions]
|
||||
sidebar_config = 1
|
||||
home_config = 1
|
||||
experimental_features = 1
|
||||
extensions = adblock.js|hidePodcasts.js|historyShortcut.js|copyPlaylist.js|wikify.js|fullScreen.js|volumePercentage.js|bookmark.js|loopyLoop.js|keyboardShortcutMy.js|genre.js|playlistIcons.js|catppuccin-macchiato.js
|
||||
custom_apps = lyrics-plus|marketplace
|
||||
|
||||
[Patch]
|
||||
|
||||
[Setting]
|
||||
spotify_path = /opt/spotify
|
||||
color_scheme = Comfy
|
||||
overwrite_assets = 1
|
||||
spotify_launch_flags =
|
||||
check_spicetify_upgrade = 0
|
||||
prefs_path = ~/.config/spotify/prefs
|
||||
current_theme = Comfy
|
||||
inject_css = 1
|
||||
replace_colors = 1
|
||||
inject_theme_js = 1
|
||||
|
||||
; DO NOT CHANGE!
|
||||
[Backup]
|
||||
version = 1.2.13.661.ga588f749
|
||||
with = Dev
|
Loading…
Add table
Reference in a new issue