diff --git a/js/app.js b/js/app.js
index ab7391a..56d5840 100644
--- a/js/app.js
+++ b/js/app.js
@@ -378,7 +378,7 @@ document.addEventListener('DOMContentLoaded', async () => {
ui.renderLibraryPage();
// Also update current page if we are on it
if (window.location.hash === `#userplaylist/${editingId}`) {
- ui.renderPlaylistPage(editingId);
+ ui.renderPlaylistPage(editingId, 'user');
}
modal.style.display = 'none';
delete modal.dataset.editingId;
@@ -553,7 +553,7 @@ document.addEventListener('DOMContentLoaded', async () => {
const trackId = playlist.tracks[index].id;
const updatedPlaylist = await db.removeTrackFromPlaylist(playlistId, trackId);
syncManager.syncUserPlaylist(updatedPlaylist, 'update');
- ui.renderPlaylistPage(playlistId);
+ ui.renderPlaylistPage(playlistId, 'user');
}
});
}
diff --git a/js/router.js b/js/router.js
index fa3839d..22606b5 100644
--- a/js/router.js
+++ b/js/router.js
@@ -17,10 +17,10 @@ export function createRouter(ui) {
ui.renderArtistPage(param);
break;
case 'playlist':
- ui.renderPlaylistPage(param);
+ ui.renderPlaylistPage(param, 'api');
break;
case 'userplaylist':
- ui.renderPlaylistPage(param);
+ ui.renderPlaylistPage(param, 'user');
break;
case 'mix':
ui.renderMixPage(param);
diff --git a/js/ui.js b/js/ui.js
index bf560ab..ffc666d 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -1103,7 +1103,7 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
}
}
- async renderPlaylistPage(playlistId) {
+ async renderPlaylistPage(playlistId, source = null) {
this.showPage('playlist');
const imageEl = document.getElementById('playlist-detail-image');
const titleEl = document.getElementById('playlist-detail-title');
@@ -1133,15 +1133,25 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
// Check if it's a user playlist (UUID format)
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(playlistId);
- const ownedPlaylist = await db.getPlaylist(playlistId);
- let playlistData = ownedPlaylist;
-
- // If not in local DB, check if it's a public Firebase playlist
- if (!playlistData) {
- try {
- playlistData = await syncManager.getPublicPlaylist(playlistId);
- } catch (e) {
- console.warn('Failed to check public Firebase playlists:', e);
+ let playlistData = null;
+ let ownedPlaylist = null;
+
+ // Priority:
+ // 1. If source is 'user', check DB/Sync.
+ // 2. If source is 'api', check API.
+ // 3. If no source, check DB if UUID, then API.
+
+ if (source === 'user' || (!source && isUUID)) {
+ ownedPlaylist = await db.getPlaylist(playlistId);
+ playlistData = ownedPlaylist;
+
+ // If not in local DB, check if it's a public Firebase playlist
+ if (!playlistData) {
+ try {
+ playlistData = await syncManager.getPublicPlaylist(playlistId);
+ } catch (e) {
+ console.warn('Failed to check public Firebase playlists:', e);
+ }
}
}
@@ -1221,9 +1231,9 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
});
document.title = `${playlistData.name || playlistData.title} - Monochrome`;
} else {
- // If it is a UUID, we know it won't be in the API.
- if (isUUID) {
- throw new Error('Playlist not found. If this is a custom playlist, make sure it is set to Public.');
+ // If source was explicitly 'user' and we didn't find it, fail.
+ if (source === 'user') {
+ throw new Error('Playlist not found. If this is a custom playlist, make sure it is set to Public.');
}
// Render API playlist
@@ -1282,7 +1292,7 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
}
// Render Actions (Shuffle + Share)
- this.updatePlaylistHeaderActions(playlist, false, tracks, true);
+ this.updatePlaylistHeaderActions(playlist, false, tracks, false);
recentActivityManager.addPlaylist(playlist);
document.title = playlist.title || 'Artist Mix';
@@ -1608,28 +1618,15 @@ async showFullscreenCover(track, nextTrack, lyricsManager, audioPlayer) {
fragment.appendChild(deleteBtn);
}
- // Share
- if (showShare || playlist.isPublic) {
+ // Share (User Playlists Only)
+ if (showShare || (isOwned && playlist.isPublic)) {
const shareBtn = document.createElement('button');
shareBtn.id = 'share-playlist-btn';
shareBtn.className = 'btn-secondary';
shareBtn.innerHTML = 'Share';
- // Determine URL based on type (User Playlist or API Playlist)
- // User Playlists use #userplaylist/ID, API use #playlist/UUID
- // But we don't have isOwned strictly here for that decision?
- // Actually, if it's owned it's #userplaylist.
- // If it's public firebase, it's also #userplaylist.
- // If it's API, it's #playlist.
-
- // Heuristic: If it has `isPublic` property (even if false), it's likely a User/Firebase playlist structure.
- // API playlists don't usually have `isPublic`.
-
- const isUserType = 'isPublic' in playlist || isOwned;
- const prefix = isUserType ? 'userplaylist' : 'playlist';
-
shareBtn.onclick = () => {
- const url = `${window.location.origin}${window.location.pathname}#${prefix}/${playlist.id || playlist.uuid}`;
+ const url = `${window.location.origin}${window.location.pathname}#userplaylist/${playlist.id || playlist.uuid}`;
navigator.clipboard.writeText(url).then(() => alert('Link copied to clipboard!'));
};
fragment.appendChild(shareBtn);
diff --git a/package-lock.json b/package-lock.json
index 2026095..780c53a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -62,6 +62,7 @@
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -2542,6 +2543,7 @@
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -2750,6 +2752,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -4296,13 +4299,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/lodash.sortby": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
- "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==",
- "dev": true,
- "license": "MIT"
- },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -4323,6 +4319,14 @@
"sourcemap-codec": "^1.4.8"
}
},
+ "node_modules/magic-string/node_modules/sourcemap-codec": {
+ "name": "@jridgewell/sourcemap-codec",
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@@ -4577,16 +4581,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/punycode": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
- "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -5053,20 +5047,6 @@
"dev": true,
"license": "MIT"
},
- "node_modules/source-map": {
- "version": "0.8.0-beta.0",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz",
- "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==",
- "deprecated": "The work that was done in this beta branch won't be included in future versions",
- "dev": true,
- "license": "BSD-3-Clause",
- "dependencies": {
- "whatwg-url": "^7.0.0"
- },
- "engines": {
- "node": ">= 8"
- }
- },
"node_modules/source-map-js": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
@@ -5089,23 +5069,15 @@
}
},
"node_modules/source-map-support/node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
- "node": ">=0.10.0"
+ "node": ">= 12"
}
},
- "node_modules/sourcemap-codec": {
- "version": "1.4.8",
- "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
- "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
- "deprecated": "Please use @jridgewell/sourcemap-codec instead",
- "dev": true,
- "license": "MIT"
- },
"node_modules/stop-iteration-iterator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz",
@@ -5384,6 +5356,7 @@
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
"dev": true,
"license": "BSD-2-Clause",
+ "peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
@@ -5414,16 +5387,6 @@
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
- "node_modules/tr46": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
- "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "punycode": "^2.1.0"
- }
- },
"node_modules/type-fest": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz",
@@ -5649,6 +5612,7 @@
"integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.27.0",
"fdir": "^6.5.0",
@@ -5749,25 +5713,6 @@
}
}
},
- "node_modules/webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
- "dev": true,
- "license": "BSD-2-Clause"
- },
- "node_modules/whatwg-url": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
- "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
- }
- },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -6045,6 +5990,7 @@
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -6055,6 +6001,16 @@
"fsevents": "~2.3.2"
}
},
+ "node_modules/workbox-build/node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/workbox-cacheable-response": {
"version": "7.4.0",
"resolved": "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-7.4.0.tgz",
diff --git a/package.json b/package.json
index 992aaed..836f62d 100644
--- a/package.json
+++ b/package.json
@@ -24,5 +24,9 @@
"devDependencies": {
"vite": "^7.3.0",
"vite-plugin-pwa": "^1.2.0"
+ },
+ "overrides": {
+ "sourcemap-codec": "npm:@jridgewell/sourcemap-codec@^1.4.14",
+ "source-map": "^0.7.4"
}
}