Когда вы нажимаете кнопку, он должен показывать такие вещи, как верхние альбомы, сколько вы слушаете и тому подобное. Ошибка. < /p>
Я также попытался отключить расширения браузера, такие как конфиденциальность, и Ublock Origin.Spotify API Error
Endpoint: /v1/me/playlists
Status Code: 403
Message: API request failed
Timestamp: 2025-03-02T01:53:33.866Z errorHandling.js:40:17
logError https://spotify.formen.cc/js/errorHandling.js:40
fetchUserData https://spotify.formen.cc/js/app.js:55
https://spotify.formen.cc/js/app.js:6
https://spotify.formen.cc/js/login.js:47
(Async: EventListener.handleEvent)
https://spotify.formen.cc/js/login.js:39
< /code>
также еще одна вещь в консоли < /p>
Full error details:
Object { timestamp: "2025-03-02T01:53:33.866Z", name: "SpotifyAPIError", message: "API request failed", stack: "SpotifyAPIError@https://spotify.formen.cc/js/errorHandl ... .js:39:8\n", context: "User Profile Fetch" }
errorHandling.js:75:13
< /code>
app.js < /p>
import { SpotifyAPIError, AuthenticationError, DataProcessingError, logError, handleApiResponse, handleAuthError, handleDataProcessingError } from './errorHandling.js';
// Listen for token received event from login.js
window.addEventListener('tokenReceived', (event) => {
const token = event.detail.token;
fetchUserData(token);
fetchTopTracks(token);
fetchTopArtists(token);
fetchRecentlyPlayed(token);
fetchSavedAlbums(token);
createListeningTimeline(token);
});
// Fetch user profile data
async function fetchUserData(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me');
const data = await response.json();
// Update profile section with more user information
document.getElementById('profile-image').src = data.images[0]?.url || '';
document.getElementById('profile-name').textContent = data.display_name;
document.getElementById('profile-country').textContent = `Country: ${data.country}`;
document.getElementById('profile-type').textContent = `Account: ${data.product}`;
document.getElementById('profile-followers').textContent = `Followers: ${data.followers.total}`;
document.getElementById('profile-uri').textContent = `Spotify URI: ${data.uri}`;
// Fetch user's playlists
const playlistsResponse = await fetch('https://api.spotify.com/v1/me/playlists?limit=6', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(playlistsResponse, '/v1/me/playlists');
const playlistsData = await playlistsResponse.json();
// Display playlists
const playlistsGrid = document.getElementById('user-playlists');
playlistsGrid.innerHTML = playlistsData.items.map(playlist => `
${playlist.name}
${playlist.tracks.total} tracks
${playlist.followers?.total || 0} followers
`).join('');
document.getElementById('dashboard').classList.remove('hidden');
document.getElementById('login-section').classList.add('hidden');
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'User Profile Fetch' });
} else {
handleDataProcessingError(error, 'user profile');
}
document.getElementById('login-section').classList.remove('hidden');
}
}
// Fetch user's top tracks
async function fetchTopTracks(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me/top/tracks?limit=5', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me/top/tracks');
const data = await response.json();
const tracksList = document.getElementById('top-tracks');
tracksList.innerHTML = data.items.map(track => `
${track.name}
${track.artists[0].name}
`).join('');
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'Top Tracks Fetch' });
} else {
handleDataProcessingError(error, 'top tracks');
}
}
}
// Fetch user's top artists
async function fetchTopArtists(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me/top/artists?limit=6', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me/top/artists');
const data = await response.json();
const artistsGrid = document.getElementById('top-artists');
artistsGrid.innerHTML = data.items.map(artist => `
${artist.name}
`).join('');
// Create genre distribution chart
const genres = data.items.flatMap(artist => artist.genres);
const genreCounts = genres.reduce((acc, genre) => {
acc[genre] = (acc[genre] || 0) + 1;
return acc;
}, {});
const sortedGenres = Object.entries(genreCounts)
.sort((a, b) => b[1] - a[1])
.slice(0, 5);
new Chart(document.getElementById('genres-chart'), {
type: 'doughnut',
data: {
labels: sortedGenres.map(([genre]) => genre),
datasets: [{
data: sortedGenres.map(([, count]) => count),
backgroundColor: [
'#1DB954', '#1ED760', '#2EBD59', '#57B660', '#7C795D'
]
}]
},
options: {
responsive: true,
plugins: {
legend: {
position: 'right',
labels: { color: '#ffffff' }
}
}
}
});
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'Top Artists Fetch' });
} else {
handleDataProcessingError(error, 'top artists');
}
}
}
// Fetch recently played tracks
async function fetchRecentlyPlayed(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me/player/re ... ed?limit=5', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me/player/recently-played');
const data = await response.json();
const recentList = document.getElementById('recent-tracks');
recentList.innerHTML = data.items.map(item => `
${item.track.name}
${item.track.artists[0].name}
Played at: ${new Date(item.played_at).toLocaleString()}
`).join('');
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'Recently Played Fetch' });
} else {
handleDataProcessingError(error, 'recently played tracks');
}
}
}
// Fetch saved albums
async function fetchSavedAlbums(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me/albums?limit=4', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me/albums');
const data = await response.json();
const albumsGrid = document.getElementById('saved-albums');
albumsGrid.innerHTML = data.items.map(item => `
${item.album.name}
${item.album.artists[0].name}
`).join('');
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'Saved Albums Fetch' });
} else {
handleDataProcessingError(error, 'saved albums');
}
}
}
// Create listening history timeline
async function createListeningTimeline(token) {
try {
const response = await fetch('https://api.spotify.com/v1/me/player/re ... d?limit=20', {
headers: { 'Authorization': `Bearer ${token}` }
});
await handleApiResponse(response, '/v1/me/player/recently-played');
const data = await response.json();
if (!data.items || !data.items.length) {
throw new Error('No listening history available');
}
// Process the data for the timeline
const timelineData = data.items.map(item => ({
timestamp: new Date(item.played_at).getTime(),
hour: new Date(item.played_at).getHours()
}));
// Group plays by hour
const hourCounts = Array(24).fill(0);
timelineData.forEach(item => {
hourCounts[item.hour]++;
});
// Create the timeline chart
new Chart(document.getElementById('history-chart'), {
type: 'bar',
data: {
labels: Array.from({length: 24}, (_, i) => `${i}:00`),
datasets: [{
label: 'Plays by Hour',
data: hourCounts,
backgroundColor: '#1DB954',
borderColor: '#1DB954',
borderWidth: 1
}]
},
options: {
responsive: true,
scales: {
y: {
beginAtZero: true,
grid: { color: '#333' },
ticks: { color: '#fff' }
},
x: {
grid: { color: '#333' },
ticks: { color: '#fff' }
}
},
plugins: {
legend: {
labels: { color: '#fff' }
}
}
}
});
} catch (error) {
if (error instanceof SpotifyAPIError || error instanceof AuthenticationError) {
logError(error, { context: 'Listening Timeline Creation' });
} else {
handleDataProcessingError(error, 'listening timeline');
}
const chartElement = document.getElementById('history-chart');
if (chartElement) {
chartElement.innerHTML = '';
}
}
}
// Theme toggle functionality
function initializeTheme() {
const savedTheme = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-theme', savedTheme);
updateThemeIcon(savedTheme);
}
function updateThemeIcon(theme) {
const themeIcon = document.querySelector('#theme-toggle i');
themeIcon.className = theme === 'dark' ? 'fas fa-moon' : 'fas fa-sun';
}
document.getElementById('theme-toggle').addEventListener('click', () => {
const currentTheme = document.documentElement.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', newTheme);
localStorage.setItem('theme', newTheme);
updateThemeIcon(newTheme);
});
// Initialize theme on page load
initializeTheme();
// Handle logout
document.getElementById('logout-button').addEventListener('click', () => {
// Clear all authentication and state data
localStorage.removeItem('spotify_access_token');
localStorage.removeItem('state');
sessionStorage.clear();
// Clear URL hash to prevent auto-login on refresh
window.location.hash = '';
// Hide dashboard and show login
document.getElementById('dashboard').classList.add('hidden');
document.getElementById('login-section').classList.remove('hidden');
// Optionally reload the page to clear any cached data
window.location.reload();
});
< /code>
login.js < /p>
// Constants for Spotify authentication
const clientId = '{clientID}';
const redirectUri = 'https://spotify.formen.cc/';
console.log(clientId);
console.log(redirectUri);
// Generate a random string for state parameter
function generateRandomString(length) {
let text = '';
const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
console.log(text);
return text;
}
// Initialize login when the button is clicked
document.getElementById('login-button').addEventListener('click', () => {
const state = generateRandomString(16);
const scope = 'user-read-private user-read-email user-top-read user-read-recently-played user-library-read playlist-read-private';
const authUrl = new URL('https://accounts.spotify.com/authorize');
const params = {
response_type: 'token',
client_id: clientId,
scope: scope,
redirect_uri: redirectUri,
state: state
};
console.log(authUrl)
console.log(params)
authUrl.search = new URLSearchParams(params).toString();
window.location.href = authUrl.toString();
});
// Handle the redirect with token
window.addEventListener('load', () => {
const hash = window.location.hash.substring(1);
if (hash) {
const params = new URLSearchParams(hash);
const accessToken = params.get('access_token');
if (accessToken) {
localStorage.setItem('spotify_access_token', accessToken);
// Trigger the data fetching functions from app.js
window.dispatchEvent(new CustomEvent('tokenReceived', { detail: { token: accessToken } }));
}
}
});
// Handle logout
document.getElementById('logout-button')?.addEventListener('click', () => {
// Clear all authentication and state data
localStorage.removeItem('spotify_access_token');
localStorage.removeItem('state');
sessionStorage.clear();
// Clear URL hash to prevent auto-login on refresh
window.location.hash = '';
// Hide dashboard and show login
document.getElementById('dashboard')?.classList.add('hidden');
document.getElementById('login-section')?.classList.remove('hidden');
// Reload the page to clear any cached data
window.location.reload();
});
< /code>
и errorhandhandling.js.// Custom error types
class SpotifyAPIError extends Error {
constructor(message, endpoint, statusCode) {
super(message);
this.name = 'SpotifyAPIError';
this.endpoint = endpoint;
this.statusCode = statusCode;
}
}
class AuthenticationError extends Error {
constructor(message, reason) {
super(message);
this.name = 'AuthenticationError';
this.reason = reason;
}
}
class DataProcessingError extends Error {
constructor(message, dataType) {
super(message);
this.name = 'DataProcessingError';
this.dataType = dataType;
}
}
// Error logging function with different severity levels
const logError = (error, context = {}) => {
const timestamp = new Date().toISOString();
const errorDetails = {
timestamp,
name: error.name,
message: error.message,
stack: error.stack,
...context
};
// Log different types of errors with appropriate formatting
if (error instanceof SpotifyAPIError) {
console.error(
'%cSpotify API Error',
'color: #e22134; font-weight: bold;',
'\nEndpoint:', error.endpoint,
'\nStatus Code:', error.statusCode,
'\nMessage:', error.message,
'\nTimestamp:', timestamp
);
} else if (error instanceof AuthenticationError) {
console.error(
'%cAuthentication Error',
'color: #f59b23; font-weight: bold;',
'\nReason:', error.reason,
'\nMessage:', error.message,
'\nTimestamp:', timestamp
);
} else if (error instanceof DataProcessingError) {
console.error(
'%cData Processing Error',
'color: #8c4b96; font-weight: bold;',
'\nData Type:', error.dataType,
'\nMessage:', error.message,
'\nTimestamp:', timestamp
);
} else {
console.error(
'%cUnexpected Error',
'color: #c41e3a; font-weight: bold;',
'\nType:', error.name,
'\nMessage:', error.message,
'\nTimestamp:', timestamp
);
}
// Log full error details for debugging
console.debug('Full error details:', errorDetails);
}
// API response handler
const handleApiResponse = async (response, endpoint) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new SpotifyAPIError(
errorData.error?.message || 'API request failed',
endpoint,
response.status
);
}
return response;
}
// Authentication error handler
const handleAuthError = (error) => {
if (error.message.includes('access_token')) {
throw new AuthenticationError('Authentication token is invalid or expired', 'Invalid Token');
}
throw new AuthenticationError('Failed to authenticate with Spotify', 'Unknown');
}
// Data processing error handler
const handleDataProcessingError = (error, dataType) => {
throw new DataProcessingError(`Failed to process ${dataType} data: ${error.message}`, dataType);
}
// Export error handling utilities
export {
SpotifyAPIError,
AuthenticationError,
DataProcessingError,
logError,
handleApiResponse,
handleAuthError,
handleDataProcessingError
};
Подробнее здесь: https://stackoverflow.com/questions/794 ... g-any-data
Мобильная версия