From 5e6fe6a11c2f0c79a93ea3a4ed23fdc6ab304e65 Mon Sep 17 00:00:00 2001 From: edideaur Date: Wed, 4 Mar 2026 17:59:22 +0000 Subject: [PATCH 1/5] undo taglib bullshit and update devcontainer --- .devcontainer/Dockerfile | 66 +++++++++++++++++++++++++++++++++ .devcontainer/devcontainer.json | 25 +++++++++++++ todo.md | 8 ---- 3 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json delete mode 100644 todo.md diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..7750aa2 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,66 @@ +# ------------------------------------------------------------ +# Base Image +# ------------------------------------------------------------ +FROM debian:unstable-slim + +ENV DEBIAN_FRONTEND=noninteractive +ENV LANG=C.UTF-8 +ENV LC_ALL=C.UTF-8 + +# ------------------------------------------------------------ +# System Dependencies +# ------------------------------------------------------------ +RUN apt-get update && apt-get upgrade -y && \ + apt-get install -y --no-install-recommends \ + curl \ + ca-certificates \ + git \ + build-essential \ + sudo \ + fish \ + unzip \ + xz-utils \ + libatomic1 \ + libc6 \ + wget && \ + rm -rf /var/lib/apt/lists/* + +# ------------------------------------------------------------ +# Create Non-Root User +# ------------------------------------------------------------ +ARG USERNAME=devuser +ARG UID=1000 +ARG GID=1000 + +RUN groupadd --gid ${GID} ${USERNAME} && \ + useradd --uid ${UID} --gid ${GID} -m -s /usr/bin/fish ${USERNAME} && \ + echo "${USERNAME} ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +USER ${USERNAME} +WORKDIR /home/${USERNAME} + +# ------------------------------------------------------------ +# Install Bun (Non-Root) +# ------------------------------------------------------------ +ENV BUN_INSTALL=/home/${USERNAME}/.bun +ENV PATH="${BUN_INSTALL}/bin:${PATH}" + +RUN curl -fsSL https://bun.sh/install | bash + +# ------------------------------------------------------------ +# Install OpenCode (Proper PATH Handling) +# ------------------------------------------------------------ +RUN curl -fsSL https://opencode.ai/install -o opencode-install && \ + chmod +x opencode-install && \ + ./opencode-install --yes && \ + rm opencode-install + +# Add OpenCode to PATH permanently +ENV PATH="/home/${USERNAME}/.opencode/bin:${PATH}" + +# ------------------------------------------------------------ +# Ensure fish is Default Shell +# ------------------------------------------------------------ +ENV SHELL=/usr/bin/fish + +CMD ["fish"] \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4f46093 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,25 @@ +{ + "name": "debian-bun-fish-devcontainer", + "build": { + "dockerfile": "Dockerfile" + }, + + "remoteUser": "devuser", + + "features": {}, + + "customizations": { + "vscode": { + "extensions": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] + } + }, + + "postCreateCommand": "bun --version && code --version", + + "remoteEnv": { + "SHELL": "/usr/bin/fish" + } +} \ No newline at end of file diff --git a/todo.md b/todo.md deleted file mode 100644 index b982ace..0000000 --- a/todo.md +++ /dev/null @@ -1,8 +0,0 @@ -# Feature Requests - -Sorted by ease of implementation (easiest to hardest): - -- [ ] effects like reverb, delay, and bitcrushing -- [ ] Customizable EQ: Allow users to change the number of EQ bands and their range (-30 to 30), with a drag-to-adjust interface similar to FL Studio's velocity editor - -[ ] SoundCloud support: Integrate SoundCloud through SoundCloak From 8bc9881b7faf7678ea247bd1769249ab5669f0c4 Mon Sep 17 00:00:00 2001 From: edideaur <182119792+edideaur@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:59:55 +0000 Subject: [PATCH 2/5] style: auto-fix linting issues --- .devcontainer/devcontainer.json | 37 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 4f46093..6033fdf 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,25 +1,22 @@ { - "name": "debian-bun-fish-devcontainer", - "build": { - "dockerfile": "Dockerfile" - }, + "name": "debian-bun-fish-devcontainer", + "build": { + "dockerfile": "Dockerfile" + }, - "remoteUser": "devuser", + "remoteUser": "devuser", - "features": {}, + "features": {}, - "customizations": { - "vscode": { - "extensions": [ - "dbaeumer.vscode-eslint", - "esbenp.prettier-vscode" - ] + "customizations": { + "vscode": { + "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] + } + }, + + "postCreateCommand": "bun --version && code --version", + + "remoteEnv": { + "SHELL": "/usr/bin/fish" } - }, - - "postCreateCommand": "bun --version && code --version", - - "remoteEnv": { - "SHELL": "/usr/bin/fish" - } -} \ No newline at end of file +} From 03ea16ac04c1cfa579f30ef6e241031576d3a7cd Mon Sep 17 00:00:00 2001 From: edideaur Date: Thu, 5 Mar 2026 17:32:53 +0000 Subject: [PATCH 3/5] fix settings > system issue --- bun.lock | 2 +- js/ui.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/bun.lock b/bun.lock index f8a22d0..cb1af31 100644 --- a/bun.lock +++ b/bun.lock @@ -19,7 +19,7 @@ "@neutralinojs/neu": "^11.7.0", "eslint": "^9.39.3", "eslint-config-prettier": "^10.1.8", - "globals": "^17.3.0", + "globals": "^17.4.0", "htmlhint": "^1.9.1", "prettier": "^3.8.1", "stylelint": "^16.26.1", diff --git a/js/ui.js b/js/ui.js index 504f0e1..6eed183 100644 --- a/js/ui.js +++ b/js/ui.js @@ -31,6 +31,7 @@ import { homePageSettings, fontSettings, contentBlockingSettings, + settingsUiState, } from './storage.js'; import { db } from './db.js'; import { getVibrantColorFromImage } from './vibrant-color.js'; @@ -1448,6 +1449,17 @@ export class UIRenderer { if (pageId === 'settings') { this.renderApiSettings(); + const savedTabName = settingsUiState.getActiveTab(); + const savedTab = document.querySelector(`.settings-tab[data-tab="${savedTabName}"]`); + if (savedTab) { + document.querySelectorAll('.settings-tab').forEach((t) => t.classList.remove('active')); + document.querySelectorAll('.settings-tab-content').forEach((c) => c.classList.remove('active')); + savedTab.classList.add('active'); + document.getElementById(`settings-tab-${savedTabName}`)?.classList.add('active'); + } + } else { + document.querySelectorAll('.settings-tab').forEach((t) => t.classList.remove('active')); + document.querySelectorAll('.settings-tab-content').forEach((c) => c.classList.remove('active')); } } From 8eefb1b79b35f27997e400ce96a939f7830da538 Mon Sep 17 00:00:00 2001 From: edideaur Date: Thu, 5 Mar 2026 18:17:53 +0000 Subject: [PATCH 4/5] open in harmony + context menu on album pages --- index.html | 24 ++++++++++++++++++++++++ js/events.js | 18 ++++++++++++++---- js/ui.js | 7 +++++++ styles.css | 7 +++++++ 4 files changed, 52 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 25b3685..07cbe4f 100644 --- a/index.html +++ b/index.html @@ -87,6 +87,7 @@
  • Go to album
  • Copy link
  • Open in new tab
  • +
  • Open in Harmony
  • Track info
  • Open original URL
  • Download
  • @@ -2710,6 +2711,29 @@ Save + diff --git a/js/events.js b/js/events.js index 3e207a6..5a8af19 100644 --- a/js/events.js +++ b/js/events.js @@ -1200,6 +1200,10 @@ export async function handleTrackAction( trackOpenInNewTab(type, item.id || item.uuid); window.open(url, '_blank'); + } else if (action === 'open-in-harmony') { + const albumId = item.id; + const harmonyUrl = `https://harmony.pulsewidth.org.uk/release?url=${encodeURIComponent(`https://tidal.com/album/${albumId}`)}>in=®ion=&musicbrainz=&deezer=&itunes=&spotify=&tidal=&beatport=`; + window.open(harmonyUrl, '_blank'); } else if (action === 'track-info') { // Show detailed track info modal const isTracker = item.isTracker; @@ -1428,9 +1432,11 @@ export async function handleTrackAction( async function updateContextMenuLikeState(contextMenu, contextTrack) { if (!contextMenu || !contextTrack) return; + const type = contextMenu._contextType || 'track'; + const likeItem = contextMenu.querySelector('li[data-action="toggle-like"]'); if (likeItem) { - const isLiked = await db.isFavorite('track', contextTrack.id); + const isLiked = await db.isFavorite(type, contextTrack.id); likeItem.textContent = isLiked ? 'Unlike' : 'Like'; } @@ -1455,7 +1461,6 @@ async function updateContextMenuLikeState(contextMenu, contextTrack) { // Update block/unblock labels const { contentBlockingSettings } = await import('./storage.js'); - const type = contextMenu._contextType || 'track'; const blockTrackItem = contextMenu.querySelector('li[data-action="block-track"]'); if (blockTrackItem) { @@ -1572,7 +1577,7 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen return; } - const cardMenuBtn = e.target.closest('.card-menu-btn'); + const cardMenuBtn = e.target.closest('.card-menu-btn, #album-menu-btn'); if (cardMenuBtn) { e.stopPropagation(); const card = cardMenuBtn.closest('.card'); @@ -1581,9 +1586,14 @@ export function initializeTrackInteractions(player, api, mainContent, contextMen let item = card ? trackDataStore.get(card) : null; + if (!item) { + // Check if item is stored on the button itself (e.g., album page header menu) + item = trackDataStore.get(cardMenuBtn); + } + if (!item) { // Fallback: create a shell item - item = { id, uuid: id, title: card.querySelector('.card-title')?.textContent || 'Item' }; + item = { id, uuid: id, title: card?.querySelector('.card-title')?.textContent || 'Item' }; } if (contextMenu._originalHTML) { diff --git a/js/ui.js b/js/ui.js index 6eed183..269dab4 100644 --- a/js/ui.js +++ b/js/ui.js @@ -2473,6 +2473,13 @@ export class UIRenderer { albumLikeBtn.classList.toggle('active', isLiked); } + // Store album data for menu button + const albumMenuBtn = document.getElementById('album-menu-btn'); + if (albumMenuBtn) { + albumMenuBtn.dataset.id = album.id; + trackDataStore.set(albumMenuBtn, album); + } + document.title = `${album.title} - ${album.artist.name}`; // "More from Artist" and Related Sections diff --git a/styles.css b/styles.css index a31eb46..5540c85 100644 --- a/styles.css +++ b/styles.css @@ -2401,6 +2401,13 @@ input[type='search']::-webkit-search-cancel-button { flex-shrink: 0; } +.detail-header-actions .card-menu-btn, +.detail-header-actions #album-menu-btn { + position: static !important; + opacity: 1 !important; + transform: none !important; +} + .detail-header-actions .btn-primary span, .detail-header-actions .btn-secondary span { display: none; From 14cf949381d30fa7616db57f0c8a43dceddf09af Mon Sep 17 00:00:00 2001 From: edideaur Date: Thu, 5 Mar 2026 18:22:54 +0000 Subject: [PATCH 5/5] fix ddosing lmao --- js/app.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/js/app.js b/js/app.js index c9f0b9f..82a466d 100644 --- a/js/app.js +++ b/js/app.js @@ -2323,14 +2323,19 @@ document.addEventListener('DOMContentLoaded', async () => { const searchForm = document.getElementById('search-form'); const searchInput = document.getElementById('search-input'); - // Setup clear button for search bar ui.setupSearchClearButton(searchInput); - const performSearch = debounce((query) => { + const performSearch = (query) => { if (query) { navigate(`/search/${encodeURIComponent(query)}`); } - }, 0); + }; + + const debouncedSearch = debounce((query) => { + if (query && query === searchInput.value.trim()) { + performSearch(query); + } + }, 3000); const handleExternalLink = (query) => { const isExternalLink = @@ -2343,9 +2348,7 @@ document.addEventListener('DOMContentLoaded', async () => { try { const urlObj = new URL(url); let path = urlObj.pathname; - // Remove trailing slashes and get just endpoint/id path = path.replace(/\/+$/, ''); - // Get just the first two segments (e.g., /album/382839956) const segments = path.split('/').filter((s) => s); if (segments.length >= 2) { path = '/' + segments[0] + '/' + segments[1]; @@ -2363,9 +2366,11 @@ document.addEventListener('DOMContentLoaded', async () => { const query = e.target.value.trim(); if (!query) return; - if (!handleExternalLink(query)) { - performSearch(query); + if (handleExternalLink(query)) { + return; } + + debouncedSearch(query); }); searchInput.addEventListener('change', (e) => { @@ -2397,7 +2402,7 @@ document.addEventListener('DOMContentLoaded', async () => { if (!handleExternalLink(query)) { ui.addToSearchHistory(query); - navigate(`/search/${encodeURIComponent(query)}`); + performSearch(query); const historyEl = document.getElementById('search-history'); if (historyEl) historyEl.style.display = 'none'; }