File size: 47,264 Bytes
19708db
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387288f
19708db
d0b4987
19708db
a20d9f6
 
19708db
 
 
9a53dab
f28c827
0c270ba
19708db
 
 
 
 
 
d0b4987
 
 
 
19708db
9a53dab
19708db
f28c827
19708db
 
387288f
 
d0b4987
9a53dab
 
19708db
387288f
f28c827
387288f
d0b4987
 
 
 
0c270ba
387288f
19708db
 
 
 
 
 
 
a20d9f6
 
 
 
 
 
 
 
19708db
 
a20d9f6
 
 
f28c827
19708db
 
 
 
 
d0b4987
 
0c270ba
d0ad9f0
f28c827
fd5019d
18bd4a5
19708db
 
 
d0b4987
 
f28c827
7857ee3
 
f28c827
19708db
 
 
 
 
 
 
d0b4987
 
19708db
 
d0b4987
387288f
f13ec06
70521ce
 
 
387288f
70521ce
f13ec06
70521ce
0c270ba
70521ce
f28c827
387288f
19708db
 
 
 
f28c827
 
7857ee3
7222679
 
 
7857ee3
d6af418
7857ee3
fee4195
 
d0b4987
 
 
 
 
7222679
981a1e4
d0b4987
7857ee3
7222679
981a1e4
a20d9f6
d0b4987
a20d9f6
d0b4987
a20d9f6
 
 
 
46da690
 
d0b4987
3df8f9b
18bd4a5
46da690
18bd4a5
79d05c5
f28c827
 
 
d0b4987
 
 
f28c827
 
7222679
 
 
d0b4987
 
 
 
b6f03f7
 
 
d0b4987
b6f03f7
981a1e4
d0b4987
19708db
7baa7eb
 
 
981a1e4
 
387288f
d0b4987
 
387288f
70521ce
d0b4987
 
 
 
70521ce
d0b4987
 
 
981a1e4
d0b4987
70521ce
981a1e4
 
 
 
d0b4987
 
 
 
 
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a20d9f6
387288f
d0b4987
32502ca
19708db
 
f28c827
fd5019d
9a53dab
19708db
d0b4987
 
 
19708db
a20d9f6
 
19708db
fd5019d
f28c827
d0b4987
 
 
 
fee4195
387288f
981a1e4
7857ee3
 
981a1e4
 
 
 
0abb3b9
981a1e4
6a1339e
64d22a7
981a1e4
 
18bd4a5
f4515b6
e8853fd
18bd4a5
 
ef7954e
18bd4a5
981a1e4
ef7954e
18bd4a5
981a1e4
7857ee3
f13ec06
d6af418
 
8e58bb9
7222679
 
d6af418
 
b6f03f7
f28c827
7222679
a20d9f6
0c270ba
f28c827
981a1e4
 
8e58bb9
fd5019d
b6f03f7
7222679
d0b4987
 
 
 
7222679
b6f03f7
fd5019d
 
981a1e4
d0b4987
 
981a1e4
 
 
d0b4987
981a1e4
d0b4987
 
 
70521ce
 
 
 
981a1e4
a20d9f6
 
 
981a1e4
 
a20d9f6
 
 
 
 
 
 
9a53dab
d0b4987
a20d9f6
89d021e
7baa7eb
387288f
a20d9f6
4ca9510
8e58bb9
fd5019d
f28c827
 
 
 
 
fd5019d
f28c827
981a1e4
b6f03f7
7222679
981a1e4
18bd4a5
981a1e4
 
 
7222679
 
 
 
fd5019d
19708db
 
 
 
 
 
 
 
7baa7eb
88a339b
 
 
 
 
 
 
 
 
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a20d9f6
 
7baa7eb
 
981a1e4
 
 
 
a20d9f6
 
 
981a1e4
a20d9f6
7baa7eb
981a1e4
 
89d021e
981a1e4
 
 
 
a20d9f6
89d021e
 
 
 
 
981a1e4
 
 
 
 
 
a20d9f6
 
19708db
981a1e4
89d021e
 
 
 
981a1e4
 
 
 
 
 
 
ef7954e
981a1e4
 
 
d0b4987
981a1e4
7baa7eb
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6a1339e
981a1e4
 
d0b4987
981a1e4
8e58bb9
981a1e4
7baa7eb
 
 
19708db
981a1e4
 
 
 
7baa7eb
8e58bb9
 
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18bd4a5
8e58bb9
 
b6f03f7
 
f28c827
981a1e4
4ca9510
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18bd4a5
 
ef7954e
981a1e4
18bd4a5
981a1e4
 
 
 
 
 
 
 
ef7954e
981a1e4
 
d5f8329
981a1e4
 
d5f8329
89d021e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f1bf7b2
 
 
89d021e
 
 
 
 
 
 
 
 
 
f1bf7b2
89d021e
f1bf7b2
 
 
 
981a1e4
 
 
 
89d021e
 
 
 
981a1e4
7c66128
981a1e4
 
 
 
89d021e
 
7c66128
981a1e4
 
 
 
 
 
 
 
 
18bd4a5
d0b4987
 
 
 
 
 
 
 
46da690
7c66128
981a1e4
18bd4a5
7baa7eb
19708db
 
 
 
89d021e
 
ef7954e
6a1339e
19708db
7baa7eb
 
981a1e4
7c66128
981a1e4
 
7baa7eb
 
 
18bd4a5
7baa7eb
7c66128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18bd4a5
 
7c66128
 
 
9fcd16b
46da690
7c66128
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0b4987
 
46da690
7c66128
 
 
 
 
 
981a1e4
1825431
19708db
46da690
 
981a1e4
46da690
 
 
981a1e4
46da690
 
 
d0b4987
 
7c66128
 
 
 
 
 
e8853fd
7c66128
 
 
 
 
 
 
 
d0b4987
64d22a7
7baa7eb
89d021e
981a1e4
 
 
 
33ba044
981a1e4
 
 
 
 
 
 
 
 
 
 
 
 
19708db
7c66128
33ba044
 
 
 
7c66128
33ba044
 
 
 
 
 
89d021e
7baa7eb
 
33ba044
 
 
 
 
 
ef7954e
981a1e4
 
 
 
 
 
 
7baa7eb
7c66128
 
981a1e4
 
7c66128
d5f8329
 
 
4ca9510
981a1e4
f28c827
 
 
b6f03f7
f28c827
 
 
 
 
b6f03f7
f28c827
 
 
 
fd5019d
f28c827
 
 
3e3025e
f28c827
3e3025e
19708db
3e3025e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
<!DOCTYPE html>  
<html lang="fa" dir="rtl">  
<head>  
    <meta charset="UTF-8">  
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">  
    <title>استودیو موزیک آلفا (Alpha)</title>  
    <link href="https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700;800&display=swap" rel="stylesheet">  
    <style>  
        :root {  
            --app-font: 'Vazirmatn', sans-serif;  
            --app-bg: #F8F9FC;  
            --panel-bg: #FFFFFF;  
            --panel-border: #EAEFF7;  
            --input-bg: #F6F8FB;  
            --input-border: #E1E7EF;  
            --text-primary: #1A202C;  
            --text-secondary: #626F86;  
            --accent-primary: #4A6CFA;  
            --accent-secondary: #9F7AEA;
            --accent-glow: rgba(74, 108, 250, 0.2);  
            --success-color: #38A169;
            --danger-color: #e53e3e;  
            --premium-gold: #FFC107;
            --premium-gradient: linear-gradient(135deg, #FFC107 0%, #FF9800 100%);
            --radius-card: 20px;  
            --radius-btn: 14px;  
        }  

        * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
        
        body { 
            font-family: var(--app-font); 
            background-color: var(--app-bg); 
            color: var(--text-primary); 
            margin: 0; 
            padding: 20px 15px; 
            min-height: 100vh;
            display: flex;
            flex-direction: column;
            align-items: center;
        }  

        .container { max-width: 650px; width: 100%; z-index: 2; position: relative; }  
        
        #music-canvas { 
            position: fixed; top: 0; left: 0; width: 100%; height: 400px; 
            z-index: 0; opacity: 0.5; pointer-events: none;
            mask-image: linear-gradient(to bottom, black, transparent);
            -webkit-mask-image: linear-gradient(to bottom, black, transparent);
        }

        header { text-align: center; margin-bottom: 2rem; position: relative; }  
        
        .logo-box {
            width: 80px; height: 80px; margin: 0 auto 15px;
            background: #fff; border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            box-shadow: 0 10px 25px var(--accent-glow);
            color: var(--accent-primary);
        }
        
        h1 { 
            font-size: 1.8rem; font-weight: 800; margin: 0; 
            background: linear-gradient(90deg, #2d3748, #4A6CFA); 
            -webkit-background-clip: text; -webkit-text-fill-color: transparent; 
        }  
        .subtitle { font-size: 0.9rem; color: var(--text-secondary); margin-top: 5px; margin-bottom: 10px; }  

        .status-badge {
            display: inline-block; padding: 6px 16px; border-radius: 20px;
            font-size: 0.85rem; font-weight: 700; margin-top: 5px;
            letter-spacing: 0.5px; opacity: 0; transform: translateY(-5px);
            transition: all 0.5s ease;
        }
        .status-badge.visible { opacity: 1; transform: translateY(0); }
        .badge-free { background: #E2E8F0; color: #64748b; }
        .badge-premium { 
            background: var(--premium-gradient); color: #fff; 
            box-shadow: 0 4px 15px rgba(255, 193, 7, 0.4);
            text-shadow: 0 1px 2px rgba(0,0,0,0.1);
        }

        .card { 
            background: var(--panel-bg); 
            border-radius: var(--radius-card); 
            box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.05); 
            border: 1px solid var(--panel-border); 
            padding: 25px; margin-bottom: 20px;
        }
        
        .form-label { display: flex; align-items: center; gap: 8px; font-weight: 700; margin-bottom: 12px; color: #2d3748; }
        .form-label svg { color: var(--accent-primary); width: 20px; }

        textarea, input, select { 
            width: 100%; background: var(--input-bg); 
            border: 2px solid var(--input-border); 
            border-radius: 12px; padding: 15px; 
            font-family: inherit; font-size: 1rem; color: #2d3748;
            outline: none; transition: border-color 0.3s;
        }
        textarea { min-height: 120px; resize: vertical; }
        textarea:focus, input:focus, select:focus { border-color: var(--accent-primary); background: #fff; }

        @keyframes move-gradient {
            0% { background-position: 0% 50%; }
            50% { background-position: 100% 50%; }
            100% { background-position: 0% 50%; }
        }
        .btn-main { 
            width: 100%; padding: 16px; 
            background: linear-gradient(110deg, var(--accent-secondary), var(--accent-primary), var(--accent-secondary));
            background-size: 200% 100%;
            color: #fff; border: none; border-radius: var(--radius-btn); 
            font-size: 1.1rem; font-weight: 700; cursor: pointer; 
            display: flex; justify-content: center; align-items: center; gap: 10px;
            transition: all 0.3s ease-out; position: relative; z-index: 1;
        }
        .btn-main-content { display: flex; align-items: center; justify-content: center; gap: 10px; transition: transform 0.3s ease; }
        .btn-main:hover { transform: translateY(-4px); box-shadow: 0 12px 28px -5px rgba(124, 93, 250, 0.4); }
        .btn-main:hover .btn-main-content { transform: scale(1.05); }
        .btn-main::before {
            content: ''; position: absolute; top: -2px; left: -2px; right: -2px; bottom: -2px;
            background: linear-gradient(110deg, var(--accent-secondary), var(--accent-primary), var(--accent-secondary));
            background-size: 400%; border-radius: 16px; z-index: -1; opacity: 0; transition: opacity 0.4s ease-out;
        }
        .btn-main:hover::before { opacity: 1; animation: move-gradient 4s linear infinite; }
        .btn-main:disabled { opacity: 0.7; cursor: not-allowed; filter: grayscale(1); }

        .btn-outline {
            background: transparent; border: 2px solid var(--input-border);
            color: var(--text-secondary); margin-top: 10px; transition: all 0.2s;
        }
        .btn-outline:hover { border-color: var(--accent-primary); color: var(--accent-primary); }

        .accordion {
            background-color: var(--input-bg); color: var(--text-primary); cursor: pointer; padding: 15px; width: 100%; border: none;
            text-align: right; outline: none; font-size: 0.95rem; font-weight: 600; border-radius: 12px;
            display: flex; justify-content: space-between; align-items: center; margin-top: 15px; border: 1px solid var(--input-border); transition: 0.3s;
        }
        .accordion:hover { background-color: #ecf0f7; border-color: var(--accent-primary); }
        .accordion:after { content: '⚙️'; font-size: 1rem; transition: transform 0.3s; }
        .accordion.active { border-radius: 12px 12px 0 0; border-bottom: none; }
        .accordion.active:after { content: '🔼'; }
        .panel {
            padding: 0 15px; background-color: var(--input-bg); max-height: 0; overflow: hidden;
            transition: max-height 0.3s ease-out; border-radius: 0 0 12px 12px;
            margin-bottom: 0; border: 1px solid var(--input-border); border-top: none;
        }
        .settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; padding: 15px 0; }
        .checkbox-wrapper { display: flex; align-items: center; gap: 10px; margin-top: 5px; padding-bottom: 15px; border-top: 1px solid #e2e8f0; padding-top: 15px; }
        .settings-group label { font-size: 0.8rem; color: var(--text-secondary); display: block; margin-bottom: 6px; font-weight: 500; }

        .player-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid var(--panel-border); }
        
        .download-btn-style {
            background-color: rgba(74, 108, 250, 0.1); color: var(--accent-primary); text-decoration: none; font-size: 0.9rem;
            font-weight: 700; padding: 8px 16px; border-radius: 10px; transition: 0.2s; display: inline-flex; align-items: center; gap: 5px; cursor: pointer; border: none;
        }
        .download-btn-style:hover { background-color: rgba(74, 108, 250, 0.2); }
        .download-btn-style.locked { background-color: #f1f5f9; color: #94a3b8; }
        .download-btn-style.locked:hover { background-color: #e2e8f0; }

        .audio-item { margin-bottom: 10px; }
        audio { width: 100%; height: 45px; border-radius: 20px; margin-top: 5px; }
        .lyrics-container {
            background: var(--input-bg); border-radius: 16px; padding: 20px; max-height: 350px; overflow-y: auto;
            white-space: pre-wrap; line-height: 2; font-size: 1rem; color: #4a5568; text-align: center; border: 1px solid var(--input-border); margin-top: 15px;
        }
        .lyrics-tag { color: var(--accent-primary); font-weight: 800; display: block; margin-top: 20px; margin-bottom: 5px; font-size: 0.9em; letter-spacing: 1px; text-transform: uppercase; }

        #loader { display: none; text-align: center; padding: 20px; }
        .wave-bars { display: flex; justify-content: center; gap: 4px; height: 30px; align-items: flex-end; }
        .bar { width: 5px; background: var(--accent-primary); animation: jump 1s infinite; border-radius: 2px; }
        .bar:nth-child(2) { animation-delay: 0.1s; height: 60%; }
        .bar:nth-child(3) { animation-delay: 0.2s; height: 80%; }
        .bar:nth-child(4) { animation-delay: 0.3s; height: 50%; }
        @keyframes jump { 0%, 100% { height: 20%; } 50% { height: 100%; } }

        #historySection { margin-top: 30px; width: 100%; }
        .history-title { font-size: 1.2rem; font-weight: 800; color: var(--text-primary); margin-bottom: 15px; display: flex; align-items: center; gap: 10px; }
        .history-list { display: grid; gap: 12px; }
        .history-card {
            background: white; border-radius: 16px; padding: 15px; display: flex; align-items: center; justify-content: space-between;
            border: 1px solid var(--panel-border); transition: all 0.3s; cursor: pointer; position: relative; overflow: hidden;
        }
        .history-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(74, 108, 250, 0.15); border-color: var(--accent-primary); }
        .h-info { display: flex; align-items: center; gap: 15px; }
        .h-icon { width: 45px; height: 45px; background: var(--input-bg); border-radius: 12px; display: flex; align-items: center; justify-content: center; color: var(--accent-primary); font-size: 1.2rem; }
        .h-details h4 { margin: 0; font-size: 1rem; color: var(--text-primary); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; }
        .h-details span { font-size: 0.8rem; color: var(--text-secondary); }
        
        .h-delete {
            position: absolute; left: 15px; 
            background: #fee2e2; color: var(--danger-color);
            width: 38px; height: 38px; border-radius: 50%;
            display: flex; align-items: center; justify-content: center;
            opacity: 0; transform: scale(0.8); transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            z-index: 10; box-shadow: 0 4px 10px rgba(229, 62, 62, 0.2);
        }
        .history-card:hover .h-delete { opacity: 1; transform: scale(1); }
        .h-delete:hover { background: var(--danger-color); color: white; transform: scale(1.1); }

        .modal-overlay {
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background: rgba(0, 0, 0, 0.6); backdrop-filter: blur(8px);
            z-index: 1000; display: none; align-items: center; justify-content: center;
            opacity: 0; transition: opacity 0.3s;
        }
        .modal-box {
            background: white; width: 90%; max-width: 400px;
            border-radius: 24px; padding: 30px; text-align: center;
            transform: scale(0.9); transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            box-shadow: 0 20px 60px rgba(0,0,0,0.2);
        }
        .modal-icon-warn {
            width: 60px; height: 60px; background: #fee2e2; color: var(--danger-color);
            border-radius: 50%; margin: 0 auto 20px; display: flex; align-items: center; justify-content: center;
        }
        .modal-box h3 { margin: 0 0 10px; color: var(--text-primary); }
        .modal-box p { color: var(--text-secondary); margin: 0 0 25px; font-size: 0.95rem; }
        .modal-actions { display: flex; gap: 10px; justify-content: center; }
        .btn-modal { padding: 12px 24px; border-radius: 12px; font-weight: 700; border: none; cursor: pointer; flex: 1; font-size: 1rem; transition: 0.2s; }
        .btn-cancel { background: var(--input-bg); color: var(--text-secondary); }
        .btn-cancel:hover { background: #e2e8f0; }
        .btn-confirm { background: var(--danger-color); color: white; box-shadow: 0 5px 15px rgba(229, 62, 62, 0.3); }
        .btn-confirm:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(229, 62, 62, 0.4); }

        @keyframes pulse-gold { 0% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.7); } 70% { box-shadow: 0 0 0 15px rgba(255, 193, 7, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); } }
        .upgrade-icon { 
            width: 70px; height: 70px; 
            background: var(--premium-gradient);
            border-radius: 50%; color: white; margin: 0 auto 20px; 
            display: flex; align-items: center; justify-content: center; 
            font-size: 2rem; animation: pulse-gold 2s infinite; 
        }
        .btn-upgrade { 
            background: var(--premium-gradient); color: #333; 
            box-shadow: 0 5px 15px rgba(255, 193, 7, 0.3); 
        }
        .btn-upgrade:hover { 
            transform: translateY(-2px); 
            box-shadow: 0 8px 25px rgba(255, 193, 7, 0.5); 
        }

        .modal-overlay.open { display: flex; opacity: 1; }
        .modal-overlay.open .modal-box { transform: scale(1); }
    </style>
</head>  
<body>  
    <canvas id="music-canvas"></canvas>

    <div class="container">
        <header>  
            <div class="logo-box">
                <svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 18V5l12-2v13"></path><circle cx="6" cy="18" r="3"></circle><circle cx="18" cy="16" r="3"></circle></svg>
            </div>
            <h1>استودیو موزیک آلفا</h1>  
            <p class="subtitle">ساخت آهنگ حرفه‌ای با هوش مصنوعی</p>
            <div id="statusBadge" class="status-badge">نسخه رایگان</div>
        </header>  

        <div id="step1" class="card">
            <div class="form-label">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path></svg>
                موضوع آهنگ چیه؟
            </div>
            <textarea id="ideaInput" placeholder="مثال: آهنگ تولد برای سمیرا، سبک پاپ شاد..."></textarea>
            
            <button class="accordion">تنظیمات پیشرفته</button>
            <div class="panel">
                <div class="settings-grid">
                    <div class="settings-group"><label>مدل هوش مصنوعی:</label><select id="model_select"><option value="acestep-v15-turbo-shift3" selected>Turbo-Shift3 (دقیق‌ترین)</option><option value="acestep-v15-turbo">Turbo (سریع‌ترین)</option></select></div>
                    <div class="settings-group"><label>تعداد خروجی (آهنگ):</label><input type="number" id="batch_size" value="1" min="1" max="4"></div>
                    <div class="settings-group"><label>تعداد گام (Steps):</label><input type="number" id="steps_input" value="20" min="4" max="50"></div>
                    <div class="settings-group"><label>سید (Seed) تصادفی=-1:</label><input type="number" id="seed_input" value="-1"></div>
                    
                    <div class="settings-group"><label>مقیاس هدایت (CFG):</label><input type="number" id="cfg_input" value="7.0" step="0.5"></div>
                    <div class="settings-group"><label>مدت زمان آهنگ:</label><select id="duration_select"><option value="unknown" selected>خودکار (استاندارد)</option><option value="short">کوتاه (حدود ۱ دقیقه)</option><option value="medium">متوسط (حدود ۲ دقیقه)</option><option value="long">طولانی (حدود ۳ دقیقه)</option></select></div>
                </div>

                <div class="settings-group" style="border-top: 1px solid #e2e8f0; padding-top: 15px; margin-bottom: 10px;">
                    <label>آپلود آهنگ نمونه (Audio Conditioning):</label>
                    <input type="file" id="audio_reference" accept="audio/*" style="padding: 10px; width: 100%; background: #fff;">
                    <div style="font-size: 0.8rem; color: #666; margin-top: 5px;">(برای هدایت بهتر هوش مصنوعی، می‌توانید یک آهنگ نمونه آپلود کنید تا خروجی نهایی از نظر ملودی و ریتم به آن نزدیک‌تر باشد.)</div>
                </div>

                <div class="checkbox-wrapper">
                    <input type="checkbox" id="instrumental_chk">
                    <label for="instrumental_chk" style="font-size: 0.9rem; cursor: pointer;"><b>حالت بی‌کلام (Instrumental)</b><br><span style="font-size: 0.8rem; color: #666;">بدون خواننده، فقط موسیقی</span></label>
                </div>

                <div class="checkbox-wrapper"><input type="checkbox" id="think_checkbox" checked><label for="think_checkbox" style="font-size: 0.9rem; cursor: pointer;"><b>فعال‌سازی تفکر مدل</b><br><span style="font-size: 0.8rem; color: #666;">افزایش کیفیت آهنگ</span></label></div>
            </div>
            <button id="processBtn" class="btn-main" style="margin-top: 15px;"><div class="btn-main-content">ساخت آهنگ <span>🎵</span></div></button>
        </div>

        <div id="loader" style="display: none;">
            <div class="wave-bars"><div class="bar"></div><div class="bar"></div><div class="bar"></div><div class="bar"></div><div class="bar"></div></div>
            <p id="loaderText">در حال پردازش...</p>
        </div>

        <div id="finalResult" class="card" style="display:none;">
            <div class="player-header">
                <div id="resultHeaderText" style="font-weight: 700; display: flex; align-items: center; gap: 5px;"></div>
                <button id="mainDownloadBtn" class="download-btn-style">دانلود آهنگ 📥</button>
            </div>
            <div id="playerWrapper"></div>
            <div class="form-label" style="margin-top: 20px; justify-content: center; color: #718096;">متن آهنگ</div>
            <div class="lyrics-container" id="finalLyricsBox"></div>
            <button onclick="location.reload()" class="btn-main btn-outline">برگشت و ساخت آهنگ جدید</button>
        </div>

        <div id="historySection">
            <div class="history-title">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
                آخرین آهنگ‌های ساخته شده
            </div>
            <div class="history-list" id="historyList"></div>
        </div>
    </div>

    <!-- مودال تایید حذف -->
    <div class="modal-overlay" id="deleteConfirmModal">
        <div class="modal-box">
            <div class="modal-icon-warn">
                <svg width="30" height="30" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path></svg>
            </div>
            <h3>آیا مطمئن هستید؟</h3>
            <p>این آهنگ برای همیشه از سوابق شما حذف خواهد شد و قابل بازگشت نیست.</p>
            <div class="modal-actions">
                <button class="btn-modal btn-cancel" onclick="closeDeleteModal()">انصراف</button>
                <button class="btn-modal btn-confirm" onclick="confirmDelete()">بله، حذف شود</button>
            </div>
        </div>
    </div>

    <!-- مودال ارتقا به نسخه کامل -->
    <div class="modal-overlay" id="upgradeModal">
        <div class="modal-box">
            <div class="upgrade-icon">👑</div>
            <h3 style="font-weight: 800; color: #333;" id="upgradeModalTitle">دانلود مخصوص اعضای ویژه</h3>
            <p style="margin-bottom: 25px; line-height: 1.6;" id="upgradeModalText">برای دانلود آهنگ‌های ساخته شده با کیفیت اصلی و بدون محدودیت، لطفا حساب کاربری خود را به نسخه نامحدود ارتقا دهید.</p>
            <div class="modal-actions" style="flex-direction: column;">
                <button class="btn-modal btn-upgrade" id="btnGoPremium">⭐️ ارتقا به نسخه کامل</button>
                <button class="btn-modal btn-cancel" onclick="closeUpgradeModal()" style="width: 100%;">فعلاً نه</button>
            </div>
        </div>
    </div>

    <script>
        const ACE_SPACE_URL = "https://ace-step-ace-step-v1-5.hf.space/";
        const PREMIUM_PAGE_ID = '1149636';
        const PREMIUM_URL = '#/nav/online/news/getSingle/1149636/eyJpdiI6InZSVUdlLzBlR0FzOHZJdXFZeWhER0E9PSIsInZhbHVlIjoiWFhqRXBLc29vSFpHdk9nYmRjZGVuWHRHRHVSZHRlTG1BUENLaE5mNXBNVVRGWFg3ZWN0djJ5K1dIY1RqTHJGaCIsIm1hYyI6IjIzYzFlZTMwYmVmMTdkYjQ0YTQ4YWMxNmFhN2RmNWQ2OTU0MjI0ZWVlZGI3ZjJjMjhkNmQxNjM4MDFlZTIxNmUiLCJ0YWciOiIifQ==/20934991';

        let db;
        let songToDeleteId = null;
        let userSubscriptionStatus = 'free';

        const ideaInput = document.getElementById('ideaInput');
        const processBtn = document.getElementById('processBtn');
        const step1 = document.getElementById('step1');
        const loader = document.getElementById('loader');
        const loaderText = document.getElementById('loaderText');
        const finalResult = document.getElementById('finalResult');
        const playerWrapper = document.getElementById('playerWrapper');
        const finalLyricsBox = document.getElementById('finalLyricsBox');
        const mainDownloadBtn = document.getElementById('mainDownloadBtn');
        const historyList = document.getElementById('historyList');
        const historySection = document.getElementById('historySection');
        const deleteModal = document.getElementById('deleteConfirmModal');
        const upgradeModal = document.getElementById('upgradeModal');
        const statusBadge = document.getElementById('statusBadge');
        const upgradeModalTitle = document.getElementById('upgradeModalTitle');
        const upgradeModalText = document.getElementById('upgradeModalText');

        const getVal = (id) => document.getElementById(id).value;
        const getNum = (id) => Number(document.getElementById(id).value);
        const getChk = (id) => document.getElementById(id).checked;

        const acc = document.getElementsByClassName("accordion");
        for (let i = 0; i < acc.length; i++) {
            acc[i].addEventListener("click", function() {
                this.classList.toggle("active");
                const panel = this.nextElementSibling;
                panel.style.maxHeight = panel.style.maxHeight ? null : panel.scrollHeight + "px";
            });
        }

        function getFingerprint() {
            let fp = localStorage.getItem('user_fingerprint');
            if (!fp) {
                fp = 'user_' + Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
                localStorage.setItem('user_fingerprint', fp);
            }
            return fp;
        }

        function isUserPaid(userObject) {
            return userObject && userObject.isLogin && userObject.accessible_pages && 
                   (userObject.accessible_pages.includes(PREMIUM_PAGE_ID) || 
                    userObject.accessible_pages.includes(parseInt(PREMIUM_PAGE_ID)));
        }

        function updateSubscriptionUI(status) {
            if (status === 'paid') {
                statusBadge.textContent = 'نسخه نامحدود';
                statusBadge.className = 'status-badge visible badge-premium';
                mainDownloadBtn.classList.remove('locked');
            } else {
                statusBadge.textContent = 'نسخه رایگان';
                statusBadge.className = 'status-badge visible badge-free';
            }
        }

        window.addEventListener('message', (event) => {
            if (event.data && event.data.type === 'USER_STATUS_RESPONSE') {
                try {
                    const userObject = JSON.parse(event.data.payload);
                    userSubscriptionStatus = isUserPaid(userObject) ? 'paid' : 'free';
                } catch (e) {
                    userSubscriptionStatus = 'free';
                }
                updateSubscriptionUI(userSubscriptionStatus);
            }
        });

        parent.postMessage({ type: 'REQUEST_USER_STATUS' }, '*');

        function handleSecureDownload(url, e) {
            if (e) e.preventDefault();
            
            if (userSubscriptionStatus === 'free') {
                upgradeModalTitle.innerText = "دانلود مخصوص اعضای ویژه";
                upgradeModalText.innerText = "برای دانلود آهنگ‌های ساخته شده با کیفیت اصلی و بدون محدودیت، لطفا حساب کاربری خود را به نسخه نامحدود ارتقا دهید.";
                upgradeModal.classList.add('open');
            } else {
                parent.postMessage({ 
                    type: 'INITIATE_DOWNLOAD_FROM_URL', 
                    payload: { audioUrl: url } 
                }, '*');
                
                const btn = e ? e.target.closest('button') : null;
                if(btn) {
                    const originalText = btn.innerHTML;
                    btn.innerHTML = 'در حال ارسال... ⏳';
                    setTimeout(() => { btn.innerHTML = originalText; }, 2000);
                }
            }
        }

        document.getElementById('btnGoPremium').addEventListener('click', () => {
            parent.postMessage({ 
                type: 'NAVIGATE_TO_PREMIUM', 
                payload: { url: PREMIUM_URL } 
            }, '*');
        });

        function closeUpgradeModal() {
            upgradeModal.classList.remove('open');
        }

        function initDB() {
            const request = indexedDB.open("alphaMusicDB", 1);
            request.onerror = (event) => console.error("IndexedDB error:", event);
            request.onsuccess = (event) => { db = event.target.result; loadHistory(); };
            request.onupgradeneeded = (event) => { event.target.result.createObjectStore("songs", { keyPath: "id" }); };
        }

        async function saveToHistory(idea, lyrics, audioUrl) {
            try {
                const response = await fetch(audioUrl);
                const audioBlob = await response.blob();
                const newItem = {
                    id: Date.now(), idea, lyrics, audioBlob,
                    date: new Date().toLocaleDateString('fa-IR', { hour: '2-digit', minute: '2-digit' })
                };
                const transaction = db.transaction(["songs"], "readwrite");
                const store = transaction.objectStore("songs");
                store.add(newItem);
                
                const countReq = store.count();
                countReq.onsuccess = () => {
                    if (countReq.result > 10) store.openCursor().onsuccess = (e) => { if(e.target.result) e.target.result.delete(); };
                };
                
                transaction.oncomplete = () => loadHistory();
            } catch (error) { console.error("Error saving:", error); }
        }

        function loadHistory() {
            if (!db) return;
            const store = db.transaction(["songs"], "readonly").objectStore("songs");
            store.getAll().onsuccess = (e) => {
                const history = e.target.result.sort((a, b) => b.id - a.id);
                historyList.innerHTML = '';
                if (history.length === 0) {
                    historyList.innerHTML = '<div style="text-align:center; color:#999; padding:20px;">هنوز آهنگی نساخته‌اید</div>';
                    return;
                }
                history.forEach((item) => {
                    const div = document.createElement('div');
                    div.className = 'history-card';
                    div.innerHTML = `
                        <div class="h-info">
                            <div class="h-icon">🎵</div>
                            <div class="h-details">
                                <h4>${item.idea.substring(0, 30)}${item.idea.length > 30 ? '...' : ''}</h4>
                                <span>${item.date}</span>
                            </div>
                        </div>
                        <div class="h-delete" onclick="askToDelete(event, ${item.id})">
                            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 6h18"></path><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path></svg>
                        </div>
                    `;
                    div.onclick = (e) => {
                        if (!e.target.closest('.h-delete')) {
                            openHistoryItem(item);
                        }
                    };
                    historyList.appendChild(div);
                });
            };
        }

        function askToDelete(event, id) {
            event.stopPropagation();
            songToDeleteId = id;
            deleteModal.classList.add('open');
        }

        function closeDeleteModal() {
            deleteModal.classList.remove('open');
            songToDeleteId = null;
        }

        function confirmDelete() {
            if (songToDeleteId && db) {
                const transaction = db.transaction(["songs"], "readwrite");
                const store = transaction.objectStore("songs");
                store.delete(songToDeleteId);
                transaction.oncomplete = () => {
                    loadHistory();
                    closeDeleteModal();
                };
            }
        }

        deleteModal.addEventListener('click', (e) => {
            if (e.target === deleteModal) closeDeleteModal();
        });
        upgradeModal.addEventListener('click', (e) => {
            if (e.target === upgradeModal) closeUpgradeModal();
        });

        function openHistoryItem(item) {
            step1.style.display = 'none';
            historySection.style.display = 'none';
            
            const audioURL = URL.createObjectURL(item.audioBlob);
            const headerText = document.getElementById('resultHeaderText');
            headerText.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg> آهنگ آرشیو شده`;
            headerText.style.color = 'var(--accent-primary)';

            mainDownloadBtn.style.display = 'inline-flex';
            mainDownloadBtn.onclick = (e) => handleSecureDownload(audioURL, e);

            playerWrapper.innerHTML = `<audio controls autoplay src="${audioURL}"></audio>`;
            finalLyricsBox.innerHTML = formatLyrics(item.lyrics);
            
            finalResult.style.display = 'block';
            window.scrollTo({ top: 0, behavior: 'smooth' });
        }
        
        initDB();

        function writeString(view, offset, string) {
            for (let i = 0; i < string.length; i++) {
                view.setUint8(offset + i, string.charCodeAt(i));
            }
        }

        function bufferToWave(abuffer, len) {
            let numOfChan = abuffer.numberOfChannels;
            let length = len * numOfChan * 2 + 44;
            let buffer = new ArrayBuffer(length);
            let view = new DataView(buffer);
            let channels = [], i, sample;
            let offset = 0;
            let pos = 0;

            writeString(view, 0, 'RIFF');
            view.setUint32(4, 36 + len * numOfChan * 2, true);
            writeString(view, 8, 'WAVE');
            writeString(view, 12, 'fmt ');
            view.setUint32(16, 16, true);
            view.setUint16(20, 1, true);
            view.setUint16(22, numOfChan, true);
            view.setUint32(24, abuffer.sampleRate, true);
            view.setUint32(28, abuffer.sampleRate * 2 * numOfChan, true);
            view.setUint16(32, numOfChan * 2, true);
            view.setUint16(34, 16, true);
            writeString(view, 36, 'data');
            view.setUint32(40, len * numOfChan * 2, true);

            for(i = 0; i < abuffer.numberOfChannels; i++)
                channels.push(abuffer.getChannelData(i));

            offset = 44;
            if (numOfChan === 2) {
                while(pos < len) {
                    for(i = 0; i < numOfChan; i++) {
                        sample = Math.max(-1, Math.min(1, channels[i][pos]));
                        sample = (sample < 0 ? sample * 0x8000 : sample * 0x7FFF) | 0;
                        view.setInt16(offset, sample, true);
                        offset += 2;
                    }
                    pos++;
                }
            } else {
                 while(pos < len) {
                    sample = Math.max(-1, Math.min(1, channels[0][pos]));
                    sample = (sample < 0 ? sample * 0x8000 : sample * 0x7FFF) | 0;
                    view.setInt16(offset, sample, true);
                    offset += 2;
                    pos++;
                 }
            }
            return new Blob([buffer], { type: "audio/wav" });
        }

        async function convertAudioToWav(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const audioContext = new (window.AudioContext || window.webkitAudioContext)();
                    audioContext.decodeAudioData(e.target.result, function(buffer) {
                        const wavBlob = bufferToWave(buffer, buffer.length);
                        const wavFile = new File([wavBlob], file.name.replace(/\.[^/.]+$/, "") + ".wav", { type: "audio/wav" });
                        resolve(wavFile);
                    }, function(e){
                         console.error("Audio decode failed", e);
                         reject("فرمت فایل صوتی پشتیبانی نمی‌شود.");
                    });
                };
                reader.onerror = reject;
                reader.readAsArrayBuffer(file);
            });
        }

        async function uploadAudioFile(file) {
            const formData = new FormData();
            formData.append("files", file);
            try {
                const response = await fetch(`${ACE_SPACE_URL}gradio_api/upload`, {
                    method: "POST",
                    body: formData
                });
                const data = await response.json();
                // ** LOGIC FIX: Return full object structure expected by Gradio **
                if (data && data.length > 0) {
                    return {
                        "path": data[0],
                        "url": `${ACE_SPACE_URL}gradio_api/file=${data[0]}`,
                        "orig_name": file.name,
                        "size": file.size,
                        "mime_type": "audio/wav",
                        "meta": {"_type": "gradio.FileData"}
                    };
                }
                return null;
            } catch (error) {
                console.error("Upload failed:", error);
                return null;
            }
        }

        processBtn.addEventListener('click', async () => {
            if (!ideaInput.value.trim()) return alert("لطفا موضوع آهنگ را بنویسید");
            
            processBtn.disabled = true;
            step1.style.display = 'none';
            historySection.style.display = 'none';
            loader.style.display = 'block';
            
            try {
                // 1. Text Generation First
                loaderText.innerText = "آلفا در حال نوشتن شعر و ملودی...";
                const isInstrumental = getChk('instrumental_chk');
                
                const response = await fetch('/api/refine', { 
                    method: 'POST', 
                    headers: {'Content-Type': 'application/json'}, 
                    body: JSON.stringify({ 
                        idea: ideaInput.value,
                        fingerprint: getFingerprint(),
                        is_premium: userSubscriptionStatus === 'paid',
                        is_instrumental: isInstrumental
                    }) 
                });

                if (response.status === 429) {
                    throw new Error("LIMIT_REACHED");
                }

                const data = await response.json();
                if (data.error) throw new Error(data.error);

                const { lyrics, musicPrompt } = data;
                
                // 2. Audio Upload (Only if file selected)
                const audioInput = document.getElementById('audio_reference');
                let uploadedAudioObj = null;
                
                if (audioInput.files.length > 0) {
                    let fileToUpload = audioInput.files[0];
                    loaderText.innerText = "در حال پردازش فایل صوتی...";
                    
                    if (fileToUpload.type !== 'audio/wav' && !fileToUpload.name.toLowerCase().endsWith('.wav')) {
                        fileToUpload = await convertAudioToWav(fileToUpload);
                    }
                    
                    loaderText.innerText = "در حال آپلود فایل نمونه...";
                    uploadedAudioObj = await uploadAudioFile(fileToUpload);
                    
                    if (!uploadedAudioObj) throw new Error("آپلود فایل با خطا مواجه شد.");
                }

                // 3. Generate Music
                loaderText.innerText = "در حال ضبط آهنگ در استودیو آلفا...";
                const finalLyrics = isInstrumental ? "" : lyrics;

                // ** CRITICAL FIX: Structure payload exactly as logs show **
                // If audio exists, index 1 is "custom" and index 2 is object
                // If no audio, index 1 is "custom" and index 2 is null (or check logs for no-audio case)
                
                const payload = [
                    getVal('model_select'),       // 0: Model
                    "custom",                     // 1: Mode (Always "custom" based on logs)
                    uploadedAudioObj,             // 2: Audio Object or null
                    getVal('duration_select'),    // 3: Duration
                    musicPrompt,                  // 4: Prompt
                    finalLyrics,                  // 5: Lyrics
                    0, "", "", "unknown",         // 6-9
                    getNum('steps_input'),        // 10: Steps
                    getNum('cfg_input'),          // 11: CFG
                    true,                         // 12
                    getNum('seed_input'),         // 13: Seed
                    null, -1, getNum('batch_size'), null, null, 0, -1, 
                    "Fill the audio semantic mask based on the given conditions:", // 22
                    1,                            // 23
                    "text2music",                 // 24: Task (Logs say text2music even with audio)
                    false, 0, 1, 3, "ode", "", "mp3", 0.85, 
                    getChk('think_checkbox'), 2, 0, 0.9, "NO USER INPUT", 
                    true, true, true, null, false, true, false, false, 0.5, 8, null, [], false, null, null, null, null
                ];

                const session_hash = Math.random().toString(36).substring(2);
                const joinResp = await fetch(`${ACE_SPACE_URL}gradio_api/queue/join`, { 
                    method: 'POST', 
                    headers: { 'Content-Type': 'application/json' }, 
                    body: JSON.stringify({ data: payload, fn_index: 77, session_hash }) 
                });
                
                if (!joinResp.ok) throw new Error('خطا در اتصال به سرور موزیک');

                const eventSource = new EventSource(`${ACE_SPACE_URL}gradio_api/queue/data?session_hash=${session_hash}`);
                eventSource.onmessage = (event) => {
                    const msg = JSON.parse(event.data);
                    if (msg.msg === 'process_starts') loaderText.innerText = "هوش مصنوعی در حال خواندن...";
                    else if (msg.msg === 'process_completed') {
                        eventSource.close();
                        loader.style.display = 'none';
                        handleAudioOutput(msg.output, lyrics, ideaInput.value);
                    }
                };
                eventSource.onerror = () => { throw new Error('ارتباط با سرور قطع شد.'); };

            } catch (e) {
                if(e.message === "LIMIT_REACHED"){
                    loader.style.display = 'none';
                    step1.style.display = 'block';
                    historySection.style.display = 'block';
                    processBtn.disabled = false;
                    upgradeModalTitle.innerText = "محدودیت ساخت روزانه";
                    upgradeModalText.innerText = "شما به سقف ۵ آهنگ رایگان در روز رسیده‌اید. برای ساخت آهنگ های بیشتر و نامحدود با امکان دانلود حساب خود را ارتقاء دهید و از همه بخش های برنامه بصورت نامحدود استفاده کنید";
                    upgradeModal.classList.add('open');
                } else {
                    alert("خطا: " + e.message);
                    loader.style.display = 'none';
                    step1.style.display = 'block';
                    historySection.style.display = 'block';
                    processBtn.disabled = false;
                }
            }
        });

        function handleAudioOutput(data, lyrics, idea) {
            const processedUrls = new Set();
            let hasResult = false;
            
            function addAudio(url) {
                if (!url) return;
                const fullUrl = url.startsWith('http') ? url : ACE_SPACE_URL.replace(/\/$/, '') + url;
                if (processedUrls.has(fullUrl)) return;
                processedUrls.add(fullUrl);
                hasResult = true;

                if (processedUrls.size === 1) {
                    mainDownloadBtn.style.display = 'inline-flex';
                    mainDownloadBtn.onclick = (e) => handleSecureDownload(fullUrl, e);
                    saveToHistory(idea, lyrics, fullUrl);
                }
                playerWrapper.innerHTML += `<div class="audio-item"><audio controls autoplay src="${fullUrl}"></audio></div>`;
            }

            function traverse(obj) {
                if (!obj) return;
                if (typeof obj === 'string') {
                    if (obj.includes('/file=') && (obj.endsWith('.mp3') || obj.endsWith('.wav'))) {
                        addAudio(obj);
                    }
                } else if (typeof obj === 'object') {
                    if (obj.url && (obj.url.endsWith('.mp3') || obj.url.endsWith('.wav'))) {
                        addAudio(obj.url);
                    }
                    if (obj.path && (obj.path.endsWith('.mp3') || obj.path.endsWith('.wav'))) {
                        addAudio(`/gradio_api/file=${obj.path}`);
                    }
                    Object.values(obj).forEach(traverse);
                }
            }

            if (data && data.data) {
                data.data.forEach(item => traverse(item));
            } else {
                traverse(data);
            }

            if (hasResult) {
                const headerText = document.getElementById('resultHeaderText');
                headerText.innerHTML = `<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"></path><polyline points="22 4 12 14.01 9 11.01"></polyline></svg>آهنگ جدید آماده شد`;
                headerText.style.color = 'var(--success-color)';
                finalResult.style.display = 'block';
                finalLyricsBox.innerHTML = formatLyrics(lyrics);
                window.scrollTo({ top: 0, behavior: 'smooth' });
            } else {
                console.log("Full Server Response for Debug:", data);
                alert("خروجی معتبری دریافت نشد. لطفاً تنظیمات را بررسی کنید.");
                step1.style.display = 'block';
                historySection.style.display = 'block';
                processBtn.disabled = false;
            }
        }

        function formatLyrics(text) { return text ? text.replace(/\[(.*?)\]/g, '<span class="lyrics-tag">[$1]</span>') : "متن آهنگ: (بی‌کلام)"; }

        const canvas = document.getElementById('music-canvas');
        const ctx = canvas.getContext('2d');
        let t = 0;
        function resize() { canvas.width = window.innerWidth; canvas.height = 400; }
        window.addEventListener('resize', resize);
        resize();
        function anim() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.beginPath();
            ctx.strokeStyle = "rgba(74, 108, 250, 0.1)";
            ctx.lineWidth = 2;
            for(let i=0; i<canvas.width; i+=20) {
                ctx.moveTo(i, 0);
                ctx.lineTo(i, Math.sin(i * 0.01 + t) * 50 + 100);
            }
            ctx.stroke();
            t += 0.02;
            requestAnimationFrame(anim);
        }
        anim();
    </script>
</body>  
</html>