horeg-audio 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1677 @@
1
+ var P = Object.defineProperty;
2
+ var B = (l, e, i) => e in l ? P(l, e, { enumerable: !0, configurable: !0, writable: !0, value: i }) : l[e] = i;
3
+ var r = (l, e, i) => B(l, typeof e != "symbol" ? e + "" : e, i);
4
+ const C = {
5
+ "horeg-classic": {
6
+ primaryGlowColor: "#f59e0b",
7
+ accentColor: "#ef4444",
8
+ cardBackground: "#121214",
9
+ textColor: "#f4f4f5",
10
+ sliderProgressColor: "#f59e0b",
11
+ borderRadius: "14px"
12
+ },
13
+ "horeg-nightclub": {
14
+ primaryGlowColor: "#06b6d4",
15
+ accentColor: "#ec4899",
16
+ cardBackground: "#0b0c10",
17
+ textColor: "#f8fafc",
18
+ sliderProgressColor: "#06b6d4",
19
+ borderRadius: "14px"
20
+ },
21
+ "horeg-stealth": {
22
+ primaryGlowColor: "#94a3b8",
23
+ accentColor: "#e2e8f0",
24
+ cardBackground: "#0f1115",
25
+ textColor: "#e2e8f0",
26
+ sliderProgressColor: "#94a3b8",
27
+ borderRadius: "8px"
28
+ }
29
+ };
30
+ function T(l = {}) {
31
+ const e = l.variant || "horeg-classic", i = C[e] || C["horeg-classic"], t = l.primaryGlowColor || i.primaryGlowColor || "#f59e0b", a = l.accentColor || i.accentColor || "#ef4444", s = l.cardBackground || i.cardBackground || "#121214", n = l.textColor || i.textColor || "#f4f4f5", c = l.sliderProgressColor || i.sliderProgressColor || t, h = l.borderRadius || i.borderRadius || "14px";
32
+ return `
33
+ :host {
34
+ --horeg-bg: ${s};
35
+ --horeg-surface: #18181b;
36
+ --horeg-surface-hover: #222226;
37
+ --horeg-border: #27272a;
38
+ --horeg-glow: ${t};
39
+ --horeg-glow-rgb: 245, 158, 11;
40
+ --horeg-accent: ${a};
41
+ --horeg-progress: ${c};
42
+ --horeg-text-main: ${n};
43
+ --horeg-text-muted: #a1a1aa;
44
+ --horeg-radius: ${h};
45
+ display: block;
46
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
47
+ box-sizing: border-box;
48
+ outline: none;
49
+ user-select: none;
50
+ -webkit-user-select: none;
51
+ }
52
+
53
+ *, *::before, *::after {
54
+ box-sizing: border-box;
55
+ margin: 0;
56
+ padding: 0;
57
+ }
58
+
59
+ .horeg-player-box {
60
+ background: var(--horeg-bg);
61
+ border: 2px solid var(--horeg-border);
62
+ border-radius: var(--horeg-radius);
63
+ box-shadow: 0 16px 40px -10px rgba(0, 0, 0, 0.9), 0 0 20px -5px var(--horeg-glow);
64
+ color: var(--horeg-text-main);
65
+ position: relative;
66
+ overflow: hidden;
67
+ max-width: 520px;
68
+ width: 100%;
69
+ margin: 0 auto;
70
+ transition: box-shadow 0.3s ease, border-color 0.3s ease;
71
+ }
72
+
73
+ /* Player Box active glow when focused within */
74
+ :host(:focus) .horeg-player-box,
75
+ :host(:focus-within) .horeg-player-box,
76
+ .horeg-player-box:focus-within {
77
+ border-color: var(--horeg-glow);
78
+ box-shadow: 0 20px 48px -10px rgba(0, 0, 0, 0.95), 0 0 30px -2px var(--horeg-glow), 0 0 10px var(--horeg-glow);
79
+ }
80
+
81
+ :host(:focus) .horeg-player-box .horeg-bolt,
82
+ :host(:focus-within) .horeg-player-box .horeg-bolt,
83
+ .horeg-player-box:focus-within .horeg-bolt {
84
+ box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.3), 0 0 4px var(--horeg-glow);
85
+ }
86
+
87
+ .horeg-speaker-grill {
88
+ position: absolute;
89
+ inset: 0;
90
+ background-image: radial-gradient(#2c2d33 1.2px, transparent 1.2px);
91
+ background-size: 8px 8px;
92
+ opacity: 0.3;
93
+ pointer-events: none;
94
+ z-index: 1;
95
+ }
96
+
97
+ /* Metal Corner Brackets / Screws (Sound System Rig Rigging) */
98
+ .horeg-bolt {
99
+ position: absolute;
100
+ width: 8px;
101
+ height: 8px;
102
+ background: #3f3f46;
103
+ border: 1px solid #18181b;
104
+ border-radius: 50%;
105
+ box-shadow: inset 0 1px 1px rgba(255,255,255,0.2), 0 1px 2px rgba(0,0,0,0.8);
106
+ z-index: 2;
107
+ }
108
+ .horeg-bolt::after {
109
+ content: '';
110
+ position: absolute;
111
+ top: 50%;
112
+ left: 50%;
113
+ width: 4px;
114
+ height: 1px;
115
+ background: #18181b;
116
+ transform: translate(-50%, -50%) rotate(45deg);
117
+ }
118
+ .horeg-bolt.top-left { top: 7px; left: 7px; }
119
+ .horeg-bolt.top-right { top: 7px; right: 7px; }
120
+ .horeg-bolt.bottom-left { bottom: 7px; left: 7px; }
121
+ .horeg-bolt.bottom-right { bottom: 7px; right: 7px; }
122
+
123
+ .horeg-content-wrap {
124
+ position: relative;
125
+ z-index: 3;
126
+ padding: 18px 20px 16px 20px;
127
+ display: flex;
128
+ flex-direction: column;
129
+ gap: 14px;
130
+ }
131
+
132
+ /* Top Rig Header */
133
+ .horeg-header {
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: space-between;
137
+ border-bottom: 1px solid #27272a;
138
+ padding-bottom: 8px;
139
+ }
140
+
141
+ .horeg-rig-badge {
142
+ display: flex;
143
+ align-items: center;
144
+ gap: 6px;
145
+ font-size: 10px;
146
+ letter-spacing: 1.5px;
147
+ text-transform: uppercase;
148
+ font-weight: 800;
149
+ color: var(--horeg-glow);
150
+ text-shadow: 0 0 8px var(--horeg-glow);
151
+ }
152
+
153
+ .horeg-badge-led {
154
+ width: 7px;
155
+ height: 7px;
156
+ background-color: var(--horeg-glow);
157
+ border-radius: 50%;
158
+ box-shadow: 0 0 6px var(--horeg-glow);
159
+ animation: ledPulse 2s infinite ease-in-out;
160
+ }
161
+
162
+ @keyframes ledPulse {
163
+ 0%, 100% { opacity: 0.5; transform: scale(0.9); }
164
+ 50% { opacity: 1; transform: scale(1.1); box-shadow: 0 0 10px var(--horeg-glow); }
165
+ }
166
+
167
+ /* Track Display & Visualizer Section */
168
+ .horeg-track-row {
169
+ display: flex;
170
+ align-items: center;
171
+ gap: 14px;
172
+ }
173
+
174
+ .horeg-cover-container {
175
+ position: relative;
176
+ width: 64px;
177
+ height: 64px;
178
+ min-width: 64px;
179
+ border-radius: 8px;
180
+ overflow: hidden;
181
+ background: #18181b;
182
+ border: 1px solid #3f3f46;
183
+ display: flex;
184
+ align-items: center;
185
+ justify-content: center;
186
+ box-shadow: inset 0 0 10px rgba(0,0,0,0.8), 0 2px 6px rgba(0,0,0,0.6);
187
+ }
188
+
189
+ .horeg-cover-img {
190
+ width: 100%;
191
+ height: 100%;
192
+ object-fit: cover;
193
+ }
194
+
195
+ .horeg-cover-fallback {
196
+ color: var(--horeg-glow);
197
+ opacity: 0.7;
198
+ }
199
+
200
+ .horeg-track-info {
201
+ flex: 1;
202
+ min-width: 0;
203
+ display: flex;
204
+ flex-direction: column;
205
+ gap: 2px;
206
+ }
207
+
208
+ .horeg-track-title {
209
+ font-size: 15px;
210
+ font-weight: 700;
211
+ white-space: nowrap;
212
+ overflow: hidden;
213
+ text-overflow: ellipsis;
214
+ color: var(--horeg-text-main);
215
+ letter-spacing: 0.2px;
216
+ }
217
+
218
+ .horeg-track-artist {
219
+ font-size: 12px;
220
+ font-weight: 500;
221
+ color: var(--horeg-text-muted);
222
+ white-space: nowrap;
223
+ overflow: hidden;
224
+ text-overflow: ellipsis;
225
+ }
226
+
227
+ .horeg-track-album {
228
+ font-size: 10px;
229
+ color: #71717a;
230
+ white-space: nowrap;
231
+ overflow: hidden;
232
+ text-overflow: ellipsis;
233
+ }
234
+
235
+ /* Mini EQ Visualizer */
236
+ .horeg-eq-wrapper {
237
+ display: flex;
238
+ align-items: flex-end;
239
+ gap: 2px;
240
+ height: 24px;
241
+ padding: 0 4px;
242
+ }
243
+
244
+ .horeg-eq-bar {
245
+ width: 3px;
246
+ height: 4px;
247
+ background: var(--horeg-glow);
248
+ border-radius: 1px;
249
+ transition: height 0.1s ease;
250
+ box-shadow: 0 0 4px var(--horeg-glow);
251
+ }
252
+
253
+ /* Scrubbing / Fader Progress Bar */
254
+ .horeg-progress-container {
255
+ display: flex;
256
+ flex-direction: column;
257
+ gap: 5px;
258
+ }
259
+
260
+ .horeg-time-row {
261
+ display: flex;
262
+ justify-content: space-between;
263
+ font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
264
+ font-size: 11px;
265
+ color: var(--horeg-text-muted);
266
+ }
267
+
268
+ .horeg-slider-track {
269
+ position: relative;
270
+ width: 100%;
271
+ height: 7px;
272
+ background: #27272a;
273
+ border-radius: 4px;
274
+ cursor: pointer;
275
+ overflow: hidden;
276
+ box-shadow: inset 0 1px 3px rgba(0,0,0,0.8);
277
+ }
278
+
279
+ .horeg-buffer-bar {
280
+ position: absolute;
281
+ top: 0;
282
+ bottom: 0;
283
+ left: 0;
284
+ width: 0%;
285
+ background: #3f3f46;
286
+ border-radius: 4px;
287
+ transition: width 0.2s linear;
288
+ }
289
+
290
+ .horeg-fill-bar {
291
+ position: absolute;
292
+ top: 0;
293
+ bottom: 0;
294
+ left: 0;
295
+ width: 0%;
296
+ background: linear-gradient(90deg, var(--horeg-accent) 0%, var(--horeg-progress) 100%);
297
+ border-radius: 4px;
298
+ box-shadow: 0 0 8px var(--horeg-glow);
299
+ transition: width 0.08s linear;
300
+ }
301
+
302
+ /* Controls Row */
303
+ .horeg-controls-row {
304
+ display: flex;
305
+ align-items: center;
306
+ justify-content: space-between;
307
+ padding-top: 4px;
308
+ }
309
+
310
+ .horeg-side-controls {
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 8px;
314
+ }
315
+
316
+ .horeg-center-controls {
317
+ display: flex;
318
+ align-items: center;
319
+ gap: 12px;
320
+ }
321
+
322
+ .horeg-btn {
323
+ background: transparent;
324
+ border: none;
325
+ outline: none;
326
+ color: var(--horeg-text-muted);
327
+ cursor: pointer;
328
+ padding: 6px;
329
+ border-radius: 8px;
330
+ display: inline-flex;
331
+ align-items: center;
332
+ justify-content: center;
333
+ transition: all 0.15s ease;
334
+ touch-action: manipulation;
335
+ }
336
+
337
+ .horeg-btn:hover {
338
+ color: var(--horeg-text-main);
339
+ background: var(--horeg-surface-hover);
340
+ }
341
+
342
+ .horeg-btn:active {
343
+ transform: scale(0.92);
344
+ filter: brightness(1.2);
345
+ }
346
+
347
+ .horeg-btn:focus-visible {
348
+ outline: 2px solid var(--horeg-glow);
349
+ outline-offset: 1px;
350
+ }
351
+
352
+ .horeg-btn.active {
353
+ color: var(--horeg-glow);
354
+ background: rgba(255, 255, 255, 0.06);
355
+ text-shadow: 0 0 8px var(--horeg-glow);
356
+ box-shadow: inset 0 0 8px rgba(255, 255, 255, 0.05);
357
+ }
358
+
359
+ /* Primary Play / Pause Button with Neon Glow Pulse */
360
+ .horeg-btn-play {
361
+ width: 44px;
362
+ height: 44px;
363
+ border-radius: 50%;
364
+ background: #1f1f23;
365
+ border: 2px solid var(--horeg-glow);
366
+ color: var(--horeg-glow);
367
+ box-shadow: 0 0 12px -2px var(--horeg-glow);
368
+ transition: transform 0.12s ease, box-shadow 0.2s ease, background 0.2s ease;
369
+ }
370
+
371
+ .horeg-btn-play:hover {
372
+ background: #27272a;
373
+ transform: scale(1.06);
374
+ box-shadow: 0 0 18px 2px var(--horeg-glow);
375
+ }
376
+
377
+ .horeg-btn-play:active {
378
+ transform: scale(0.96);
379
+ }
380
+
381
+ .horeg-btn-play.playing {
382
+ background: var(--horeg-glow);
383
+ color: #09090b;
384
+ box-shadow: 0 0 20px var(--horeg-glow), inset 0 0 8px rgba(255, 255, 255, 0.4);
385
+ animation: playPulse 2.2s infinite ease-in-out;
386
+ }
387
+
388
+ @keyframes playPulse {
389
+ 0%, 100% {
390
+ box-shadow: 0 0 15px var(--horeg-glow);
391
+ }
392
+ 50% {
393
+ box-shadow: 0 0 25px var(--horeg-glow), 0 0 8px #fff;
394
+ }
395
+ }
396
+
397
+ /* Volume Slider Rel Mixer */
398
+ .horeg-volume-wrap {
399
+ display: flex;
400
+ align-items: center;
401
+ gap: 6px;
402
+ }
403
+
404
+ .horeg-volume-slider {
405
+ -webkit-appearance: none;
406
+ appearance: none;
407
+ width: 70px;
408
+ height: 5px;
409
+ background: #27272a;
410
+ border-radius: 3px;
411
+ outline: none;
412
+ cursor: pointer;
413
+ }
414
+
415
+ .horeg-volume-slider::-webkit-slider-thumb {
416
+ -webkit-appearance: none;
417
+ appearance: none;
418
+ width: 12px;
419
+ height: 12px;
420
+ border-radius: 50%;
421
+ background: var(--horeg-glow);
422
+ border: 1px solid #18181b;
423
+ box-shadow: 0 0 6px var(--horeg-glow);
424
+ cursor: pointer;
425
+ transition: transform 0.1s ease;
426
+ }
427
+
428
+ .horeg-volume-slider::-webkit-slider-thumb:hover {
429
+ transform: scale(1.2);
430
+ }
431
+
432
+ .horeg-volume-slider::-moz-range-thumb {
433
+ width: 12px;
434
+ height: 12px;
435
+ border-radius: 50%;
436
+ background: var(--horeg-glow);
437
+ border: 1px solid #18181b;
438
+ box-shadow: 0 0 6px var(--horeg-glow);
439
+ cursor: pointer;
440
+ }
441
+
442
+ /* Drag Over Highlight on main player */
443
+ .horeg-player-box.drag-over {
444
+ border-color: var(--horeg-glow);
445
+ box-shadow: 0 0 25px var(--horeg-glow), 0 8px 32px rgba(0, 0, 0, 0.9);
446
+ }
447
+
448
+ /* Rack Mount Playlist Drawer */
449
+ .horeg-drawer {
450
+ max-height: 0;
451
+ opacity: 0;
452
+ overflow-y: auto;
453
+ transition: max-height 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.25s ease;
454
+ background: #141416;
455
+ border-top: 1px solid #27272a;
456
+ border-radius: 0 0 calc(var(--horeg-radius) - 2px) calc(var(--horeg-radius) - 2px);
457
+ scrollbar-width: thin;
458
+ scrollbar-color: #3f3f46 #18181b;
459
+ position: relative;
460
+ z-index: 3;
461
+ }
462
+
463
+ .horeg-drawer.open {
464
+ max-height: 220px;
465
+ max-height: 380px;
466
+ opacity: 1;
467
+ }
468
+
469
+ /* Drawer Header */
470
+ .horeg-drawer-header {
471
+ display: flex;
472
+ align-items: center;
473
+ justify-content: space-between;
474
+ padding: 10px 14px 8px 14px;
475
+ border-bottom: 1px solid #27272a;
476
+ position: sticky;
477
+ top: 0;
478
+ background: #141416;
479
+ z-index: 2;
480
+ }
481
+
482
+ .horeg-drawer-heading {
483
+ display: flex;
484
+ align-items: center;
485
+ gap: 8px;
486
+ font-size: 11px;
487
+ font-weight: 700;
488
+ letter-spacing: 0.8px;
489
+ color: var(--horeg-text-muted);
490
+ text-transform: uppercase;
491
+ font-family: ui-monospace, monospace;
492
+ }
493
+
494
+ .horeg-drawer-count {
495
+ padding: 1px 6px;
496
+ background: #27272a;
497
+ color: var(--horeg-glow);
498
+ border-radius: 10px;
499
+ font-size: 10px;
500
+ font-weight: 700;
501
+ }
502
+
503
+ .horeg-btn-add-track {
504
+ display: inline-flex;
505
+ align-items: center;
506
+ gap: 5px;
507
+ padding: 4px 9px;
508
+ font-size: 11px;
509
+ font-weight: 600;
510
+ color: var(--horeg-text-main);
511
+ background: #1f1f23;
512
+ border: 1px solid #3f3f46;
513
+ border-radius: 5px;
514
+ cursor: pointer;
515
+ transition: all 0.15s ease;
516
+ }
517
+
518
+ .horeg-btn-add-track:hover {
519
+ background: #27272a;
520
+ border-color: var(--horeg-glow);
521
+ color: var(--horeg-glow);
522
+ box-shadow: 0 0 8px rgba(245, 158, 11, 0.2);
523
+ }
524
+
525
+ .horeg-btn-add-track.active {
526
+ background: #27272a;
527
+ border-color: var(--horeg-glow);
528
+ color: var(--horeg-glow);
529
+ box-shadow: 0 0 12px var(--horeg-glow);
530
+ text-shadow: 0 0 6px var(--horeg-glow);
531
+ }
532
+
533
+ .horeg-btn-add-track:active {
534
+ transform: scale(0.95);
535
+ }
536
+
537
+ /* Add Track Panel Form */
538
+ .horeg-add-panel {
539
+ display: none;
540
+ flex-direction: column;
541
+ gap: 10px;
542
+ margin: 10px 12px;
543
+ padding: 12px;
544
+ background: #18181b;
545
+ border: 1px solid #3f3f46;
546
+ border-radius: 8px;
547
+ box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
548
+ animation: fadeIn 0.2s ease;
549
+ }
550
+
551
+ .horeg-add-panel.open {
552
+ display: flex;
553
+ }
554
+
555
+ .horeg-add-tabs {
556
+ display: flex;
557
+ gap: 6px;
558
+ border-bottom: 1px solid #27272a;
559
+ padding-bottom: 8px;
560
+ }
561
+
562
+ .horeg-tab-btn {
563
+ flex: 1;
564
+ display: flex;
565
+ align-items: center;
566
+ justify-content: center;
567
+ gap: 6px;
568
+ padding: 6px 10px;
569
+ font-size: 11px;
570
+ font-weight: 600;
571
+ background: #202024;
572
+ color: var(--horeg-text-muted);
573
+ border: 1px solid #2e2e33;
574
+ border-radius: 5px;
575
+ cursor: pointer;
576
+ transition: all 0.15s ease;
577
+ }
578
+
579
+ .horeg-tab-btn:hover {
580
+ color: var(--horeg-text-main);
581
+ border-color: #52525b;
582
+ }
583
+
584
+ .horeg-tab-btn.active {
585
+ background: #27272a;
586
+ color: var(--horeg-glow);
587
+ border-color: var(--horeg-glow);
588
+ box-shadow: 0 0 10px var(--horeg-glow);
589
+ text-shadow: 0 0 6px var(--horeg-glow);
590
+ }
591
+
592
+ .horeg-tab-btn:active {
593
+ transform: scale(0.97);
594
+ }
595
+
596
+ .horeg-tab-pane {
597
+ display: none;
598
+ flex-direction: column;
599
+ gap: 8px;
600
+ }
601
+
602
+ .horeg-tab-pane.active {
603
+ display: flex;
604
+ }
605
+
606
+ /* Dropzone for local file */
607
+ .horeg-dropzone {
608
+ display: flex;
609
+ flex-direction: column;
610
+ align-items: center;
611
+ justify-content: center;
612
+ gap: 6px;
613
+ padding: 16px 10px;
614
+ border: 2px dashed #3f3f46;
615
+ border-radius: 6px;
616
+ background: #141416;
617
+ cursor: pointer;
618
+ transition: all 0.2s ease;
619
+ text-align: center;
620
+ }
621
+
622
+ .horeg-dropzone:hover,
623
+ .horeg-dropzone.drag-active {
624
+ border-color: var(--horeg-glow);
625
+ background: rgba(245, 158, 11, 0.05);
626
+ box-shadow: 0 0 10px rgba(245, 158, 11, 0.15);
627
+ }
628
+
629
+ .horeg-dropzone-icon {
630
+ color: var(--horeg-glow);
631
+ display: flex;
632
+ align-items: center;
633
+ justify-content: center;
634
+ }
635
+
636
+ .horeg-dropzone-text {
637
+ font-size: 11px;
638
+ font-weight: 600;
639
+ color: var(--horeg-text-main);
640
+ }
641
+
642
+ .horeg-dropzone-hint {
643
+ font-size: 10px;
644
+ color: var(--horeg-text-muted);
645
+ }
646
+
647
+ /* Inputs for URL / Meta */
648
+ .horeg-input-field {
649
+ width: 100%;
650
+ box-sizing: border-box;
651
+ padding: 7px 10px;
652
+ font-size: 12px;
653
+ background: #121214;
654
+ border: 1px solid #3f3f46;
655
+ border-radius: 5px;
656
+ color: var(--horeg-text-main);
657
+ outline: none;
658
+ transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
659
+ }
660
+
661
+ .horeg-input-field:focus {
662
+ border-color: var(--horeg-glow);
663
+ background: #18181b;
664
+ box-shadow: 0 0 0 1px var(--horeg-glow), 0 0 10px var(--horeg-glow);
665
+ outline: none;
666
+ }
667
+
668
+ .horeg-input-field::placeholder {
669
+ color: #71717a;
670
+ font-size: 11px;
671
+ }
672
+
673
+ .horeg-form-actions {
674
+ display: flex;
675
+ align-items: center;
676
+ justify-content: flex-end;
677
+ gap: 6px;
678
+ margin-top: 4px;
679
+ }
680
+
681
+ .horeg-btn-submit {
682
+ display: inline-flex;
683
+ align-items: center;
684
+ gap: 5px;
685
+ padding: 6px 12px;
686
+ font-size: 11px;
687
+ font-weight: 700;
688
+ background: var(--horeg-glow);
689
+ color: #09090b;
690
+ border: none;
691
+ border-radius: 5px;
692
+ cursor: pointer;
693
+ transition: opacity 0.15s ease, transform 0.1s ease;
694
+ }
695
+
696
+ .horeg-btn-submit:hover {
697
+ opacity: 0.9;
698
+ transform: translateY(-1px);
699
+ }
700
+
701
+ .horeg-btn-submit:active {
702
+ transform: scale(0.96);
703
+ filter: brightness(1.15);
704
+ }
705
+
706
+ .horeg-btn-cancel {
707
+ padding: 6px 10px;
708
+ font-size: 11px;
709
+ font-weight: 600;
710
+ background: transparent;
711
+ color: var(--horeg-text-muted);
712
+ border: 1px solid transparent;
713
+ border-radius: 5px;
714
+ cursor: pointer;
715
+ transition: color 0.15s ease, transform 0.1s ease;
716
+ }
717
+
718
+ .horeg-btn-cancel:hover {
719
+ color: var(--horeg-text-main);
720
+ }
721
+
722
+ .horeg-btn-cancel:active {
723
+ transform: scale(0.96);
724
+ }
725
+
726
+ .horeg-drawer-inner {
727
+ padding: 6px 10px 10px 10px;
728
+ display: flex;
729
+ flex-direction: column;
730
+ gap: 4px;
731
+ }
732
+
733
+ .horeg-track-item {
734
+ display: flex;
735
+ align-items: center;
736
+ gap: 10px;
737
+ padding: 8px 10px;
738
+ border-radius: 6px;
739
+ cursor: pointer;
740
+ transition: background 0.15s ease;
741
+ font-size: 13px;
742
+ }
743
+
744
+ .horeg-track-item:hover {
745
+ background: #1f1f23;
746
+ }
747
+
748
+ .horeg-track-item.active {
749
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0.08) 0%, rgba(255, 255, 255, 0.02) 100%);
750
+ color: var(--horeg-glow);
751
+ border-left: 3px solid var(--horeg-glow);
752
+ box-shadow: inset 3px 0 6px -2px var(--horeg-glow), 0 2px 8px rgba(0, 0, 0, 0.4);
753
+ position: relative;
754
+ }
755
+
756
+ .horeg-track-item.active .horeg-track-num {
757
+ color: var(--horeg-glow);
758
+ font-weight: 700;
759
+ text-shadow: 0 0 8px var(--horeg-glow);
760
+ }
761
+
762
+ .horeg-track-item.active .horeg-item-title {
763
+ color: var(--horeg-glow);
764
+ font-weight: 700;
765
+ text-shadow: 0 0 8px var(--horeg-glow);
766
+ }
767
+
768
+ .horeg-track-item.active .horeg-item-artist {
769
+ color: var(--horeg-text-main);
770
+ opacity: 0.9;
771
+ }
772
+
773
+ .horeg-track-item.active .horeg-item-duration {
774
+ color: var(--horeg-glow);
775
+ opacity: 0.9;
776
+ }
777
+
778
+ .horeg-track-item:focus-visible {
779
+ outline: 2px solid var(--horeg-glow);
780
+ outline-offset: -1px;
781
+ }
782
+
783
+ .horeg-track-num {
784
+ font-family: ui-monospace, monospace;
785
+ font-size: 11px;
786
+ color: var(--horeg-text-muted);
787
+ width: 18px;
788
+ }
789
+
790
+ .horeg-track-details {
791
+ flex: 1;
792
+ min-width: 0;
793
+ }
794
+
795
+ .horeg-item-title {
796
+ font-weight: 600;
797
+ white-space: nowrap;
798
+ overflow: hidden;
799
+ text-overflow: ellipsis;
800
+ }
801
+
802
+ .horeg-item-artist {
803
+ font-size: 11px;
804
+ color: var(--horeg-text-muted);
805
+ white-space: nowrap;
806
+ overflow: hidden;
807
+ text-overflow: ellipsis;
808
+ }
809
+
810
+ .horeg-item-duration {
811
+ font-family: ui-monospace, monospace;
812
+ font-size: 11px;
813
+ color: var(--horeg-text-muted);
814
+ margin-right: 4px;
815
+ }
816
+
817
+ /* Track Item Actions (Remove button) */
818
+ .horeg-track-actions {
819
+ display: flex;
820
+ align-items: center;
821
+ opacity: 0.5;
822
+ transition: opacity 0.15s ease;
823
+ }
824
+
825
+ .horeg-track-item:hover .horeg-track-actions {
826
+ opacity: 1;
827
+ }
828
+
829
+ .horeg-btn-remove {
830
+ background: transparent;
831
+ border: none;
832
+ color: var(--horeg-text-muted);
833
+ cursor: pointer;
834
+ padding: 4px;
835
+ border-radius: 4px;
836
+ display: flex;
837
+ align-items: center;
838
+ justify-content: center;
839
+ transition: all 0.15s ease;
840
+ }
841
+
842
+ .horeg-btn-remove:hover {
843
+ color: #ef4444;
844
+ background: rgba(239, 68, 68, 0.15);
845
+ }
846
+
847
+ .horeg-empty-playlist {
848
+ padding: 24px 12px;
849
+ text-align: center;
850
+ color: var(--horeg-text-muted);
851
+ font-size: 12px;
852
+ font-style: italic;
853
+ }
854
+ `;
855
+ }
856
+ function b(l) {
857
+ if (isNaN(l) || !isFinite(l) || l < 0)
858
+ return "00:00";
859
+ const e = Math.floor(l), i = Math.floor(e / 3600), t = Math.floor(e % 3600 / 60), a = e % 60, s = (n) => n.toString().padStart(2, "0");
860
+ return i > 0 ? `${i}:${s(t)}:${s(a)}` : `${s(t)}:${s(a)}`;
861
+ }
862
+ function u(l, e, i) {
863
+ return Math.min(Math.max(l, e), i);
864
+ }
865
+ class M {
866
+ constructor(e, i = {}) {
867
+ r(this, "audio");
868
+ r(this, "playlist", []);
869
+ r(this, "currentIndex", 0);
870
+ r(this, "loopMode", "all");
871
+ r(this, "shuffleMode", !1);
872
+ r(this, "volumeLevel", 0.8);
873
+ r(this, "previousVolume", 0.8);
874
+ r(this, "callbacks", {});
875
+ r(this, "handlePlay", () => {
876
+ const e = this.getCurrentTrack();
877
+ e && this.callbacks.onPlay && this.callbacks.onPlay(e);
878
+ });
879
+ r(this, "handlePause", () => {
880
+ this.callbacks.onPause && this.callbacks.onPause();
881
+ });
882
+ r(this, "handleTimeUpdate", () => {
883
+ const e = this.audio.currentTime || 0, i = this.getDuration();
884
+ this.callbacks.onTimeUpdate && this.callbacks.onTimeUpdate(e, i);
885
+ });
886
+ r(this, "handleProgress", () => {
887
+ if (this.audio.buffered.length > 0 && this.audio.duration > 0) {
888
+ const e = this.audio.buffered.end(this.audio.buffered.length - 1), i = u(e / this.audio.duration * 100, 0, 100);
889
+ this.callbacks.onBufferUpdate && this.callbacks.onBufferUpdate(i);
890
+ }
891
+ });
892
+ r(this, "handleLoadedMetadata", () => {
893
+ const e = this.audio.currentTime || 0, i = this.getDuration();
894
+ this.callbacks.onTimeUpdate && this.callbacks.onTimeUpdate(e, i), this.handleProgress();
895
+ });
896
+ r(this, "handleWaiting", () => {
897
+ this.callbacks.onLoadingChange && this.callbacks.onLoadingChange(!0);
898
+ });
899
+ r(this, "handlePlaying", () => {
900
+ this.callbacks.onLoadingChange && this.callbacks.onLoadingChange(!1);
901
+ });
902
+ r(this, "handleEnded", () => {
903
+ const e = this.getCurrentTrack();
904
+ e && this.callbacks.onEnded && this.callbacks.onEnded(e), this.loopMode === "one" ? (this.audio.currentTime = 0, this.play()) : this.next(!0);
905
+ });
906
+ r(this, "handleError", () => {
907
+ const e = this.audio.error || new Error("Unknown audio playback error");
908
+ this.callbacks.onError && this.callbacks.onError(e);
909
+ });
910
+ this.audio = new Audio(), this.playlist = [...e.playlist || []], this.currentIndex = e.initialIndex !== void 0 ? u(e.initialIndex, 0, Math.max(0, this.playlist.length - 1)) : 0, this.loopMode = e.loop || "all", this.shuffleMode = !!e.shuffle, this.volumeLevel = e.volume !== void 0 ? u(e.volume, 0, 1) : 0.8, this.callbacks = i || {
911
+ onPlay: e.onPlay,
912
+ onPause: e.onPause,
913
+ onTrackChange: e.onTrackChange,
914
+ onPlaylistChange: e.onPlaylistChange,
915
+ onTimeUpdate: e.onTimeUpdate,
916
+ onEnded: e.onEnded,
917
+ onError: e.onError
918
+ }, this.audio.volume = this.volumeLevel, this.attachEvents(), this.playlist.length > 0 && this.loadTrack(this.currentIndex, !!e.autoplay);
919
+ }
920
+ attachEvents() {
921
+ this.audio.addEventListener("play", this.handlePlay), this.audio.addEventListener("pause", this.handlePause), this.audio.addEventListener("timeupdate", this.handleTimeUpdate), this.audio.addEventListener("progress", this.handleProgress), this.audio.addEventListener("ended", this.handleEnded), this.audio.addEventListener("error", this.handleError), this.audio.addEventListener("waiting", this.handleWaiting), this.audio.addEventListener("playing", this.handlePlaying), this.audio.addEventListener("loadedmetadata", this.handleLoadedMetadata);
922
+ }
923
+ detachEvents() {
924
+ this.audio.removeEventListener("play", this.handlePlay), this.audio.removeEventListener("pause", this.handlePause), this.audio.removeEventListener("timeupdate", this.handleTimeUpdate), this.audio.removeEventListener("progress", this.handleProgress), this.audio.removeEventListener("ended", this.handleEnded), this.audio.removeEventListener("error", this.handleError), this.audio.removeEventListener("waiting", this.handleWaiting), this.audio.removeEventListener("playing", this.handlePlaying), this.audio.removeEventListener("loadedmetadata", this.handleLoadedMetadata);
925
+ }
926
+ getCurrentTrack() {
927
+ return this.playlist[this.currentIndex];
928
+ }
929
+ getCurrentIndex() {
930
+ return this.currentIndex;
931
+ }
932
+ getPlaylist() {
933
+ return this.playlist;
934
+ }
935
+ setPlaylist(e, i = 0) {
936
+ this.playlist = [...e], this.currentIndex = u(i, 0, Math.max(0, this.playlist.length - 1)), this.loadTrack(this.currentIndex, !1), this.callbacks.onPlaylistChange && this.callbacks.onPlaylistChange([...this.playlist], this.currentIndex), this.playlist.length > 0 ? this.loadTrack(this.currentIndex, !1) : (this.audio.pause(), this.audio.src = "", this.callbacks.onTrackChange && this.callbacks.onTrackChange({ title: "No Track Loaded", src: "" }, 0));
937
+ }
938
+ addTrack(e, i = !1) {
939
+ const t = this.playlist.length === 0;
940
+ this.playlist.push(e);
941
+ const a = this.playlist.length - 1;
942
+ return this.callbacks.onPlaylistChange && this.callbacks.onPlaylistChange([...this.playlist], this.currentIndex), t ? this.loadTrack(0, i) : i && this.loadTrack(a, !0), a;
943
+ }
944
+ addTracks(e, i = !1) {
945
+ if (!e || e.length === 0) return;
946
+ const t = this.playlist.length === 0, a = this.playlist.length;
947
+ this.playlist.push(...e), this.callbacks.onPlaylistChange && this.callbacks.onPlaylistChange([...this.playlist], this.currentIndex), t ? this.loadTrack(0, i) : i && this.loadTrack(a, !0);
948
+ }
949
+ removeTrack(e) {
950
+ if (e < 0 || e >= this.playlist.length) return;
951
+ const i = e === this.currentIndex;
952
+ if (this.playlist.splice(e, 1), this.playlist.length === 0)
953
+ this.currentIndex = 0, this.audio.pause(), this.audio.src = "", this.callbacks.onTrackChange && this.callbacks.onTrackChange({ title: "No Track Loaded", src: "" }, 0);
954
+ else if (i) {
955
+ const t = u(e, 0, this.playlist.length - 1);
956
+ this.loadTrack(t, !1);
957
+ } else e < this.currentIndex && this.currentIndex--;
958
+ this.callbacks.onPlaylistChange && this.callbacks.onPlaylistChange([...this.playlist], this.currentIndex);
959
+ }
960
+ getDuration() {
961
+ const e = this.audio.duration;
962
+ if (e && !isNaN(e) && isFinite(e))
963
+ return e;
964
+ const i = this.getCurrentTrack();
965
+ return (i == null ? void 0 : i.duration) || 0;
966
+ }
967
+ getCurrentTime() {
968
+ return this.audio.currentTime || 0;
969
+ }
970
+ isPlaying() {
971
+ return !this.audio.paused && !this.audio.ended;
972
+ }
973
+ isMuted() {
974
+ return this.audio.muted || this.audio.volume === 0;
975
+ }
976
+ getVolume() {
977
+ return this.audio.volume;
978
+ }
979
+ getLoop() {
980
+ return this.loopMode;
981
+ }
982
+ isShuffle() {
983
+ return this.shuffleMode;
984
+ }
985
+ loadTrack(e, i = !1) {
986
+ let t;
987
+ typeof e == "number" ? t = u(e, 0, Math.max(0, this.playlist.length - 1)) : (t = this.playlist.findIndex((s) => s.src === e.src), t === -1 && (this.playlist.push(e), t = this.playlist.length - 1)), this.currentIndex = t;
988
+ const a = this.playlist[this.currentIndex];
989
+ a && (this.audio.src = a.src, this.callbacks.onTrackChange && this.callbacks.onTrackChange(a, this.currentIndex), i && this.play());
990
+ }
991
+ async play() {
992
+ try {
993
+ await this.audio.play();
994
+ } catch (e) {
995
+ console.warn("[HoregAudio] Autoplay / Audio play was prevented by browser policy:", e);
996
+ }
997
+ }
998
+ pause() {
999
+ this.audio.pause();
1000
+ }
1001
+ toggle() {
1002
+ this.audio.paused ? this.play() : this.pause();
1003
+ }
1004
+ seek(e) {
1005
+ const i = this.getDuration(), t = u(e, 0, i > 0 ? i : 1 / 0);
1006
+ this.audio.currentTime = t;
1007
+ }
1008
+ setVolume(e) {
1009
+ const i = u(e, 0, 1);
1010
+ this.volumeLevel = i, this.audio.volume = i, i > 0 && (this.audio.muted = !1, this.previousVolume = i);
1011
+ }
1012
+ toggleMute() {
1013
+ return this.isMuted() ? (this.audio.muted = !1, this.setVolume(this.previousVolume > 0 ? this.previousVolume : 0.5), !1) : (this.previousVolume = this.audio.volume, this.audio.muted = !0, !0);
1014
+ }
1015
+ next(e = !1) {
1016
+ if (this.playlist.length === 0) return;
1017
+ if (this.shuffleMode && this.playlist.length > 1) {
1018
+ let t;
1019
+ do
1020
+ t = Math.floor(Math.random() * this.playlist.length);
1021
+ while (t === this.currentIndex);
1022
+ this.loadTrack(t, !0);
1023
+ return;
1024
+ }
1025
+ const i = this.currentIndex + 1;
1026
+ i < this.playlist.length ? this.loadTrack(i, !0) : this.loopMode === "all" ? this.loadTrack(0, !0) : e ? this.pause() : this.loadTrack(0, !0);
1027
+ }
1028
+ prev() {
1029
+ if (this.playlist.length === 0) return;
1030
+ if (this.audio.currentTime > 2) {
1031
+ this.seek(0);
1032
+ return;
1033
+ }
1034
+ if (this.shuffleMode && this.playlist.length > 1) {
1035
+ let i;
1036
+ do
1037
+ i = Math.floor(Math.random() * this.playlist.length);
1038
+ while (i === this.currentIndex);
1039
+ this.loadTrack(i, !0);
1040
+ return;
1041
+ }
1042
+ const e = this.currentIndex - 1;
1043
+ e >= 0 ? this.loadTrack(e, !0) : this.loopMode === "all" ? this.loadTrack(this.playlist.length - 1, !0) : this.seek(0);
1044
+ }
1045
+ setLoop(e) {
1046
+ this.loopMode = e;
1047
+ }
1048
+ setShuffle(e) {
1049
+ this.shuffleMode = e;
1050
+ }
1051
+ setCallbacks(e) {
1052
+ this.callbacks = { ...this.callbacks, ...e };
1053
+ }
1054
+ destroy() {
1055
+ this.detachEvents(), this.audio.pause(), this.audio.src = "", this.audio.load();
1056
+ }
1057
+ }
1058
+ const d = {
1059
+ play: '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M8 5v14l11-7z"/></svg>',
1060
+ pause: '<svg viewBox="0 0 24 24" fill="currentColor" width="20" height="20"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>',
1061
+ prev: '<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/></svg>',
1062
+ next: '<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>',
1063
+ volumeHigh: '<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/></svg>',
1064
+ volumeMute: '<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27l4.73 4.73H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/></svg>',
1065
+ shuffle: '<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M10.59 9.17L5.41 4 4 5.41l5.17 5.17 1.42-1.41zM14.5 4l2.04 2.04L4 18.59 5.41 20 17.96 7.46 20 9.5V4h-5.5zm.33 9.41l-1.41 1.41 3.13 3.13L14.5 20H20v-5.5l-2.04 2.04-3.13-3.13z"/></svg>',
1066
+ repeat: '<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4z"/></svg>',
1067
+ repeatOne: '<svg viewBox="0 0 24 24" fill="currentColor" width="16" height="16"><path d="M7 7h10v3l4-4-4-4v3H5v6h2V7zm10 10H7v-3l-4 4 4 4v-3h12v-6h-2v4zm-4-2V9h-1l-2 1v1h1.5v4H13z"/></svg>',
1068
+ playlist: '<svg viewBox="0 0 24 24" fill="currentColor" width="18" height="18"><path d="M3 10h11v2H3zm0-4h11v2H3zm0 8h7v2H3zm13-1v8l6-4-6-4z"/></svg>',
1069
+ speaker: '<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M17 2H7c-1.1 0-2 .9-2 2v16c0 1.1.9 1.99 2 1.99L17 22c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-5 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm0 16c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg>',
1070
+ plus: '<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>',
1071
+ trash: '<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>',
1072
+ upload: '<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"/></svg>',
1073
+ link: '<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7c-2.76 0-5 2.24-5 5s2.24 5 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1zM8 13h8v-2H8v2zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4c2.76 0 5-2.24 5-5s-2.24-5-5-5z"/></svg>'
1074
+ };
1075
+ function o(l, e) {
1076
+ const i = document.createElement(l);
1077
+ if (e != null && e.className && (i.className = e.className), e != null && e.attributes)
1078
+ for (const [t, a] of Object.entries(e.attributes))
1079
+ i.setAttribute(t, a);
1080
+ return e != null && e.innerHTML ? i.innerHTML = e.innerHTML : e != null && e.textContent && (i.textContent = e.textContent), i;
1081
+ }
1082
+ class I {
1083
+ constructor(e) {
1084
+ r(this, "root");
1085
+ r(this, "eqContainer");
1086
+ r(this, "playBtn");
1087
+ r(this, "prevBtn");
1088
+ r(this, "nextBtn");
1089
+ r(this, "shuffleBtn");
1090
+ r(this, "loopBtn");
1091
+ r(this, "muteBtn");
1092
+ r(this, "drawerBtn");
1093
+ r(this, "titleEl");
1094
+ r(this, "artistEl");
1095
+ r(this, "albumEl");
1096
+ r(this, "coverImgEl", null);
1097
+ r(this, "coverContainer");
1098
+ r(this, "currentTimeEl");
1099
+ r(this, "durationEl");
1100
+ r(this, "sliderTrack");
1101
+ r(this, "fillBar");
1102
+ r(this, "bufferBar");
1103
+ r(this, "volumeSlider");
1104
+ r(this, "drawerEl");
1105
+ r(this, "drawerCountEl");
1106
+ r(this, "addTrackBtn");
1107
+ r(this, "addPanelEl");
1108
+ r(this, "fileInputEl");
1109
+ r(this, "tabBtnFile");
1110
+ r(this, "tabBtnUrl");
1111
+ r(this, "tabPaneFile");
1112
+ r(this, "tabPaneUrl");
1113
+ r(this, "urlInput");
1114
+ r(this, "titleInput");
1115
+ r(this, "artistInput");
1116
+ r(this, "submitUrlBtn");
1117
+ r(this, "cancelAddBtn");
1118
+ r(this, "dropzoneEl");
1119
+ r(this, "drawerInner");
1120
+ r(this, "isScrubbing", !1);
1121
+ r(this, "currentDuration", 0);
1122
+ r(this, "events");
1123
+ r(this, "startScrubbing", (e) => {
1124
+ e.preventDefault(), this.isScrubbing = !0, this.handleScrubbingMove(e);
1125
+ const i = (a) => {
1126
+ this.isScrubbing && this.handleScrubbingMove(a);
1127
+ }, t = (a) => {
1128
+ this.isScrubbing && (this.isScrubbing = !1, this.finishScrubbing(a), window.removeEventListener("mousemove", i), window.removeEventListener("mouseup", t), window.removeEventListener("touchmove", i), window.removeEventListener("touchend", t));
1129
+ };
1130
+ window.addEventListener("mousemove", i), window.addEventListener("mouseup", t), window.addEventListener("touchmove", i, { passive: !1 }), window.addEventListener("touchend", t);
1131
+ });
1132
+ this.events = e, this.root = o("div", { className: "horeg-player-box" });
1133
+ const i = o("div", { className: "horeg-speaker-grill" });
1134
+ this.root.appendChild(i), ["top-left", "top-right", "bottom-left", "bottom-right"].forEach((L) => {
1135
+ this.root.appendChild(o("div", { className: `horeg-bolt ${L}` }));
1136
+ });
1137
+ const t = o("div", { className: "horeg-content-wrap" });
1138
+ this.root.appendChild(t);
1139
+ const a = o("div", { className: "horeg-header" }), s = o("div", {
1140
+ className: "horeg-rig-badge",
1141
+ innerHTML: '<span class="horeg-badge-led"></span> HOREG RIG • HIGH VOLTAGE'
1142
+ });
1143
+ a.appendChild(s), t.appendChild(a);
1144
+ const n = o("div", { className: "horeg-track-row" });
1145
+ this.coverContainer = o("div", { className: "horeg-cover-container" }), this.coverContainer.innerHTML = `<span class="horeg-cover-fallback">${d.speaker}</span>`, n.appendChild(this.coverContainer);
1146
+ const c = o("div", { className: "horeg-track-info" });
1147
+ this.titleEl = o("div", { className: "horeg-track-title", textContent: "No Track Loaded" }), this.artistEl = o("div", { className: "horeg-track-artist", textContent: "Unknown Artist" }), this.albumEl = o("div", { className: "horeg-track-album", textContent: "" }), c.appendChild(this.titleEl), c.appendChild(this.artistEl), c.appendChild(this.albumEl), n.appendChild(c), this.eqContainer = o("div", { className: "horeg-eq-wrapper" }), n.appendChild(this.eqContainer), t.appendChild(n);
1148
+ const h = o("div", { className: "horeg-progress-container" }), g = o("div", { className: "horeg-time-row" });
1149
+ this.currentTimeEl = o("span", { textContent: "00:00" }), this.durationEl = o("span", { textContent: "00:00" }), g.appendChild(this.currentTimeEl), g.appendChild(this.durationEl), h.appendChild(g), this.sliderTrack = o("div", {
1150
+ className: "horeg-slider-track",
1151
+ attributes: {
1152
+ role: "slider",
1153
+ "aria-label": "Seek progress",
1154
+ "aria-valuemin": "0",
1155
+ "aria-valuemax": "100",
1156
+ "aria-valuenow": "0",
1157
+ tabindex: "0"
1158
+ }
1159
+ }), this.bufferBar = o("div", { className: "horeg-buffer-bar" }), this.fillBar = o("div", { className: "horeg-fill-bar" }), this.sliderTrack.appendChild(this.bufferBar), this.sliderTrack.appendChild(this.fillBar), h.appendChild(this.sliderTrack), t.appendChild(h);
1160
+ const p = o("div", { className: "horeg-controls-row" }), f = o("div", { className: "horeg-side-controls" });
1161
+ this.shuffleBtn = o("button", {
1162
+ className: "horeg-btn",
1163
+ attributes: { "aria-label": "Toggle shuffle", type: "button" },
1164
+ innerHTML: d.shuffle
1165
+ }), this.loopBtn = o("button", {
1166
+ className: "horeg-btn active",
1167
+ attributes: { "aria-label": "Toggle loop mode", type: "button" },
1168
+ innerHTML: d.repeat
1169
+ }), f.appendChild(this.shuffleBtn), f.appendChild(this.loopBtn), p.appendChild(f);
1170
+ const v = o("div", { className: "horeg-center-controls" });
1171
+ this.prevBtn = o("button", {
1172
+ className: "horeg-btn",
1173
+ attributes: { "aria-label": "Previous track", type: "button" },
1174
+ innerHTML: d.prev
1175
+ }), this.playBtn = o("button", {
1176
+ className: "horeg-btn horeg-btn-play",
1177
+ attributes: { "aria-label": "Play track", type: "button" },
1178
+ innerHTML: d.play
1179
+ }), this.nextBtn = o("button", {
1180
+ className: "horeg-btn",
1181
+ attributes: { "aria-label": "Next track", type: "button" },
1182
+ innerHTML: d.next
1183
+ }), v.appendChild(this.prevBtn), v.appendChild(this.playBtn), v.appendChild(this.nextBtn), p.appendChild(v);
1184
+ const m = o("div", { className: "horeg-side-controls" }), x = o("div", { className: "horeg-volume-wrap" });
1185
+ this.muteBtn = o("button", {
1186
+ className: "horeg-btn",
1187
+ attributes: { "aria-label": "Toggle mute", type: "button" },
1188
+ innerHTML: d.volumeHigh
1189
+ }), this.volumeSlider = o("input", {
1190
+ className: "horeg-volume-slider",
1191
+ attributes: {
1192
+ type: "range",
1193
+ min: "0",
1194
+ max: "1",
1195
+ step: "0.01",
1196
+ value: "0.8",
1197
+ "aria-label": "Volume control"
1198
+ }
1199
+ }), x.appendChild(this.muteBtn), x.appendChild(this.volumeSlider), m.appendChild(x), this.drawerBtn = o("button", {
1200
+ className: "horeg-btn",
1201
+ attributes: { "aria-label": "Toggle playlist drawer", type: "button" },
1202
+ innerHTML: d.playlist
1203
+ }), m.appendChild(this.drawerBtn), p.appendChild(m), t.appendChild(p), this.drawerEl = o("div", { className: "horeg-drawer" });
1204
+ const w = o("div", { className: "horeg-drawer-header" }), y = o("div", { className: "horeg-drawer-heading" });
1205
+ y.innerHTML = "<span>PLAYLIST</span>", this.drawerCountEl = o("span", { className: "horeg-drawer-count", textContent: "0" }), y.appendChild(this.drawerCountEl), w.appendChild(y), this.addTrackBtn = o("button", {
1206
+ className: "horeg-btn-add-track",
1207
+ attributes: { type: "button", "aria-label": "Add track to playlist" },
1208
+ innerHTML: `${d.plus} <span>Add Track</span>`
1209
+ }), w.appendChild(this.addTrackBtn), this.drawerEl.appendChild(w), this.addPanelEl = o("div", { className: "horeg-add-panel" });
1210
+ const k = o("div", { className: "horeg-add-tabs" });
1211
+ this.tabBtnFile = o("button", {
1212
+ className: "horeg-tab-btn active",
1213
+ attributes: { type: "button" },
1214
+ innerHTML: `${d.upload} <span>File Lokal</span>`
1215
+ }), this.tabBtnUrl = o("button", {
1216
+ className: "horeg-tab-btn",
1217
+ attributes: { type: "button" },
1218
+ innerHTML: `${d.link} <span>Audio URL</span>`
1219
+ }), k.appendChild(this.tabBtnFile), k.appendChild(this.tabBtnUrl), this.addPanelEl.appendChild(k), this.tabPaneFile = o("div", { className: "horeg-tab-pane active" }), this.fileInputEl = o("input", {
1220
+ attributes: { type: "file", accept: "audio/*", multiple: "true", style: "display: none;" }
1221
+ }), this.dropzoneEl = o("div", { className: "horeg-dropzone" }), this.dropzoneEl.innerHTML = `
1222
+ <div class="horeg-dropzone-icon">${d.upload}</div>
1223
+ <div class="horeg-dropzone-text">Pilih File Audio Komputer</div>
1224
+ <div class="horeg-dropzone-hint">Klik di sini atau drag & drop file (.mp3, .wav, .flac, .ogg, .m4a)</div>
1225
+ `, this.tabPaneFile.appendChild(this.fileInputEl), this.tabPaneFile.appendChild(this.dropzoneEl), this.addPanelEl.appendChild(this.tabPaneFile), this.tabPaneUrl = o("div", { className: "horeg-tab-pane" }), this.urlInput = o("input", {
1226
+ className: "horeg-input-field",
1227
+ attributes: { type: "url", placeholder: "Audio URL (https://...mp3/wav)", required: "true" }
1228
+ }), this.titleInput = o("input", {
1229
+ className: "horeg-input-field",
1230
+ attributes: { type: "text", placeholder: "Judul Lagu (Opsional)" }
1231
+ }), this.artistInput = o("input", {
1232
+ className: "horeg-input-field",
1233
+ attributes: { type: "text", placeholder: "Nama Artis (Opsional)" }
1234
+ });
1235
+ const E = o("div", { className: "horeg-form-actions" });
1236
+ this.cancelAddBtn = o("button", {
1237
+ className: "horeg-btn-cancel",
1238
+ attributes: { type: "button" },
1239
+ textContent: "Batal"
1240
+ }), this.submitUrlBtn = o("button", {
1241
+ className: "horeg-btn-submit",
1242
+ attributes: { type: "button" },
1243
+ innerHTML: `${d.plus} Tambah`
1244
+ }), E.appendChild(this.cancelAddBtn), E.appendChild(this.submitUrlBtn), this.tabPaneUrl.appendChild(this.urlInput), this.tabPaneUrl.appendChild(this.titleInput), this.tabPaneUrl.appendChild(this.artistInput), this.tabPaneUrl.appendChild(E), this.addPanelEl.appendChild(this.tabPaneUrl), this.drawerEl.appendChild(this.addPanelEl), this.drawerInner = o("div", { className: "horeg-drawer-inner" }), this.drawerEl.appendChild(this.drawerInner), this.root.appendChild(this.drawerEl), this.bindDOMEvents();
1245
+ }
1246
+ bindDOMEvents() {
1247
+ this.playBtn.addEventListener("click", () => this.events.onPlayPauseClick()), this.prevBtn.addEventListener("click", () => this.events.onPrevClick()), this.nextBtn.addEventListener("click", () => this.events.onNextClick()), this.shuffleBtn.addEventListener("click", () => this.events.onShuffleToggle()), this.loopBtn.addEventListener("click", () => this.events.onLoopToggle()), this.muteBtn.addEventListener("click", () => this.events.onMuteToggle()), this.volumeSlider.addEventListener("input", () => {
1248
+ this.events.onVolumeChange(parseFloat(this.volumeSlider.value));
1249
+ }), this.drawerBtn.addEventListener("click", () => {
1250
+ this.toggleDrawer();
1251
+ }), this.addTrackBtn.addEventListener("click", () => {
1252
+ const t = this.addPanelEl.classList.toggle("open");
1253
+ this.addTrackBtn.classList.toggle("active", t), t && this.toggleDrawer(!0);
1254
+ }), this.tabBtnFile.addEventListener("click", () => {
1255
+ this.tabBtnFile.classList.add("active"), this.tabBtnUrl.classList.remove("active"), this.tabPaneFile.classList.add("active"), this.tabPaneUrl.classList.remove("active");
1256
+ }), this.tabBtnUrl.addEventListener("click", () => {
1257
+ this.tabBtnUrl.classList.add("active"), this.tabBtnFile.classList.remove("active"), this.tabPaneUrl.classList.add("active"), this.tabPaneFile.classList.remove("active"), this.urlInput.focus();
1258
+ }), this.dropzoneEl.addEventListener("click", () => {
1259
+ this.fileInputEl.click();
1260
+ }), this.fileInputEl.addEventListener("change", () => {
1261
+ if (this.fileInputEl.files && this.fileInputEl.files.length > 0) {
1262
+ const t = Array.from(this.fileInputEl.files);
1263
+ this.events.onAddTrackFiles && this.events.onAddTrackFiles(t), this.fileInputEl.value = "", this.closeAddPanel();
1264
+ }
1265
+ }), this.dropzoneEl.addEventListener("dragover", (t) => {
1266
+ t.preventDefault(), this.dropzoneEl.classList.add("drag-active");
1267
+ }), this.dropzoneEl.addEventListener("dragleave", () => {
1268
+ this.dropzoneEl.classList.remove("drag-active");
1269
+ }), this.dropzoneEl.addEventListener("drop", (t) => {
1270
+ var a;
1271
+ if (t.preventDefault(), this.dropzoneEl.classList.remove("drag-active"), (a = t.dataTransfer) != null && a.files && t.dataTransfer.files.length > 0) {
1272
+ const s = Array.from(t.dataTransfer.files).filter(
1273
+ (n) => n.type.startsWith("audio/") || /\.(mp3|wav|ogg|flac|m4a|aac)$/i.test(n.name)
1274
+ );
1275
+ s.length > 0 && this.events.onAddTrackFiles && (this.events.onAddTrackFiles(s), this.closeAddPanel());
1276
+ }
1277
+ }), this.root.addEventListener("dragover", (t) => {
1278
+ t.preventDefault(), this.root.classList.add("drag-over");
1279
+ }), this.root.addEventListener("dragleave", (t) => {
1280
+ this.root.contains(t.relatedTarget) || this.root.classList.remove("drag-over");
1281
+ }), this.root.addEventListener("drop", (t) => {
1282
+ var a;
1283
+ if (t.preventDefault(), this.root.classList.remove("drag-over"), (a = t.dataTransfer) != null && a.files && t.dataTransfer.files.length > 0) {
1284
+ const s = Array.from(t.dataTransfer.files).filter(
1285
+ (n) => n.type.startsWith("audio/") || /\.(mp3|wav|ogg|flac|m4a|aac)$/i.test(n.name)
1286
+ );
1287
+ s.length > 0 && this.events.onAddTrackFiles && (this.events.onAddTrackFiles(s), this.closeAddPanel());
1288
+ }
1289
+ });
1290
+ const e = () => {
1291
+ const t = this.urlInput.value.trim();
1292
+ if (!t) {
1293
+ this.urlInput.focus();
1294
+ return;
1295
+ }
1296
+ const a = this.titleInput.value.trim(), s = this.artistInput.value.trim();
1297
+ this.events.onAddTrackUrl && this.events.onAddTrackUrl(t, a || void 0, s || void 0), this.urlInput.value = "", this.titleInput.value = "", this.artistInput.value = "", this.closeAddPanel();
1298
+ };
1299
+ this.submitUrlBtn.addEventListener("click", e);
1300
+ const i = (t) => {
1301
+ t.stopPropagation(), t.key === "Enter" && (t.preventDefault(), e());
1302
+ };
1303
+ this.urlInput.addEventListener("keydown", i), this.titleInput.addEventListener("keydown", i), this.artistInput.addEventListener("keydown", i), this.cancelAddBtn.addEventListener("click", () => {
1304
+ this.closeAddPanel();
1305
+ }), this.sliderTrack.addEventListener("mousedown", this.startScrubbing), this.sliderTrack.addEventListener("touchstart", this.startScrubbing, { passive: !1 }), this.sliderTrack.addEventListener("keydown", (t) => {
1306
+ if (this.currentDuration) {
1307
+ if (t.key === "ArrowRight" || t.key === "ArrowUp") {
1308
+ t.preventDefault();
1309
+ const a = parseFloat(this.fillBar.style.width) / 100 * this.currentDuration;
1310
+ this.events.onSeek(Math.min(a + 5, this.currentDuration));
1311
+ } else if (t.key === "ArrowLeft" || t.key === "ArrowDown") {
1312
+ t.preventDefault();
1313
+ const a = parseFloat(this.fillBar.style.width) / 100 * this.currentDuration;
1314
+ this.events.onSeek(Math.max(a - 5, 0));
1315
+ }
1316
+ }
1317
+ });
1318
+ }
1319
+ calculateProgressPercent(e) {
1320
+ const i = this.sliderTrack.getBoundingClientRect(), t = "touches" in e ? (e.touches[0] || e.changedTouches[0]).clientX : e.clientX, a = u(t - i.left, 0, i.width);
1321
+ return i.width > 0 ? a / i.width * 100 : 0;
1322
+ }
1323
+ handleScrubbingMove(e) {
1324
+ const i = this.calculateProgressPercent(e);
1325
+ if (this.fillBar.style.width = `${i}%`, this.currentDuration > 0) {
1326
+ const t = i / 100 * this.currentDuration;
1327
+ this.currentTimeEl.textContent = b(t);
1328
+ }
1329
+ }
1330
+ finishScrubbing(e) {
1331
+ const i = this.calculateProgressPercent(e);
1332
+ if (this.currentDuration > 0) {
1333
+ const t = i / 100 * this.currentDuration;
1334
+ this.events.onSeek(t);
1335
+ }
1336
+ }
1337
+ updateTrackInfo(e) {
1338
+ this.titleEl.textContent = e.title || "Untitled Track", this.artistEl.textContent = e.artist || "Unknown Artist", this.albumEl.textContent = e.album || "", e.coverArt ? (this.coverContainer.innerHTML = "", this.coverImgEl = o("img", {
1339
+ className: "horeg-cover-img",
1340
+ attributes: {
1341
+ src: e.coverArt,
1342
+ alt: `${e.title} cover`
1343
+ }
1344
+ }), this.coverImgEl.onerror = () => {
1345
+ this.coverContainer.innerHTML = `<span class="horeg-cover-fallback">${d.speaker}</span>`;
1346
+ }, this.coverContainer.appendChild(this.coverImgEl)) : this.coverContainer.innerHTML = `<span class="horeg-cover-fallback">${d.speaker}</span>`;
1347
+ }
1348
+ updatePlayState(e) {
1349
+ e ? (this.playBtn.classList.add("playing"), this.playBtn.innerHTML = d.pause, this.playBtn.setAttribute("aria-label", "Pause track")) : (this.playBtn.classList.remove("playing"), this.playBtn.innerHTML = d.play, this.playBtn.setAttribute("aria-label", "Play track"));
1350
+ }
1351
+ updateProgress(e, i) {
1352
+ if (this.currentDuration = i, this.durationEl.textContent = b(i), !this.isScrubbing) {
1353
+ this.currentTimeEl.textContent = b(e);
1354
+ const t = i > 0 ? e / i * 100 : 0;
1355
+ this.fillBar.style.width = `${u(t, 0, 100)}%`, this.sliderTrack.setAttribute("aria-valuenow", Math.round(t).toString());
1356
+ }
1357
+ }
1358
+ updateBuffer(e) {
1359
+ this.bufferBar.style.width = `${u(e, 0, 100)}%`;
1360
+ }
1361
+ updateVolume(e, i) {
1362
+ this.volumeSlider.value = e.toString(), i || e === 0 ? (this.muteBtn.innerHTML = d.volumeMute, this.muteBtn.setAttribute("aria-label", "Unmute")) : (this.muteBtn.innerHTML = d.volumeHigh, this.muteBtn.setAttribute("aria-label", "Mute"));
1363
+ }
1364
+ updateLoopState(e) {
1365
+ e === "none" ? (this.loopBtn.classList.remove("active"), this.loopBtn.innerHTML = d.repeat) : e === "all" ? (this.loopBtn.classList.add("active"), this.loopBtn.innerHTML = d.repeat) : e === "one" && (this.loopBtn.classList.add("active"), this.loopBtn.innerHTML = d.repeatOne), this.loopBtn.setAttribute("aria-label", `Repeat mode: ${e}`);
1366
+ }
1367
+ updateShuffleState(e) {
1368
+ e ? this.shuffleBtn.classList.add("active") : this.shuffleBtn.classList.remove("active");
1369
+ }
1370
+ toggleDrawer(e) {
1371
+ (e !== void 0 ? e : !this.drawerEl.classList.contains("open")) ? (this.drawerEl.classList.add("open"), this.drawerBtn.classList.add("active")) : (this.drawerEl.classList.remove("open"), this.drawerBtn.classList.remove("active"), this.closeAddPanel());
1372
+ }
1373
+ closeAddPanel() {
1374
+ this.addPanelEl.classList.remove("open"), this.addTrackBtn.classList.remove("active");
1375
+ }
1376
+ renderPlaylist(e, i) {
1377
+ if (this.drawerCountEl.textContent = e.length.toString(), this.drawerInner.innerHTML = "", e.length === 0) {
1378
+ const t = o("div", {
1379
+ className: "horeg-empty-playlist",
1380
+ textContent: 'Playlist masih kosong. Klik "Add Track" untuk menambahkan lagu.'
1381
+ });
1382
+ this.drawerInner.appendChild(t);
1383
+ return;
1384
+ }
1385
+ e.forEach((t, a) => {
1386
+ const s = o("div", {
1387
+ className: `horeg-track-item ${a === i ? "active" : ""}`
1388
+ }), n = o("div", {
1389
+ className: "horeg-track-num",
1390
+ textContent: (a + 1).toString().padStart(2, "0")
1391
+ });
1392
+ s.appendChild(n);
1393
+ const c = o("div", { className: "horeg-track-details" }), h = o("div", {
1394
+ className: "horeg-item-title",
1395
+ textContent: t.title
1396
+ }), g = o("div", {
1397
+ className: "horeg-item-artist",
1398
+ textContent: t.artist || "Unknown Artist"
1399
+ });
1400
+ if (c.appendChild(h), c.appendChild(g), s.appendChild(c), t.duration) {
1401
+ const v = o("div", {
1402
+ className: "horeg-item-duration",
1403
+ textContent: b(t.duration)
1404
+ });
1405
+ s.appendChild(v);
1406
+ }
1407
+ const p = o("div", { className: "horeg-track-actions" }), f = o("button", {
1408
+ className: "horeg-btn-remove",
1409
+ attributes: { type: "button", "aria-label": "Hapus lagu dari playlist" },
1410
+ innerHTML: d.trash
1411
+ });
1412
+ f.addEventListener("click", (v) => {
1413
+ v.stopPropagation(), this.events.onRemoveTrack && this.events.onRemoveTrack(a);
1414
+ }), p.appendChild(f), s.appendChild(p), s.addEventListener("click", () => {
1415
+ this.events.onTrackSelect(a);
1416
+ }), this.drawerInner.appendChild(s);
1417
+ });
1418
+ }
1419
+ destroy() {
1420
+ this.root.remove();
1421
+ }
1422
+ }
1423
+ class z {
1424
+ constructor(e) {
1425
+ r(this, "container");
1426
+ r(this, "bars", []);
1427
+ r(this, "isRunning", !1);
1428
+ r(this, "animFrameId", null);
1429
+ r(this, "isEnabled", !0);
1430
+ r(this, "baseHeights", []);
1431
+ r(this, "loop", () => {
1432
+ if (!this.isRunning) return;
1433
+ const e = Date.now() / 150;
1434
+ for (let i = 0; i < this.bars.length; i++) {
1435
+ const t = Math.sin(e * 1.8 + i * 1.2), a = Math.cos(e * 2.5 + i * 0.8), s = Math.abs(t * 0.6 + a * 0.4), n = Math.floor(4 + s * 18);
1436
+ this.bars[i].style.height = `${n}px`;
1437
+ }
1438
+ this.animFrameId = requestAnimationFrame(this.loop);
1439
+ });
1440
+ this.container = e.container, this.isEnabled = e.enableAnimation !== !1;
1441
+ const i = e.barCount || 5;
1442
+ this.initBars(i);
1443
+ }
1444
+ initBars(e) {
1445
+ this.container.innerHTML = "", this.bars = [], this.baseHeights = [];
1446
+ for (let i = 0; i < e; i++) {
1447
+ const t = document.createElement("span");
1448
+ t.className = "horeg-eq-bar", this.container.appendChild(t), this.bars.push(t), this.baseHeights.push(3 + i % 2 * 2), t.style.height = `${this.baseHeights[i]}px`;
1449
+ }
1450
+ }
1451
+ setEnabled(e) {
1452
+ this.isEnabled = e, e || this.stop();
1453
+ }
1454
+ start() {
1455
+ this.isRunning || !this.isEnabled || (this.isRunning = !0, this.loop());
1456
+ }
1457
+ stop() {
1458
+ this.isRunning = !1, this.animFrameId !== null && (cancelAnimationFrame(this.animFrameId), this.animFrameId = null);
1459
+ for (let e = 0; e < this.bars.length; e++)
1460
+ this.bars[e].style.height = `${this.baseHeights[e] || 3}px`;
1461
+ }
1462
+ destroy() {
1463
+ this.stop(), this.bars = [], this.container.innerHTML = "";
1464
+ }
1465
+ }
1466
+ class N {
1467
+ constructor(e) {
1468
+ r(this, "container");
1469
+ r(this, "shadow");
1470
+ r(this, "styleEl");
1471
+ r(this, "audioEngine");
1472
+ r(this, "ui");
1473
+ r(this, "visualizer");
1474
+ r(this, "theme");
1475
+ r(this, "boundKeyHandler");
1476
+ if (typeof e.container == "string") {
1477
+ const t = document.querySelector(e.container);
1478
+ if (!t)
1479
+ throw new Error(`[HoregAudio] Container "${e.container}" not found in DOM.`);
1480
+ this.container = t;
1481
+ } else if (e.container instanceof HTMLElement)
1482
+ this.container = e.container;
1483
+ else
1484
+ throw new Error("[HoregAudio] Invalid container option provided.");
1485
+ this.theme = e.theme || { variant: "horeg-classic" }, this.shadow = this.container.attachShadow({ mode: "open" }), this.styleEl = document.createElement("style"), this.styleEl.textContent = T(this.theme), this.shadow.appendChild(this.styleEl), this.ui = new I({
1486
+ onPlayPauseClick: () => this.toggle(),
1487
+ onPrevClick: () => this.prev(),
1488
+ onNextClick: () => this.next(),
1489
+ onSeek: (t) => this.seek(t),
1490
+ onVolumeChange: (t) => this.setVolume(t),
1491
+ onMuteToggle: () => {
1492
+ const t = this.audioEngine.toggleMute();
1493
+ this.ui.updateVolume(this.audioEngine.getVolume(), t);
1494
+ },
1495
+ onShuffleToggle: () => {
1496
+ const t = !this.audioEngine.isShuffle();
1497
+ this.audioEngine.setShuffle(t), this.ui.updateShuffleState(t);
1498
+ },
1499
+ onLoopToggle: () => {
1500
+ const t = this.audioEngine.getLoop(), a = t === "all" ? "one" : t === "one" ? "none" : "all";
1501
+ this.audioEngine.setLoop(a), this.ui.updateLoopState(a);
1502
+ },
1503
+ onTrackSelect: (t) => {
1504
+ this.loadTrack(t, !0);
1505
+ },
1506
+ onAddTrackFiles: (t) => {
1507
+ this.addTrackFromFiles(t, !1);
1508
+ },
1509
+ onAddTrackUrl: (t, a, s) => {
1510
+ this.addTrackFromUrl(t, { title: a, artist: s }, !1);
1511
+ },
1512
+ onRemoveTrack: (t) => {
1513
+ this.removeTrack(t);
1514
+ }
1515
+ }), this.shadow.appendChild(this.ui.root), this.visualizer = new z({
1516
+ container: this.ui.eqContainer,
1517
+ enableAnimation: this.theme.enableEqAnimation !== !1
1518
+ }), this.audioEngine = new M(e, {
1519
+ onPlay: (t) => {
1520
+ this.ui.updatePlayState(!0), this.visualizer.start(), e.onPlay && e.onPlay(t);
1521
+ },
1522
+ onPause: () => {
1523
+ this.ui.updatePlayState(!1), this.visualizer.stop(), e.onPause && e.onPause();
1524
+ },
1525
+ onTrackChange: (t, a) => {
1526
+ this.ui.updateTrackInfo(t);
1527
+ const s = this.audioEngine ? this.audioEngine.getPlaylist() : e.playlist || [];
1528
+ this.ui.renderPlaylist(s, a), this.ui.updateProgress(0, t.duration || 0), e.onTrackChange && e.onTrackChange(t, a);
1529
+ },
1530
+ onPlaylistChange: (t, a) => {
1531
+ this.ui.renderPlaylist(t, a), e.onPlaylistChange && e.onPlaylistChange(t, a);
1532
+ },
1533
+ onTimeUpdate: (t, a) => {
1534
+ this.ui.updateProgress(t, a), e.onTimeUpdate && e.onTimeUpdate(t, a);
1535
+ },
1536
+ onBufferUpdate: (t) => {
1537
+ this.ui.updateBuffer(t);
1538
+ },
1539
+ onEnded: (t) => {
1540
+ this.visualizer.stop(), e.onEnded && e.onEnded(t);
1541
+ },
1542
+ onError: (t) => {
1543
+ this.ui.updatePlayState(!1), this.visualizer.stop(), e.onError && e.onError(t);
1544
+ }
1545
+ }), this.ui.updateVolume(this.audioEngine.getVolume(), this.audioEngine.isMuted()), this.ui.updateLoopState(this.audioEngine.getLoop()), this.ui.updateShuffleState(this.audioEngine.isShuffle()), this.ui.renderPlaylist(this.audioEngine.getPlaylist(), this.audioEngine.getCurrentIndex());
1546
+ const i = this.audioEngine.getCurrentTrack();
1547
+ i && (this.ui.updateTrackInfo(i), this.ui.renderPlaylist(this.audioEngine.getPlaylist(), this.audioEngine.getCurrentIndex())), this.boundKeyHandler = this.handleKeyDown.bind(this), this.container.tabIndex = this.container.tabIndex >= 0 ? this.container.tabIndex : 0, this.container.addEventListener("keydown", this.boundKeyHandler);
1548
+ }
1549
+ handleKeyDown(e) {
1550
+ var n;
1551
+ const i = e.composedPath ? e.composedPath() : [], t = i.length > 0 ? i[0] : e.target, a = ((n = this.shadow) == null ? void 0 : n.activeElement) || document.activeElement, s = (c) => {
1552
+ if (!c) return !1;
1553
+ const h = c.tagName;
1554
+ return h === "INPUT" || h === "TEXTAREA" || h === "SELECT" || c.isContentEditable;
1555
+ };
1556
+ if (!(s(t) || s(a)))
1557
+ if (e.code === "Space") {
1558
+ if ((t == null ? void 0 : t.tagName) === "BUTTON" || (a == null ? void 0 : a.tagName) === "BUTTON")
1559
+ return;
1560
+ e.preventDefault(), this.toggle();
1561
+ } else e.key === "ArrowRight" && !e.shiftKey ? (e.preventDefault(), this.seek(this.audioEngine.getCurrentTime() + 5)) : e.key === "ArrowLeft" && !e.shiftKey ? (e.preventDefault(), this.seek(this.audioEngine.getCurrentTime() - 5)) : e.key === "ArrowUp" ? (e.preventDefault(), this.setVolume(this.audioEngine.getVolume() + 0.05)) : e.key === "ArrowDown" && (e.preventDefault(), this.setVolume(this.audioEngine.getVolume() - 0.05));
1562
+ }
1563
+ // --- Public API Methods ---
1564
+ async play() {
1565
+ await this.audioEngine.play();
1566
+ }
1567
+ pause() {
1568
+ this.audioEngine.pause();
1569
+ }
1570
+ toggle() {
1571
+ this.audioEngine.toggle();
1572
+ }
1573
+ next() {
1574
+ this.audioEngine.next();
1575
+ }
1576
+ prev() {
1577
+ this.audioEngine.prev();
1578
+ }
1579
+ seek(e) {
1580
+ this.audioEngine.seek(e);
1581
+ }
1582
+ setVolume(e) {
1583
+ this.audioEngine.setVolume(e), this.ui.updateVolume(this.audioEngine.getVolume(), this.audioEngine.isMuted());
1584
+ }
1585
+ loadTrack(e, i = !1) {
1586
+ this.audioEngine.loadTrack(e, i);
1587
+ }
1588
+ addTrack(e, i = !1) {
1589
+ const t = this.audioEngine.addTrack(e, i);
1590
+ return this.ui.renderPlaylist(this.audioEngine.getPlaylist(), this.audioEngine.getCurrentIndex()), t;
1591
+ }
1592
+ addTracks(e, i = !1) {
1593
+ this.audioEngine.addTracks(e, i), this.ui.renderPlaylist(this.audioEngine.getPlaylist(), this.audioEngine.getCurrentIndex());
1594
+ }
1595
+ async addTrackFromFile(e, i = !1) {
1596
+ const t = URL.createObjectURL(e), a = e.name.replace(/\.[^/.]+$/, ""), s = {
1597
+ id: `local-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`,
1598
+ title: a,
1599
+ artist: "File Audio Lokal",
1600
+ src: t
1601
+ };
1602
+ try {
1603
+ const n = await this.probeAudioDuration(t);
1604
+ n > 0 && (s.duration = n);
1605
+ } catch {
1606
+ }
1607
+ return this.addTrack(s, i), s;
1608
+ }
1609
+ async addTrackFromFiles(e, i = !1) {
1610
+ const t = Array.from(e), a = [];
1611
+ for (let s = 0; s < t.length; s++) {
1612
+ const n = t[s], c = i && s === 0, h = await this.addTrackFromFile(n, c);
1613
+ a.push(h);
1614
+ }
1615
+ return a;
1616
+ }
1617
+ async addTrackFromUrl(e, i = {}, t = !1) {
1618
+ var n, c;
1619
+ let a = "Online Track";
1620
+ try {
1621
+ const g = new URL(e).pathname, p = g.substring(g.lastIndexOf("/") + 1);
1622
+ p && (a = decodeURIComponent(p).replace(/\.[^/.]+$/, ""));
1623
+ } catch {
1624
+ }
1625
+ const s = {
1626
+ id: i.id || `url-${Date.now()}-${Math.random().toString(36).substring(2, 7)}`,
1627
+ title: ((n = i.title) == null ? void 0 : n.trim()) || a,
1628
+ artist: ((c = i.artist) == null ? void 0 : c.trim()) || "Audio Stream",
1629
+ album: i.album,
1630
+ coverArt: i.coverArt,
1631
+ src: e,
1632
+ duration: i.duration
1633
+ };
1634
+ if (!s.duration)
1635
+ try {
1636
+ const h = await this.probeAudioDuration(e);
1637
+ h > 0 && (s.duration = h);
1638
+ } catch {
1639
+ }
1640
+ return this.addTrack(s, t), s;
1641
+ }
1642
+ removeTrack(e) {
1643
+ this.audioEngine.removeTrack(e), this.ui.renderPlaylist(this.audioEngine.getPlaylist(), this.audioEngine.getCurrentIndex());
1644
+ const i = this.audioEngine.getCurrentTrack();
1645
+ i ? this.ui.updateTrackInfo(i) : this.ui.updateTrackInfo({ title: "No Track Loaded", src: "" });
1646
+ }
1647
+ getPlaylist() {
1648
+ return this.audioEngine.getPlaylist();
1649
+ }
1650
+ probeAudioDuration(e) {
1651
+ return new Promise((i) => {
1652
+ const t = new Audio();
1653
+ let a = !1;
1654
+ const s = (h) => {
1655
+ a || (a = !0, t.removeEventListener("loadedmetadata", n), t.removeEventListener("error", c), t.src = "", i(h));
1656
+ }, n = () => {
1657
+ const h = t.duration;
1658
+ s(h && !isNaN(h) && isFinite(h) ? h : 0);
1659
+ }, c = () => s(0);
1660
+ t.addEventListener("loadedmetadata", n), t.addEventListener("error", c), t.src = e, setTimeout(() => s(0), 3e3);
1661
+ });
1662
+ }
1663
+ setTheme(e) {
1664
+ this.theme = { ...this.theme, ...e }, this.styleEl.textContent = T(this.theme), this.theme.enableEqAnimation !== void 0 && this.visualizer.setEnabled(this.theme.enableEqAnimation);
1665
+ }
1666
+ getAudioEngine() {
1667
+ return this.audioEngine;
1668
+ }
1669
+ destroy() {
1670
+ this.container.removeEventListener("keydown", this.boundKeyHandler), this.audioEngine.destroy(), this.visualizer.destroy(), this.ui.destroy(), this.shadow.innerHTML = "";
1671
+ }
1672
+ }
1673
+ export {
1674
+ N as HoregAudio,
1675
+ N as default
1676
+ };
1677
+ //# sourceMappingURL=horeg-audio.js.map