2023-04-16 02:43:55 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-31 13:27:16 +02:00
|
|
|
let DribbblishShared = {};
|
|
|
|
|
2023-06-21 02:17:59 +02:00
|
|
|
// back shadow
|
2023-04-16 02:43:55 +02:00
|
|
|
waitForElement([".Root__top-container"], ([topContainer]) => {
|
|
|
|
const shadow = document.createElement("div");
|
|
|
|
shadow.id = "dribbblish-back-shadow";
|
|
|
|
topContainer.prepend(shadow);
|
|
|
|
});
|
|
|
|
|
2023-07-31 13:27:16 +02:00
|
|
|
// Spicetify.Platform.ConnectAPI.state.connectionStatus;
|
|
|
|
|
2023-04-16 02:43:55 +02:00
|
|
|
// add fade effect on playlist/folder list
|
2023-06-21 02:17:59 +02:00
|
|
|
waitForElement([".main-navBar-mainNav .os-viewport.os-viewport-native-scrollbars-invisible"], ([scrollNode]) => {
|
2023-04-16 02:43:55 +02:00
|
|
|
scrollNode.setAttribute("fade", "bottom");
|
|
|
|
scrollNode.addEventListener("scroll", () => {
|
|
|
|
if (scrollNode.scrollTop == 0) {
|
|
|
|
scrollNode.setAttribute("fade", "bottom");
|
|
|
|
} else if (scrollNode.scrollHeight - scrollNode.clientHeight - scrollNode.scrollTop == 0) {
|
|
|
|
scrollNode.setAttribute("fade", "top");
|
|
|
|
} else {
|
|
|
|
scrollNode.setAttribute("fade", "full");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2023-07-31 13:27:16 +02:00
|
|
|
let version;
|
2023-11-10 00:48:00 +01:00
|
|
|
let ylx;
|
2023-07-31 13:27:16 +02:00
|
|
|
|
2023-04-16 02:43:55 +02:00
|
|
|
(function Dribbblish() {
|
|
|
|
// dynamic playback time tooltip
|
|
|
|
const progBar = document.querySelector(".playback-bar");
|
|
|
|
const root = document.querySelector(".Root");
|
|
|
|
|
|
|
|
if (!Spicetify.Player.origin || !progBar || !root) {
|
|
|
|
setTimeout(Dribbblish, 300);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-07-31 13:27:16 +02:00
|
|
|
version = Spicetify.Platform.PlatformData.event_sender_context_information.client_version_int;
|
|
|
|
|
|
|
|
if (version < 121200000) {
|
|
|
|
document.documentElement.classList.add("legacy");
|
|
|
|
legacy();
|
|
|
|
} else if (version >= 121200000 && version < 121400000) {
|
|
|
|
document.documentElement.classList.add("legacy-gridChange");
|
|
|
|
legacy();
|
|
|
|
} else if (version >= 121400000) {
|
|
|
|
document.documentElement.classList.add("ylx");
|
2023-11-10 00:48:00 +01:00
|
|
|
ylx = true;
|
2023-07-31 13:27:16 +02:00
|
|
|
}
|
|
|
|
|
2023-04-16 02:43:55 +02:00
|
|
|
const tooltip = document.createElement("div");
|
|
|
|
tooltip.className = "prog-tooltip";
|
|
|
|
progBar.append(tooltip);
|
|
|
|
|
|
|
|
function updateProgTime({ data: e }) {
|
|
|
|
const maxWidth = progBar.offsetWidth;
|
|
|
|
const curWidth = Spicetify.Player.getProgressPercent() * maxWidth;
|
|
|
|
const ttWidth = tooltip.offsetWidth / 2;
|
2023-06-21 02:17:59 +02:00
|
|
|
if (curWidth < ttWidth + 12) {
|
|
|
|
tooltip.style.left = "12px";
|
|
|
|
} else if (curWidth > maxWidth - ttWidth - 12) {
|
|
|
|
tooltip.style.left = String(maxWidth - ttWidth * 2 - 12) + "px";
|
2023-04-16 02:43:55 +02:00
|
|
|
} else {
|
2023-06-21 02:17:59 +02:00
|
|
|
tooltip.style.left = String(curWidth - ttWidth) + "px";
|
2023-04-16 02:43:55 +02:00
|
|
|
}
|
2023-06-21 02:17:59 +02:00
|
|
|
tooltip.innerText = Spicetify.Player.formatTime(e) + " / " + Spicetify.Player.formatTime(Spicetify.Player.getDuration());
|
2023-04-16 02:43:55 +02:00
|
|
|
}
|
|
|
|
Spicetify.Player.addEventListener("onprogress", updateProgTime);
|
|
|
|
updateProgTime({ data: Spicetify.Player.getProgress() });
|
2023-07-31 13:27:16 +02:00
|
|
|
|
|
|
|
// filepicker for custom folder images
|
|
|
|
const filePickerForm = document.createElement("form");
|
|
|
|
filePickerForm.setAttribute("aria-hidden", true);
|
|
|
|
filePickerForm.innerHTML = '<input type="file" class="hidden-visually" />';
|
|
|
|
/** @type {HTMLInputElement} */
|
|
|
|
const filePickerInput = filePickerForm.childNodes[0];
|
|
|
|
filePickerInput.accept = ["image/jpeg", "image/apng", "image/avif", "image/gif", "image/png", "image/svg+xml", "image/webp"].join(",");
|
|
|
|
|
|
|
|
filePickerInput.onchange = () => {
|
|
|
|
if (!filePickerInput.files.length) return;
|
|
|
|
|
|
|
|
const file = filePickerInput.files[0];
|
|
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = event => {
|
|
|
|
const result = event.target.result;
|
|
|
|
const id = Spicetify.URI.from(filePickerInput.uri).id;
|
|
|
|
try {
|
|
|
|
localStorage.setItem("dribbblish:folder-image:" + id, result);
|
|
|
|
} catch {
|
|
|
|
Spicetify.showNotification("File too large");
|
|
|
|
}
|
2023-11-10 00:48:00 +01:00
|
|
|
DribbblishShared.loadPlaylistImage?.call();
|
2023-07-31 13:27:16 +02:00
|
|
|
};
|
|
|
|
reader.readAsDataURL(file);
|
|
|
|
};
|
|
|
|
|
|
|
|
// context menu items for custom folder images
|
|
|
|
new Spicetify.ContextMenu.Item(
|
|
|
|
"Remove folder image",
|
|
|
|
([uri]) => {
|
|
|
|
const id = Spicetify.URI.from(uri).id;
|
|
|
|
localStorage.removeItem("dribbblish:folder-image:" + id);
|
2023-11-10 00:48:00 +01:00
|
|
|
DribbblishShared.loadPlaylistImage?.call();
|
2023-07-31 13:27:16 +02:00
|
|
|
},
|
2023-11-10 00:48:00 +01:00
|
|
|
([uri]) => Spicetify.URI.isFolder(uri) && !ylx,
|
2023-07-31 13:27:16 +02:00
|
|
|
"x"
|
|
|
|
).register();
|
|
|
|
new Spicetify.ContextMenu.Item(
|
|
|
|
"Choose folder image",
|
|
|
|
([uri]) => {
|
|
|
|
filePickerInput.uri = uri;
|
|
|
|
filePickerForm.reset();
|
|
|
|
filePickerInput.click();
|
|
|
|
},
|
2023-11-10 00:48:00 +01:00
|
|
|
([uri]) => Spicetify.URI.isFolder(uri) && !ylx,
|
2023-07-31 13:27:16 +02:00
|
|
|
"edit"
|
|
|
|
).register();
|
2023-06-21 02:17:59 +02:00
|
|
|
})();
|
2023-04-16 02:43:55 +02:00
|
|
|
|
2023-06-21 02:17:59 +02:00
|
|
|
// LEGACY NAVBAR ONLY
|
|
|
|
function legacy() {
|
|
|
|
if (!Spicetify.Platform) {
|
|
|
|
setTimeout(legacy, 300);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// allow resizing of the navbar
|
2023-07-31 13:27:16 +02:00
|
|
|
waitForElement([".Root__nav-bar .LayoutResizer__input"], ([resizer]) => {
|
2023-06-21 02:17:59 +02:00
|
|
|
const observer = new MutationObserver(updateVariable);
|
2023-07-31 13:27:16 +02:00
|
|
|
observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
|
2023-06-21 02:17:59 +02:00
|
|
|
function updateVariable() {
|
2023-07-31 13:27:16 +02:00
|
|
|
let value = resizer.value;
|
|
|
|
if (value < 121) {
|
|
|
|
value = 72;
|
2023-06-21 02:17:59 +02:00
|
|
|
document.documentElement.classList.add("left-sidebar-collapsed");
|
|
|
|
} else {
|
|
|
|
document.documentElement.classList.remove("left-sidebar-collapsed");
|
|
|
|
}
|
2023-07-31 13:27:16 +02:00
|
|
|
document.documentElement.style.setProperty("--nav-bar-width", value + "px");
|
|
|
|
}
|
|
|
|
updateVariable();
|
|
|
|
});
|
|
|
|
|
|
|
|
// allow resizing of the buddy feed
|
|
|
|
waitForElement([".Root__right-sidebar .LayoutResizer__input"], ([resizer]) => {
|
|
|
|
const observer = new MutationObserver(updateVariable);
|
|
|
|
observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
|
|
|
|
function updateVariable() {
|
|
|
|
let value = resizer.value;
|
|
|
|
let min_value = version < 121200000 ? 321 : 281;
|
|
|
|
if (value < min_value) {
|
|
|
|
value = 72;
|
|
|
|
document.documentElement.classList.add("buddyFeed-hide-text");
|
|
|
|
} else {
|
|
|
|
document.documentElement.classList.remove("buddyFeed-hide-text");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
updateVariable();
|
|
|
|
});
|
|
|
|
|
|
|
|
waitForElement([".main-nowPlayingBar-container"], ([nowPlayingBar]) => {
|
|
|
|
const observer = new MutationObserver(updateVariable);
|
|
|
|
observer.observe(nowPlayingBar, { childList: true });
|
|
|
|
function updateVariable() {
|
|
|
|
if (nowPlayingBar.childElementCount === 2) {
|
|
|
|
document.documentElement.classList.add("connected");
|
|
|
|
} else {
|
|
|
|
document.documentElement.classList.remove("connected");
|
|
|
|
}
|
2023-06-21 02:17:59 +02:00
|
|
|
}
|
|
|
|
updateVariable();
|
|
|
|
});
|
|
|
|
|
|
|
|
// add fade effect on playlist/folder list
|
|
|
|
waitForElement([".main-navBar-navBar .os-viewport.os-viewport-native-scrollbars-invisible"], ([scrollNode]) => {
|
|
|
|
scrollNode.setAttribute("fade", "bottom");
|
|
|
|
scrollNode.addEventListener("scroll", () => {
|
|
|
|
if (scrollNode.scrollTop == 0) {
|
|
|
|
scrollNode.setAttribute("fade", "bottom");
|
|
|
|
} else if (scrollNode.scrollHeight - scrollNode.clientHeight - scrollNode.scrollTop == 0) {
|
|
|
|
scrollNode.setAttribute("fade", "top");
|
|
|
|
} else {
|
|
|
|
scrollNode.setAttribute("fade", "full");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
waitForElement([`ul[tabindex="0"]`, `ul[tabindex="0"] .GlueDropTarget--playlists.GlueDropTarget--folders`], ([root, firstItem]) => {
|
|
|
|
const listElem = firstItem.parentElement;
|
|
|
|
root.classList.add("dribs-playlist-list");
|
|
|
|
|
|
|
|
/** Replace Playlist name with their pictures */
|
|
|
|
function loadPlaylistImage() {
|
|
|
|
for (const item of listElem.children) {
|
|
|
|
let link = item.querySelector("a");
|
|
|
|
if (!link) continue;
|
|
|
|
|
|
|
|
let [_, app, uid] = link.pathname.split("/");
|
|
|
|
let uri;
|
|
|
|
if (app === "playlist") {
|
|
|
|
uri = `spotify:playlist:${uid}`;
|
|
|
|
} else if (app === "folder") {
|
|
|
|
const base64 = localStorage.getItem("dribbblish:folder-image:" + uid);
|
|
|
|
let img = link.querySelector("img");
|
|
|
|
if (!img) {
|
|
|
|
img = document.createElement("img");
|
|
|
|
img.classList.add("playlist-picture");
|
|
|
|
link.prepend(img);
|
|
|
|
}
|
|
|
|
img.src = base64 || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Spicetify.CosmosAsync.get(`sp://core-playlist/v1/playlist/${uri}/metadata`, { policy: { picture: true } }).then(res => {
|
|
|
|
const meta = res.metadata;
|
|
|
|
let img = link.querySelector("img");
|
|
|
|
if (!img) {
|
|
|
|
img = document.createElement("img");
|
|
|
|
img.classList.add("playlist-picture");
|
|
|
|
link.prepend(img);
|
|
|
|
}
|
|
|
|
img.src = meta.picture || "https://cdn.jsdelivr.net/gh/spicetify/spicetify-themes@master/Dribbblish/images/tracklist-row-song-fallback.svg";
|
|
|
|
});
|
|
|
|
}
|
2023-04-16 02:43:55 +02:00
|
|
|
}
|
2023-06-21 02:17:59 +02:00
|
|
|
|
|
|
|
DribbblishShared.loadPlaylistImage = loadPlaylistImage;
|
|
|
|
loadPlaylistImage();
|
|
|
|
|
|
|
|
new MutationObserver(loadPlaylistImage).observe(listElem, { childList: true });
|
2023-04-16 02:43:55 +02:00
|
|
|
});
|
2023-06-21 02:17:59 +02:00
|
|
|
}
|