KEXEL commited on
Commit
cf5bf60
·
verified ·
1 Parent(s): 5283ff2
Files changed (1) hide show
  1. rdapp.html +451 -0
rdapp.html ADDED
@@ -0,0 +1,451 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Web Radio Player</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
+ @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap');
11
+
12
+ body {
13
+ font-family: 'Poppins', sans-serif;
14
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
15
+ color: #fff;
16
+ min-height: 100vh;
17
+ }
18
+
19
+ .radio-container {
20
+ background: rgba(255, 255, 255, 0.05);
21
+ backdrop-filter: blur(10px);
22
+ border-radius: 20px;
23
+ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2);
24
+ overflow: hidden;
25
+ }
26
+
27
+ .station-card {
28
+ transition: all 0.3s ease;
29
+ cursor: pointer;
30
+ background: rgba(255, 255, 255, 0.03);
31
+ border: 1px solid rgba(255, 255, 255, 0.1);
32
+ }
33
+
34
+ .station-card:hover {
35
+ transform: translateY(-5px);
36
+ background: rgba(255, 255, 255, 0.1);
37
+ border-color: rgba(255, 255, 255, 0.3);
38
+ }
39
+
40
+ .station-card.active {
41
+ background: rgba(59, 130, 246, 0.2);
42
+ border-color: rgba(59, 130, 246, 0.5);
43
+ }
44
+
45
+ .progress-bar {
46
+ height: 4px;
47
+ background: rgba(255, 255, 255, 0.1);
48
+ }
49
+
50
+ .progress {
51
+ height: 100%;
52
+ background: linear-gradient(90deg, #3b82f6 0%, #8b5cf6 100%);
53
+ width: 0%;
54
+ transition: width 0.1s linear;
55
+ }
56
+
57
+ .volume-slider::-webkit-slider-thumb {
58
+ -webkit-appearance: none;
59
+ width: 15px;
60
+ height: 15px;
61
+ border-radius: 50%;
62
+ background: #fff;
63
+ cursor: pointer;
64
+ }
65
+
66
+ .now-playing-artwork {
67
+ animation: rotate 20s linear infinite;
68
+ animation-play-state: paused;
69
+ }
70
+
71
+ .now-playing-artwork.playing {
72
+ animation-play-state: running;
73
+ }
74
+
75
+ @keyframes rotate {
76
+ from { transform: rotate(0deg); }
77
+ to { transform: rotate(360deg); }
78
+ }
79
+
80
+ .equalizer {
81
+ display: flex;
82
+ align-items: flex-end;
83
+ height: 30px;
84
+ gap: 3px;
85
+ }
86
+
87
+ .equalizer-bar {
88
+ width: 4px;
89
+ background: #3b82f6;
90
+ border-radius: 2px;
91
+ animation: equalize 1.5s infinite ease-in-out;
92
+ }
93
+
94
+ .equalizer-bar:nth-child(1) { animation-delay: 0.1s; height: 60%; }
95
+ .equalizer-bar:nth-child(2) { animation-delay: 0.3s; height: 30%; }
96
+ .equalizer-bar:nth-child(3) { animation-delay: 0.5s; height: 75%; }
97
+ .equalizer-bar:nth-child(4) { animation-delay: 0.2s; height: 40%; }
98
+ .equalizer-bar:nth-child(5) { animation-delay: 0.4s; height: 65%; }
99
+
100
+ @keyframes equalize {
101
+ 0%, 100% { transform: scaleY(1); }
102
+ 50% { transform: scaleY(1.5); }
103
+ }
104
+ </style>
105
+ </head>
106
+ <body class="flex items-center justify-center p-4">
107
+ <div class="radio-container w-full max-w-4xl">
108
+ <!-- Header -->
109
+ <div class="p-6 bg-gradient-to-r from-blue-600 to-purple-600 flex justify-between items-center">
110
+ <div>
111
+ <h1 class="text-2xl font-bold">Web Radio Player</h1>
112
+ <p class="text-sm opacity-80">Escolha sua estação favorita</p>
113
+ </div>
114
+ <div class="flex items-center space-x-2">
115
+ <div class="equalizer hidden" id="equalizer">
116
+ <div class="equalizer-bar"></div>
117
+ <div class="equalizer-bar"></div>
118
+ <div class="equalizer-bar"></div>
119
+ <div class="equalizer-bar"></div>
120
+ <div class="equalizer-bar"></div>
121
+ </div>
122
+ <span class="text-sm" id="current-time">00:00</span>
123
+ </div>
124
+ </div>
125
+
126
+ <!-- Main Content -->
127
+ <div class="grid grid-cols-1 md:grid-cols-3 gap-0">
128
+ <!-- Station List -->
129
+ <div class="p-4 md:col-span-1 bg-gray-900 bg-opacity-50 overflow-y-auto max-h-[500px]">
130
+ <div class="mb-4 relative">
131
+ <input type="text" placeholder="Buscar rádio..." class="w-full bg-gray-800 bg-opacity-50 border border-gray-700 rounded-lg px-4 py-2 text-white focus:outline-none focus:ring-2 focus:ring-blue-500">
132
+ <i class="fas fa-search absolute right-3 top-3 text-gray-400"></i>
133
+ </div>
134
+
135
+ <h3 class="font-medium text-gray-300 mb-3">Categorias</h3>
136
+ <div class="flex flex-wrap gap-2 mb-4">
137
+ <span class="px-3 py-1 bg-blue-600 bg-opacity-30 rounded-full text-xs cursor-pointer hover:bg-opacity-50">Todas</span>
138
+ <span class="px-3 py-1 bg-gray-700 rounded-full text-xs cursor-pointer hover:bg-gray-600">Pop</span>
139
+ <span class="px-3 py-1 bg-gray-700 rounded-full text-xs cursor-pointer hover:bg-gray-600">Rock</span>
140
+ <span class="px-3 py-1 bg-gray-700 rounded-full text-xs cursor-pointer hover:bg-gray-600">Eletrônica</span>
141
+ <span class="px-3 py-1 bg-gray-700 rounded-full text-xs cursor-pointer hover:bg-gray-600">Jazz</span>
142
+ </div>
143
+
144
+ <h3 class="font-medium text-gray-300 mb-3">Estações</h3>
145
+ <div class="space-y-2" id="station-list">
146
+ <!-- Stations will be added here by JavaScript -->
147
+ </div>
148
+ </div>
149
+
150
+ <!-- Now Playing -->
151
+ <div class="p-6 md:col-span-2 flex flex-col bg-gray-900 bg-opacity-30">
152
+ <div class="flex flex-col md:flex-row items-center mb-6">
153
+ <div class="relative mb-4 md:mb-0 md:mr-6">
154
+ <div class="now-playing-artwork w-40 h-40 rounded-full overflow-hidden border-4 border-white border-opacity-10">
155
+ <img src="https://source.unsplash.com/random/400x400/?music" alt="Album Art" class="w-full h-full object-cover" id="station-artwork">
156
+ </div>
157
+ <div class="absolute -bottom-2 -right-2 bg-blue-600 rounded-full p-2 shadow-lg">
158
+ <i class="fas fa-music text-white"></i>
159
+ </div>
160
+ </div>
161
+
162
+ <div class="text-center md:text-left">
163
+ <h2 class="text-xl font-bold" id="station-name">Selecione uma estação</h2>
164
+ <p class="text-gray-300 mb-2" id="station-genre">Gênero</p>
165
+ <p class="text-sm text-gray-400" id="current-song">Nenhuma música tocando</p>
166
+ </div>
167
+ </div>
168
+
169
+ <!-- Progress Bar -->
170
+ <div class="progress-bar mb-4 rounded-full">
171
+ <div class="progress rounded-full" id="progress-bar"></div>
172
+ </div>
173
+
174
+ <!-- Controls -->
175
+ <div class="flex justify-between items-center mb-6">
176
+ <button class="text-gray-400 hover:text-white" id="btn-shuffle">
177
+ <i class="fas fa-random"></i>
178
+ </button>
179
+
180
+ <button class="text-gray-400 hover:text-white" id="btn-prev">
181
+ <i class="fas fa-step-backward text-2xl"></i>
182
+ </button>
183
+
184
+ <button class="bg-blue-600 hover:bg-blue-700 rounded-full w-12 h-12 flex items-center justify-center text-white" id="btn-play">
185
+ <i class="fas fa-play"></i>
186
+ </button>
187
+
188
+ <button class="text-gray-400 hover:text-white" id="btn-next">
189
+ <i class="fas fa-step-forward text-2xl"></i>
190
+ </button>
191
+
192
+ <button class="text-gray-400 hover:text-white" id="btn-repeat">
193
+ <i class="fas fa-redo"></i>
194
+ </button>
195
+ </div>
196
+
197
+ <!-- Volume Control -->
198
+ <div class="flex items-center">
199
+ <i class="fas fa-volume-down text-gray-400 mr-2"></i>
200
+ <input type="range" min="0" max="100" value="70" class="volume-slider w-full h-1 bg-gray-700 rounded-lg appearance-none cursor-pointer" id="volume-control">
201
+ <i class="fas fa-volume-up text-gray-400 ml-2"></i>
202
+ </div>
203
+ </div>
204
+ </div>
205
+
206
+ <!-- Footer -->
207
+ <div class="p-4 bg-gray-900 bg-opacity-50 text-center text-sm text-gray-400">
208
+ Web Radio Player © 2025 - Todos os direitos reservados
209
+ </div>
210
+ </div>
211
+
212
+ <script>
213
+ // Sample radio stations data
214
+ const stations = [
215
+ {
216
+ id: 1,
217
+ name: "Radio Pop Hits",
218
+ genre: "Pop",
219
+ url: "https://stream.laut.fm/pophits",
220
+ image: "https://source.unsplash.com/random/300x300/?pop,music",
221
+ currentSong: "Dua Lipa - Don't Start Now"
222
+ },
223
+ {
224
+ id: 2,
225
+ name: "Rock FM",
226
+ genre: "Rock",
227
+ url: "https://stream.laut.fm/rockfm",
228
+ image: "https://source.unsplash.com/random/300x300/?rock,music",
229
+ currentSong: "Foo Fighters - Everlong"
230
+ },
231
+ {
232
+ id: 3,
233
+ name: "Jazz Lounge",
234
+ genre: "Jazz",
235
+ url: "https://stream.laut.fm/jazzlounge",
236
+ image: "https://source.unsplash.com/random/300x300/?jazz,music",
237
+ currentSong: "Miles Davis - So What"
238
+ },
239
+ {
240
+ id: 4,
241
+ name: "EDM Festival",
242
+ genre: "Eletrônica",
243
+ url: "https://stream.laut.fm/edmfestival",
244
+ image: "https://source.unsplash.com/random/300x300/?electronic,music",
245
+ currentSong: "Swedish House Mafia - Don't You Worry Child"
246
+ },
247
+ {
248
+ id: 5,
249
+ name: "Classical Radio",
250
+ genre: "Clássica",
251
+ url: "https://stream.laut.fm/classicalradio",
252
+ image: "https://source.unsplash.com/random/300x300/?classical,music",
253
+ currentSong: "Beethoven - Symphony No. 5"
254
+ },
255
+ {
256
+ id: 6,
257
+ name: "Hip Hop Nation",
258
+ genre: "Hip Hop",
259
+ url: "https://stream.laut.fm/hiphopnation",
260
+ image: "https://source.unsplash.com/random/300x300/?hiphop,music",
261
+ currentSong: "Kendrick Lamar - HUMBLE."
262
+ }
263
+ ];
264
+
265
+ // DOM Elements
266
+ const stationList = document.getElementById('station-list');
267
+ const stationName = document.getElementById('station-name');
268
+ const stationGenre = document.getElementById('station-genre');
269
+ const currentSong = document.getElementById('current-song');
270
+ const stationArtwork = document.getElementById('station-artwork');
271
+ const btnPlay = document.getElementById('btn-play');
272
+ const btnPrev = document.getElementById('btn-prev');
273
+ const btnNext = document.getElementById('btn-next');
274
+ const btnShuffle = document.getElementById('btn-shuffle');
275
+ const btnRepeat = document.getElementById('btn-repeat');
276
+ const volumeControl = document.getElementById('volume-control');
277
+ const progressBar = document.getElementById('progress-bar');
278
+ const equalizer = document.getElementById('equalizer');
279
+ const currentTime = document.getElementById('current-time');
280
+
281
+ // Audio context
282
+ const audio = new Audio();
283
+ let isPlaying = false;
284
+ let currentStationIndex = 0;
285
+ let progressInterval;
286
+ let updateTimeInterval;
287
+
288
+ // Initialize the app
289
+ function init() {
290
+ renderStations();
291
+ setupEventListeners();
292
+ }
293
+
294
+ // Render stations list
295
+ function renderStations() {
296
+ stationList.innerHTML = '';
297
+ stations.forEach((station, index) => {
298
+ const stationElement = document.createElement('div');
299
+ stationElement.className = 'station-card p-3 rounded-lg';
300
+ stationElement.innerHTML = `
301
+ <div class="flex items-center">
302
+ <img src="${station.image}" alt="${station.name}" class="w-12 h-12 rounded-lg object-cover mr-3">
303
+ <div>
304
+ <h4 class="font-medium">${station.name}</h4>
305
+ <p class="text-xs text-gray-400">${station.genre}</p>
306
+ </div>
307
+ </div>
308
+ `;
309
+ stationElement.addEventListener('click', () => selectStation(index));
310
+ stationList.appendChild(stationElement);
311
+ });
312
+ }
313
+
314
+ // Select a station
315
+ function selectStation(index) {
316
+ // Update UI
317
+ const stationCards = document.querySelectorAll('.station-card');
318
+ stationCards.forEach(card => card.classList.remove('active'));
319
+ stationCards[index].classList.add('active');
320
+
321
+ // Update current station
322
+ currentStationIndex = index;
323
+ const station = stations[index];
324
+
325
+ // Update now playing info
326
+ stationName.textContent = station.name;
327
+ stationGenre.textContent = station.genre;
328
+ currentSong.textContent = station.currentSong;
329
+ stationArtwork.src = station.image;
330
+
331
+ // Load and play the station
332
+ audio.src = station.url;
333
+ playStation();
334
+ }
335
+
336
+ // Play the selected station
337
+ function playStation() {
338
+ audio.play()
339
+ .then(() => {
340
+ isPlaying = true;
341
+ btnPlay.innerHTML = '<i class="fas fa-pause"></i>';
342
+ document.querySelector('.now-playing-artwork').classList.add('playing');
343
+ equalizer.classList.remove('hidden');
344
+
345
+ // Start progress bar and time updates
346
+ startProgressUpdate();
347
+ startTimeUpdate();
348
+ })
349
+ .catch(error => {
350
+ console.error('Error playing audio:', error);
351
+ alert('Erro ao reproduzir a estação. Verifique sua conexão ou tente outra estação.');
352
+ });
353
+ }
354
+
355
+ // Pause the current station
356
+ function pauseStation() {
357
+ audio.pause();
358
+ isPlaying = false;
359
+ btnPlay.innerHTML = '<i class="fas fa-play"></i>';
360
+ document.querySelector('.now-playing-artwork').classList.remove('playing');
361
+ equalizer.classList.add('hidden');
362
+
363
+ // Stop progress updates
364
+ stopProgressUpdate();
365
+ stopTimeUpdate();
366
+ }
367
+
368
+ // Toggle play/pause
369
+ function togglePlayPause() {
370
+ if (isPlaying) {
371
+ pauseStation();
372
+ } else {
373
+ if (audio.src) {
374
+ playStation();
375
+ } else {
376
+ // If no station is selected, select the first one
377
+ selectStation(0);
378
+ }
379
+ }
380
+ }
381
+
382
+ // Play next station
383
+ function playNext() {
384
+ const nextIndex = (currentStationIndex + 1) % stations.length;
385
+ selectStation(nextIndex);
386
+ }
387
+
388
+ // Play previous station
389
+ function playPrev() {
390
+ const prevIndex = (currentStationIndex - 1 + stations.length) % stations.length;
391
+ selectStation(prevIndex);
392
+ }
393
+
394
+ // Update progress bar
395
+ function startProgressUpdate() {
396
+ // For live streams, we'll simulate progress
397
+ let progress = 0;
398
+ progressInterval = setInterval(() => {
399
+ progress = (progress + 0.5) % 100;
400
+ progressBar.style.width = `${progress}%`;
401
+ }, 1000);
402
+ }
403
+
404
+ function stopProgressUpdate() {
405
+ clearInterval(progressInterval);
406
+ }
407
+
408
+ // Update current time
409
+ function startTimeUpdate() {
410
+ let seconds = 0;
411
+ updateTimeInterval = setInterval(() => {
412
+ seconds++;
413
+ const mins = Math.floor(seconds / 60);
414
+ const secs = seconds % 60;
415
+ currentTime.textContent = `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
416
+ }, 1000);
417
+ }
418
+
419
+ function stopTimeUpdate() {
420
+ clearInterval(updateTimeInterval);
421
+ }
422
+
423
+ // Setup event listeners
424
+ function setupEventListeners() {
425
+ btnPlay.addEventListener('click', togglePlayPause);
426
+ btnNext.addEventListener('click', playNext);
427
+ btnPrev.addEventListener('click', playPrev);
428
+
429
+ // Volume control
430
+ volumeControl.addEventListener('input', () => {
431
+ audio.volume = volumeControl.value / 100;
432
+ });
433
+
434
+ // Shuffle and repeat buttons
435
+ btnShuffle.addEventListener('click', () => {
436
+ btnShuffle.classList.toggle('text-blue-400');
437
+ });
438
+
439
+ btnRepeat.addEventListener('click', () => {
440
+ btnRepeat.classList.toggle('text-blue-400');
441
+ });
442
+
443
+ // Select first station by default
444
+ selectStation(0);
445
+ }
446
+
447
+ // Initialize the app when DOM is loaded
448
+ document.addEventListener('DOMContentLoaded', init);
449
+ </script>
450
+ </body>
451
+ </html>