utils.js
1 import { CliError } from '@jackwener/opencli/errors'; 2 const SPOTIFY_PLACEHOLDER_PATTERNS = [ 3 /^your_spotify_client_id_here$/i, 4 /^your_spotify_client_secret_here$/i, 5 /^your_.+_here$/i, 6 ]; 7 export function parseDotEnv(content) { 8 return Object.fromEntries(content 9 .split(/\r?\n/) 10 .map(line => line.trim()) 11 .filter(line => line && !line.startsWith('#') && line.includes('=')) 12 .map(line => { 13 const index = line.indexOf('='); 14 return [line.slice(0, index).trim(), line.slice(index + 1).trim()]; 15 })); 16 } 17 export function resolveSpotifyCredentials(fileEnv, processEnv = process.env) { 18 return { 19 clientId: processEnv.SPOTIFY_CLIENT_ID || fileEnv.SPOTIFY_CLIENT_ID || '', 20 clientSecret: processEnv.SPOTIFY_CLIENT_SECRET || fileEnv.SPOTIFY_CLIENT_SECRET || '', 21 }; 22 } 23 export function isPlaceholderCredential(value) { 24 const normalized = value?.trim() || ''; 25 if (!normalized) 26 return false; 27 return SPOTIFY_PLACEHOLDER_PATTERNS.some(pattern => pattern.test(normalized)); 28 } 29 export function hasConfiguredSpotifyCredentials(credentials) { 30 return Boolean(credentials.clientId.trim()) && 31 Boolean(credentials.clientSecret.trim()) && 32 !isPlaceholderCredential(credentials.clientId) && 33 !isPlaceholderCredential(credentials.clientSecret); 34 } 35 export function assertSpotifyCredentialsConfigured(credentials, envFile) { 36 if (hasConfiguredSpotifyCredentials(credentials)) 37 return; 38 throw new CliError('CONFIG', `Missing Spotify credentials.\n\n` + 39 `1. Go to https://developer.spotify.com/dashboard and create an app\n` + 40 `2. Add ${'http://127.0.0.1:8888/callback'} as a Redirect URI\n` + 41 `3. Copy your Client ID and Client Secret\n` + 42 `4. Open the file: ${envFile}\n` + 43 `5. Fill in SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET, then save\n` + 44 `6. Run: opencli spotify auth`); 45 } 46 export function mapSpotifyTrackResults(data) { 47 const items = data?.tracks?.items; 48 if (!Array.isArray(items)) 49 return []; 50 return items.map((track) => ({ 51 track: track?.name || '', 52 artist: Array.isArray(track?.artists) ? track.artists.map((artist) => artist.name).join(', ') : '', 53 album: track?.album?.name || '', 54 uri: track?.uri || '', 55 })); 56 } 57 export function getFirstSpotifyTrack(data) { 58 const track = mapSpotifyTrackResults(data)[0]; 59 if (!track) 60 return null; 61 return { 62 uri: track.uri, 63 name: track.track, 64 artist: track.artist, 65 }; 66 }