Kipss commited on
Commit
d670def
·
verified ·
1 Parent(s): dd9f659

Delete rebel-v2.html

Browse files
Files changed (1) hide show
  1. rebel-v2.html +0 -329
rebel-v2.html DELETED
@@ -1,329 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ar" dir="rtl">
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1">
6
- <title>Rebel</title>
7
- <link href="https://fonts.googleapis.com/css2?family=Readex+Pro:wght@300;400;600&display=swap" rel="stylesheet">
8
- <style>
9
- :root{--bg:#0e0b16;--panel:#171225;--line:#2d2447;--ink:#f1ecff;--mute:#9a8fb8;--acc:#8b5cf6;--acc2:#f5b942;--ok:#4ade80;--err:#fb7185}
10
- *{box-sizing:border-box}
11
- body{margin:0;background:var(--bg);color:var(--ink);font-family:'Readex Pro',system-ui,sans-serif;line-height:1.6}
12
- .wrap{max-width:640px;margin:auto;padding:16px 16px 60px}
13
- h1{font-size:22px;margin:8px 0 14px;font-weight:600}
14
- .tabs{display:flex;gap:8px;margin-bottom:14px}
15
- .tab{flex:1;padding:12px 2px;font-size:14px;border-radius:14px;background:var(--panel);border:1px solid var(--line);color:var(--mute);font:inherit;cursor:pointer}
16
- .tab.on{background:var(--acc);color:#fff;border-color:var(--acc)}
17
- .tab small{display:block;font-size:10px;opacity:.8}
18
- textarea,select{width:100%;background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:14px;padding:12px;font:inherit}
19
- textarea{min-height:100px;resize:vertical}
20
- .row{display:flex;gap:8px;margin:10px 0}.row>*{flex:1}
21
- .chips{display:flex;gap:6px;overflow-x:auto;padding:4px 0 8px}
22
- .chip{flex:none;padding:6px 12px;border-radius:99px;border:1px solid var(--line);background:none;color:var(--mute);font:inherit;font-size:13px;cursor:pointer}
23
- .chip.on{border-color:var(--acc2);color:var(--acc2)}
24
- label.sw{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--mute);margin:6px 0}
25
- button.go{width:100%;padding:15px;border:0;border-radius:14px;background:var(--acc);color:#fff;font:inherit;font-weight:600;font-size:16px;cursor:pointer}
26
- button.go:disabled{opacity:.55}
27
- #st{min-height:26px;margin:10px 0;font-size:14px;color:var(--acc2)}
28
- #st.err{color:var(--err)}
29
- .bar{height:3px;background:var(--line);border-radius:3px;overflow:hidden;display:none}
30
- .bar i{display:block;height:100%;width:40%;background:var(--acc2);animation:m 1.2s infinite ease-in-out}
31
- @keyframes m{0%{margin-right:-40%}100%{margin-right:100%}}
32
- @media(prefers-reduced-motion:reduce){.bar i{animation:none;width:100%}}
33
- #out img{width:100%;border-radius:16px;display:block;background:var(--panel)}
34
- .dl{display:flex;gap:8px;margin:10px 0}
35
- .dl button{flex:1;padding:10px;border-radius:12px;border:1px solid var(--acc);background:none;color:var(--ink);font:inherit;cursor:pointer}
36
- #src{font-size:12px;color:var(--mute)}
37
- h2{font-size:15px;margin:22px 0 8px;color:var(--mute);font-weight:400}
38
- #hist{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
39
- #hist img{width:100%;aspect-ratio:1;object-fit:cover;border-radius:10px;cursor:pointer}
40
- .up{display:block;text-align:center;padding:16px;border:1px dashed var(--acc);border-radius:14px;color:var(--acc);cursor:pointer}
41
- .f{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px;margin-top:8px;font-size:13px;word-break:break-all}
42
- .f img,.f video{max-width:100%;border-radius:8px;margin-top:6px}.f audio{width:100%;margin-top:6px}
43
- .soon{padding:30px 10px;text-align:center;color:var(--mute);border:1px dashed var(--line);border-radius:14px}
44
- #vst{word-break:break-word}
45
- :focus-visible{outline:2px solid var(--acc2);outline-offset:2px}
46
- </style>
47
- </head>
48
- <body>
49
- <div class="wrap">
50
- <h1>🐢 أهلاً في Rebel</h1>
51
- <div class="tabs">
52
- <button class="tab on" data-t="img">🖼️ صور</button>
53
- <button class="tab" data-t="mus">🎵 أغاني<small>قريباً</small></button>
54
- <button class="tab" data-t="vid">🎬 فيديو</button>
55
- <button class="tab" data-t="sing">🎤 مغنٍّ</button>
56
- </div>
57
-
58
- <section id="p-img">
59
- <textarea id="pr" placeholder="صف الصورة بالعربية أو الإنجليزية"></textarea>
60
- <div class="chips" id="styles"></div>
61
- <div class="row">
62
- <select id="ratio"><option value="1024x1024">مربع 1:1</option><option value="768x1024">طولي 3:4</option><option value="1024x768">عرضي 4:3</option><option value="720x1280">قصة 9:16</option><option value="1280x720">فيديو 16:9</option></select>
63
- <select id="mode"><option value="auto">تلقائي (الأسرع)</option><option value="flux">Flux</option><option value="turbo">Turbo</option><option value="horde">AI Horde</option></select>
64
- </div>
65
- <label class="sw"><input type="checkbox" id="enh" checked> حسّن الوصف تلقائياً وترجمه للإنجليزية</label>
66
- <button class="go" id="go">توليد</button>
67
- <div class="bar" id="bar"><i></i></div>
68
- <div id="st"></div>
69
- <div id="out"></div>
70
- <div class="dl" id="dl" hidden>
71
- <button data-f="jpeg">JPG</button><button data-f="png">PNG</button><button data-f="webp">WEBP</button><button id="tosing">🎤 أرسل للمغني</button>
72
- </div>
73
- <div id="src"></div>
74
- <h2>آخر أعمالك</h2>
75
- <div id="hist"></div>
76
- </section>
77
-
78
- <section id="p-vid" hidden>
79
- <textarea id="vp" placeholder="صف مشهد الفيديو بالإنجليزية للحصول على نتيجة أفضل"></textarea>
80
- <label class="sw" style="margin-top:10px">Spaces المستخدمة (تُجرَّب بالترتيب، افصل بفاصلة)</label>
81
- <textarea id="vsp" style="min-height:60px;direction:ltr;font-size:13px">Lightricks/ltx-video-distilled</textarea>
82
- <label class="sw" style="margin-top:10px">مفتاح Hugging Face (اختياري: يرفع حصة GPU، يُحفظ على هاتفك فقط)</label>
83
- <input id="vtok" type="password" placeholder="hf_..." autocomplete="off" autocapitalize="off" spellcheck="false" style="width:100%;background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:14px;padding:12px;font:inherit;direction:ltr;text-align:left">
84
- <div class="row"><select id="vdur"><option value="2">مدة 2 ثانية (الأسرع)</option><option value="4">مدة 4 ثوانٍ</option><option value="6">مدة 6 ثوانٍ</option></select><select id="vsz"><option value="704x512">عرضي</option><option value="512x704">طولي</option></select></div>
85
- <button class="go" id="vgo" style="margin-top:10px">توليد فيديو</button>
86
- <div class="bar" id="vbar"><i></i></div>
87
- <div id="vst" style="min-height:26px;margin:10px 0;font-size:14px;color:var(--acc2)"></div>
88
- <div id="vout"></div>
89
- <div id="vsrc" style="font-size:12px;color:var(--mute)"></div>
90
- </section>
91
- <section id="p-sing" hidden>
92
- <p style="font-size:14px;color:var(--mute);margin-top:0">جهّز مقطع الأغنية بالصيغة التي يطلبها InfiniteTalk: WAV أحادي بتردد 16kHz.</p>
93
- <div class="f" id="simgbox"><div id="simgp" style="color:var(--mute);font-size:13px">صورة المغني: ولّد صورة من تبويب الصور ثم اضغط «🎤 أرسل للمغني»، أو ارفع صورة جاهزة:</div>
94
- <label class="up" style="margin-top:8px;padding:10px">🖼️ ارفع صورة جاهزة<input type="file" id="simgf" accept="image/*" hidden></label>
95
- <div class="dl"><button id="simgdl" hidden>تنزيل الصورة PNG لرفعها في Space</button></div></div>
96
- <label class="up" style="margin-top:10px">🎵 اختر الأغنية<input id="sf" type="file" accept="audio/*,video/*" hidden></label>
97
- <div id="sn" style="font-size:13px;color:var(--mute);margin:6px 0"></div>
98
- <div class="row"><select id="sst"><option value="0">البداية: 0 ث</option><option value="10">البداية: 10 ث</option><option value="20">البداية: 20 ث</option><option value="30">البداية: 30 ث</option><option value="60">البداية: 60 ث</option></select>
99
- <select id="sln"><option value="20">المدة: 20 ث (اختبار)</option><option value="30">المدة: 30 ث</option><option value="60">المدة: 60 ث (دقيقة)</option></select></div>
100
- <label class="sw"><input type="checkbox" id="sall"> قصّ الأغنية كلها إلى أجزاء بهذه المدة</label>
101
- <button class="go" id="sgo">قصّ الأغنية</button>
102
- <div id="sst2" style="min-height:26px;margin:10px 0;font-size:14px;color:var(--acc2)"></div>
103
- <div id="sout"></div>
104
- <h2>بعد القص: أنشئ فيديو المغني</h2>
105
- <div class="f">1) افتح Space وارفع الصورة وجزء الأغنية:<br>
106
- <a style="color:var(--acc2)" target="_blank" href="https://huggingface.co/spaces/apexstudio/infinitetalk">apexstudio/infinitetalk</a><br>
107
- <a style="color:var(--acc2)" target="_blank" href="https://huggingface.co/spaces/ShalomKing/infinitetalk">ShalomKing/infinitetalk</a><br>
108
- <a style="color:var(--acc2)" target="_blank" href="https://huggingface.co/spaces/artificialguybr/EchoMimicV3-Demo">artificialguybr/EchoMimicV3-Demo</a><br>
109
- 2) للأغنية الطويلة استخدم دفتر Colab المذكور في المحادثة.</div>
110
- </section>
111
- <section id="p-soon" hidden><div class="soon">قسم الأغاني قيد البناء.<br>سنفعّله بعد الفيديو.</div></section>
112
-
113
- <h2>الملفات</h2>
114
- <label class="up">📎 رفع ملفات (أغاني، صور، وثائق، أي صيغة)<input id="fi" type="file" multiple hidden></label>
115
- <div id="files"></div>
116
- </div>
117
-
118
- <script>
119
- const $=s=>document.querySelector(s);
120
- const gl=k=>{try{return localStorage.getItem(k)||''}catch{return ''}};
121
- const sl=(k,v)=>{try{localStorage.setItem(k,v)}catch{}};
122
- const STY={"بدون":"","واقعي":", photorealistic, 85mm lens, natural light, highly detailed","سينمائي":", cinematic still, dramatic lighting, shallow depth of field, film grain","أنمي":", anime style, vibrant colors, clean line art, studio quality","ثلاثي الأبعاد":", 3D render, octane, soft studio lighting, detailed","لوحة زيتية":", oil painting, rich brush strokes, museum quality","فانتازيا":", epic fantasy concept art, intricate, volumetric light"};
123
- let sty="بدون",blob=null,curPrompt="";
124
- const st=(t,e)=>{$('#st').textContent=t;$('#st').className=e?'err':''};
125
- $('#styles').innerHTML=Object.keys(STY).map(k=>`<button class="chip${k==sty?' on':''}">${k}</button>`).join('');
126
- $('#styles').onclick=e=>{if(!e.target.classList.contains('chip'))return;sty=e.target.textContent;document.querySelectorAll('.chip').forEach(c=>c.classList.toggle('on',c==e.target))};
127
- document.querySelectorAll('.tab').forEach(b=>b.onclick=()=>{document.querySelectorAll('.tab').forEach(x=>x.classList.toggle('on',x==b));const t=b.dataset.t;$('#p-img').hidden=t!='img';$('#p-vid').hidden=t!='vid';$('#p-sing').hidden=t!='sing';$('#p-soon').hidden=t!='mus'});
128
-
129
- const to=(p,ms)=>Promise.race([p,new Promise((_,r)=>setTimeout(()=>r(new Error('timeout')),ms))]);
130
- async function enhance(p){
131
- try{
132
- const q='Rewrite this as one detailed English image-generation prompt (subject, setting, lighting, style). Output only the prompt: '+p;
133
- const r=await to(fetch('https://text.pollinations.ai/'+encodeURIComponent(q)),15000);
134
- const t=(await r.text()).trim();
135
- return t.length>8&&t.length<900?t:p;
136
- }catch{return p}
137
- }
138
- async function viaPoll(p,w,h,model){
139
- const u=`https://image.pollinations.ai/prompt/${encodeURIComponent(p)}?width=${w}&height=${h}&model=${model}&nologo=true&seed=${Math.floor(Math.random()*1e9)}`;
140
- const r=await to(fetch(u),90000);
141
- if(!r.ok)throw new Error('http '+r.status);
142
- const b=await r.blob();
143
- if(!b.type.startsWith('image'))throw new Error('not image');
144
- return b;
145
- }
146
- async function viaHorde(p,w,h){
147
- const k=Math.min(1,576/Math.max(w,h)),W=Math.max(64,Math.round(w*k/64)*64),H=Math.max(64,Math.round(h*k/64)*64);
148
- const H0={apikey:'0000000000','Content-Type':'application/json','Client-Agent':'rebel:2:kipss'};
149
- const r=await fetch('https://aihorde.net/api/v2/generate/async',{method:'POST',headers:H0,body:JSON.stringify({prompt:p,params:{width:W,height:H,steps:25,n:1},nsfw:false,censor_nsfw:true,r2:true})});
150
- const j=await r.json();if(!j.id)throw new Error(j.message||'horde');
151
- for(let i=0;i<90;i++){
152
- await new Promise(s=>setTimeout(s,3000));
153
- const c=await(await fetch('https://aihorde.net/api/v2/generate/check/'+j.id)).json();
154
- st(c.queue_position?`في طابور AI Horde: رقمك ${c.queue_position}`:'AI Horde يولّد الصورة…');
155
- if(c.done)break;
156
- }
157
- const s=await(await fetch('https://aihorde.net/api/v2/generate/status/'+j.id)).json();
158
- const g=s.generations&&s.generations[0];if(!g)throw new Error('horde empty');
159
- if(g.img.startsWith('http'))return await(await fetch(g.img)).blob();
160
- return await(await fetch('data:image/webp;base64,'+g.img)).blob();
161
- }
162
- $('#go').onclick=async()=>{
163
- const raw=$('#pr').value.trim();if(!raw){st('اكتب وصفاً أولاً',1);return}
164
- const [w,h]=$('#ratio').value.split('x').map(Number),mode=$('#mode').value;
165
- $('#go').disabled=true;$('#bar').style.display='block';$('#dl').hidden=true;$('#src').textContent='';
166
- let p=raw;
167
- if($('#enh').checked){st('أحسّن الوصف…');p=await enhance(raw)}
168
- p+=STY[sty];curPrompt=p;
169
- const jobs={flux:['Flux',()=>viaPoll(p,w,h,'flux')],turbo:['Turbo',()=>viaPoll(p,w,h,'turbo')],horde:['AI Horde',()=>viaHorde(p,w,h)]};
170
- const order=mode=='auto'?['flux','turbo','horde']:[mode];
171
- let ok=false;
172
- for(const k of order){
173
- try{st('يولّد عبر '+jobs[k][0]+'…');blob=await jobs[k][1]();ok=true;$('#src').textContent='المصدر: '+jobs[k][0];break}
174
- catch(e){if(order.length>1)st('تعذّر '+jobs[k][0]+'، أجرّب مصدراً آخر…')}
175
- }
176
- $('#bar').style.display='none';$('#go').disabled=false;
177
- if(!ok){st('فشلت كل المصادر الآن. أعد المحاولة بعد قليل أو غيّر الوصف.',1);return}
178
- st('');
179
- const url=URL.createObjectURL(blob);
180
- $('#out').innerHTML=`<img src="${url}" alt="">`;$('#dl').hidden=false;
181
- saveHist();
182
- };
183
- async function conv(f,src){
184
- const bm=await createImageBitmap(src||blob),c=document.createElement('canvas');c.width=bm.width;c.height=bm.height;
185
- const x=c.getContext('2d');if(f=='jpeg'){x.fillStyle='#fff';x.fillRect(0,0,c.width,c.height)}
186
- x.drawImage(bm,0,0);
187
- return new Promise(r=>c.toBlob(r,'image/'+f,.95));
188
- }
189
- $('#dl').onclick=async e=>{
190
- const f=e.target.dataset.f;if(!f||!blob)return;
191
- const b=await conv(f),a=document.createElement('a');
192
- a.href=URL.createObjectURL(b);a.download='rebel-'+Date.now()+'.'+(f=='jpeg'?'jpg':f);a.click();
193
- };
194
- async function saveHist(){
195
- try{
196
- const bm=await createImageBitmap(blob),c=document.createElement('canvas');c.width=c.height=220;
197
- const s=Math.max(220/bm.width,220/bm.height);c.getContext('2d').drawImage(bm,(220-bm.width*s)/2,(220-bm.height*s)/2,bm.width*s,bm.height*s);
198
- const h=JSON.parse(localStorage.getItem('rb_h')||'[]');h.unshift({t:c.toDataURL('image/jpeg',.7),p:curPrompt});
199
- localStorage.setItem('rb_h',JSON.stringify(h.slice(0,12)));drawHist();
200
- }catch{}
201
- }
202
- function drawHist(){
203
- let h=[];try{h=JSON.parse(localStorage.getItem('rb_h')||'[]')}catch{}
204
- $('#hist').innerHTML=h.length?h.map((x,i)=>`<img src="${x.t}" data-i="${i}" alt="">`).join(''):'<span style="color:var(--mute);font-size:13px">لا توجد أعمال بعد. ولّد أول صورة.</span>';
205
- }
206
- $('#hist').onclick=e=>{if(e.target.dataset.i==null)return;const h=JSON.parse(localStorage.getItem('rb_h'));$('#pr').value=h[e.target.dataset.i].p;scrollTo({top:0,behavior:'smooth'})};
207
-
208
- $('#vtok').value=gl('rb_tok');
209
- const vs=(t,e)=>{$('#vst').textContent=t;$('#vst').style.color=e?'var(--err)':'var(--acc2)'};
210
- function findVid(x){
211
- if(!x)return null;
212
- if(typeof x=='string')return /\.(mp4|webm)(\?|$)/i.test(x)?x:null;
213
- if(Array.isArray(x)){for(const i of x){const r=findVid(i);if(r)return r}return null}
214
- if(typeof x=='object'){if(x.url&&/\.(mp4|webm)/i.test(x.url))return x.url;for(const k in x){const r=findVid(x[k]);if(r)return r}}
215
- return null;
216
- }
217
- const NEG='worst quality, inconsistent motion, blurry, jittery, distorted';
218
- function fillParam(x,p,vw,vh){
219
- const n=(x.parameter_name||'').toLowerCase(),has=!!x.parameter_has_default,d=x.parameter_default;
220
- if(/negative/.test(n))return has&&d?d:NEG;
221
- if(/prompt/.test(n))return p;
222
- if(/height/.test(n))return vh;
223
- if(/width/.test(n))return vw;
224
- if(/duration/.test(n))return Number($('#vdur').value);
225
- if(/^mode$|task/.test(n))return 'text-to-video';
226
- if(/random/.test(n))return true;
227
- if(/seed/.test(n))return has&&d!=null?d:42;
228
- if(/guidance/.test(n))return has&&d!=null?d:1;
229
- if(/frames/.test(n))return has&&d!=null?d:9;
230
- if(/improve|texture/.test(n))return has&&d!=null?d:true;
231
- return has?d:null;
232
- }
233
- $('#vgo').onclick=async()=>{
234
- const p=$('#vp').value.trim();if(!p){vs('اكتب وصف المشهد أولاً',1);return}
235
- const list=$('#vsp').value.split(',').map(s=>s.trim()).filter(Boolean);
236
- const [vw,vh]=$('#vsz').value.split('x').map(Number);
237
- const tok=$('#vtok').value.trim();sl('rb_tok',tok);
238
- $('#vgo').disabled=true;$('#vbar').style.display='block';$('#vout').innerHTML='';$('#vsrc').textContent='';
239
- let url=null,used='',lastErr='';
240
- try{
241
- const {Client}=await import('https://cdn.jsdelivr.net/npm/@gradio/client/dist/index.min.js');
242
- for(const sp of list){
243
- try{
244
- vs('أتصل بـ '+sp+'…');
245
- const c=await to(Client.connect(sp,tok.startsWith('hf_')?{hf_token:tok}:{}),60000);
246
- const api=await c.view_api(),all=api.named_endpoints||{};
247
- const eps=Object.entries(all).filter(([n,e])=>(e.returns||[]).some(r=>/video/i.test((r.component||'')+(r.label||'')+JSON.stringify(r.type||''))));
248
- eps.sort((a,b)=>(/text/i.test(b[0])?1:0)-(/text/i.test(a[0])?1:0));
249
- if(!eps.length){lastErr=sp+': لا يوجد مسار فيديو. المسارات الموجودة: '+Object.keys(all).join(' ، ');vs('تعذّر '+lastErr,1);continue}
250
- const name=eps[0][0],e=eps[0][1],data={};
251
- (e.parameters||[]).forEach(x=>{data[x.parameter_name]=fillParam(x,p,vw,vh)});
252
- vs('يولّد الفيديو عبر '+sp+' ('+name+')، قد يستغرق دقائق…');
253
- let res=null;
254
- for await(const m of c.submit(name,data)){
255
- if(m.type=='status'&&m.stage=='pending'){vs(m.position!=null?'في الطابور: رقمك '+(m.position+1):'ينتظر دوره…')}
256
- if(m.type=='status'&&m.stage=='error')throw new Error(m.message||'error');
257
- if(m.type=='data')res=m.data;
258
- }
259
- url=findVid(res);
260
- if(url){used=sp;break}
261
- lastErr=sp+': وصلت نتيجة بلا فيديو: '+JSON.stringify(res).slice(0,200);vs('تعذّر '+lastErr,1);
262
- }catch(err){lastErr=sp+': '+(err.message||JSON.stringify(err));vs('تعذّر '+lastErr+(list.length>1?' — أجرّب التالي…':''),1)}
263
- }
264
- }catch(err){lastErr='تعذّر تحميل مكتبة الاتصال';vs(lastErr,1)}
265
- $('#vbar').style.display='none';$('#vgo').disabled=false;
266
- if(!url){vs('تعذّر توليد الفيديو. '+(lastErr||'جرّب لاحقاً أو أضف Space آخر.'),1);return}
267
- vs('');
268
- $('#vout').innerHTML=`<video controls loop playsinline style="width:100%;border-radius:16px" src="${url}"></video><div class="dl"><button onclick="window.open('${url}','_blank')">فتح / تنزيل MP4</button></div>`;
269
- $('#vsrc').textContent='المصدر: '+used;
270
- };
271
-
272
- const ss=t=>$('#sst2').textContent=t;
273
- $('#sf').onchange=e=>{const f=e.target.files[0];$('#sn').textContent=f?f.name+' ('+(f.size/1048576).toFixed(1)+' MB)':''};
274
- function wav16(buf){
275
- const d=buf.getChannelData(0),n=d.length,o=new DataView(new ArrayBuffer(44+n*2));
276
- const w=(p,t)=>{for(let i=0;i<t.length;i++)o.setUint8(p+i,t.charCodeAt(i))};
277
- w(0,'RIFF');o.setUint32(4,36+n*2,true);w(8,'WAVEfmt ');o.setUint32(16,16,true);o.setUint16(20,1,true);o.setUint16(22,1,true);
278
- o.setUint32(24,16000,true);o.setUint32(28,32000,true);o.setUint16(32,2,true);o.setUint16(34,16,true);w(36,'data');o.setUint32(40,n*2,true);
279
- for(let i=0;i<n;i++){const v=Math.max(-1,Math.min(1,d[i]));o.setInt16(44+i*2,v<0?v*32768:v*32767,true)}
280
- return new Blob([o],{type:'audio/wav'});
281
- }
282
- $('#sgo').onclick=async()=>{
283
- const f=$('#sf').files[0];if(!f){ss('اختر الأغنية أولاً');return}
284
- $('#sgo').disabled=true;$('#sout').innerHTML='';
285
- try{
286
- ss('أفكّ ترميز الأغنية…');
287
- const AC=window.AudioContext||window.webkitAudioContext,ac=new AC();
288
- const buf=await ac.decodeAudioData(await f.arrayBuffer());ac.close();
289
- const len=Number($('#sln').value),st0=Number($('#sst').value),all=$('#sall').checked;
290
- const starts=[];if(all){for(let t=0;t<buf.duration-0.5;t+=len)starts.push(t)}else starts.push(st0);
291
- if(!all&&st0>=buf.duration){ss('البداية بعد نهاية الأغنية (مدتها '+Math.floor(buf.duration)+' ث)');$('#sgo').disabled=false;return}
292
- let k=0;
293
- for(const s0 of starts){
294
- k++;ss('أجهّز الجزء '+k+' من '+starts.length+'…');
295
- const dur=Math.min(len,buf.duration-s0),oc=new OfflineAudioContext(1,Math.ceil(dur*16000),16000),src=oc.createBufferSource();
296
- src.buffer=buf;src.connect(oc.destination);src.start(0,s0,dur);
297
- const b=wav16(await oc.startRendering()),u=URL.createObjectURL(b),nm='part'+String(k).padStart(2,'0')+'_'+Math.round(s0)+'s.wav';
298
- const d=document.createElement('div');d.className='f';
299
- d.innerHTML=`🎵 ${nm} (${Math.round(dur)} ث، ${(b.size/1048576).toFixed(1)} MB)<audio controls src="${u}"></audio><a href="${u}" download="${nm}" style="color:var(--acc2);display:inline-block;margin-top:6px">تنزيل WAV</a>`;
300
- $('#sout').appendChild(d);
301
- }
302
- ss('تم. نزّل الجزء الذي تريده.');
303
- }catch(err){ss('تعذّر قراءة الملف: '+(err.message||'صيغة غير مدعومة'))}
304
- $('#sgo').disabled=false;
305
- };
306
-
307
- let singBlob=null;
308
- function setSing(b){singBlob=b;$('#simgp').innerHTML='<img src="'+URL.createObjectURL(b)+'" alt="" style="max-width:100%;border-radius:12px;display:block">';$('#simgdl').hidden=false}
309
- $('#tosing').onclick=()=>{if(!blob)return;setSing(blob);document.querySelector('[data-t=sing]').click();scrollTo({top:0,behavior:'smooth'})};
310
- $('#simgf').onchange=e=>{if(e.target.files[0])setSing(e.target.files[0])};
311
- $('#simgdl').onclick=async()=>{if(!singBlob)return;const b=await conv('png',singBlob),a=document.createElement('a');a.href=URL.createObjectURL(b);a.download='singer-'+Date.now()+'.png';a.click()};
312
- drawHist();
313
-
314
- $('#fi').onchange=e=>{
315
- for(const f of e.target.files){
316
- const u=URL.createObjectURL(f),d=document.createElement('div');d.className='f';
317
- const kb=f.size>1048576?(f.size/1048576).toFixed(1)+' MB':Math.ceil(f.size/1024)+' KB';
318
- let m='';
319
- if(f.type.startsWith('image'))m=`<img src="${u}" alt="">`;
320
- else if(f.type.startsWith('audio'))m=`<audio controls src="${u}"></audio>`;
321
- else if(f.type.startsWith('video'))m=`<video controls src="${u}"></video>`;
322
- else m=`<br><a href="${u}" download="${f.name}" style="color:var(--acc2)">تنزيل</a>`;
323
- d.innerHTML=`📄 ${f.name.replace(/</g,'&lt;')} (${kb})${m}`;$('#files').prepend(d);
324
- }
325
- e.target.value='';
326
- };
327
- </script>
328
- </body>
329
- </html>