1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Thank you for the feedback! You're right, we need to handle cases where playlist images might be missing.
// Let's update the code to handle this gracefully and provide a default image when necessary.
import { Hono } from "npm:hono@3";
const app = new Hono();
const CLIENT_ID = "605b681271294a05ba5a574f790ac409";
const REDIRECT_URI = "https://ejfox-spotify.web.val.run/callback";
app.get("/", (c) => {
const html = `
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spotify Playlist Viewer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
<style>
body { font-family: 'Poppins', sans-serif; }
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen flex items-center justify-center">
<div class="bg-gray-800 p-10 rounded-xl shadow-2xl max-w-md w-full">
<h1 class="text-4xl font-bold mb-8 text-center text-green-400">Spotify Playlist Viewer</h1>
<a href="https://accounts.spotify.com/authorize?client_id=${CLIENT_ID}&response_type=token&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&scope=playlist-read-private"
class="block w-full text-center bg-green-500 hover:bg-green-600 text-white font-semibold py-3 px-6 rounded-full transition duration-300 ease-in-out transform hover:scale-105 focus:outline-none focus:ring-2 focus:ring-green-400 focus:ring-opaci
Login with Spotify
</a>
<div id="error" class="mt-6 text-red-400 text-center"></div>
</div>
<script>
const errorDiv = document.getElementById('error');
const link = document.querySelector('a');
link.addEventListener('click', (e) => {
e.preventDefault();
const url = e.target.href;
console.log('Redirecting to:', url);
window.location.href = url;
});
window.onerror = function(message, source, lineno, colno, error) {
console.error('An error occurred:', error);
errorDiv.textContent = 'An error occurred: ' + message;
};
</script>
</body>
</html>
`;
return c.html(html);
});
app.get("/callback", (c) => {
const html = `
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spotify Playlists</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<style>
body { font-family: 'Poppins', sans-serif; }
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: #2D3748; }
::-webkit-scrollbar-thumb { background: #4A5568; border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: #718096; }
</style>
<script>
const hash = window.location.hash.substring(1);
const params = new URLSearchParams(hash);
const accessToken = params.get('access_token');
const error = params.get('error');
if (error) {
console.error('Spotify authentication error:', error);
document.body.innerHTML = '<div class="flex items-center justify-center min-h-screen bg-gray-900"><div class="text-center"><h1 class="text-4xl font-bold text-red-500 mb-4">Authentication Error</h1><p class="text-xl text-gray-300">' + error + '<
} else if (!accessToken) {
console.error('No access token found in URL');
document.body.innerHTML = '<div class="flex items-center justify-center min-h-screen bg-gray-900"><div class="text-center"><h1 class="text-4xl font-bold text-red-500 mb-4">Error</h1><p class="text-xl text-gray-300">No access token found. Please
} else {
console.log('Access token received');
async function fetchPlaylists() {
try {
const response = await axios.get('https://api.spotify.com/v1/me/playlists', {
headers: { 'Authorization': 'Bearer ' + accessToken }
});
const playlists = response.data.items;
const playlistsDiv = document.getElementById('playlists');
playlistsDiv.innerHTML = '';
playlists.forEach(playlist => {
const playlistEl = document.createElement('div');
playlistEl.className = 'bg-gray-800 rounded-lg p-4 mb-4 flex items-center cursor-pointer hover:bg-gray-700 transition-colors duration-300';
playlistEl.onclick = () => fetchTracks(playlist.id, playlist.name);
const imageUrl = playlist.images && playlist.images.length > 0 ? playlist.images[0].url : 'https://via.placeholder.com/60';
playlistEl.innerHTML = \`
<img src="\${imageUrl}" alt="\${playlist.name}" class="w-16 h-16 rounded-md mr-4 object-cover">
<div>