Multimedix commited on
Commit
630a10b
·
verified ·
1 Parent(s): 726b5bb

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +930 -1104
index.html CHANGED
@@ -1,1115 +1,941 @@
1
  <!DOCTYPE html>
2
  <html lang="de">
3
-
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Deutsche Radio Stream - Live Radio aus Deutschland</title>
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <style>
10
- * {
11
- margin: 0;
12
- padding: 0;
13
- box-sizing: border-box;
14
- }
15
-
16
- :root {
17
- --primary-color: #1e3a8a;
18
- --secondary-color: #3b82f6;
19
- --accent-color: #f59e0b;
20
- --dark-bg: #0f172a;
21
- --light-bg: #1e293b;
22
- --text-primary: #f1f5f9;
23
- --text-secondary: #94a3b8;
24
- --glass-bg: rgba(30, 41, 59, 0.5);
25
- --glass-border: rgba(148, 163, 184, 0.2);
26
- --success-color: #10b981;
27
- --error-color: #ef4444;
28
- --warning-color: #f59e0b;
29
- }
30
-
31
- body {
32
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
33
- background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
34
- min-height: 100vh;
35
- color: var(--text-primary);
36
- overflow-x: hidden;
37
- }
38
-
39
- /* Animated Background */
40
- .bg-animation {
41
- position: fixed;
42
- width: 100%;
43
- height: 100%;
44
- top: 0;
45
- left: 0;
46
- z-index: -1;
47
- background: linear-gradient(135deg, #0f172a 0%, #1e293b 50%, #334155 100%);
48
- overflow: hidden;
49
- }
50
-
51
- .bg-animation::before {
52
- content: '';
53
- position: absolute;
54
- width: 200%;
55
- height: 200%;
56
- top: -50%;
57
- left: -50%;
58
- background: radial-gradient(circle, rgba(59, 130, 246, 0.1) 0%, transparent 70%);
59
- animation: rotate 30s linear infinite;
60
- }
61
-
62
- @keyframes rotate {
63
- 0% {
64
- transform: rotate(0deg);
65
- }
66
- 100% {
67
- transform: rotate(360deg);
68
- }
69
- }
70
-
71
- /* Header */
72
- header {
73
- background: var(--glass-bg);
74
- backdrop-filter: blur(10px);
75
- border-bottom: 1px solid var(--glass-border);
76
- padding: 1.5rem 2rem;
77
- position: sticky;
78
- top: 0;
79
- z-index: 100;
80
- }
81
-
82
- .header-content {
83
- max-width: 800px;
84
- margin: 0 auto;
85
- display: flex;
86
- justify-content: space-between;
87
- align-items: center;
88
- flex-wrap: wrap;
89
- gap: 1rem;
90
- }
91
-
92
- .logo {
93
- display: flex;
94
- align-items: center;
95
- gap: 1rem;
96
- font-size: 1.5rem;
97
- font-weight: bold;
98
- color: var(--text-primary);
99
- }
100
-
101
- .logo i {
102
- font-size: 2rem;
103
- background: linear-gradient(135deg, var(--secondary-color), var(--accent-color));
104
- -webkit-background-clip: text;
105
- -webkit-text-fill-color: transparent;
106
- animation: pulse 2s ease-in-out infinite;
107
- }
108
-
109
- @keyframes pulse {
110
- 0%, 100% {
111
- transform: scale(1);
112
- }
113
- 50% {
114
- transform: scale(1.1);
115
- }
116
- }
117
-
118
- .attribution {
119
- font-size: 0.875rem;
120
- color: var(--text-secondary);
121
- }
122
-
123
- .attribution a {
124
- color: var(--secondary-color);
125
- text-decoration: none;
126
- transition: color 0.3s;
127
- }
128
-
129
- .attribution a:hover {
130
- color: var(--accent-color);
131
- }
132
-
133
- .live-indicator {
134
- background: linear-gradient(135deg, var(--success-color), #059669);
135
- color: white;
136
- padding: 0.25rem 0.75rem;
137
- border-radius: 20px;
138
- font-size: 0.75rem;
139
- font-weight: bold;
140
- display: flex;
141
- align-items: center;
142
- gap: 0.5rem;
143
- animation: glow-green 2s ease-in-out infinite;
144
- }
145
-
146
- .live-dot {
147
- width: 8px;
148
- height: 8px;
149
- background: white;
150
- border-radius: 50%;
151
- animation: blink 1s infinite;
152
- }
153
-
154
- @keyframes glow-green {
155
- 0%, 100% {
156
- box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
157
- }
158
- 50% {
159
- box-shadow: 0 0 20px rgba(16, 185, 129, 0.8);
160
- }
161
- }
162
-
163
- @keyframes blink {
164
- 0%, 100% {
165
- opacity: 1;
166
- }
167
- 50% {
168
- opacity: 0.5;
169
- }
170
- }
171
-
172
- /* Main Container */
173
- .container {
174
- max-width: 800px;
175
- margin: 2rem auto;
176
- padding: 0 2rem;
177
- }
178
-
179
- /* Player Section */
180
- .player-section {
181
- background: var(--glass-bg);
182
- backdrop-filter: blur(10px);
183
- border: 1px solid var(--glass-border);
184
- border-radius: 20px;
185
- padding: 2rem;
186
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
187
- }
188
-
189
- .now-playing {
190
- text-align: center;
191
- margin-bottom: 2rem;
192
- }
193
-
194
- .station-logo {
195
- width: 150px;
196
- height: 150px;
197
- margin: 0 auto 2rem;
198
- background: linear-gradient(135deg, var(--secondary-color), var(--accent-color));
199
- border-radius: 30px;
200
- display: flex;
201
- align-items: center;
202
- justify-content: center;
203
- font-size: 4rem;
204
- color: white;
205
- box-shadow: 0 15px 40px rgba(59, 130, 246, 0.4);
206
- animation: float 3s ease-in-out infinite;
207
- position: relative;
208
- overflow: hidden;
209
- }
210
-
211
- .station-logo.playing::after {
212
- content: '';
213
- position: absolute;
214
- top: -50%;
215
- left: -50%;
216
- width: 200%;
217
- height: 200%;
218
- background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
219
- animation: shine 3s infinite;
220
- }
221
-
222
- @keyframes shine {
223
- 0% {
224
- transform: rotate(0deg);
225
- }
226
- 100% {
227
- transform: rotate(360deg);
228
- }
229
- }
230
-
231
- @keyframes float {
232
- 0%, 100% {
233
- transform: translateY(0);
234
- }
235
- 50% {
236
- transform: translateY(-10px);
237
- }
238
- }
239
-
240
- .station-name {
241
- font-size: 2.5rem;
242
- font-weight: bold;
243
- margin-bottom: 0.5rem;
244
- background: linear-gradient(135deg, var(--text-primary), var(--secondary-color));
245
- -webkit-background-clip: text;
246
- -webkit-text-fill-color: transparent;
247
- }
248
-
249
- .current-track {
250
- color: var(--text-secondary);
251
- font-size: 1.2rem;
252
- margin-bottom: 1.5rem;
253
- min-height: 40px;
254
- display: flex;
255
- align-items: center;
256
- justify-content: center;
257
- gap: 0.5rem;
258
- }
259
-
260
- .track-info {
261
- display: flex;
262
- flex-direction: column;
263
- gap: 0.25rem;
264
- }
265
-
266
- .track-title {
267
- font-size: 1.1rem;
268
- color: var(--text-primary);
269
- }
270
-
271
- .track-artist {
272
- font-size: 0.95rem;
273
- color: var(--text-secondary);
274
- }
275
-
276
- .loading-spinner {
277
- display: none;
278
- width: 24px;
279
- height: 24px;
280
- border: 2px solid var(--text-secondary);
281
- border-top-color: var(--secondary-color);
282
- border-radius: 50%;
283
- animation: spin 1s linear infinite;
284
- }
285
-
286
- .loading-spinner.active {
287
- display: inline-block;
288
- }
289
-
290
- @keyframes spin {
291
- to {
292
- transform: rotate(360deg);
293
- }
294
- }
295
-
296
- .visualizer {
297
- height: 80px;
298
- display: flex;
299
- align-items: center;
300
- justify-content: center;
301
- gap: 4px;
302
- margin-bottom: 2.5rem;
303
- }
304
-
305
- .bar {
306
- width: 5px;
307
- background: linear-gradient(to top, var(--secondary-color), var(--accent-color));
308
- border-radius: 3px;
309
- animation: wave 1s ease-in-out infinite;
310
- transform-origin: bottom;
311
- }
312
-
313
- .bar:nth-child(1) { animation-delay: 0s; height: 25px; }
314
- .bar:nth-child(2) { animation-delay: 0.1s; height: 35px; }
315
- .bar:nth-child(3) { animation-delay: 0.2s; height: 30px; }
316
- .bar:nth-child(4) { animation-delay: 0.3s; height: 40px; }
317
- .bar:nth-child(5) { animation-delay: 0.4s; height: 25px; }
318
- .bar:nth-child(6) { animation-delay: 0.5s; height: 35px; }
319
- .bar:nth-child(7) { animation-delay: 0.6s; height: 30px; }
320
- .bar:nth-child(8) { animation-delay: 0.7s; height: 40px; }
321
-
322
- .visualizer.paused .bar {
323
- animation-play-state: paused;
324
- opacity: 0.3;
325
- }
326
-
327
- @keyframes wave {
328
- 0%, 100% {
329
- transform: scaleY(1);
330
- }
331
- 50% {
332
- transform: scaleY(1.5);
333
- }
334
- }
335
-
336
- /* Player Controls */
337
- .player-controls {
338
- display: flex;
339
- justify-content: center;
340
- align-items: center;
341
- gap: 2rem;
342
- margin-bottom: 2.5rem;
343
- }
344
-
345
- .control-btn {
346
- background: var(--glass-bg);
347
- border: 1px solid var(--glass-border);
348
- color: var(--text-primary);
349
- width: 60px;
350
- height: 60px;
351
- border-radius: 50%;
352
- display: flex;
353
- align-items: center;
354
- justify-content: center;
355
- cursor: pointer;
356
- transition: all 0.3s;
357
- font-size: 1.3rem;
358
- position: relative;
359
- overflow: hidden;
360
- }
361
-
362
- .control-btn::before {
363
- content: '';
364
- position: absolute;
365
- top: 50%;
366
- left: 50%;
367
- width: 0;
368
- height: 0;
369
- background: rgba(59, 130, 246, 0.3);
370
- border-radius: 50%;
371
- transform: translate(-50%, -50%);
372
- transition: width 0.6s, height 0.6s;
373
- }
374
-
375
- .control-btn:hover::before {
376
- width: 100%;
377
- height: 100%;
378
- }
379
-
380
- .control-btn:hover {
381
- background: var(--secondary-color);
382
- transform: scale(1.1);
383
- box-shadow: 0 5px 20px rgba(59, 130, 246, 0.4);
384
- }
385
-
386
- .play-btn {
387
- width: 80px;
388
- height: 80px;
389
- font-size: 1.8rem;
390
- background: linear-gradient(135deg, var(--secondary-color), var(--accent-color));
391
- border: none;
392
- }
393
-
394
- .play-btn:hover {
395
- box-shadow: 0 10px 30px rgba(59, 130, 246, 0.5);
396
- }
397
-
398
- /* Volume Control */
399
- .volume-control {
400
- display: flex;
401
- align-items: center;
402
- gap: 1.5rem;
403
- background: var(--glass-bg);
404
- padding: 1.5rem;
405
- border-radius: 20px;
406
- border: 1px solid var(--glass-border);
407
- margin-bottom: 1.5rem;
408
- }
409
-
410
- .volume-slider {
411
- flex: 1;
412
- -webkit-appearance: none;
413
- appearance: none;
414
- height: 8px;
415
- background: var(--light-bg);
416
- border-radius: 4px;
417
- outline: none;
418
- position: relative;
419
- }
420
-
421
- .volume-slider::-webkit-slider-thumb {
422
- -webkit-appearance: none;
423
- appearance: none;
424
- width: 20px;
425
- height: 20px;
426
- background: var(--secondary-color);
427
- border-radius: 50%;
428
- cursor: pointer;
429
- transition: all 0.3s;
430
- box-shadow: 0 2px 10px rgba(59, 130, 246, 0.3);
431
- }
432
-
433
- .volume-slider::-webkit-slider-thumb:hover {
434
- background: var(--accent-color);
435
- transform: scale(1.2);
436
- }
437
-
438
- .volume-slider::-moz-range-thumb {
439
- width: 20px;
440
- height: 20px;
441
- background: var(--secondary-color);
442
- border-radius: 50%;
443
- cursor: pointer;
444
- transition: all 0.3s;
445
- box-shadow: 0 2px 10px rgba(59, 130, 246, 0.3);
446
- }
447
-
448
- /* Station Selector */
449
- .station-selector {
450
- background: var(--glass-bg);
451
- border: 1px solid var(--glass-border);
452
- border-radius: 15px;
453
- padding: 1rem;
454
- margin-bottom: 1.5rem;
455
- }
456
-
457
- .station-selector select {
458
- width: 100%;
459
- padding: 0.75rem;
460
- background: var(--light-bg);
461
- border: 1px solid var(--glass-border);
462
- border-radius: 10px;
463
- color: var(--text-primary);
464
- font-size: 1rem;
465
- cursor: pointer;
466
- transition: all 0.3s;
467
- }
468
-
469
- .station-selector select:hover {
470
- border-color: var(--secondary-color);
471
- }
472
-
473
- .station-selector select:focus {
474
- outline: none;
475
- border-color: var(--accent-color);
476
- box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.2);
477
- }
478
-
479
- /* Status Bar */
480
- .status-bar {
481
- background: var(--glass-bg);
482
- border: 1px solid var(--glass-border);
483
- border-radius: 15px;
484
- padding: 1rem 1.5rem;
485
- margin-top: 1.5rem;
486
- display: flex;
487
- align-items: center;
488
- justify-content: space-between;
489
- font-size: 0.95rem;
490
- }
491
-
492
- .status-text {
493
- display: flex;
494
- align-items: center;
495
- gap: 0.5rem;
496
- }
497
-
498
- .status-indicator {
499
- width: 10px;
500
- height: 10px;
501
- border-radius: 50%;
502
- background: var(--text-secondary);
503
- }
504
-
505
- .status-indicator.connected {
506
- background: var(--success-color);
507
- animation: pulse 2s infinite;
508
- }
509
-
510
- .status-indicator.error {
511
- background: var(--error-color);
512
- animation: blink 1s infinite;
513
- }
514
-
515
- .status-indicator.warning {
516
- background: var(--warning-color);
517
- animation: blink 2s infinite;
518
- }
519
-
520
- .bitrate {
521
- color: var(--secondary-color);
522
- font-weight: 600;
523
- }
524
-
525
- /* Retry Button */
526
- .retry-btn {
527
- background: var(--secondary-color);
528
- color: white;
529
- border: none;
530
- padding: 0.5rem 1rem;
531
- border-radius: 8px;
532
- cursor: pointer;
533
- font-size: 0.9rem;
534
- transition: all 0.3s;
535
- }
536
-
537
- .retry-btn:hover {
538
- background: var(--accent-color);
539
- transform: scale(1.05);
540
- }
541
-
542
- /* Toast Notification */
543
- .toast {
544
- position: fixed;
545
- bottom: 2rem;
546
- left: 50%;
547
- transform: translateX(-50%) translateY(100px);
548
- background: var(--light-bg);
549
- border: 1px solid var(--glass-border);
550
- border-radius: 15px;
551
- padding: 1rem 2rem;
552
- display: flex;
553
- align-items: center;
554
- gap: 1rem;
555
- opacity: 0;
556
- transition: all 0.3s;
557
- z-index: 1000;
558
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
559
- }
560
-
561
- .toast.show {
562
- transform: translateX(-50%) translateY(0);
563
- opacity: 1;
564
- }
565
-
566
- .toast i {
567
- font-size: 1.5rem;
568
- }
569
-
570
- .toast.success i {
571
- color: var(--success-color);
572
- }
573
-
574
- .toast.error i {
575
- color: var(--error-color);
576
- }
577
-
578
- .toast.warning i {
579
- color: var(--warning-color);
580
- }
581
-
582
- .toast.info i {
583
- color: var(--secondary-color);
584
- }
585
-
586
- /* Error Panel */
587
- .error-panel {
588
- background: rgba(239, 68, 68, 0.1);
589
- border: 1px solid var(--error-color);
590
- border-radius: 15px;
591
- padding: 1.5rem;
592
- margin-top: 1rem;
593
- display: none;
594
- animation: slideIn 0.3s ease-out;
595
- }
596
-
597
- .error-panel.show {
598
- display: block;
599
- }
600
-
601
- .error-panel h3 {
602
- color: var(--error-color);
603
- margin-bottom: 0.5rem;
604
- display: flex;
605
- align-items: center;
606
- gap: 0.5rem;
607
- }
608
-
609
- .error-panel p {
610
- color: var(--text-secondary);
611
- margin-bottom: 1rem;
612
- }
613
-
614
- @keyframes slideIn {
615
- from {
616
- opacity: 0;
617
- transform: translateY(-10px);
618
- }
619
- to {
620
- opacity: 1;
621
- transform: translateY(0);
622
- }
623
- }
624
-
625
- /* Hidden Stations Section */
626
- .stations-section {
627
- display: none;
628
- }
629
-
630
- /* Responsive Design */
631
- @media (max-width: 640px) {
632
- header {
633
- padding: 1rem;
634
- }
635
-
636
- .header-content {
637
- flex-direction: column;
638
- text-align: center;
639
- }
640
-
641
- .container {
642
- padding: 0 1rem;
643
- margin: 1rem auto;
644
- }
645
-
646
- .player-section {
647
- padding: 1.5rem;
648
- }
649
-
650
- .station-logo {
651
- width: 120px;
652
- height: 120px;
653
- font-size: 3rem;
654
- }
655
-
656
- .station-name {
657
- font-size: 2rem;
658
- }
659
-
660
- .play-btn {
661
- width: 70px;
662
- height: 70px;
663
- font-size: 1.5rem;
664
- }
665
-
666
- .control-btn {
667
- width: 50px;
668
- height: 50px;
669
- font-size: 1.1rem;
670
- }
671
-
672
- .status-bar {
673
- flex-direction: column;
674
- gap: 0.75rem;
675
- text-align: center;
676
- }
677
-
678
- .volume-control {
679
- padding: 1rem;
680
- }
681
- }
682
- </style>
683
- </head>
684
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
685
  <body>
686
- <div class="bg-animation"></div>
687
-
688
- <header>
689
- <div class="header-content">
690
- <div class="logo">
691
- <i class="fas fa-radio"></i>
692
- <span>Deutsche Radio Stream</span>
693
- <div class="live-indicator">
694
- <span class="live-dot"></span>
695
- LIVE
696
- </div>
697
- </div>
698
- <div class="attribution">
699
- Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
700
- </div>
701
  </div>
702
- </header>
703
-
704
- <main class="container">
705
- <section class="player-section">
706
- <div class="station-selector">
707
- <select id="stationSelect">
708
- <option value="">Wähle eine Station...</option>
709
- </select>
710
- </div>
711
-
712
- <div class="now-playing">
713
- <div class="station-logo" id="stationLogo">
714
- <i class="fas fa-broadcast-tower"></i>
 
715
  </div>
716
- <h2 class="station-name" id="stationName">Wähle eine Station</h2>
717
- <div class="current-track" id="currentTrack">
718
- <div class="track-info">
719
- <span class="track-title">--- Bitte Station auswählen ---</span>
720
- <span class="track-artist"></span>
721
- </div>
722
- <div class="loading-spinner" id="loadingSpinner"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  </div>
724
 
725
- <div class="visualizer paused" id="visualizer">
726
- <div class="bar"></div>
727
- <div class="bar"></div>
728
- <div class="bar"></div>
729
- <div class="bar"></div>
730
- <div class="bar"></div>
731
- <div class="bar"></div>
732
- <div class="bar"></div>
733
- <div class="bar"></div>
734
  </div>
735
- </div>
736
-
737
- <div class="player-controls">
738
- <button class="control-btn" id="prevBtn">
739
- <i class="fas fa-backward"></i>
740
- </button>
741
- <button class="control-btn play-btn" id="playBtn">
742
- <i class="fas fa-play"></i>
743
- </button>
744
- <button class="control-btn" id="nextBtn">
745
- <i class="fas fa-forward"></i>
746
- </button>
747
- </div>
748
-
749
- <div class="volume-control">
750
- <i class="fas fa-volume-down"></i>
751
- <input type="range" class="volume-slider" id="volumeSlider" min="0" max="100" value="70">
752
- <i class="fas fa-volume-up"></i>
753
- <span id="volumeValue">70%</span>
754
- </div>
755
-
756
- <div class="status-bar">
757
- <div class="status-text">
758
- <span class="status-indicator" id="statusIndicator"></span>
759
- <span id="statusText">Bereit</span>
760
- <button class="retry-btn" id="retryBtn" style="display: none;">
761
- <i class="fas fa-redo"></i> Erneut versuchen
762
- </button>
763
  </div>
764
- <div class="bitrate" id="bitrate">128 kbps</div>
765
- </div>
766
-
767
- <div class="error-panel" id="errorPanel">
768
- <h3><i class="fas fa-exclamation-triangle"></i> Stream-Verbindungsfehler</h3>
769
- <p id="errorMessage">Der Stream konnte nicht geladen werden. Dies kann an Netzwerkproblemen oder daran liegen, dass der Stream derzeit nicht verfügbar ist.</p>
770
- <button class="retry-btn" onclick="retryCurrentStation()">
771
- <i class="fas fa-redo"></i> Nochmal versuchen
772
- </button>
773
- </div>
774
- </section>
775
-
776
- <section class="stations-section">
777
- <!-- Hidden stations section for functionality -->
778
- </section>
779
- </main>
780
-
781
- <div class="toast" id="toast">
782
- <i class="fas fa-info-circle"></i>
783
- <span id="toastMessage">Nachricht</span>
784
- </div>
785
-
786
- <!-- Hidden audio element -->
787
- <audio id="audioPlayer" crossorigin="anonymous"></audio>
788
-
789
- <script>
790
- // Updated German Radio Stations with working streaming URLs and fallbacks
791
- const radioStations = [
792
- {
793
- id: 1,
794
- name: "ANTENNE BAYERN",
795
- genre: "Pop",
796
- category: "pop",
797
- icon: "fa-broadcast-tower",
798
- urls: [
799
- "https://mp3channels.webradio.antenne.de/antenne-bayern",
800
- "https://mp3channels.webradio.antenne.de/antenne-bayern-mp3",
801
- "https://stream.antenne.de/antenne-bayern/live/mp3"
802
- ],
803
- bitrate: "128"
804
- },
805
- {
806
- id: 2,
807
- name: "BAYERN 3",
808
- genre: "Pop & Rock",
809
- category: "pop",
810
- icon: "fa-music",
811
- urls: [
812
- "https://br-br3-live.cast.addradio.de/br/br3/live/mp3/128/stream.mp3",
813
- "https://br-br3-live.cast.addradio.de/br/br3/live/mp3/64/stream.mp3"
814
- ],
815
- bitrate: "128"
816
- },
817
- {
818
- id: 3,
819
- name: "DEUTSCHLANDFUNK",
820
- genre: "Nachrichten & Info",
821
- category: "news",
822
- icon: "fa-newspaper",
823
- urls: [
824
- "https://st01.dlf.de/dlf/01/128/mp3/stream.mp3",
825
- "https://st02.dlf.de/dlf/02/128/mp3/stream.mp3"
826
- ],
827
- bitrate: "128"
828
- },
829
- {
830
- id: 4,
831
- name: "HR3",
832
- genre: "Pop",
833
- category: "pop",
834
- icon: "fa-radio",
835
- urls: [
836
- "https://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/128/stream.mp3",
837
- "https://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/64/stream.mp3"
838
- ],
839
- bitrate: "128"
840
- },
841
- {
842
- id: 5,
843
- name: "WDR 2",
844
- genre: "Pop & News",
845
- category: "pop",
846
- icon: "fa-microphone",
847
- urls: [
848
- "https://wdr-wdr2-live.icecast.wdr.de/wdr/wdr2/live/mp3/128/stream.mp3",
849
- "https://wdr-wdr2-live.icecast.wdr.de/wdr/wdr2/live/mp3/64/stream.mp3"
850
- ],
851
- bitrate: "128"
852
- },
853
- {
854
- id: 6,
855
- name: "SWR3",
856
- genre: "Pop",
857
- category: "pop",
858
- icon: "fa-headphones",
859
- urls: [
860
- "https://swr-swr3-live.cast.addradio.de/swr/swr3/live/mp3/128/stream.mp3",
861
- "https://swr-swr3-live.cast.addradio.de/swr/swr3/live/mp3/64/stream.mp3"
862
- ],
863
- bitrate: "128"
864
- },
865
- {
866
- id: 7,
867
- name: "NDR 2",
868
- genre: "Pop & Rock",
869
- category: "rock",
870
- icon: "fa-guitar",
871
- urls: [
872
- "https://ndr-ndr2-niedersachsen.cast.addradio.de/ndr/ndr2/niedersachsen/mp3/128/stream.mp3",
873
- "https://ndr-ndr2-niedersachsen.cast.addradio.de/ndr/ndr2/niedersachsen/mp3/64/stream.mp3"
874
- ],
875
- bitrate: "128"
876
- },
877
- {
878
- id: 8,
879
- name: "MDR JUMP",
880
- genre: "Pop & Rock",
881
- category: "rock",
882
- icon: "fa-compact-disc",
883
- urls: [
884
- "https://mdr-mdr-jump-sachsen.cast.addradio.de/mdr/mdr-jump/sachsen/mp3/128/stream.mp3",
885
- "https://mdr-mdr-jump-sachsen.cast.addradio.de/mdr/mdr-jump/sachsen/mp3/64/stream.mp3"
886
- ],
887
- bitrate: "128"
888
- },
889
- {
890
- id: 9,
891
- name: "RBB 88.8",
892
- genre: "Pop",
893
- category: "pop",
894
- icon: "fa-broadcast-tower",
895
- urls: [
896
- "https://rbb-88-8-live.cast.addradio.de/rbb/rbb888/live/mp3/128/stream.mp3",
897
- "https://rbb-88-8-live.cast.addradio.de/rbb/rbb888/live/mp3/64/stream.mp3"
898
- ],
899
- bitrate: "128"
900
- },
901
- {
902
- id: 10,
903
- name: "BR-KLASSIK",
904
- genre: "Klassik",
905
- category: "classic",
906
- icon: "fa-violin",
907
- urls: [
908
- "https://br-brklassik-live.cast.addradio.de/br/brklassik/live/mp3/128/stream.mp3",
909
- "https://br-brklassik-live.cast.addradio.de/br/brklassik/live/mp3/64/stream.mp3"
910
- ],
911
- bitrate: "128"
912
- },
913
- {
914
- id: 11,
915
- name: "DASDING",
916
- genre: "Pop & Electro",
917
- category: "pop",
918
- icon: "fa-bolt",
919
- urls: [
920
- "https://swr-dasding-live.cast.addradio.de/swr/dasding/live/mp3/128/stream.mp3",
921
- "https://swr-dasding-live.cast.addradio.de/swr/dasding/live/mp3/64/stream.mp3"
922
- ],
923
- bitrate: "128"
924
- },
925
- {
926
- id: 12,
927
- name: "YOU FM",
928
- genre: "Pop & Electro",
929
- category: "pop",
930
- icon: "fa-star",
931
- urls: [
932
- "https://hr-youfm-live.cast.addradio.de/hr/youfm/live/mp3/128/stream.mp3",
933
- "https://hr-youfm-live.cast.addradio.de/hr/youfm/live/mp3/64/stream.mp3"
934
- ],
935
- bitrate: "128"
936
- },
937
- {
938
- id: 13,
939
- name: "1LIVE",
940
- genre: "Pop & Electro",
941
- category: "pop",
942
- icon: "fa-broadcast-tower",
943
- urls: [
944
- "https://wdr-1live-live.icecast.wdr.de/wdr/1live/live/mp3/128/stream.mp3",
945
- "https://wdr-1live-live.icecast.wdr.de/wdr/1live/live/mp3/64/stream.mp3"
946
- ],
947
- bitrate: "128"
948
- },
949
- {
950
- id: 14,
951
- name: "N-JOY",
952
- genre: "Pop & Electro",
953
- category: "pop",
954
- icon: "fa-headphones",
955
- urls: [
956
- "https://ndr-n-joy-niedersachsen.cast.addradio.de/ndr/njoy/niedersachsen/mp3/128/stream.mp3",
957
- "https://ndr-n-joy-niedersachsen.cast.addradio.de/ndr/njoy/niedersachsen/mp3/64/stream.mp3"
958
- ],
959
- bitrate: "128"
960
- },
961
- {
962
- id: 15,
963
- name: "BR24",
964
- genre: "Nachrichten",
965
- category: "news",
966
- icon: "fa-newspaper",
967
- urls: [
968
- "https://br-br24-live.cast.addradio.de/br/br24/live/mp3/128/stream.mp3",
969
- "https://br-br24-live.cast.addradio.de/br/br24/live/mp3/64/stream.mp3"
970
- ],
971
- bitrate: "128"
972
- }
973
- ];
974
-
975
- let currentStation = null;
976
- let isPlaying = false;
977
- let currentStationIndex = -1;
978
- let audioPlayer;
979
- let currentUrlIndex = 0;
980
- let retryCount = 0;
981
- const maxRetries = 3;
982
-
983
- // DOM Elements
984
- const playBtn = document.getElementById('playBtn');
985
- const prevBtn = document.getElementById('prevBtn');
986
- const nextBtn = document.getElementById('nextBtn');
987
- const volumeSlider = document.getElementById('volumeSlider');
988
- const volumeValue = document.getElementById('volumeValue');
989
- const stationName = document.getElementById('stationName');
990
- const currentTrack = document.getElementById('currentTrack');
991
- const stationLogo = document.getElementById('stationLogo');
992
- const visualizer = document.getElementById('visualizer');
993
- const stationSelect = document.getElementById('stationSelect');
994
- const toast = document.getElementById('toast');
995
- const toastMessage = document.getElementById('toastMessage');
996
- const loadingSpinner = document.getElementById('loadingSpinner');
997
- const statusIndicator = document.getElementById('statusIndicator');
998
- const statusText = document.getElementById('statusText');
999
- const bitrate = document.getElementById('bitrate');
1000
- const retryBtn = document.getElementById('retryBtn');
1001
- const errorPanel = document.getElementById('errorPanel');
1002
- const errorMessage = document.getElementById('errorMessage');
1003
-
1004
- // Initialize
1005
- function init() {
1006
- audioPlayer = document.getElementById('audioPlayer');
1007
- audioPlayer.volume = 0.7;
1008
- audioPlayer.preload = 'none';
1009
-
1010
- populateStationSelect();
1011
- setupEventListeners();
1012
- setupAudioEventListeners();
1013
- updateStatus('Bereit', 'idle');
1014
- }
1015
-
1016
- // Populate station select dropdown
1017
- function populateStationSelect() {
1018
- radioStations.forEach(station => {
1019
- const option = document.createElement('option');
1020
- option.value = station.id;
1021
- option.textContent = `${station.name} - ${station.genre}`;
1022
- stationSelect.appendChild(option);
1023
- });
1024
- }
1025
-
1026
- // Setup audio event listeners with enhanced error handling
1027
- function setupAudioEventListeners() {
1028
- audioPlayer.addEventListener('loadstart', () => {
1029
- loadingSpinner.classList.add('active');
1030
- updateStatus('Laden...', 'loading');
1031
- hideErrorPanel();
1032
- });
1033
-
1034
- audioPlayer.addEventListener('canplay', () => {
1035
- loadingSpinner.classList.remove('active');
1036
- updateStatus('Verbunden', 'connected');
1037
- retryCount = 0;
1038
- currentUrlIndex = 0;
1039
- showToast('Stream erfolgreich geladen!', 'success');
1040
- });
1041
-
1042
- audioPlayer.addEventListener('play', () => {
1043
- isPlaying = true;
1044
- playBtn.innerHTML = '<i class="fas fa-pause"></i>';
1045
- visualizer.classList.remove('paused');
1046
- stationLogo.classList.add('playing');
1047
- updateStatus('Spielt', 'connected');
1048
- });
1049
-
1050
- audioPlayer.addEventListener('pause', () => {
1051
- isPlaying = false;
1052
- playBtn.innerHTML = '<i class="fas fa-play"></i>';
1053
- visualizer.classList.add('paused');
1054
- stationLogo.classList.remove('playing');
1055
- updateStatus('Pausiert', 'idle');
1056
- });
1057
-
1058
- audioPlayer.addEventListener('ended', () => {
1059
- isPlaying = false;
1060
- playBtn.innerHTML = '<i class="fas fa-play"></i>';
1061
- visualizer.classList.add('paused');
1062
- stationLogo.classList.remove('playing');
1063
- updateStatus('Beendet', 'idle');
1064
- });
1065
-
1066
- audioPlayer.addEventListener('error', (e) => {
1067
- handleAudioError(e);
1068
- });
1069
-
1070
- // Network status detection
1071
- audioPlayer.addEventListener('stalled', () => {
1072
- if (isPlaying) {
1073
- updateStatus('Verbindung unterbrochen', 'warning');
1074
- showToast('Verbindung unterbrochen, versuche erneut...', 'warning');
1075
- }
1076
- });
1077
-
1078
- audioPlayer.addEventListener('waiting', () => {
1079
- if (isPlaying) {
1080
- loadingSpinner.classList.add('active');
1081
- updateStatus('Puffern...', 'loading');
1082
- }
1083
- });
1084
-
1085
- // Simulate track info updates
1086
- setInterval(() => {
1087
- if (isPlaying && currentStation) {
1088
- updateTrackInfo();
1089
- }
1090
- }, 30000);
1091
- }
1092
-
1093
- // Handle audio errors with fallback mechanism
1094
- function handleAudioError(error) {
1095
- loadingSpinner.classList.remove('active');
1096
-
1097
- console.error('Audio error:', error);
1098
-
1099
- if (currentStation && currentUrlIndex < currentStation.urls.length - 1) {
1100
- // Try next URL
1101
- currentUrlIndex++;
1102
- console.log(`Trying fallback URL ${currentUrlIndex + 1}/${currentStation.urls.length}`);
1103
- audioPlayer.src = currentStation.urls[currentUrlIndex];
1104
- audioPlayer.play();
1105
- showToast(`Versuche alternative Stream-URL...`, 'info');
1106
- } else if (retryCount < maxRetries) {
1107
- // Retry with same URL
1108
- retryCount++;
1109
- currentUrlIndex = 0;
1110
- setTimeout(() => {
1111
- console.log(`Retry attempt ${retryCount}/${maxRetries}`);
1112
- audioPlayer.src = currentStation.urls[0];
1113
- audioPlayer.play();
1114
- showToast(`Versuch ${retryCount}/${maxRetries}...`, 'warning');
1115
- }, 2000 *
 
1
  <!DOCTYPE html>
2
  <html lang="de">
 
3
  <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Radio Player Deutschland</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ :root {
16
+ --primary-color: #1e3c72;
17
+ --secondary-color: #2a5298;
18
+ --accent-color: #ff6b6b;
19
+ --text-light: #ffffff;
20
+ --text-dark: #333333;
21
+ --bg-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
22
+ --card-bg: rgba(255, 255, 255, 0.1);
23
+ --glass-bg: rgba(255, 255, 255, 0.1);
24
+ --glass-border: rgba(255, 255, 255, 0.2);
25
+ }
26
+
27
+ body {
28
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
29
+ background: var(--bg-gradient);
30
+ min-height: 100vh;
31
+ color: var(--text-light);
32
+ overflow-x: hidden;
33
+ position: relative;
34
+ }
35
+
36
+ /* Animated Background */
37
+ .bg-animation {
38
+ position: fixed;
39
+ width: 100%;
40
+ height: 100%;
41
+ top: 0;
42
+ left: 0;
43
+ z-index: -1;
44
+ opacity: 0.3;
45
+ }
46
+
47
+ .bg-animation span {
48
+ position: absolute;
49
+ display: block;
50
+ width: 20px;
51
+ height: 20px;
52
+ background: rgba(255, 255, 255, 0.2);
53
+ animation: move 25s linear infinite;
54
+ bottom: -150px;
55
+ }
56
+
57
+ .bg-animation span:nth-child(1) {
58
+ left: 25%;
59
+ width: 80px;
60
+ height: 80px;
61
+ animation-delay: 0s;
62
+ }
63
+
64
+ .bg-animation span:nth-child(2) {
65
+ left: 10%;
66
+ width: 20px;
67
+ height: 20px;
68
+ animation-delay: 2s;
69
+ animation-duration: 12s;
70
+ }
71
+
72
+ .bg-animation span:nth-child(3) {
73
+ left: 70%;
74
+ width: 20px;
75
+ height: 20px;
76
+ animation-delay: 4s;
77
+ }
78
+
79
+ .bg-animation span:nth-child(4) {
80
+ left: 40%;
81
+ width: 60px;
82
+ height: 60px;
83
+ animation-delay: 0s;
84
+ animation-duration: 18s;
85
+ }
86
+
87
+ .bg-animation span:nth-child(5) {
88
+ left: 65%;
89
+ width: 20px;
90
+ height: 20px;
91
+ animation-delay: 0s;
92
+ }
93
+
94
+ .bg-animation span:nth-child(6) {
95
+ left: 75%;
96
+ width: 110px;
97
+ height: 110px;
98
+ animation-delay: 3s;
99
+ }
100
+
101
+ .bg-animation span:nth-child(7) {
102
+ left: 35%;
103
+ width: 150px;
104
+ height: 150px;
105
+ animation-delay: 7s;
106
+ }
107
+
108
+ .bg-animation span:nth-child(8) {
109
+ left: 50%;
110
+ width: 25px;
111
+ height: 25px;
112
+ animation-delay: 15s;
113
+ animation-duration: 45s;
114
+ }
115
+
116
+ .bg-animation span:nth-child(9) {
117
+ left: 20%;
118
+ width: 15px;
119
+ height: 15px;
120
+ animation-delay: 2s;
121
+ animation-duration: 35s;
122
+ }
123
+
124
+ .bg-animation span:nth-child(10) {
125
+ left: 85%;
126
+ width: 150px;
127
+ height: 150px;
128
+ animation-delay: 0s;
129
+ animation-duration: 11s;
130
+ }
131
+
132
+ @keyframes move {
133
+ 0% {
134
+ transform: translateY(0) rotate(0deg);
135
+ opacity: 1;
136
+ border-radius: 0;
137
+ }
138
+ 100% {
139
+ transform: translateY(-1000px) rotate(720deg);
140
+ opacity: 0;
141
+ border-radius: 50%;
142
+ }
143
+ }
144
+
145
+ /* Header */
146
+ header {
147
+ background: var(--glass-bg);
148
+ backdrop-filter: blur(10px);
149
+ border-bottom: 1px solid var(--glass-border);
150
+ padding: 1rem 0;
151
+ position: sticky;
152
+ top: 0;
153
+ z-index: 100;
154
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
155
+ }
156
+
157
+ .header-content {
158
+ max-width: 1200px;
159
+ margin: 0 auto;
160
+ padding: 0 2rem;
161
+ display: flex;
162
+ justify-content: space-between;
163
+ align-items: center;
164
+ }
165
+
166
+ .logo {
167
+ display: flex;
168
+ align-items: center;
169
+ gap: 1rem;
170
+ font-size: 1.5rem;
171
+ font-weight: bold;
172
+ }
173
+
174
+ .logo i {
175
+ font-size: 2rem;
176
+ color: var(--accent-color);
177
+ animation: pulse 2s infinite;
178
+ }
179
+
180
+ @keyframes pulse {
181
+ 0%, 100% {
182
+ transform: scale(1);
183
+ }
184
+ 50% {
185
+ transform: scale(1.1);
186
+ }
187
+ }
188
+
189
+ .header-links a {
190
+ color: var(--text-light);
191
+ text-decoration: none;
192
+ margin-left: 2rem;
193
+ transition: color 0.3s;
194
+ }
195
+
196
+ .header-links a:hover {
197
+ color: var(--accent-color);
198
+ }
199
+
200
+ /* Main Container */
201
+ .container {
202
+ max-width: 1200px;
203
+ margin: 2rem auto;
204
+ padding: 0 2rem;
205
+ }
206
+
207
+ /* Main Player */
208
+ .main-player {
209
+ background: var(--glass-bg);
210
+ backdrop-filter: blur(10px);
211
+ border-radius: 20px;
212
+ padding: 2rem;
213
+ margin-bottom: 2rem;
214
+ border: 1px solid var(--glass-border);
215
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
216
+ }
217
+
218
+ .player-header {
219
+ text-align: center;
220
+ margin-bottom: 2rem;
221
+ }
222
+
223
+ .station-info {
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ gap: 1rem;
228
+ margin-bottom: 1rem;
229
+ }
230
+
231
+ .station-logo {
232
+ width: 80px;
233
+ height: 80px;
234
+ border-radius: 50%;
235
+ background: linear-gradient(135deg, #667eea, #764ba2);
236
+ display: flex;
237
+ align-items: center;
238
+ justify-content: center;
239
+ font-size: 2rem;
240
+ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
241
+ }
242
+
243
+ .station-details h2 {
244
+ font-size: 1.8rem;
245
+ margin-bottom: 0.5rem;
246
+ }
247
+
248
+ .station-details p {
249
+ opacity: 0.8;
250
+ }
251
+
252
+ /* Visualizer */
253
+ .visualizer {
254
+ height: 100px;
255
+ display: flex;
256
+ align-items: flex-end;
257
+ justify-content: center;
258
+ gap: 4px;
259
+ margin: 2rem 0;
260
+ }
261
+
262
+ .bar {
263
+ width: 4px;
264
+ background: linear-gradient(to top, var(--accent-color), #feca57);
265
+ border-radius: 2px;
266
+ animation: dance 0.6s ease-in-out infinite;
267
+ }
268
+
269
+ .bar:nth-child(1) { animation-delay: 0s; height: 20px; }
270
+ .bar:nth-child(2) { animation-delay: 0.1s; height: 30px; }
271
+ .bar:nth-child(3) { animation-delay: 0.2s; height: 25px; }
272
+ .bar:nth-child(4) { animation-delay: 0.3s; height: 40px; }
273
+ .bar:nth-child(5) { animation-delay: 0.4s; height: 35px; }
274
+ .bar:nth-child(6) { animation-delay: 0.5s; height: 45px; }
275
+ .bar:nth-child(7) { animation-delay: 0.6s; height: 30px; }
276
+ .bar:nth-child(8) { animation-delay: 0.7s; height: 25px; }
277
+ .bar:nth-child(9) { animation-delay: 0.8s; height: 35px; }
278
+ .bar:nth-child(10) { animation-delay: 0.9s; height: 40px; }
279
+ .bar:nth-child(11) { animation-delay: 1s; height: 30px; }
280
+ .bar:nth-child(12) { animation-delay: 1.1s; height: 25px; }
281
+
282
+ .visualizer.paused .bar {
283
+ animation-play-state: paused;
284
+ opacity: 0.3;
285
+ }
286
+
287
+ @keyframes dance {
288
+ 0%, 100% {
289
+ transform: scaleY(1);
290
+ }
291
+ 50% {
292
+ transform: scaleY(1.5);
293
+ }
294
+ }
295
+
296
+ /* Controls */
297
+ .controls {
298
+ display: flex;
299
+ justify-content: center;
300
+ align-items: center;
301
+ gap: 2rem;
302
+ margin: 2rem 0;
303
+ }
304
+
305
+ .control-btn {
306
+ background: rgba(255, 255, 255, 0.1);
307
+ border: 2px solid var(--glass-border);
308
+ color: var(--text-light);
309
+ width: 60px;
310
+ height: 60px;
311
+ border-radius: 50%;
312
+ display: flex;
313
+ align-items: center;
314
+ justify-content: center;
315
+ cursor: pointer;
316
+ transition: all 0.3s;
317
+ font-size: 1.2rem;
318
+ }
319
+
320
+ .control-btn:hover {
321
+ background: rgba(255, 255, 255, 0.2);
322
+ transform: scale(1.1);
323
+ }
324
+
325
+ .control-btn.play-pause {
326
+ width: 80px;
327
+ height: 80px;
328
+ background: var(--accent-color);
329
+ border-color: var(--accent-color);
330
+ font-size: 1.5rem;
331
+ }
332
+
333
+ .control-btn.play-pause:hover {
334
+ background: #ff5252;
335
+ border-color: #ff5252;
336
+ }
337
+
338
+ /* Volume Control */
339
+ .volume-control {
340
+ display: flex;
341
+ align-items: center;
342
+ gap: 1rem;
343
+ justify-content: center;
344
+ margin-top: 1rem;
345
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
+ .volume-slider {
348
+ width: 200px;
349
+ height: 6px;
350
+ background: rgba(255, 255, 255, 0.2);
351
+ border-radius: 3px;
352
+ outline: none;
353
+ -webkit-appearance: none;
354
+ }
355
+
356
+ .volume-slider::-webkit-slider-thumb {
357
+ -webkit-appearance: none;
358
+ width: 20px;
359
+ height: 20px;
360
+ background: var(--accent-color);
361
+ border-radius: 50%;
362
+ cursor: pointer;
363
+ }
364
+
365
+ .volume-slider::-moz-range-thumb {
366
+ width: 20px;
367
+ height: 20px;
368
+ background: var(--accent-color);
369
+ border-radius: 50%;
370
+ cursor: pointer;
371
+ border: none;
372
+ }
373
+
374
+ /* Station Grid */
375
+ .stations-grid {
376
+ display: grid;
377
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
378
+ gap: 1.5rem;
379
+ margin-bottom: 2rem;
380
+ }
381
+
382
+ .station-card {
383
+ background: var(--glass-bg);
384
+ backdrop-filter: blur(10px);
385
+ border: 1px solid var(--glass-border);
386
+ border-radius: 15px;
387
+ padding: 1.5rem;
388
+ cursor: pointer;
389
+ transition: all 0.3s;
390
+ position: relative;
391
+ overflow: hidden;
392
+ }
393
+
394
+ .station-card::before {
395
+ content: '';
396
+ position: absolute;
397
+ top: 0;
398
+ left: -100%;
399
+ width: 100%;
400
+ height: 100%;
401
+ background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
402
+ transition: left 0.5s;
403
+ }
404
+
405
+ .station-card:hover::before {
406
+ left: 100%;
407
+ }
408
+
409
+ .station-card:hover {
410
+ transform: translateY(-5px);
411
+ box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
412
+ background: rgba(255, 255, 255, 0.15);
413
+ }
414
+
415
+ .station-card.active {
416
+ background: rgba(255, 107, 107, 0.2);
417
+ border-color: var(--accent-color);
418
+ }
419
+
420
+ .station-card-header {
421
+ display: flex;
422
+ align-items: center;
423
+ gap: 1rem;
424
+ margin-bottom: 1rem;
425
+ }
426
+
427
+ .station-card-logo {
428
+ width: 50px;
429
+ height: 50px;
430
+ border-radius: 10px;
431
+ background: linear-gradient(135deg, #667eea, #764ba2);
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ font-size: 1.5rem;
436
+ }
437
+
438
+ .station-card-info h3 {
439
+ font-size: 1.2rem;
440
+ margin-bottom: 0.25rem;
441
+ }
442
+
443
+ .station-card-info p {
444
+ font-size: 0.9rem;
445
+ opacity: 0.8;
446
+ }
447
+
448
+ .station-genre {
449
+ display: inline-block;
450
+ background: rgba(255, 255, 255, 0.1);
451
+ padding: 0.25rem 0.75rem;
452
+ border-radius: 20px;
453
+ font-size: 0.85rem;
454
+ margin-top: 0.5rem;
455
+ }
456
+
457
+ /* Categories */
458
+ .categories {
459
+ display: flex;
460
+ gap: 1rem;
461
+ margin-bottom: 2rem;
462
+ flex-wrap: wrap;
463
+ }
464
+
465
+ .category-btn {
466
+ background: var(--glass-bg);
467
+ backdrop-filter: blur(10px);
468
+ border: 1px solid var(--glass-border);
469
+ color: var(--text-light);
470
+ padding: 0.75rem 1.5rem;
471
+ border-radius: 25px;
472
+ cursor: pointer;
473
+ transition: all 0.3s;
474
+ font-size: 0.95rem;
475
+ }
476
+
477
+ .category-btn:hover {
478
+ background: rgba(255, 255, 255, 0.2);
479
+ transform: translateY(-2px);
480
+ }
481
+
482
+ .category-btn.active {
483
+ background: var(--accent-color);
484
+ border-color: var(--accent-color);
485
+ }
486
+
487
+ /* Footer */
488
+ footer {
489
+ background: var(--glass-bg);
490
+ backdrop-filter: blur(10px);
491
+ border-top: 1px solid var(--glass-border);
492
+ padding: 2rem 0;
493
+ margin-top: 3rem;
494
+ text-align: center;
495
+ }
496
+
497
+ .footer-content {
498
+ max-width: 1200px;
499
+ margin: 0 auto;
500
+ padding: 0 2rem;
501
+ }
502
+
503
+ .social-links {
504
+ display: flex;
505
+ justify-content: center;
506
+ gap: 1.5rem;
507
+ margin-top: 1rem;
508
+ }
509
+
510
+ .social-links a {
511
+ color: var(--text-light);
512
+ font-size: 1.5rem;
513
+ transition: color 0.3s, transform 0.3s;
514
+ }
515
+
516
+ .social-links a:hover {
517
+ color: var(--accent-color);
518
+ transform: translateY(-3px);
519
+ }
520
+
521
+ /* Responsive Design */
522
+ @media (max-width: 768px) {
523
+ .header-content {
524
+ flex-direction: column;
525
+ gap: 1rem;
526
+ }
527
+
528
+ .header-links {
529
+ display: none;
530
+ }
531
+
532
+ .stations-grid {
533
+ grid-template-columns: 1fr;
534
+ }
535
+
536
+ .controls {
537
+ gap: 1rem;
538
+ }
539
+
540
+ .control-btn {
541
+ width: 50px;
542
+ height: 50px;
543
+ }
544
+
545
+ .control-btn.play-pause {
546
+ width: 70px;
547
+ height: 70px;
548
+ }
549
+
550
+ .volume-slider {
551
+ width: 150px;
552
+ }
553
+ }
554
+
555
+ /* Loading Animation */
556
+ .loading {
557
+ display: inline-block;
558
+ width: 20px;
559
+ height: 20px;
560
+ border: 3px solid rgba(255, 255, 255, 0.3);
561
+ border-radius: 50%;
562
+ border-top-color: var(--accent-color);
563
+ animation: spin 1s ease-in-out infinite;
564
+ }
565
+
566
+ @keyframes spin {
567
+ to { transform: rotate(360deg); }
568
+ }
569
+
570
+ /* Toast Notification */
571
+ .toast {
572
+ position: fixed;
573
+ bottom: 2rem;
574
+ right: 2rem;
575
+ background: rgba(0, 0, 0, 0.8);
576
+ color: white;
577
+ padding: 1rem 1.5rem;
578
+ border-radius: 10px;
579
+ transform: translateX(400px);
580
+ transition: transform 0.3s;
581
+ z-index: 1000;
582
+ }
583
+
584
+ .toast.show {
585
+ transform: translateX(0);
586
+ }
587
+ </style>
588
+ </head>
589
  <body>
590
+ <!-- Animated Background -->
591
+ <div class="bg-animation">
592
+ <span></span>
593
+ <span></span>
594
+ <span></span>
595
+ <span></span>
596
+ <span></span>
597
+ <span></span>
598
+ <span></span>
599
+ <span></span>
600
+ <span></span>
601
+ <span></span>
 
 
 
602
  </div>
603
+
604
+ <!-- Header -->
605
+ <header>
606
+ <div class="header-content">
607
+ <div class="logo">
608
+ <i class="fas fa-radio"></i>
609
+ <span>Radio Player Deutschland</span>
610
+ </div>
611
+ <div class="header-links">
612
+ <a href="#" onclick="showToast('Startseite'); return false;">Start</a>
613
+ <a href="#" onclick="showToast('Beliebte Sender'); return false;">Beliebt</a>
614
+ <a href="#" onclick="showToast('Neue Sender'); return false;">Neu</a>
615
+ <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a>
616
+ </div>
617
  </div>
618
+ </header>
619
+
620
+ <!-- Main Container -->
621
+ <div class="container">
622
+ <!-- Main Player -->
623
+ <div class="main-player">
624
+ <div class="player-header">
625
+ <div class="station-info">
626
+ <div class="station-logo">
627
+ <i class="fas fa-broadcast-tower"></i>
628
+ </div>
629
+ <div class="station-details">
630
+ <h2 id="currentStation">Wähle einen Sender</h2>
631
+ <p id="currentGenre">Genre</p>
632
+ </div>
633
+ </div>
634
+ </div>
635
+
636
+ <!-- Visualizer -->
637
+ <div class="visualizer paused" id="visualizer">
638
+ <div class="bar"></div>
639
+ <div class="bar"></div>
640
+ <div class="bar"></div>
641
+ <div class="bar"></div>
642
+ <div class="bar"></div>
643
+ <div class="bar"></div>
644
+ <div class="bar"></div>
645
+ <div class="bar"></div>
646
+ <div class="bar"></div>
647
+ <div class="bar"></div>
648
+ <div class="bar"></div>
649
+ <div class="bar"></div>
650
+ </div>
651
+
652
+ <!-- Controls -->
653
+ <div class="controls">
654
+ <button class="control-btn" onclick="previousStation()">
655
+ <i class="fas fa-backward"></i>
656
+ </button>
657
+ <button class="control-btn" onclick="toggleMute()">
658
+ <i class="fas fa-volume-down"></i>
659
+ </button>
660
+ <button class="control-btn play-pause" id="playPauseBtn" onclick="togglePlayPause()">
661
+ <i class="fas fa-play"></i>
662
+ </button>
663
+ <button class="control-btn" onclick="toggleMute()">
664
+ <i class="fas fa-volume-up"></i>
665
+ </button>
666
+ <button class="control-btn" onclick="nextStation()">
667
+ <i class="fas fa-forward"></i>
668
+ </button>
669
+ </div>
670
+
671
+ <!-- Volume Control -->
672
+ <div class="volume-control">
673
+ <i class="fas fa-volume-down"></i>
674
+ <input type="range" class="volume-slider" id="volumeSlider" min="0" max="100" value="70">
675
+ <i class="fas fa-volume-up"></i>
676
+ <span style="margin-left: 1rem;" id="volumeValue">70%</span>
677
+ </div>
678
+ </div>
679
+
680
+ <!-- Categories -->
681
+ <div class="categories">
682
+ <button class="category-btn active" onclick="filterStations('all')">Alle</button>
683
+ <button class="category-btn" onclick="filterStations('pop')">Pop</button>
684
+ <button class="category-btn" onclick="filterStations('rock')">Rock</button>
685
+ <button class="category-btn" onclick="filterStations('jazz')">Jazz</button>
686
+ <button class="category-btn" onclick="filterStations('klassik')">Klassik</button>
687
+ <button class="category-btn" onclick="filterStations('news')">Nachrichten</button>
688
  </div>
689
 
690
+ <!-- Stations Grid -->
691
+ <div class="stations-grid" id="stationsGrid">
692
+ <!-- Stations will be dynamically added here -->
 
 
 
 
 
 
693
  </div>
694
+ </div>
695
+
696
+ <!-- Footer -->
697
+ <footer>
698
+ <div class="footer-content">
699
+ <p>&copy; 2024 Radio Player Deutschland. Alle Rechte vorbehalten.</p>
700
+ <div class="social-links">
701
+ <a href="#" onclick="showToast('Facebook'); return false;"><i class="fab fa-facebook"></i></a>
702
+ <a href="#" onclick="showToast('Twitter'); return false;"><i class="fab fa-twitter"></i></a>
703
+ <a href="#" onclick="showToast('Instagram'); return false;"><i class="fab fa-instagram"></i></a>
704
+ <a href="#" onclick="showToast('YouTube'); return false;"><i class="fab fa-youtube"></i></a>
705
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
706
  </div>
707
+ </footer>
708
+
709
+ <!-- Toast Notification -->
710
+ <div class="toast" id="toast"></div>
711
+
712
+ <!-- Audio Element -->
713
+ <audio id="audioPlayer"></audio>
714
+
715
+ <script>
716
+ // Radio Stations Data
717
+ const stations = [
718
+ { id: 1, name: 'Deutschlandfunk', genre: 'Nachrichten', url: 'https://st01.dlf.de/dlf/01/128/mp3/stream.mp3', category: 'news', icon: '📻' },
719
+ { id: 2, name: 'Bayern 3', genre: 'Pop', url: 'https://br-br3-live.cast.addradio.de/br/br3/live/mp3/128/stream.mp3', category: 'pop', icon: '🎵' },
720
+ { id: 3, name: 'WDR 4', genre: 'Schlager', url: 'https://wdr-4-live.icecast.wdr.de/wdr/wdr4/live/mp3/128/stream.mp3', category: 'pop', icon: '🎶' },
721
+ { id: 4, name: 'NDR 2', genre: 'Pop/Rock', url: 'https://ndr-ndr2-niedersachsen.cast.addradio.de/ndr/ndr2/niedersachsen/mp3/128/stream.mp3', category: 'rock', icon: '🎸' },
722
+ { id: 5, name: 'SWR3', genre: 'Pop', url: 'https://swr-swr3-live.cast.addradio.de/swr/swr3/live/mp3/128/stream.mp3', category: 'pop', icon: '🎼' },
723
+ { id: 6, name: 'HR3', genre: 'Pop', url: 'https://hr-hr3-live.cast.addradio.de/hr/hr3/live/mp3/128/stream.mp3', category: 'pop', icon: '🎤' },
724
+ { id: 7, name: 'MDR Jump', genre: 'Rock/Pop', url: 'https://mdr-jump-live.cast.addradio.de/mdr/mdr-jump/live/mp3/128/stream.mp3', category: 'rock', icon: '🎧' },
725
+ { id: 8, name: 'RPR1', genre: 'Pop', url: 'https://streams.rpr1.de/rpr-mp3-128', category: 'pop', icon: '🎹' },
726
+ { id: 9, name: 'Radio Bremen', genre: 'Nachrichten', url: 'https://rb-media.rb-radio.de/rb/bremen/live/mp3/128/stream.mp3', category: 'news', icon: '📰' },
727
+ { id: 10, name: 'SR 1', genre: 'Pop', url: 'https://sr-sr1-live.cast.addradio.de/sr/sr1/live/mp3/128/stream.mp3', category: 'pop', icon: '🎺' },
728
+ { id: 11, name: 'JazzRadio', genre: 'Jazz', url: 'http://stream.jazzradio.de/jazzradio/mp3-192', category: 'jazz', icon: '🎷' },
729
+ { id: 12, name: 'BR-Klassik', genre: 'Klassik', url: 'https://br-brklassik-live.cast.addradio.de/br/brklassik/live/mp3/128/stream.mp3', category: 'klassik', icon: '🎻' },
730
+ { id: 13, name: 'DLF Kultur', genre: 'Kultur', url: 'https://st02.dlf.de/dlf/02/128/mp3/stream.mp3', category: 'news', icon: '🎭' },
731
+ { id: 14, name: 'Antenne Bayern', genre: 'Pop', url: 'https://mp3channels.webradio.antenne.de/antenne-bayern', category: 'pop', icon: '📡' },
732
+ { id: 15, name: 'Radio Hamburg', genre: 'Pop', url: 'https://stream.radiohamburg.de/rhh-live/mp3-128', category: 'pop', icon: '⚓' },
733
+ { id: 16, name: 'FFH', genre: 'Pop', url: 'https://mp3.ffh.de/radioffh/hqlivestream.mp3', category: 'pop', icon: '🎪' }
734
+ ];
735
+
736
+ let currentStationIndex = -1;
737
+ let isPlaying = false;
738
+ let currentCategory = 'all';
739
+
740
+ // Initialize
741
+ document.addEventListener('DOMContentLoaded', function() {
742
+ renderStations();
743
+ setupVolumeControl();
744
+ });
745
+
746
+ // Render Stations
747
+ function renderStations() {
748
+ const grid = document.getElementById('stationsGrid');
749
+ grid.innerHTML = '';
750
+
751
+ const filteredStations = currentCategory === 'all'
752
+ ? stations
753
+ : stations.filter(s => s.category === currentCategory);
754
+
755
+ filteredStations.forEach((station, index) => {
756
+ const card = document.createElement('div');
757
+ card.className = 'station-card';
758
+ card.innerHTML = `
759
+ <div class="station-card-header">
760
+ <div class="station-card-logo">${station.icon}</div>
761
+ <div class="station-card-info">
762
+ <h3>${station.name}</h3>
763
+ <p>${station.genre}</p>
764
+ </div>
765
+ </div>
766
+ <span class="station-genre">${station.category}</span>
767
+ `;
768
+ card.onclick = () => selectStation(station);
769
+ grid.appendChild(card);
770
+ });
771
+ }
772
+
773
+ // Select Station
774
+ function selectStation(station) {
775
+ const audioPlayer = document.getElementById('audioPlayer');
776
+ const playPauseBtn = document.getElementById('playPauseBtn');
777
+
778
+ // Update UI
779
+ document.getElementById('currentStation').textContent = station.name;
780
+ document.getElementById('currentGenre').textContent = station.genre;
781
+
782
+ // Update active card
783
+ document.querySelectorAll('.station-card').forEach(card => {
784
+ card.classList.remove('active');
785
+ if (card.querySelector('h3').textContent === station.name) {
786
+ card.classList.add('active');
787
+ }
788
+ });
789
+
790
+ // Set audio source
791
+ audioPlayer.src = station.url;
792
+ currentStationIndex = stations.findIndex(s => s.id === station.id);
793
+
794
+ // Auto play
795
+ if (!isPlaying) {
796
+ togglePlayPause();
797
+ }
798
+
799
+ showToast(`Sender gewechselt: ${station.name}`);
800
+ }
801
+
802
+ // Toggle Play/Pause
803
+ function togglePlayPause() {
804
+ const audioPlayer = document.getElementById('audioPlayer');
805
+ const playPauseBtn = document.getElementById('playPauseBtn');
806
+ const visualizer = document.getElementById('visualizer');
807
+
808
+ if (currentStationIndex === -1) {
809
+ showToast('Bitte wähle zuerst einen Sender aus');
810
+ return;
811
+ }
812
+
813
+ if (isPlaying) {
814
+ audioPlayer.pause();
815
+ playPauseBtn.innerHTML = '<i class="fas fa-play"></i>';
816
+ visualizer.classList.add('paused');
817
+ showToast('Pausiert');
818
+ } else {
819
+ audioPlayer.play().catch(e => {
820
+ showToast('Fehler beim Abspielen');
821
+ console.error(e);
822
+ });
823
+ playPauseBtn.innerHTML = '<i class="fas fa-pause"></i>';
824
+ visualizer.classList.remove('paused');
825
+ showToast('Wiedergabe gestartet');
826
+ }
827
+
828
+ isPlaying = !isPlaying;
829
+ }
830
+
831
+ // Previous Station
832
+ function previousStation() {
833
+ if (currentStationIndex > 0) {
834
+ selectStation(stations[currentStationIndex - 1]);
835
+ } else if (currentStationIndex === 0) {
836
+ selectStation(stations[stations.length - 1]);
837
+ }
838
+ }
839
+
840
+ // Next Station
841
+ function nextStation() {
842
+ if (currentStationIndex < stations.length - 1) {
843
+ selectStation(stations[currentStationIndex + 1]);
844
+ } else if (currentStationIndex === stations.length - 1) {
845
+ selectStation(stations[0]);
846
+ }
847
+ }
848
+
849
+ // Volume Control
850
+ function setupVolumeControl() {
851
+ const volumeSlider = document.getElementById('volumeSlider');
852
+ const volumeValue = document.getElementById('volumeValue');
853
+ const audioPlayer = document.getElementById('audioPlayer');
854
+
855
+ volumeSlider.addEventListener('input', function() {
856
+ const volume = this.value / 100;
857
+ audioPlayer.volume = volume;
858
+ volumeValue.textContent = this.value + '%';
859
+ });
860
+
861
+ // Set initial volume
862
+ audioPlayer.volume = 0.7;
863
+ }
864
+
865
+ // Toggle Mute
866
+ function toggleMute() {
867
+ const audioPlayer = document.getElementById('audioPlayer');
868
+ audioPlayer.muted = !audioPlayer.muted;
869
+ showToast(audioPlayer.muted ? 'Stumm geschaltet' : 'Stumm aufgehoben');
870
+ }
871
+
872
+ // Filter Stations
873
+ function filterStations(category) {
874
+ currentCategory = category;
875
+
876
+ // Update active button
877
+ document.querySelectorAll('.category-btn').forEach(btn => {
878
+ btn.classList.remove('active');
879
+ if (btn.textContent.toLowerCase().includes(category) ||
880
+ (category === 'all' && btn.textContent === 'Alle')) {
881
+ btn.classList.add('active');
882
+ }
883
+ });
884
+
885
+ renderStations();
886
+ }
887
+
888
+ // Toast Notification
889
+ function showToast(message) {
890
+ const toast = document.getElementById('toast');
891
+ toast.textContent = message;
892
+ toast.classList.add('show');
893
+
894
+ setTimeout(() => {
895
+ toast.classList.remove('show');
896
+ }, 3000);
897
+ }
898
+
899
+ // Keyboard Controls
900
+ document.addEventListener('keydown', function(e) {
901
+ switch(e.key) {
902
+ case ' ':
903
+ e.preventDefault();
904
+ togglePlayPause();
905
+ break;
906
+ case 'ArrowRight':
907
+ nextStation();
908
+ break;
909
+ case 'ArrowLeft':
910
+ previousStation();
911
+ break;
912
+ case 'ArrowUp':
913
+ const volumeSlider = document.getElementById('volumeSlider');
914
+ volumeSlider.value = Math.min(100, parseInt(volumeSlider.value) + 5);
915
+ volumeSlider.dispatchEvent(new Event('input'));
916
+ break;
917
+ case 'ArrowDown':
918
+ const volumeSliderDown = document.getElementById('volumeSlider');
919
+ volumeSliderDown.value = Math.max(0, parseInt(volumeSliderDown.value) - 5);
920
+ volumeSliderDown.dispatchEvent(new Event('input'));
921
+ break;
922
+ }
923
+ });
924
+
925
+ // Handle audio errors
926
+ document.getElementById('audioPlayer').addEventListener('error', function() {
927
+ showToast('Fehler beim Laden des Streams');
928
+ isPlaying = false;
929
+ document.getElementById('playPauseBtn').innerHTML = '<i class="fas fa-play"></i>';
930
+ document.getElementById('visualizer').classList.add('paused');
931
+ });
932
+
933
+ // Handle audio ended
934
+ document.getElementById('audioPlayer').addEventListener('ended', function() {
935
+ isPlaying = false;
936
+ document.getElementById('playPauseBtn').innerHTML = '<i class="fas fa-play"></i>';
937
+ document.getElementById('visualizer').classList.add('paused');
938
+ });
939
+ </script>
940
+ </body>
941
+ </html>