import axios, { AxiosRequestConfig } from 'axios';
import { tokenManager } from '../auth/token-manager.js';
const BASE_URL = 'https://api.spotify.com/v1';
/**
* Generic helper to make authenticated requests to Spotify API
* Handles token management, error handling, and response formatting
*/
export async function spotifyRequest<T>(
method: 'GET' | 'POST' | 'PUT' | 'DELETE',
endpoint: string,
data?: any,
params?: any
): Promise<T | null> {
const token = await tokenManager.getValidAccessToken();
const config: AxiosRequestConfig = {
method,
url: `${BASE_URL}${endpoint}`,
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
params,
data
};
try {
const response = await axios(config);
return response.data;
} catch (error: any) {
if (error.response) {
// Clean error messaging for the LLM
const status = error.response.status;
const msg = error.response.data?.error?.message || error.message;
if (status === 401) {
throw new Error(`Spotify Authentication Error: ${msg}. Try re-running 'npm run auth'.`);
}
if (status === 403) {
throw new Error(`Spotify Forbidden: ${msg}. This may require Spotify Premium or specific device settings.`);
}
if (status === 404) {
throw new Error(`Spotify Not Found: ${msg}. Is a device active and playing?`);
}
if (status === 429) {
throw new Error(`Spotify Rate Limit: Too many requests. Please wait a moment.`);
}
throw new Error(`Spotify API Error ${status}: ${msg}`);
}
throw error;
}
}
/**
* Format duration from milliseconds to human-readable format
*/
export function formatDuration(ms: number): string {
const seconds = Math.floor((ms / 1000) % 60);
const minutes = Math.floor((ms / (1000 * 60)) % 60);
const hours = Math.floor(ms / (1000 * 60 * 60));
if (hours > 0) {
return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
}
return `${minutes}:${seconds.toString().padStart(2, '0')}`;
}
/**
* Calculate percentage progress
*/
export function calculateProgress(current: number, total: number): number {
if (total === 0) return 0;
return Math.round((current / total) * 100);
}