feat: Spotify Importer — link → yt-dlp download + optional Navidrome playlist
- New 'Spotify Importer' page under Entdecken (sidebar + mobile nav) - Backend: POST /api/spotify/resolve — resolves track/album/playlist URLs via Spotify API - Backend: new 'playlist' download type accepting pre-resolved track list (no iTunes re-fetch) - Frontend: paste Spotify link → preview with cover, type badge, track list - Track: single download or full album via iTunes fallback - Album: download all tracks with Spotify metadata - Playlist: download all tracks + optional 'Als Navidrome-Playlist speichern' checkbox - Navidrome playlist creation: searches library by title/artist after download, creates playlist - Spotify Client ID + Secret stored in app settings (setup screen + settings modal) - iTunes metadata tags kept for all downloaded files (existing pipeline unchanged) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
9f68deea94
commit
f7a5247f17
6 files changed
+398
-18
No files matched your search
+13
-10
@@ -14,7 +14,7 @@ import {
|
||||
navigate, _navGoBack, _navLoad, loadHomeData, onLocalSearch, onMobileSearch,
|
||||
onGlobalSearch, s_goArtist, s_goAlbum, playerBarGoArtist, playerBarGoAlbum,
|
||||
searchSimilarArtist, searchAndPreview, loadItunesAlbum, expandArtistBio,
|
||||
loadRandom,
|
||||
loadRandom, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll,
|
||||
} from './views.js';
|
||||
import {
|
||||
openNowPlaying, closeNowPlaying, switchNpTab, npGoArtist, npGoAlbum,
|
||||
@@ -22,23 +22,25 @@ import {
|
||||
checkBackend, openSidebar, closeSidebar, switchNavMode, showCtxMenu,
|
||||
openPlModal, closePlModal, addSongsToPlaylist, createAndAddPlaylist,
|
||||
createPlaylistPrompt, showSongInfo, closeInfoModal, openDlModal, closeDlModal,
|
||||
selectDlType, executeDownload, openEditPlModal, closeEditPlModal,
|
||||
selectDlType, executeDownload, executeSpotifyDownload, openEditPlModal, closeEditPlModal,
|
||||
saveEditPlaylist, editPlUploadCover, editPlCoverSelected, editPlRemoveCover,
|
||||
toggleMobileSearch, closeMobileSearch, switchSetupTab,
|
||||
} from './ui.js';
|
||||
|
||||
// ─── CONNECT ───
|
||||
async function doConnect() {
|
||||
const url = document.getElementById('srv-url').value.trim().replace(/\/$/,'');
|
||||
const user = document.getElementById('srv-user').value.trim();
|
||||
const pass = document.getElementById('srv-pass').value;
|
||||
const lfKey = document.getElementById('lastfm-key').value.trim();
|
||||
const backUrl = document.getElementById('backend-url').value.trim().replace(/\/$/,'');
|
||||
const url = document.getElementById('srv-url').value.trim().replace(/\/$/,'');
|
||||
const user = document.getElementById('srv-user').value.trim();
|
||||
const pass = document.getElementById('srv-pass').value;
|
||||
const lfKey = document.getElementById('lastfm-key').value.trim();
|
||||
const backUrl = document.getElementById('backend-url').value.trim().replace(/\/$/,'');
|
||||
const spId = document.getElementById('spotify-client-id').value.trim();
|
||||
const spSecret = document.getElementById('spotify-client-secret').value.trim();
|
||||
if(!url || !user || !pass) { _showSetupError('Bitte Server-URL, Benutzernamen und Passwort ausfüllen.'); return; }
|
||||
const btn = document.getElementById('btn-connect');
|
||||
btn.disabled=true; btn.textContent='Verbinde…';
|
||||
document.getElementById('setup-error').style.display='none';
|
||||
S.cfg = {url, user, pass, lastfmKey:lfKey, backendUrl:backUrl};
|
||||
S.cfg = {url, user, pass, lastfmKey:lfKey, backendUrl:backUrl, spotifyClientId:spId, spotifyClientSecret:spSecret};
|
||||
try {
|
||||
await api('ping');
|
||||
localStorage.setItem('ns_cfg', JSON.stringify(S.cfg));
|
||||
@@ -55,7 +57,7 @@ function disconnect() {
|
||||
localStorage.removeItem('ns_cfg');
|
||||
localStorage.removeItem('ns_last_played');
|
||||
sessionStorage.removeItem('ns_nav');
|
||||
S.cfg = {url:'', user:'', pass:'', lastfmKey:'', backendUrl:''};
|
||||
S.cfg = {url:'', user:'', pass:'', lastfmKey:'', backendUrl:'', spotifyClientId:'', spotifyClientSecret:''};
|
||||
S.queue=[]; S.qIdx=-1; S._navStack=[]; S._navCursor=-1;
|
||||
S.audio.pause(); S.audio.src='';
|
||||
document.getElementById('app').style.display='none';
|
||||
@@ -183,7 +185,8 @@ Object.assign(window, {
|
||||
openSettings, closeSettings, saveSettings, checkBackend,
|
||||
openSidebar, closeSidebar, switchNavMode, showCtxMenu,
|
||||
// Views
|
||||
loadRandom,
|
||||
loadRandom, loadSpotifyImporter, resolveSpotifyLink, clearSpotifyPreview, spotifyDlAll,
|
||||
executeSpotifyDownload,
|
||||
openPlModal, closePlModal, addSongsToPlaylist, createAndAddPlaylist, createPlaylistPrompt,
|
||||
showSongInfo, closeInfoModal,
|
||||
openDlModal, closeDlModal, selectDlType, executeDownload,
|
||||
|
||||
Reference in new issue
Block a user