nock2 commited on
Commit
a92ea16
·
verified ·
1 Parent(s): bc3f2da

undefined - Initial Deployment

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +533 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Playlist Migrator
3
- emoji: 🏢
4
- colorFrom: indigo
5
- colorTo: blue
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: playlist-migrator
3
+ emoji: 🐳
4
+ colorFrom: purple
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,533 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Playlist Migrator | Move Spotify to YouTube</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ .gradient-bg {
11
+ background: linear-gradient(135deg, #1DB954 0%, #FF0000 100%);
12
+ }
13
+ .spotify-btn {
14
+ background-color: #1DB954;
15
+ transition: all 0.3s ease;
16
+ }
17
+ .spotify-btn:hover {
18
+ background-color: #1ed760;
19
+ transform: translateY(-2px);
20
+ }
21
+ .youtube-btn {
22
+ background-color: #FF0000;
23
+ transition: all 0.3s ease;
24
+ }
25
+ .youtube-btn:hover {
26
+ background-color: #ff3333;
27
+ transform: translateY(-2px);
28
+ }
29
+ .migrate-btn {
30
+ background: linear-gradient(135deg, #1DB954 0%, #FF0000 100%);
31
+ transition: all 0.3s ease;
32
+ }
33
+ .migrate-btn:hover {
34
+ transform: translateY(-2px);
35
+ box-shadow: 0 10px 20px rgba(0,0,0,0.2);
36
+ }
37
+ .playlist-card {
38
+ transition: all 0.3s ease;
39
+ }
40
+ .playlist-card:hover {
41
+ transform: translateY(-5px);
42
+ box-shadow: 0 10px 25px rgba(0,0,0,0.1);
43
+ }
44
+ .progress-bar {
45
+ height: 6px;
46
+ background-color: #e0e0e0;
47
+ border-radius: 3px;
48
+ }
49
+ .progress-fill {
50
+ height: 100%;
51
+ border-radius: 3px;
52
+ background: linear-gradient(90deg, #1DB954 0%, #FF0000 100%);
53
+ transition: width 0.4s ease;
54
+ }
55
+ </style>
56
+ </head>
57
+ <body class="bg-gray-50 min-h-screen">
58
+ <!-- Header -->
59
+ <header class="gradient-bg text-white shadow-lg">
60
+ <div class="container mx-auto px-4 py-6">
61
+ <div class="flex justify-between items-center">
62
+ <div class="flex items-center space-x-2">
63
+ <i class="fab fa-spotify text-3xl"></i>
64
+ <i class="fas fa-exchange-alt text-xl"></i>
65
+ <i class="fab fa-youtube text-3xl"></i>
66
+ <h1 class="text-2xl font-bold">Playlist Migrator</h1>
67
+ </div>
68
+ <button class="bg-white text-gray-800 px-4 py-2 rounded-full font-semibold hover:bg-gray-100 transition">
69
+ <i class="fas fa-question-circle mr-2"></i>Help
70
+ </button>
71
+ </div>
72
+ </div>
73
+ </header>
74
+
75
+ <!-- Main Content -->
76
+ <main class="container mx-auto px-4 py-8">
77
+ <div class="max-w-4xl mx-auto">
78
+ <!-- Intro Section -->
79
+ <section class="bg-white rounded-xl shadow-md p-6 mb-8">
80
+ <h2 class="text-2xl font-bold text-gray-800 mb-4">Migrate Your Spotify Playlists to YouTube</h2>
81
+ <p class="text-gray-600 mb-6">
82
+ Easily transfer your favorite Spotify playlists to YouTube Music. Our migrator preserves your playlist
83
+ names, descriptions, and tracks with the highest possible match accuracy.
84
+ </p>
85
+ <div class="flex flex-wrap gap-4">
86
+ <div class="flex-1 min-w-[200px] bg-green-50 p-4 rounded-lg">
87
+ <div class="flex items-center mb-2">
88
+ <i class="fab fa-spotify text-green-500 text-2xl mr-2"></i>
89
+ <h3 class="font-semibold">Spotify Features</h3>
90
+ </div>
91
+ <ul class="text-sm text-gray-700 space-y-1">
92
+ <li><i class="fas fa-check text-green-500 mr-2"></i>Connect your Spotify account</li>
93
+ <li><i class="fas fa-check text-green-500 mr-2"></i>View all your playlists</li>
94
+ <li><i class="fas fa-check text-green-500 mr-2"></i>Select tracks to migrate</li>
95
+ </ul>
96
+ </div>
97
+ <div class="flex-1 min-w-[200px] bg-red-50 p-4 rounded-lg">
98
+ <div class="flex items-center mb-2">
99
+ <i class="fab fa-youtube text-red-500 text-2xl mr-2"></i>
100
+ <h3 class="font-semibold">YouTube Features</h3>
101
+ </div>
102
+ <ul class="text-sm text-gray-700 space-y-1">
103
+ <li><i class="fas fa-check text-red-500 mr-2"></i>Connect your YouTube account</li>
104
+ <li><i class="fas fa-check text-red-500 mr-2"></i>Create new playlists</li>
105
+ <li><i class="fas fa-check text-red-500 mr-2"></i>Add matched tracks</li>
106
+ </ul>
107
+ </div>
108
+ </div>
109
+ </section>
110
+
111
+ <!-- Connection Section -->
112
+ <section class="bg-white rounded-xl shadow-md p-6 mb-8">
113
+ <h2 class="text-xl font-bold text-gray-800 mb-6">Connect Your Accounts</h2>
114
+ <div class="grid md:grid-cols-2 gap-6">
115
+ <!-- Spotify Connection -->
116
+ <div class="border border-gray-200 rounded-lg p-4">
117
+ <div class="flex items-center mb-4">
118
+ <i class="fab fa-spotify text-green-500 text-3xl mr-3"></i>
119
+ <div>
120
+ <h3 class="font-semibold">Spotify</h3>
121
+ <p class="text-sm text-gray-500">Connect to view your playlists</p>
122
+ </div>
123
+ </div>
124
+ <div id="spotify-status" class="mb-4">
125
+ <div class="flex items-center text-sm text-gray-600">
126
+ <div class="w-3 h-3 rounded-full bg-gray-300 mr-2"></div>
127
+ <span>Not connected</span>
128
+ </div>
129
+ </div>
130
+ <button id="connect-spotify" class="spotify-btn text-white w-full py-3 rounded-lg font-semibold flex items-center justify-center">
131
+ <i class="fab fa-spotify mr-2"></i> Connect Spotify
132
+ </button>
133
+ </div>
134
+
135
+ <!-- YouTube Connection -->
136
+ <div class="border border-gray-200 rounded-lg p-4">
137
+ <div class="flex items-center mb-4">
138
+ <i class="fab fa-youtube text-red-500 text-3xl mr-3"></i>
139
+ <div>
140
+ <h3 class="font-semibold">YouTube</h3>
141
+ <p class="text-sm text-gray-500">Connect to create playlists</p>
142
+ </div>
143
+ </div>
144
+ <div id="youtube-status" class="mb-4">
145
+ <div class="flex items-center text-sm text-gray-600">
146
+ <div class="w-3 h-3 rounded-full bg-gray-300 mr-2"></div>
147
+ <span>Not connected</span>
148
+ </div>
149
+ </div>
150
+ <button id="connect-youtube" class="youtube-btn text-white w-full py-3 rounded-lg font-semibold flex items-center justify-center">
151
+ <i class="fab fa-youtube mr-2"></i> Connect YouTube
152
+ </button>
153
+ </div>
154
+ </div>
155
+ </section>
156
+
157
+ <!-- Playlist Selection (Hidden Initially) -->
158
+ <section id="playlist-section" class="hidden bg-white rounded-xl shadow-md p-6 mb-8">
159
+ <div class="flex justify-between items-center mb-6">
160
+ <h2 class="text-xl font-bold text-gray-800">Your Spotify Playlists</h2>
161
+ <div class="relative">
162
+ <input type="text" placeholder="Search playlists..." class="pl-10 pr-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-green-500">
163
+ <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
164
+ </div>
165
+ </div>
166
+
167
+ <div id="playlist-container" class="grid md:grid-cols-2 gap-4 mb-6">
168
+ <!-- Playlist cards will be inserted here by JavaScript -->
169
+ </div>
170
+
171
+ <div class="flex justify-between items-center">
172
+ <div class="text-sm text-gray-500">
173
+ <span id="selected-count">0</span> of <span id="total-count">0</span> playlists selected
174
+ </div>
175
+ <button id="select-all" class="text-green-600 font-medium hover:text-green-700">
176
+ <i class="fas fa-check-circle mr-1"></i> Select All
177
+ </button>
178
+ </div>
179
+ </section>
180
+
181
+ <!-- Migration Section (Hidden Initially) -->
182
+ <section id="migration-section" class="hidden bg-white rounded-xl shadow-md p-6">
183
+ <h2 class="text-xl font-bold text-gray-800 mb-6">Ready to Migrate</h2>
184
+
185
+ <div class="mb-6">
186
+ <div class="flex justify-between mb-1">
187
+ <span class="font-medium">Migration Progress</span>
188
+ <span id="progress-percent" class="font-medium">0%</span>
189
+ </div>
190
+ <div class="progress-bar">
191
+ <div id="progress-fill" class="progress-fill" style="width: 0%"></div>
192
+ </div>
193
+ </div>
194
+
195
+ <div id="migration-details" class="mb-6">
196
+ <div class="grid md:grid-cols-3 gap-4">
197
+ <div class="bg-gray-50 p-4 rounded-lg">
198
+ <div class="text-gray-500 text-sm mb-1">Playlists</div>
199
+ <div id="playlist-count" class="text-2xl font-bold">0</div>
200
+ </div>
201
+ <div class="bg-gray-50 p-4 rounded-lg">
202
+ <div class="text-gray-500 text-sm mb-1">Tracks</div>
203
+ <div id="track-count" class="text-2xl font-bold">0</div>
204
+ </div>
205
+ <div class="bg-gray-50 p-4 rounded-lg">
206
+ <div class="text-gray-500 text-sm mb-1">Estimated Time</div>
207
+ <div id="time-estimate" class="text-2xl font-bold">~2 min</div>
208
+ </div>
209
+ </div>
210
+ </div>
211
+
212
+ <div class="flex flex-col sm:flex-row gap-4">
213
+ <button id="start-migration" class="migrate-btn text-white flex-1 py-3 rounded-lg font-bold flex items-center justify-center">
214
+ <i class="fas fa-exchange-alt mr-2"></i> Start Migration
215
+ </button>
216
+ <button id="save-for-later" class="border border-gray-300 flex-1 py-3 rounded-lg font-medium flex items-center justify-center hover:bg-gray-50">
217
+ <i class="far fa-save mr-2"></i> Save for Later
218
+ </button>
219
+ </div>
220
+ </section>
221
+
222
+ <!-- Migration Results (Hidden Initially) -->
223
+ <section id="results-section" class="hidden bg-white rounded-xl shadow-md p-6 mt-8">
224
+ <div class="text-center">
225
+ <div class="w-16 h-16 bg-green-100 rounded-full flex items-center justify-center mx-auto mb-4">
226
+ <i class="fas fa-check text-green-500 text-2xl"></i>
227
+ </div>
228
+ <h2 class="text-xl font-bold text-gray-800 mb-2">Migration Complete!</h2>
229
+ <p class="text-gray-600 mb-6">Your playlists have been successfully transferred to YouTube Music.</p>
230
+
231
+ <div class="grid md:grid-cols-3 gap-4 mb-8">
232
+ <div class="bg-green-50 p-4 rounded-lg">
233
+ <div class="text-green-500 text-sm mb-1">Successful</div>
234
+ <div id="success-count" class="text-2xl font-bold">12</div>
235
+ </div>
236
+ <div class="bg-yellow-50 p-4 rounded-lg">
237
+ <div class="text-yellow-500 text-sm mb-1">Partial Matches</div>
238
+ <div id="partial-count" class="text-2xl font-bold">3</div>
239
+ </div>
240
+ <div class="bg-red-50 p-4 rounded-lg">
241
+ <div class="text-red-500 text-sm mb-1">Not Found</div>
242
+ <div id="failed-count" class="text-2xl font-bold">1</div>
243
+ </div>
244
+ </div>
245
+
246
+ <button id="view-playlists" class="bg-green-600 text-white px-6 py-3 rounded-lg font-semibold hover:bg-green-700 transition mb-4">
247
+ <i class="fab fa-youtube mr-2"></i> View on YouTube
248
+ </button>
249
+ <div class="text-sm text-gray-500">
250
+ <button class="text-blue-600 hover:underline mr-4">
251
+ <i class="fas fa-download mr-1"></i> Download Report
252
+ </button>
253
+ <button class="text-blue-600 hover:underline">
254
+ <i class="fas fa-redo mr-1"></i> Migrate Another
255
+ </button>
256
+ </div>
257
+ </div>
258
+ </section>
259
+ </div>
260
+ </main>
261
+
262
+ <!-- Footer -->
263
+ <footer class="bg-gray-800 text-white py-8">
264
+ <div class="container mx-auto px-4">
265
+ <div class="flex flex-col md:flex-row justify-between items-center">
266
+ <div class="mb-4 md:mb-0">
267
+ <div class="flex items-center space-x-2">
268
+ <i class="fab fa-spotify text-2xl"></i>
269
+ <i class="fas fa-exchange-alt text-lg"></i>
270
+ <i class="fab fa-youtube text-2xl"></i>
271
+ <span class="font-bold">Playlist Migrator</span>
272
+ </div>
273
+ <p class="text-gray-400 text-sm mt-2">The easiest way to move your music between platforms</p>
274
+ </div>
275
+ <div class="flex space-x-6">
276
+ <a href="#" class="hover:text-green-400 transition"><i class="fab fa-github text-xl"></i></a>
277
+ <a href="#" class="hover:text-green-400 transition"><i class="fab fa-twitter text-xl"></i></a>
278
+ <a href="#" class="hover:text-green-400 transition"><i class="fab fa-discord text-xl"></i></a>
279
+ </div>
280
+ </div>
281
+ <div class="border-t border-gray-700 mt-6 pt-6 text-sm text-gray-400">
282
+ <div class="flex flex-col md:flex-row justify-between items-center">
283
+ <div class="mb-4 md:mb-0">
284
+ &copy; 2023 Playlist Migrator. Not affiliated with Spotify or YouTube.
285
+ </div>
286
+ <div class="flex space-x-4">
287
+ <a href="#" class="hover:text-white transition">Privacy Policy</a>
288
+ <a href="#" class="hover:text-white transition">Terms of Service</a>
289
+ <a href="#" class="hover:text-white transition">Contact</a>
290
+ </div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </footer>
295
+
296
+ <script>
297
+ // Sample data for demonstration
298
+ const samplePlaylists = [
299
+ {
300
+ id: '1',
301
+ name: 'Workout Mix',
302
+ description: 'High energy tracks for my workouts',
303
+ image: 'https://misc.scdn.co/liked-songs/liked-songs-64.png',
304
+ tracks: 32,
305
+ owner: 'You'
306
+ },
307
+ {
308
+ id: '2',
309
+ name: 'Chill Vibes',
310
+ description: 'Relaxing music for evenings',
311
+ image: 'https://i.scdn.co/image/ab67706c0000bebbc0d4f8172c9d486d5c8769d8',
312
+ tracks: 45,
313
+ owner: 'You'
314
+ },
315
+ {
316
+ id: '3',
317
+ name: 'Road Trip',
318
+ description: 'Perfect for long drives',
319
+ image: 'https://i.scdn.co/image/ab67706c0000bebbc0d4f8172c9d486d5c8769d8',
320
+ tracks: 28,
321
+ owner: 'You'
322
+ },
323
+ {
324
+ id: '4',
325
+ name: 'Party Hits',
326
+ description: 'All the latest party tracks',
327
+ image: 'https://misc.scdn.co/liked-songs/liked-songs-64.png',
328
+ tracks: 50,
329
+ owner: 'You'
330
+ }
331
+ ];
332
+
333
+ // DOM Elements
334
+ const connectSpotifyBtn = document.getElementById('connect-spotify');
335
+ const connectYoutubeBtn = document.getElementById('connect-youtube');
336
+ const spotifyStatus = document.getElementById('spotify-status');
337
+ const youtubeStatus = document.getElementById('youtube-status');
338
+ const playlistSection = document.getElementById('playlist-section');
339
+ const playlistContainer = document.getElementById('playlist-container');
340
+ const migrationSection = document.getElementById('migration-section');
341
+ const resultsSection = document.getElementById('results-section');
342
+ const progressFill = document.getElementById('progress-fill');
343
+ const progressPercent = document.getElementById('progress-percent');
344
+ const startMigrationBtn = document.getElementById('start-migration');
345
+ const selectAllBtn = document.getElementById('select-all');
346
+ const selectedCount = document.getElementById('selected-count');
347
+ const totalCount = document.getElementById('total-count');
348
+ const playlistCount = document.getElementById('playlist-count');
349
+ const trackCount = document.getElementById('track-count');
350
+
351
+ // State
352
+ let spotifyConnected = false;
353
+ let youtubeConnected = false;
354
+ let selectedPlaylists = [];
355
+
356
+ // Event Listeners
357
+ connectSpotifyBtn.addEventListener('click', connectSpotify);
358
+ connectYoutubeBtn.addEventListener('click', connectYouTube);
359
+ selectAllBtn.addEventListener('click', toggleSelectAll);
360
+ startMigrationBtn.addEventListener('click', startMigration);
361
+
362
+ // Functions
363
+ function connectSpotify() {
364
+ // Simulate Spotify connection
365
+ spotifyConnected = true;
366
+ connectSpotifyBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Connected';
367
+ connectSpotifyBtn.classList.remove('spotify-btn');
368
+ connectSpotifyBtn.classList.add('bg-gray-200', 'text-gray-800');
369
+ connectSpotifyBtn.disabled = true;
370
+
371
+ spotifyStatus.innerHTML = `
372
+ <div class="flex items-center text-sm text-green-600">
373
+ <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
374
+ <span>Connected as <span class="font-medium">user123</span></span>
375
+ </div>
376
+ `;
377
+
378
+ // Load playlists after connection
379
+ loadPlaylists();
380
+ checkConnections();
381
+ }
382
+
383
+ function connectYouTube() {
384
+ // Simulate YouTube connection
385
+ youtubeConnected = true;
386
+ connectYoutubeBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Connected';
387
+ connectYoutubeBtn.classList.remove('youtube-btn');
388
+ connectYoutubeBtn.classList.add('bg-gray-200', 'text-gray-800');
389
+ connectYoutubeBtn.disabled = true;
390
+
391
+ youtubeStatus.innerHTML = `
392
+ <div class="flex items-center text-sm text-green-600">
393
+ <div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
394
+ <span>Connected as <span class="font-medium">[email protected]</span></span>
395
+ </div>
396
+ `;
397
+
398
+ checkConnections();
399
+ }
400
+
401
+ function checkConnections() {
402
+ if (spotifyConnected && youtubeConnected) {
403
+ // Both connected
404
+ playlistSection.classList.remove('hidden');
405
+ }
406
+ }
407
+
408
+ function loadPlaylists() {
409
+ playlistContainer.innerHTML = '';
410
+ totalCount.textContent = samplePlaylists.length;
411
+
412
+ samplePlaylists.forEach(playlist => {
413
+ const playlistCard = document.createElement('div');
414
+ playlistCard.className = 'playlist-card bg-white border border-gray-200 rounded-lg overflow-hidden hover:shadow-md cursor-pointer';
415
+ playlistCard.innerHTML = `
416
+ <div class="p-4 flex items-start">
417
+ <img src="${playlist.image}" alt="${playlist.name}" class="w-16 h-16 rounded mr-4">
418
+ <div class="flex-1">
419
+ <h3 class="font-semibold text-gray-800">${playlist.name}</h3>
420
+ <p class="text-sm text-gray-500 mb-1">${playlist.description}</p>
421
+ <div class="flex items-center text-xs text-gray-400">
422
+ <span>${playlist.tracks} tracks</span>
423
+ <span class="mx-2">•</span>
424
+ <span>${playlist.owner}</span>
425
+ </div>
426
+ </div>
427
+ <div class="checkbox-container">
428
+ <input type="checkbox" id="playlist-${playlist.id}" class="hidden playlist-checkbox">
429
+ <label for="playlist-${playlist.id}" class="w-6 h-6 border-2 border-gray-300 rounded-full flex items-center justify-center cursor-pointer">
430
+ <i class="fas fa-check text-white text-xs"></i>
431
+ </label>
432
+ </div>
433
+ </div>
434
+ `;
435
+
436
+ playlistContainer.appendChild(playlistCard);
437
+
438
+ // Add event listener to checkbox
439
+ const checkbox = playlistCard.querySelector('.playlist-checkbox');
440
+ checkbox.addEventListener('change', function() {
441
+ updateSelectedPlaylists(this, playlist);
442
+ });
443
+
444
+ // Add click event to the whole card
445
+ playlistCard.addEventListener('click', function(e) {
446
+ // Don't toggle if clicking on the checkbox
447
+ if (!e.target.closest('.checkbox-container')) {
448
+ const checkbox = this.querySelector('.playlist-checkbox');
449
+ checkbox.checked = !checkbox.checked;
450
+ checkbox.dispatchEvent(new Event('change'));
451
+ }
452
+ });
453
+ });
454
+ }
455
+
456
+ function updateSelectedPlaylists(checkbox, playlist) {
457
+ const label = checkbox.nextElementSibling;
458
+
459
+ if (checkbox.checked) {
460
+ label.classList.add('bg-green-500', 'border-green-500');
461
+ selectedPlaylists.push(playlist);
462
+ } else {
463
+ label.classList.remove('bg-green-500', 'border-green-500');
464
+ selectedPlaylists = selectedPlaylists.filter(p => p.id !== playlist.id);
465
+ }
466
+
467
+ selectedCount.textContent = selectedPlaylists.length;
468
+
469
+ // Show/hide migration section
470
+ if (selectedPlaylists.length > 0) {
471
+ migrationSection.classList.remove('hidden');
472
+ updateMigrationDetails();
473
+ } else {
474
+ migrationSection.classList.add('hidden');
475
+ }
476
+ }
477
+
478
+ function toggleSelectAll() {
479
+ const checkboxes = document.querySelectorAll('.playlist-checkbox');
480
+ const isAllSelected = selectedPlaylists.length === samplePlaylists.length;
481
+
482
+ checkboxes.forEach(checkbox => {
483
+ if (!isAllSelected) {
484
+ checkbox.checked = true;
485
+ } else {
486
+ checkbox.checked = false;
487
+ }
488
+ checkbox.dispatchEvent(new Event('change'));
489
+ });
490
+
491
+ selectAllBtn.innerHTML = isAllSelected ?
492
+ '<i class="fas fa-check-circle mr-1"></i> Select All' :
493
+ '<i class="fas fa-times-circle mr-1"></i> Deselect All';
494
+ }
495
+
496
+ function updateMigrationDetails() {
497
+ const totalTracks = selectedPlaylists.reduce((sum, playlist) => sum + playlist.tracks, 0);
498
+ playlistCount.textContent = selectedPlaylists.length;
499
+ trackCount.textContent = totalTracks;
500
+ }
501
+
502
+ function startMigration() {
503
+ // Disable button and show loading state
504
+ startMigrationBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Migrating...';
505
+ startMigrationBtn.disabled = true;
506
+
507
+ // Simulate migration progress
508
+ let progress = 0;
509
+ const interval = setInterval(() => {
510
+ progress += Math.random() * 10;
511
+ if (progress >= 100) {
512
+ progress = 100;
513
+ clearInterval(interval);
514
+ migrationComplete();
515
+ }
516
+ progressFill.style.width = `${progress}%`;
517
+ progressPercent.textContent = `${Math.round(progress)}%`;
518
+ }, 500);
519
+ }
520
+
521
+ function migrationComplete() {
522
+ // Hide migration section and show results
523
+ migrationSection.classList.add('hidden');
524
+ resultsSection.classList.remove('hidden');
525
+
526
+ // Update results
527
+ document.getElementById('success-count').textContent = selectedPlaylists.length;
528
+ document.getElementById('partial-count').textContent = Math.floor(selectedPlaylists.length * 0.3);
529
+ document.getElementById('failed-count').textContent = Math.floor(selectedPlaylists.length * 0.1);
530
+ }
531
+ </script>
532
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=nock2/playlist-migrator" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
533
+ </html>