first
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
[AdditionalOptions]
|
||||
extensions = autoSkipVideo.js|fullAppDisplay.js|keyboardShortcut.js
|
||||
custom_apps =
|
||||
sidebar_config = 1
|
||||
home_config = 1
|
||||
experimental_features = 1
|
||||
|
||||
[Patch]
|
||||
|
||||
[Setting]
|
||||
inject_css = 1
|
||||
check_spicetify_upgrade = 0
|
||||
current_theme = wal
|
||||
color_scheme = wal
|
||||
replace_colors = 1
|
||||
overwrite_assets = 0
|
||||
spotify_launch_flags =
|
||||
spotify_path = /opt/spotify
|
||||
prefs_path = /home/emh/.config/spotify/prefs
|
||||
|
||||
[Preprocesses]
|
||||
disable_upgrade_check = 1
|
||||
disable_sentry = 1
|
||||
disable_ui_logging = 1
|
||||
remove_rtl_rule = 1
|
||||
expose_apis = 1
|
||||
|
||||
; DO NOT CHANGE!
|
||||
[Backup]
|
||||
version = 1.1.72.439.gc253025e
|
||||
with = 2.8.4
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
// @ts-check
|
||||
|
||||
// NAME: Auto Skip Video
|
||||
// AUTHOR: khanhas
|
||||
// DESCRIPTION: Auto skip video
|
||||
|
||||
/// <reference path="../globals.d.ts" />
|
||||
|
||||
(function SkipVideo() {
|
||||
Spicetify.Player.addEventListener("songchange", () => {
|
||||
const data = Spicetify.Player.data || Spicetify.Queue;
|
||||
if (!data) return;
|
||||
|
||||
const meta = data.track.metadata;
|
||||
// Ads are also video media type so I need to exclude them out.
|
||||
if (meta["media.type"] === "video" && meta.is_advertisement !== "true") {
|
||||
Spicetify.Player.next();
|
||||
}
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,764 @@
|
||||
// @ts-check
|
||||
// NAME: Full App Display
|
||||
// AUTHOR: khanhas
|
||||
// VERSION: 1.0
|
||||
// DESCRIPTION: Fancy artwork and track status display.
|
||||
|
||||
/// <reference path="../globals.d.ts" />
|
||||
(function FullAppDisplay() {
|
||||
if (!Spicetify.Keyboard || !Spicetify.React || !Spicetify.ReactDOM) {
|
||||
setTimeout(FullAppDisplay, 200);
|
||||
return;
|
||||
}
|
||||
|
||||
const { React: react, ReactDOM: reactDOM } = Spicetify;
|
||||
const { useState, useEffect } = react;
|
||||
|
||||
const CONFIG = getConfig();
|
||||
let updateVisual;
|
||||
|
||||
const style = document.createElement("style");
|
||||
const styleBase = `
|
||||
#full-app-display {
|
||||
display: none;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: default;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
#fad-header {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
#fad-body {
|
||||
height: 100vh;
|
||||
}
|
||||
#fad-foreground {
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: scale(var(--fad-scale));
|
||||
}
|
||||
#fad-art-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 100%;
|
||||
border-radius: 15px;
|
||||
background-size: cover;
|
||||
}
|
||||
#fad-art-inner {
|
||||
position: absolute;
|
||||
left: 3%;
|
||||
bottom: 0;
|
||||
width: 94%;
|
||||
height: 94%;
|
||||
z-index: -1;
|
||||
backface-visibility: hidden;
|
||||
transform: translateZ(0);
|
||||
filter: blur(6px);
|
||||
backdrop-filter: blur(6px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
#fad-progress-container {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
#fad-progress {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff50;
|
||||
overflow: hidden;
|
||||
}
|
||||
#fad-progress-inner {
|
||||
height: 100%;
|
||||
border-radius: 6px;
|
||||
background-color: #ffffff;
|
||||
box-shadow: 4px 0 12px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
#fad-duration {
|
||||
margin-left: 10px;
|
||||
}
|
||||
#fad-background {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -2;
|
||||
}
|
||||
body.fad-activated #full-app-display {
|
||||
display: block
|
||||
}
|
||||
.fad-background-fade {
|
||||
transition: background-image 1s linear;
|
||||
}
|
||||
body.video-full-screen.video-full-screen--hide-ui {
|
||||
cursor: auto;
|
||||
}
|
||||
#fad-controls button {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
color: currentColor;
|
||||
padding: 0 5px;
|
||||
}
|
||||
#fad-artist svg, #fad-album svg {
|
||||
display: inline-block;
|
||||
}
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const styleChoices = [
|
||||
`
|
||||
#fad-foreground {
|
||||
flex-direction: row;
|
||||
text-align: left;
|
||||
}
|
||||
#fad-art {
|
||||
width: calc(100vw - 840px);
|
||||
min-width: 200px;
|
||||
max-width: 340px;
|
||||
}
|
||||
#fad-details {
|
||||
padding-left: 50px;
|
||||
line-height: initial;
|
||||
max-width: 70%;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#fad-title {
|
||||
font-size: 87px;
|
||||
font-weight: var(--glue-font-weight-black);
|
||||
}
|
||||
#fad-artist, #fad-album {
|
||||
font-size: 54px;
|
||||
font-weight: var(--glue-font-weight-medium);
|
||||
}
|
||||
#fad-artist svg, #fad-album svg {
|
||||
margin-right: 5px;
|
||||
}
|
||||
#fad-status {
|
||||
display: flex;
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
align-items: center;
|
||||
}
|
||||
#fad-status.active {
|
||||
margin-top: 20px;
|
||||
}
|
||||
#fad-controls {
|
||||
display: flex;
|
||||
margin-right: 10px;
|
||||
}
|
||||
#fad-elapsed {
|
||||
min-width: 52px;
|
||||
}`,
|
||||
`
|
||||
#fad-art {
|
||||
width: calc(100vh - 400px);
|
||||
max-width: 340px;
|
||||
}
|
||||
#fad-foreground {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
#fad-details {
|
||||
padding-top: 50px;
|
||||
line-height: initial;
|
||||
max-width: 70%;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
#fad-title {
|
||||
font-size: 54px;
|
||||
font-weight: var(--glue-font-weight-black);
|
||||
}
|
||||
#fad-artist, #fad-album {
|
||||
font-size: 33px;
|
||||
font-weight: var(--glue-font-weight-medium);
|
||||
}
|
||||
#fad-artist svg, #fad-album svg {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin-right: 5px;
|
||||
}
|
||||
#fad-status {
|
||||
display: flex;
|
||||
min-width: 400px;
|
||||
max-width: 400px;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
#fad-status.active {
|
||||
margin: 20px auto 0;
|
||||
}
|
||||
#fad-controls {
|
||||
margin-top: 20px;
|
||||
order: 2
|
||||
}
|
||||
#fad-elapsed {
|
||||
min-width: 56px;
|
||||
margin-right: 10px;
|
||||
text-align: right;
|
||||
}`,
|
||||
];
|
||||
|
||||
const lyricsPlusBase = `
|
||||
#fad-body {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
#fad-foreground {
|
||||
padding: 0 50px 0 100px;
|
||||
width: 50vw;
|
||||
}
|
||||
#fad-lyrics-plus-container {
|
||||
width: 50vw;
|
||||
}
|
||||
`;
|
||||
const lyricsPlusStyleChoices = [
|
||||
`
|
||||
#fad-title {
|
||||
font-size: 54px;
|
||||
}
|
||||
#fad-art {
|
||||
max-width: 210px;
|
||||
margin-left: 50px;
|
||||
}`,
|
||||
``,
|
||||
];
|
||||
updateStyle();
|
||||
|
||||
const DisplayIcon = ({ icon, size }) => {
|
||||
return react.createElement("svg", {
|
||||
width: size,
|
||||
height: size,
|
||||
viewBox: "0 0 16 16",
|
||||
fill: "currentColor",
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: icon,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const SubInfo = ({ text, id, icon }) => {
|
||||
return react.createElement(
|
||||
"div",
|
||||
{
|
||||
id,
|
||||
},
|
||||
CONFIG.icons && react.createElement(DisplayIcon, { icon, size: 35 }),
|
||||
react.createElement("span", null, text)
|
||||
);
|
||||
};
|
||||
|
||||
const ButtonIcon = ({ icon, onClick }) => {
|
||||
return react.createElement(
|
||||
"button",
|
||||
{
|
||||
onClick,
|
||||
},
|
||||
react.createElement(DisplayIcon, { icon, size: 20 })
|
||||
);
|
||||
};
|
||||
|
||||
const ProgressBar = () => {
|
||||
const [value, setValue] = useState(Spicetify.Player.getProgress());
|
||||
useEffect(() => {
|
||||
const update = ({ data }) => setValue(data);
|
||||
Spicetify.Player.addEventListener("onprogress", update);
|
||||
return () => Spicetify.Player.removeEventListener("onprogress", update);
|
||||
});
|
||||
const duration = Spicetify.Platform.PlayerAPI._state.duration;
|
||||
return react.createElement(
|
||||
"div",
|
||||
{ id: "fad-progress-container" },
|
||||
react.createElement("span", { id: "fad-elapsed" }, Spicetify.Player.formatTime(value)),
|
||||
react.createElement(
|
||||
"div",
|
||||
{ id: "fad-progress" },
|
||||
react.createElement("div", {
|
||||
id: "fad-progress-inner",
|
||||
style: {
|
||||
width: (value / duration) * 100 + "%",
|
||||
},
|
||||
})
|
||||
),
|
||||
react.createElement("span", { id: "fad-duration" }, Spicetify.Player.formatTime(duration))
|
||||
);
|
||||
};
|
||||
|
||||
const PlayerControls = () => {
|
||||
const [value, setValue] = useState(Spicetify.Player.isPlaying());
|
||||
useEffect(() => {
|
||||
const update = ({ data }) => setValue(!data.is_paused);
|
||||
Spicetify.Player.addEventListener("onplaypause", update);
|
||||
return () => Spicetify.Player.removeEventListener("onplaypause", update);
|
||||
});
|
||||
return react.createElement(
|
||||
"div",
|
||||
{ id: "fad-controls" },
|
||||
react.createElement(ButtonIcon, {
|
||||
icon: Spicetify.SVGIcons["skip-back"],
|
||||
onClick: Spicetify.Player.back,
|
||||
}),
|
||||
react.createElement(ButtonIcon, {
|
||||
icon: Spicetify.SVGIcons[value ? "pause" : "play"],
|
||||
onClick: Spicetify.Player.togglePlay,
|
||||
}),
|
||||
react.createElement(ButtonIcon, {
|
||||
icon: Spicetify.SVGIcons["skip-forward"],
|
||||
onClick: Spicetify.Player.next,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
class FAD extends react.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
title: "",
|
||||
artist: "",
|
||||
album: "",
|
||||
cover: "",
|
||||
};
|
||||
this.currTrackImg = new Image();
|
||||
this.nextTrackImg = new Image();
|
||||
this.mousetrap = new Spicetify.Mousetrap();
|
||||
}
|
||||
|
||||
async getAlbumDate(uri) {
|
||||
const id = uri.replace("spotify:album:", "");
|
||||
const albumInfo = await Spicetify.CosmosAsync.get(`hm://album/v1/album-app/album/${id}/desktop`);
|
||||
|
||||
const albumDate = new Date(albumInfo.year, (albumInfo.month || 1) - 1, albumInfo.day || 0);
|
||||
const recentDate = new Date();
|
||||
recentDate.setMonth(recentDate.getMonth() - 6);
|
||||
return albumDate.toLocaleString("default", albumDate > recentDate ? { year: "numeric", month: "short" } : { year: "numeric" });
|
||||
}
|
||||
|
||||
async fetchInfo() {
|
||||
const meta = Spicetify.Player.data.track.metadata;
|
||||
|
||||
// prepare title
|
||||
let rawTitle = meta.title;
|
||||
if (CONFIG.trimTitle) {
|
||||
rawTitle = rawTitle
|
||||
.replace(/\(.+?\)/g, "")
|
||||
.replace(/\[.+?\]/g, "")
|
||||
.replace(/\s\-\s.+?$/, "")
|
||||
.trim();
|
||||
}
|
||||
|
||||
// prepare artist
|
||||
let artistName;
|
||||
if (CONFIG.showAllArtists) {
|
||||
artistName = Object.keys(meta)
|
||||
.filter((key) => key.startsWith("artist_name"))
|
||||
.sort()
|
||||
.map((key) => meta[key])
|
||||
.join(", ");
|
||||
} else {
|
||||
artistName = meta.artist_name;
|
||||
}
|
||||
|
||||
// prepare album
|
||||
let albumText = meta.album_title || "";
|
||||
if (CONFIG.showAlbum) {
|
||||
const albumURI = meta.album_uri;
|
||||
if (albumURI?.startsWith("spotify:album:")) {
|
||||
albumText += " • " + (await this.getAlbumDate(albumURI));
|
||||
}
|
||||
}
|
||||
|
||||
if (meta.image_xlarge_url === this.currTrackImg.src) {
|
||||
this.setState({
|
||||
title: rawTitle || "",
|
||||
artist: artistName || "",
|
||||
album: albumText || "",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Pre-load next track
|
||||
// Wait until next track image is downloaded then update UI text and images
|
||||
const previousImg = this.currTrackImg.cloneNode();
|
||||
this.currTrackImg.src = meta.image_xlarge_url;
|
||||
this.currTrackImg.onload = () => {
|
||||
const bgImage = `url("${this.currTrackImg.src}")`;
|
||||
|
||||
this.animateCanvas(previousImg, this.currTrackImg);
|
||||
this.setState({
|
||||
title: rawTitle || "",
|
||||
artist: artistName || "",
|
||||
album: albumText || "",
|
||||
cover: bgImage,
|
||||
});
|
||||
};
|
||||
this.currTrackImg.onerror = () => {
|
||||
// Placeholder
|
||||
this.currTrackImg.src =
|
||||
"data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHZpZXdCb3g9IjAgMCA0MCA0MCI+CiAgPHJlY3Qgc3R5bGU9ImZpbGw6I2ZmZmZmZiIgd2lkdGg9IjQwIiBoZWlnaHQ9IjQwIiB4PSIwIiB5PSIwIiAvPgogIDxwYXRoIGZpbGw9IiNCM0IzQjMiIGQ9Ik0yNi4yNSAxNi4xNjJMMjEuMDA1IDEzLjEzNEwyMS4wMTIgMjIuNTA2QzIwLjU5NCAyMi4xOTIgMjAuMDgxIDIxLjk5OSAxOS41MTkgMjEuOTk5QzE4LjE0MSAyMS45OTkgMTcuMDE5IDIzLjEyMSAxNy4wMTkgMjQuNDk5QzE3LjAxOSAyNS44NzggMTguMTQxIDI2Ljk5OSAxOS41MTkgMjYuOTk5QzIwLjg5NyAyNi45OTkgMjIuMDE5IDI1Ljg3OCAyMi4wMTkgMjQuNDk5QzIyLjAxOSAyNC40MjIgMjIuMDA2IDE0Ljg2NyAyMi4wMDYgMTQuODY3TDI1Ljc1IDE3LjAyOUwyNi4yNSAxNi4xNjJaTTE5LjUxOSAyNS45OThDMTguNjkyIDI1Ljk5OCAxOC4wMTkgMjUuMzI1IDE4LjAxOSAyNC40OThDMTguMDE5IDIzLjY3MSAxOC42OTIgMjIuOTk4IDE5LjUxOSAyMi45OThDMjAuMzQ2IDIyLjk5OCAyMS4wMTkgMjMuNjcxIDIxLjAxOSAyNC40OThDMjEuMDE5IDI1LjMyNSAyMC4zNDYgMjUuOTk4IDE5LjUxOSAyNS45OThaIi8+Cjwvc3ZnPgo=";
|
||||
};
|
||||
}
|
||||
|
||||
animateCanvas(prevImg, nextImg) {
|
||||
const { innerWidth: width, innerHeight: height } = window;
|
||||
this.back.width = width;
|
||||
this.back.height = height;
|
||||
const dim = width > height ? width : height;
|
||||
|
||||
const ctx = this.back.getContext("2d");
|
||||
ctx.imageSmoothingEnabled = false;
|
||||
ctx.filter = `blur(30px) brightness(0.6)`;
|
||||
const blur = 30;
|
||||
|
||||
if (!CONFIG.enableFade) {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.drawImage(nextImg, -blur * 2, -blur * 2 - (width - height) / 2, dim + 4 * blur, dim + 4 * blur);
|
||||
return;
|
||||
}
|
||||
|
||||
let factor = 0.0;
|
||||
const animate = () => {
|
||||
ctx.globalAlpha = 1;
|
||||
ctx.drawImage(prevImg, -blur * 2, -blur * 2 - (width - height) / 2, dim + 4 * blur, dim + 4 * blur);
|
||||
ctx.globalAlpha = Math.sin((Math.PI / 2) * factor);
|
||||
ctx.drawImage(nextImg, -blur * 2, -blur * 2 - (width - height) / 2, dim + 4 * blur, dim + 4 * blur);
|
||||
|
||||
if (factor < 1.0) {
|
||||
factor += 0.016;
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.updateInfo = this.fetchInfo.bind(this);
|
||||
Spicetify.Player.addEventListener("songchange", this.updateInfo);
|
||||
this.updateInfo();
|
||||
|
||||
updateVisual = () => {
|
||||
updateStyle();
|
||||
this.fetchInfo();
|
||||
};
|
||||
|
||||
this.onQueueChange = async (queue) => {
|
||||
queue = queue.data;
|
||||
let nextTrack;
|
||||
if (queue.queued.length) {
|
||||
nextTrack = queue.queued[0];
|
||||
} else {
|
||||
nextTrack = queue.nextUp[0];
|
||||
}
|
||||
this.nextTrackImg.src = nextTrack.metadata.image_xlarge_url;
|
||||
};
|
||||
|
||||
const scaleLimit = { min: 0.1, max: 4, step: 0.05 };
|
||||
this.onScaleChange = (event) => {
|
||||
if (!event.ctrlKey) return;
|
||||
let dir = event.deltaY < 0 ? 1 : -1;
|
||||
let temp = (CONFIG["scale"] || 1) + dir * scaleLimit.step;
|
||||
if (temp < scaleLimit.min) {
|
||||
temp = scaleLimit.min;
|
||||
} else if (temp > scaleLimit.max) {
|
||||
temp = scaleLimit.max;
|
||||
}
|
||||
CONFIG["scale"] = temp;
|
||||
saveConfig();
|
||||
updateVisual();
|
||||
};
|
||||
|
||||
Spicetify.Platform.PlayerAPI._events.addListener("queue_update", this.onQueueChange);
|
||||
this.mousetrap.bind("esc", deactivate);
|
||||
window.dispatchEvent(new Event("fad-request"));
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
Spicetify.Player.removeEventListener("songchange", this.updateInfo);
|
||||
Spicetify.Platform.PlayerAPI._events.removeListener("queue_update", this.onQueueChange);
|
||||
this.mousetrap.unbind("esc");
|
||||
}
|
||||
|
||||
render() {
|
||||
return react.createElement(
|
||||
"div",
|
||||
{
|
||||
id: "full-app-display",
|
||||
className: "Video VideoPlayer--fullscreen VideoPlayer--landscape",
|
||||
onDoubleClick: deactivate,
|
||||
onContextMenu: openConfig,
|
||||
},
|
||||
react.createElement("canvas", {
|
||||
id: "fad-background",
|
||||
ref: (el) => (this.back = el),
|
||||
}),
|
||||
react.createElement("div", { id: "fad-header" }),
|
||||
react.createElement(
|
||||
"div",
|
||||
{ id: "fad-body" },
|
||||
react.createElement(
|
||||
"div",
|
||||
{
|
||||
id: "fad-foreground",
|
||||
style: {
|
||||
"--fad-scale": CONFIG["scale"] || 1,
|
||||
},
|
||||
ref: (el) => {
|
||||
if (!el) return;
|
||||
el.onmousewheel = this.onScaleChange;
|
||||
},
|
||||
},
|
||||
react.createElement(
|
||||
"div",
|
||||
{ id: "fad-art" },
|
||||
react.createElement(
|
||||
"div",
|
||||
{
|
||||
id: "fad-art-image",
|
||||
className: CONFIG.enableFade && "fad-background-fade",
|
||||
style: {
|
||||
backgroundImage: this.state.cover,
|
||||
},
|
||||
},
|
||||
react.createElement("div", { id: "fad-art-inner" })
|
||||
)
|
||||
),
|
||||
react.createElement(
|
||||
"div",
|
||||
{ id: "fad-details" },
|
||||
react.createElement("div", { id: "fad-title" }, this.state.title),
|
||||
react.createElement(SubInfo, {
|
||||
id: "fad-artist",
|
||||
text: this.state.artist,
|
||||
icon: Spicetify.SVGIcons.artist,
|
||||
}),
|
||||
CONFIG.showAlbum &&
|
||||
react.createElement(SubInfo, {
|
||||
id: "fad-album",
|
||||
text: this.state.album,
|
||||
icon: Spicetify.SVGIcons.album,
|
||||
}),
|
||||
react.createElement(
|
||||
"div",
|
||||
{
|
||||
id: "fad-status",
|
||||
className: (CONFIG.enableControl || CONFIG.enableProgress) && "active",
|
||||
},
|
||||
CONFIG.enableControl && react.createElement(PlayerControls),
|
||||
CONFIG.enableProgress && react.createElement(ProgressBar)
|
||||
)
|
||||
)
|
||||
),
|
||||
CONFIG.lyricsPlus &&
|
||||
react.createElement("div", {
|
||||
id: "fad-lyrics-plus-container",
|
||||
style: {
|
||||
"--lyrics-color-active": "#ffffff",
|
||||
"--lyrics-color-inactive": "#ffffff50",
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const classes = ["video", "video-full-screen", "video-full-window", "video-full-screen--hide-ui", "fad-activated"];
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.id = "fad-main";
|
||||
let lastApp;
|
||||
|
||||
async function toggleFullscreen() {
|
||||
if (CONFIG.enableFullscreen) {
|
||||
await document.documentElement.requestFullscreen();
|
||||
} else if (document.webkitIsFullScreen) {
|
||||
await document.exitFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
async function activate() {
|
||||
await toggleFullscreen();
|
||||
|
||||
document.body.classList.add(...classes);
|
||||
document.body.append(style, container);
|
||||
reactDOM.render(react.createElement(FAD), container);
|
||||
|
||||
requestLyricsPlus();
|
||||
}
|
||||
|
||||
function deactivate() {
|
||||
if (CONFIG.enableFullscreen || document.webkitIsFullScreen) {
|
||||
document.exitFullscreen();
|
||||
}
|
||||
document.body.classList.remove(...classes);
|
||||
reactDOM.unmountComponentAtNode(container);
|
||||
style.remove();
|
||||
container.remove();
|
||||
window.dispatchEvent(new Event("fad-request"));
|
||||
|
||||
if (lastApp && lastApp !== "/lyrics-plus") {
|
||||
Spicetify.Platform.History.push(lastApp);
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFad() {
|
||||
if (document.body.classList.contains("fad-activated")) {
|
||||
deactivate();
|
||||
} else {
|
||||
activate();
|
||||
}
|
||||
}
|
||||
|
||||
function updateStyle() {
|
||||
style.innerHTML =
|
||||
styleBase +
|
||||
styleChoices[CONFIG.vertical ? 1 : 0] +
|
||||
(CONFIG.lyricsPlus ? lyricsPlusBase + lyricsPlusStyleChoices[CONFIG.vertical ? 1 : 0] : "");
|
||||
}
|
||||
|
||||
function requestLyricsPlus() {
|
||||
if (CONFIG.lyricsPlus) {
|
||||
lastApp = Spicetify.Platform.History.location.pathname;
|
||||
if (lastApp !== "/lyrics-plus") {
|
||||
Spicetify.Platform.History.push("/lyrics-plus");
|
||||
}
|
||||
}
|
||||
window.dispatchEvent(new Event("fad-request"));
|
||||
}
|
||||
|
||||
function getConfig() {
|
||||
try {
|
||||
const parsed = JSON.parse(Spicetify.LocalStorage.get("full-app-display-config"));
|
||||
if (parsed && typeof parsed === "object") {
|
||||
return parsed;
|
||||
}
|
||||
throw "";
|
||||
} catch {
|
||||
Spicetify.LocalStorage.set("full-app-display-config", "{}");
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
Spicetify.LocalStorage.set("full-app-display-config", JSON.stringify(CONFIG));
|
||||
}
|
||||
|
||||
const ConfigItem = ({ name, field, func }) => {
|
||||
const [value, setValue] = useState(CONFIG[field]);
|
||||
return react.createElement(
|
||||
"div",
|
||||
{ className: "setting-row" },
|
||||
react.createElement("label", { className: "col description" }, name),
|
||||
react.createElement(
|
||||
"div",
|
||||
{ className: "col action" },
|
||||
react.createElement(
|
||||
"button",
|
||||
{
|
||||
className: "switch" + (value ? "" : " disabled"),
|
||||
onClick: () => {
|
||||
const state = !value;
|
||||
CONFIG[field] = state;
|
||||
setValue(state);
|
||||
saveConfig();
|
||||
func();
|
||||
},
|
||||
},
|
||||
react.createElement(DisplayIcon, { icon: Spicetify.SVGIcons.check, size: 16 })
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
function openConfig(event) {
|
||||
event.preventDefault();
|
||||
const style = react.createElement("style", {
|
||||
dangerouslySetInnerHTML: {
|
||||
__html: `
|
||||
.setting-row::after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
.setting-row .col {
|
||||
display: flex;
|
||||
padding: 10px 0;
|
||||
align-items: center;
|
||||
}
|
||||
.setting-row .col.description {
|
||||
float: left;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.setting-row .col.action {
|
||||
float: right;
|
||||
text-align: right;
|
||||
}
|
||||
button.switch {
|
||||
align-items: center;
|
||||
border: 0px;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(var(--spice-rgb-shadow), .7);
|
||||
color: var(--spice-text);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
margin-inline-start: 12px;
|
||||
padding: 8px;
|
||||
}
|
||||
button.switch.disabled {
|
||||
color: rgba(var(--spice-rgb-text), .3);
|
||||
}
|
||||
`,
|
||||
},
|
||||
});
|
||||
let configContainer = react.createElement(
|
||||
"div",
|
||||
null,
|
||||
style,
|
||||
react.createElement(ConfigItem, {
|
||||
name: "Enable Lyrics Plus integration",
|
||||
field: "lyricsPlus",
|
||||
func: () => {
|
||||
updateVisual();
|
||||
requestLyricsPlus();
|
||||
},
|
||||
}),
|
||||
react.createElement(ConfigItem, { name: "Enable progress bar", field: "enableProgress", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Enable controls", field: "enableControl", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Trim title", field: "trimTitle", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Show album", field: "showAlbum", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Show all artists", field: "showAllArtists", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Show icons", field: "icons", func: updateVisual }),
|
||||
react.createElement(ConfigItem, { name: "Vertical mode", field: "vertical", func: updateStyle }),
|
||||
react.createElement(ConfigItem, { name: "Enable fullscreen", field: "enableFullscreen", func: toggleFullscreen }),
|
||||
react.createElement(ConfigItem, { name: "Enable song change animation", field: "enableFade", func: updateVisual })
|
||||
);
|
||||
Spicetify.PopupModal.display({
|
||||
title: "Full App Display",
|
||||
content: configContainer,
|
||||
});
|
||||
}
|
||||
|
||||
// Add activator on top bar
|
||||
new Spicetify.Topbar.Button(
|
||||
"Full App Display",
|
||||
`<svg role="img" height="16" width="16" viewBox="0 0 16 16" fill="currentColor">${Spicetify.SVGIcons.projector}</svg>`,
|
||||
activate
|
||||
);
|
||||
|
||||
Spicetify.Mousetrap.bind("f11", toggleFad);
|
||||
})();
|
||||
@@ -0,0 +1,460 @@
|
||||
//@ts-check
|
||||
|
||||
// NAME: Keyboard Shortcut
|
||||
// AUTHOR: khanhas
|
||||
// DESCRIPTION: Register a few more keybinds to support keyboard-driven navigation in Spotify client.
|
||||
|
||||
/// <reference path="../globals.d.ts" />
|
||||
|
||||
(function KeyboardShortcut() {
|
||||
if (!Spicetify.Keyboard) {
|
||||
setTimeout(KeyboardShortcut, 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.
|
||||
*/
|
||||
|
||||
// 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);
|
||||
|
||||
if (window.navigator.userAgent.indexOf("Win") === -1) {
|
||||
// CTRL + Arrow Left Next and CTRL + Arrow Right Previous Song
|
||||
registerBind("ARROW_RIGHT", true, false, false, nextSong);
|
||||
registerBind("ARROW_LEFT", true, false, false, previousSong);
|
||||
|
||||
// CTRL + Arrow Up Increase Volume CTRL + Arrow Down Decrease Volume
|
||||
registerBind("ARROW_UP", true, false, false, increaseVolume);
|
||||
registerBind("ARROW_DOWN", true, false, false, decreaseVolume);
|
||||
}
|
||||
|
||||
// F to activate Link Follow function
|
||||
const vim = new VimBind();
|
||||
registerBind("F", false, false, false, vim.activate.bind(vim));
|
||||
// Esc to cancel Link Follow
|
||||
vim.setCancelKey("ESCAPE");
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
function nextSong() {
|
||||
document.querySelector(".main-skipForwardButton-button").click();
|
||||
}
|
||||
|
||||
function previousSong() {
|
||||
document.querySelector(".main-skipBackButton-button").click();
|
||||
}
|
||||
|
||||
function increaseVolume() {
|
||||
Spicetify.Player.origin.setVolume(Spicetify.Player.getVolume() + 0.1);
|
||||
}
|
||||
|
||||
function decreaseVolume() {
|
||||
Spicetify.Player.origin.setVolume(Spicetify.Player.getVolume() - 0.1);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
[Base]
|
||||
text = ${xrdb:foreground}
|
||||
subtext = ${xrdb:color8}
|
||||
main = ${xrdb:background}
|
||||
sidebar = ${xrdb:color0}
|
||||
player = ${xrdb:background}
|
||||
card = ${xrdb:color4}
|
||||
shadow = ${xrdb:color0}
|
||||
selected-row = ${xrdb:color15}
|
||||
button = ${xrdb:color1}
|
||||
button-active = ${xrdb:color9}
|
||||
button-disabled = ${xrdb:color0}
|
||||
tab-active = ${xrdb:color0}
|
||||
notification = ${xrdb:color4}
|
||||
notification-error = ${xrdb:color1}
|
||||
misc = ${xrdb:color5}
|
||||
|
||||
[wal]
|
||||
text = ${xrdb:foreground}
|
||||
subtext = ${xrdb:color15}
|
||||
main = ${xrdb:background}
|
||||
sidebar = ${xrdb:color0}
|
||||
player = ${xrdb:background}
|
||||
card = ${xrdb:color4}
|
||||
shadow = ${xrdb:color0}
|
||||
selected-row = ${xrdb:color15}
|
||||
button = ${xrdb:color1}
|
||||
button-active = ${xrdb:color9}
|
||||
button-disabled = ${xrdb:color8}
|
||||
tab-active = ${xrdb:color0}
|
||||
notification = ${xrdb:color4}
|
||||
notification-error = ${xrdb:color1}
|
||||
misc = ${xrdb:color5}
|
||||
@@ -0,0 +1,11 @@
|
||||
.main-leaderboardComponent-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-home-content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.main-home-homeHeader {
|
||||
display: none;
|
||||
}
|
||||
Reference in New Issue
Block a user