Spaces:
Runtime error
Runtime error
Update index.html
Browse files- index.html +277 -125
index.html
CHANGED
|
@@ -2,158 +2,310 @@
|
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
-
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
| 6 |
-
<title>Recap Studio โ
|
| 7 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 8 |
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
|
|
|
| 9 |
<style>
|
| 10 |
:root{
|
| 11 |
-
--bg:#f5f6fa;--bg2:#fff;
|
| 12 |
-
--border:#e2e4ee;
|
| 13 |
--text:#1a1d2e;--muted:#6b6f8a;--muted2:#9ba1bc;
|
| 14 |
-
--primary:#5b4cf5;--
|
|
|
|
|
|
|
|
|
|
| 15 |
--F:'Plus Jakarta Sans',sans-serif;
|
| 16 |
}
|
| 17 |
*{box-sizing:border-box;margin:0;padding:0}
|
| 18 |
-
body{background:
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
.
|
| 22 |
-
.
|
| 23 |
-
.
|
| 24 |
-
.
|
| 25 |
-
.
|
| 26 |
-
.
|
| 27 |
-
.
|
| 28 |
-
.
|
| 29 |
-
.
|
| 30 |
-
.
|
| 31 |
-
.
|
| 32 |
-
.
|
| 33 |
-
.
|
| 34 |
-
.
|
| 35 |
-
.
|
| 36 |
-
.
|
| 37 |
-
|
| 38 |
-
.
|
| 39 |
-
.
|
| 40 |
-
.
|
| 41 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
</style>
|
| 43 |
</head>
|
| 44 |
<body>
|
| 45 |
-
<div
|
| 46 |
-
<
|
| 47 |
-
<div class="
|
| 48 |
-
<
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
</div>
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
</div>
|
| 56 |
|
| 57 |
-
<
|
| 58 |
-
|
| 59 |
-
<div class="
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
<div class="
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
</button>
|
|
|
|
| 68 |
</div>
|
| 69 |
</div>
|
| 70 |
|
| 71 |
-
<
|
| 72 |
-
|
| 73 |
-
<div class="
|
| 74 |
-
|
| 75 |
-
|
|
|
|
|
|
|
| 76 |
</div>
|
| 77 |
|
| 78 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
</div>
|
| 80 |
</div>
|
| 81 |
|
| 82 |
-
<
|
| 83 |
-
function stab(t){
|
| 84 |
-
['li','re'].forEach(x=>{
|
| 85 |
-
document.getElementById('tab-'+x).classList.toggle('on',x===t);
|
| 86 |
-
document.getElementById('pane-'+x).style.display=x===t?'':'none';
|
| 87 |
-
});
|
| 88 |
-
document.getElementById('am').style.display='none';
|
| 89 |
-
}
|
| 90 |
-
function sam(msg,ok){
|
| 91 |
-
const e=document.getElementById('am');
|
| 92 |
-
e.textContent=msg;
|
| 93 |
-
e.className='am '+(ok?'am-ok':'am-err');
|
| 94 |
-
e.style.display='block';
|
| 95 |
-
}
|
| 96 |
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
if(!u){sam('โ Username required',false);return;}
|
| 100 |
-
try{
|
| 101 |
-
const r=await fetch('/api/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:u,password:p})});
|
| 102 |
-
const d=await r.json();
|
| 103 |
-
if(d.ok){
|
| 104 |
-
sessionStorage.setItem('recap_user',JSON.stringify({u:u,coins:d.coins,is_admin:d.is_admin,name:u}));
|
| 105 |
-
window.location.href='/app';
|
| 106 |
-
} else {
|
| 107 |
-
sam(d.msg||'โ Login failed',false);
|
| 108 |
-
}
|
| 109 |
-
}catch{sam('โ Connection error',false);}
|
| 110 |
-
}
|
| 111 |
-
|
| 112 |
-
async function doReg(){
|
| 113 |
-
const u=document.getElementById('r-u').value.trim(),p=document.getElementById('r-p').value;
|
| 114 |
-
try{
|
| 115 |
-
const r=await fetch('/api/register',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:u,password:p})});
|
| 116 |
-
const d=await r.json();
|
| 117 |
-
if(d.ok){
|
| 118 |
-
sam('โ
'+d.username+' created!',true);
|
| 119 |
-
setTimeout(()=>{
|
| 120 |
-
sessionStorage.setItem('recap_user',JSON.stringify({u:d.username,coins:d.coins,is_admin:false,name:d.username}));
|
| 121 |
-
window.location.href='/app';
|
| 122 |
-
},700);
|
| 123 |
-
} else {
|
| 124 |
-
sam(d.msg||'โ Failed',false);
|
| 125 |
-
}
|
| 126 |
-
}catch{sam('โ Connection error',false);}
|
| 127 |
-
}
|
| 128 |
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
window.open('/auth/google','Google Login',`width=${width},height=${height},left=${left},top=${top}`);
|
| 134 |
-
}
|
| 135 |
|
| 136 |
-
|
| 137 |
-
fetch('/api/auth/google_enabled').then(r=>r.json()).then(d=>{
|
| 138 |
-
if(d.enabled) document.getElementById('google-btn-wrap').style.display='block';
|
| 139 |
-
}).catch(()=>{});
|
| 140 |
-
const sp=new URLSearchParams(location.search);
|
| 141 |
-
if(sp.get('auth')==='google'){
|
| 142 |
-
const u=sp.get('u'),n=sp.get('n'),c=parseInt(sp.get('c')||'0'),a=sp.get('a')==='1';
|
| 143 |
-
if(u){
|
| 144 |
-
sessionStorage.setItem('recap_user',JSON.stringify({u:u,coins:c,is_admin:a,name:n}));
|
| 145 |
-
window.location.href='/app';
|
| 146 |
-
}
|
| 147 |
-
} else if(sp.get('auth_error')){
|
| 148 |
-
sam('โ Google login failed: '+sp.get('auth_error'),false);
|
| 149 |
-
history.replaceState({},'','/');
|
| 150 |
-
}
|
| 151 |
const saved=sessionStorage.getItem('recap_user');
|
| 152 |
-
if(saved){
|
| 153 |
-
|
| 154 |
-
}
|
| 155 |
});
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
</script>
|
| 158 |
</body>
|
| 159 |
</html>
|
|
|
|
| 2 |
<html lang="en">
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
|
| 6 |
+
<title>Recap Studio โ Create Viral Videos</title>
|
| 7 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 8 |
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
| 9 |
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css">
|
| 10 |
<style>
|
| 11 |
:root{
|
| 12 |
+
--bg:#f5f6fa;--bg2:#fff;--bg3:#f0f1f7;--bg4:#e8eaf2;
|
| 13 |
+
--border:#e2e4ee;--border2:#cdd0e0;
|
| 14 |
--text:#1a1d2e;--muted:#6b6f8a;--muted2:#9ba1bc;
|
| 15 |
+
--primary:#5b4cf5;--primary2:#4a3de0;
|
| 16 |
+
--orange:#ff6b35;--orange2:#e85a25;
|
| 17 |
+
--green:#10b981;--red:#ef4444;--blue:#3b82f6;--purple:#8b5cf6;
|
| 18 |
+
--gold:#f59e0b;
|
| 19 |
--F:'Plus Jakarta Sans',sans-serif;
|
| 20 |
}
|
| 21 |
*{box-sizing:border-box;margin:0;padding:0}
|
| 22 |
+
body{background:var(--bg);color:var(--text);font-family:var(--F);min-height:100vh}
|
| 23 |
+
#app-screen{display:block}
|
| 24 |
+
|
| 25 |
+
.hdr{display:flex;align-items:center;justify-content:space-between;padding:0 16px;height:56px;background:#fff;border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100;box-shadow:0 1px 8px rgba(0,0,0,.06)}
|
| 26 |
+
.brand{display:flex;align-items:center;gap:9px;font-weight:800;font-size:1rem;color:var(--text)}
|
| 27 |
+
.brand-i{width:30px;height:30px;background:linear-gradient(135deg,var(--primary),var(--purple));border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.75rem}
|
| 28 |
+
.hr{display:flex;align-items:center;gap:7px}
|
| 29 |
+
.cpill{display:flex;align-items:center;gap:5px;padding:5px 12px;background:linear-gradient(135deg,#fff7ed,#fef3c7);border:1.5px solid #fcd34d;border-radius:20px;font-size:.78rem;font-weight:700;color:#92400e;cursor:pointer;transition:.2s}
|
| 30 |
+
.cpill:hover{box-shadow:0 2px 8px rgba(245,158,11,.2)}
|
| 31 |
+
.hb{padding:7px 13px;border-radius:8px;border:1.5px solid var(--border);background:#fff;color:var(--muted);font-family:var(--F);font-size:.78rem;font-weight:600;cursor:pointer;transition:.2s}
|
| 32 |
+
.hb:hover{border-color:var(--primary);color:var(--primary)}
|
| 33 |
+
.hb-p{background:linear-gradient(135deg,var(--orange),var(--orange2));border-color:transparent;color:#fff}
|
| 34 |
+
.hb-p:hover{box-shadow:0 4px 14px rgba(255,107,53,.3);transform:translateY(-1px)}
|
| 35 |
+
.mbtn{width:33px;height:33px;border:1.5px solid var(--border);background:#fff;border-radius:8px;cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;transition:.2s}
|
| 36 |
+
.mbtn span{display:block;width:15px;height:1.5px;background:var(--muted);border-radius:2px}
|
| 37 |
+
.dov{display:none;position:fixed;inset:0;z-index:200}
|
| 38 |
+
.dov.on{display:block}
|
| 39 |
+
.dbg{position:absolute;inset:0;background:rgba(0,0,0,.4);backdrop-filter:blur(3px)}
|
| 40 |
+
.drw{position:absolute;top:0;right:0;width:280px;height:100%;background:#fff;box-shadow:-8px 0 32px rgba(0,0,0,.12);display:flex;flex-direction:column;animation:sli .2s ease}
|
| 41 |
+
@keyframes sli{from{transform:translateX(100%)}to{transform:translateX(0)}}
|
| 42 |
+
.drw-h{padding:18px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
|
| 43 |
+
.drw-u{display:flex;align-items:center;gap:11px}
|
| 44 |
+
.av{width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,var(--primary),var(--purple));display:flex;align-items:center;justify-content:center;font-weight:700;font-size:.95rem;color:#fff}
|
| 45 |
+
.dn{font-weight:700;font-size:.9rem}
|
| 46 |
+
.drl{font-size:.68rem;color:var(--muted);margin-top:1px}
|
| 47 |
+
.dxbtn{width:28px;height:28px;border:1.5px solid var(--border);background:#fff;color:var(--muted);border-radius:7px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:.75rem}
|
| 48 |
+
.drw-s{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:14px 18px;border-bottom:1px solid var(--border)}
|
| 49 |
+
.ds{background:var(--bg);border-radius:10px;padding:12px;text-align:center}
|
| 50 |
+
.dsv{font-size:1.3rem;font-weight:800;color:var(--primary)}
|
| 51 |
+
.dsl{font-size:.63rem;color:var(--muted);margin-top:2px}
|
| 52 |
+
.drw-n{flex:1;padding:8px}
|
| 53 |
+
.dni{display:flex;align-items:center;gap:9px;padding:10px 13px;border-radius:9px;cursor:pointer;border:none;background:transparent;width:100%;text-align:left;font-family:var(--F);font-size:.83rem;font-weight:500;color:var(--text)}
|
| 54 |
+
.dni:hover{background:var(--bg)}
|
| 55 |
+
.dni i{width:17px;color:var(--muted)}
|
| 56 |
+
.dni-r{color:var(--red)}.dni-r i{color:var(--red)}
|
| 57 |
+
.drw-f{padding:12px 18px;border-top:1px solid var(--border);font-size:.66rem;color:var(--muted2);text-align:center}
|
| 58 |
+
.ab{max-width:900px;margin:0 auto;padding:18px 14px 70px}
|
| 59 |
+
.card{background:#fff;border:1px solid var(--border);border-radius:16px;padding:16px;margin-bottom:12px;box-shadow:0 1px 6px rgba(0,0,0,.04)}
|
| 60 |
+
.ch{display:flex;align-items:center;gap:8px;margin-bottom:13px}
|
| 61 |
+
.ci{width:28px;height:28px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:.74rem}
|
| 62 |
+
.ci-p{background:linear-gradient(135deg,#ede9fe,#ddd6fe);color:var(--primary)}
|
| 63 |
+
.ci-o{background:linear-gradient(135deg,#fff7ed,#fed7aa);color:var(--orange)}
|
| 64 |
+
.ci-g{background:linear-gradient(135deg,#d1fae5,#a7f3d0);color:var(--green)}
|
| 65 |
+
.ct{font-weight:800;font-size:.88rem}
|
| 66 |
+
.uw{position:relative}
|
| 67 |
+
.uinp{width:100%;padding:11px 100px 11px 42px;background:var(--bg);border:1.5px solid var(--border);border-radius:10px;font-family:var(--F);font-size:.86rem;outline:none}
|
| 68 |
+
.uinp:focus{border-color:var(--primary);background:#fff}
|
| 69 |
+
.uico{position:absolute;left:13px;top:50%;transform:translateY(-50%);color:var(--muted)}
|
| 70 |
+
.paste-btn{position:absolute;right:10px;top:50%;transform:translateY(-50%);padding:5px 11px;background:var(--primary);border:none;border-radius:7px;color:#fff;font-size:.72rem;font-weight:700;cursor:pointer}
|
| 71 |
+
.orsep{text-align:center;color:var(--muted2);font-size:.73rem;margin:10px 0;position:relative}
|
| 72 |
+
.orsep::before,.orsep::after{content:'';position:absolute;top:50%;width:44%;height:1px;background:var(--border)}
|
| 73 |
+
.orsep::before{left:0}.orsep::after{right:0}
|
| 74 |
+
.upz{border:2px dashed var(--border2);border-radius:10px;padding:14px;text-align:center;cursor:pointer;position:relative}
|
| 75 |
+
.upz:hover{border-color:var(--primary);background:#faf9ff}
|
| 76 |
+
.upz input{position:absolute;inset:0;opacity:0;cursor:pointer}
|
| 77 |
+
.upz-t{font-size:.78rem;color:var(--muted)}
|
| 78 |
+
.upz-n{font-size:.76rem;color:var(--green);margin-top:3px;display:none}
|
| 79 |
+
.sgrid{display:grid;grid-template-columns:1fr 1fr;gap:9px}
|
| 80 |
+
@media(max-width:460px){.sgrid{grid-template-columns:1fr}}
|
| 81 |
+
.si{background:var(--bg);border:1.5px solid var(--border);border-radius:10px;padding:11px 13px}
|
| 82 |
+
.sil{font-size:.65rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--muted);margin-bottom:6px}
|
| 83 |
+
.ssel{width:100%;background:transparent;border:none;color:var(--text);font-family:var(--F);font-size:.84rem;font-weight:500;outline:none;cursor:pointer}
|
| 84 |
+
.vrow{display:flex;align-items:center;gap:7px}
|
| 85 |
+
.vrow .ssel{flex:1;background:var(--bg);border:1.5px solid var(--border);border-radius:9px;padding:9px 11px}
|
| 86 |
+
.pvbtn{width:34px;height:34px;background:#fff;border:1.5px solid var(--border);border-radius:9px;color:var(--muted);cursor:pointer}
|
| 87 |
+
.spd-row{display:flex;align-items:center;gap:9px;margin-top:9px}
|
| 88 |
+
.spd-row label{font-size:.7rem;font-weight:600;color:var(--muted);width:52px}
|
| 89 |
+
.spd-sl{flex:1;-webkit-appearance:none;height:4px;border-radius:2px;background:var(--bg4)}
|
| 90 |
+
.spd-sl::-webkit-slider-thumb{-webkit-appearance:none;width:14px;height:14px;border-radius:50%;background:var(--primary);cursor:pointer}
|
| 91 |
+
.spd-v{font-size:.73rem;color:var(--primary);font-weight:700;width:36px;text-align:right}
|
| 92 |
+
.egrid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
|
| 93 |
+
.icon-toggle{display:flex;align-items:center;justify-content:center;gap:5px;padding:8px 10px;background:var(--bg);border:1.5px solid var(--border);border-radius:8px;cursor:pointer;font-size:.79rem;font-weight:600;color:var(--muted);width:100%}
|
| 94 |
+
.icon-toggle.on{background:linear-gradient(135deg,#ede9fe,#e0e7ff);border-color:var(--primary);color:var(--primary)}
|
| 95 |
+
.btn-auto{width:100%;padding:15px;background:linear-gradient(135deg,var(--primary),var(--purple));border:none;border-radius:12px;color:#fff;font-family:var(--F);font-size:.94rem;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:8px;box-shadow:0 4px 18px rgba(91,76,245,.3)}
|
| 96 |
+
.btn-auto:disabled{opacity:.5;cursor:not-allowed}
|
| 97 |
+
.pc{background:#fff;border:1px solid var(--border);border-radius:16px;padding:18px;margin-top:12px;display:none}
|
| 98 |
+
.ph{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}
|
| 99 |
+
.ptit{font-weight:800;font-size:.86rem}
|
| 100 |
+
.ptmr{font-size:.73rem;color:var(--primary);font-weight:700;background:#ede9fe;padding:3px 9px;border-radius:20px}
|
| 101 |
+
.pb-bg{height:6px;background:var(--bg4);border-radius:3px;overflow:hidden;margin-bottom:9px}
|
| 102 |
+
.pb{height:100%;background:linear-gradient(90deg,var(--primary),var(--orange));border-radius:3px;width:0%}
|
| 103 |
+
.pmsg{font-size:.8rem;color:var(--muted);font-weight:500}
|
| 104 |
+
.psteps{display:flex;gap:5px;margin-top:11px;flex-wrap:wrap}
|
| 105 |
+
.ps{font-size:.66rem;font-weight:600;padding:4px 10px;border-radius:20px;background:var(--bg);color:var(--muted2);border:1px solid var(--border)}
|
| 106 |
+
.ps.active{background:#ede9fe;color:var(--primary);border-color:#c4b5fd}
|
| 107 |
+
.ps.done{background:#d1fae5;color:#065f46;border-color:#6ee7b7}
|
| 108 |
+
.rc{background:#fff;border:1px solid var(--border);border-radius:16px;overflow:hidden;margin-top:12px;display:none}
|
| 109 |
+
.rvw{background:#000}
|
| 110 |
+
.rvw video{width:100%;display:block;max-height:380px;object-fit:contain}
|
| 111 |
+
.rb{padding:15px}
|
| 112 |
+
.rtm{font-size:.7rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:4px}
|
| 113 |
+
.rtit{font-weight:800;font-size:.94rem;margin-bottom:5px}
|
| 114 |
+
.rtag{font-size:.73rem;color:var(--primary);margin-bottom:12px}
|
| 115 |
+
.ract{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
| 116 |
+
.rb-btn{padding:11px;border-radius:9px;border:none;font-family:var(--F);font-size:.81rem;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center;gap:6px}
|
| 117 |
+
.rb-g{background:#d1fae5;color:#065f46}
|
| 118 |
+
.rb-b{background:#dbeafe;color:#1d4ed8}
|
| 119 |
+
.admp{background:#fff;border:2px solid #fef3c7;border-radius:16px;padding:16px;margin-top:12px;display:none}
|
| 120 |
+
.admbadge{font-size:.63rem;font-weight:700;padding:3px 8px;background:#fef3c7;color:#92400e;border-radius:20px;margin-left:8px}
|
| 121 |
+
.admg{display:grid;grid-template-columns:1fr 1fr;gap:9px;margin-bottom:11px}
|
| 122 |
+
.ai-row{display:flex;gap:5px}
|
| 123 |
+
.ai{flex:1;padding:8px 10px;background:var(--bg);border:1.5px solid var(--border);border-radius:8px;font-family:var(--F);font-size:.8rem;outline:none}
|
| 124 |
+
.abtn{padding:8px 12px;border-radius:8px;border:none;font-size:.76rem;font-weight:700;cursor:pointer}
|
| 125 |
+
.ab-g{background:#ede9fe;color:var(--primary)}
|
| 126 |
+
.ab-r{background:#fee2e2;color:#dc2626}
|
| 127 |
+
.ut{width:100%;border-collapse:collapse;font-size:.76rem;margin-top:10px}
|
| 128 |
+
.ut th{padding:7px 9px;text-align:left;font-size:.63rem;font-weight:700;color:var(--muted);border-bottom:2px solid var(--border)}
|
| 129 |
+
.ut td{padding:7px 9px;border-bottom:1px solid var(--bg4)}
|
| 130 |
+
#toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--text);border-radius:10px;padding:9px 16px;font-size:.8rem;color:#fff;z-index:9999;opacity:0;transition:.3s;pointer-events:none;white-space:nowrap}
|
| 131 |
+
#toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
|
| 132 |
+
@keyframes spin{to{transform:rotate(360deg)}}
|
| 133 |
+
.sp{display:inline-block;animation:spin .7s linear infinite}
|
| 134 |
+
.modal-ov{display:none;position:fixed;inset:0;z-index:300;align-items:flex-end;justify-content:center}
|
| 135 |
+
.modal-ov.on{display:flex}
|
| 136 |
+
.modal-bg{position:absolute;inset:0;background:rgba(0,0,0,.45);backdrop-filter:blur(3px)}
|
| 137 |
+
.modal-sheet{position:relative;width:100%;max-width:480px;background:#fff;border-radius:20px 20px 0 0;padding:24px 20px 36px;animation:slideUp .25s ease}
|
| 138 |
+
@keyframes slideUp{from{transform:translateY(100%)}to{transform:translateY(0)}}
|
| 139 |
+
.modal-sheet h3{font-size:1.1rem;font-weight:800;margin-bottom:4px}
|
| 140 |
+
.modal-sheet p{font-size:.8rem;color:var(--muted);margin-bottom:18px}
|
| 141 |
+
.pkg-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
|
| 142 |
+
.pkg-card{background:var(--bg);border:1.5px solid var(--border);border-radius:12px;padding:14px 12px;text-align:center;cursor:pointer;transition:.2s;position:relative}
|
| 143 |
+
.pkg-card:hover{border-color:var(--primary);background:#faf9ff}
|
| 144 |
+
.pkg-card.popular{border-color:var(--primary);background:#faf9ff}
|
| 145 |
+
.pkg-pop-badge{position:absolute;top:-9px;left:50%;transform:translateX(-50%);background:var(--primary);color:#fff;font-size:.6rem;font-weight:700;padding:2px 8px;border-radius:10px}
|
| 146 |
+
.pkg-emoji{font-size:1.5rem;margin-bottom:5px}
|
| 147 |
+
.pkg-name{font-size:.75rem;font-weight:700;margin-bottom:3px}
|
| 148 |
+
.pkg-coins{font-size:1.2rem;font-weight:800;color:var(--primary)}
|
| 149 |
+
.pkg-coins span{font-size:.7rem;font-weight:500;color:var(--muted)}
|
| 150 |
+
.pkg-contact{background:var(--bg);border:1.5px solid var(--border);border-radius:10px;padding:12px;text-align:center;font-size:.8rem}
|
| 151 |
+
.pkg-contact a{color:var(--primary);font-weight:600;text-decoration:none}
|
| 152 |
+
.modal-close{position:absolute;top:14px;right:16px;width:28px;height:28px;border:1.5px solid var(--border);background:#fff;border-radius:7px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:.75rem}
|
| 153 |
</style>
|
| 154 |
</head>
|
| 155 |
<body>
|
| 156 |
+
<div id="app-screen">
|
| 157 |
+
<header class="hdr">
|
| 158 |
+
<div class="brand"><div class="brand-i">๐ฌ</div>Recap Studio</div>
|
| 159 |
+
<div class="hr">
|
| 160 |
+
<div class="cpill" id="cpill" onclick="openPkg()">๐ช <span id="hcoins">0</span> coins</div>
|
| 161 |
+
<button class="hb hb-p" onclick="window.location.href='/payment'">Buy Coins</button>
|
| 162 |
+
<button class="mbtn" onclick="odw()"><span></span><span></span><span></span></button>
|
| 163 |
+
</div>
|
| 164 |
+
</header>
|
| 165 |
+
|
| 166 |
+
<div class="dov" id="dov">
|
| 167 |
+
<div class="dbg" onclick="cdw()"></div>
|
| 168 |
+
<div class="drw">
|
| 169 |
+
<div class="drw-h">
|
| 170 |
+
<div class="drw-u"><div class="av" id="dav">U</div><div><div class="dn" id="dun">โ</div><div class="drl" id="drl">Member</div></div></div>
|
| 171 |
+
<button class="dxbtn" onclick="cdw()"><i class="fas fa-times"></i></button>
|
| 172 |
+
</div>
|
| 173 |
+
<div class="drw-s">
|
| 174 |
+
<div class="ds"><div class="dsv" id="dcoins">0</div><div class="dsl">Coins</div></div>
|
| 175 |
+
<div class="ds"><div class="dsv" id="dvids">0</div><div class="dsl">Videos</div></div>
|
| 176 |
+
</div>
|
| 177 |
+
<div class="drw-n">
|
| 178 |
+
<button class="dni" onclick="cdw()"><i class="fas fa-home"></i>Home</button>
|
| 179 |
+
<button class="dni" onclick="window.location.href='/payment-history';cdw()"><i class="fas fa-history"></i>Payment History</button>
|
| 180 |
+
<button class="dni" id="adm-dlink" style="display:none" onclick="scrollToAdmin();cdw()"><i class="fas fa-crown"></i>Admin Panel</button>
|
| 181 |
+
<button class="dni dni-r" onclick="doLogout()"><i class="fas fa-sign-out-alt"></i>Logout</button>
|
| 182 |
+
</div>
|
| 183 |
+
<div class="drw-f">recap.psonline.shop</div>
|
| 184 |
+
</div>
|
| 185 |
</div>
|
| 186 |
+
|
| 187 |
+
<div class="ab">
|
| 188 |
+
<div class="card">
|
| 189 |
+
<div class="ch"><div class="ci ci-p"><i class="fas fa-video"></i></div><div class="ct">Video Source</div></div>
|
| 190 |
+
<div class="uw">
|
| 191 |
+
<i class="fas fa-link uico"></i>
|
| 192 |
+
<input class="uinp" id="vurl" placeholder="Paste YouTube / TikTok / Facebook / Instagram linkโฆ" oninput="onUrl(this.value)">
|
| 193 |
+
<button class="paste-btn" onclick="doPaste()"><i class="fas fa-paste"></i> Paste</button>
|
| 194 |
+
</div>
|
| 195 |
+
<div class="orsep">or upload file</div>
|
| 196 |
+
<div class="upz">
|
| 197 |
+
<input type="file" id="vfile" accept="video/*" onchange="onFile(this)">
|
| 198 |
+
<div class="upz-t"><i class="fas fa-cloud-upload-alt"></i> Click or drag video file here</div>
|
| 199 |
+
<div class="upz-n" id="upzn"></div>
|
| 200 |
+
</div>
|
| 201 |
</div>
|
| 202 |
|
| 203 |
+
<div class="card">
|
| 204 |
+
<div class="ch"><div class="ci ci-o"><i class="fas fa-sliders-h"></i></div><div class="ct">Settings</div></div>
|
| 205 |
+
<div class="sgrid">
|
| 206 |
+
<div class="si"><div class="sil">Language</div><select class="ssel" id="vlang" onchange="onLang()"><option value="my">๐ฒ๐ฒ Myanmar</option><option value="th">๐น๐ญ Thai</option><option value="en">๐ฌ๐ง English</option></select></div>
|
| 207 |
+
<div class="si"><div class="sil">Content Type</div><select class="ssel" id="ctype"><option value="Movie Recap">๐ฌ Movie Recap</option><option value="Medical/Health">๐ Medical</option></select></div>
|
| 208 |
+
<div class="si"><div class="sil">AI Model</div><select class="ssel" id="aimodel"><option value="Gemini">โจ Gemini</option><option value="DeepSeek">๐ค DeepSeek</option></select></div>
|
| 209 |
+
<div class="si"><div class="sil">TTS Engine</div><select class="ssel" id="engine" onchange="onEng()"><option value="ms">๐๏ธ Edge TTS</option><option value="gemini">๐ฎ Gemini TTS</option></select></div>
|
| 210 |
+
</div>
|
| 211 |
+
<div style="margin-top:10px">
|
| 212 |
+
<div class="sil" style="margin-bottom:6px">Voice</div>
|
| 213 |
+
<div class="vrow"><select class="ssel" id="vsel"></select><button class="pvbtn" id="pvbtn" onclick="doPrevVoice()"><i class="fas fa-play"></i></button></div>
|
| 214 |
+
<div class="spd-row"><label>Speed</label><input type="range" class="spd-sl" id="spd" min="-50" max="100" value="30" oninput="document.getElementById('spdv').textContent=this.value+'%'"><span class="spd-v" id="spdv">30%</span></div>
|
| 215 |
</div>
|
| 216 |
</div>
|
| 217 |
|
| 218 |
+
<div class="card">
|
| 219 |
+
<div class="ch"><div class="ci ci-g"><i class="fas fa-film"></i></div><div class="ct">Video Options</div></div>
|
| 220 |
+
<div class="egrid">
|
| 221 |
+
<div class="si"><div class="sil">Aspect Ratio</div><select class="ssel" id="crop"><option value="9:16">9:16 TikTok</option><option value="16:9">16:9 YouTube</option><option value="1:1">1:1 Square</option></select></div>
|
| 222 |
+
<div class="si"><div class="sil">Flip</div><button class="icon-toggle" id="btn-flip" onclick="toggleOpt('flip')"><i class="fas fa-arrows-alt-h"></i> Off</button></div>
|
| 223 |
+
<div class="si"><div class="sil">Color Boost</div><button class="icon-toggle" id="btn-col" onclick="toggleOpt('col')"><i class="fas fa-adjust"></i> Off</button></div>
|
| 224 |
+
</div>
|
| 225 |
</div>
|
| 226 |
|
| 227 |
+
<button class="btn-auto" id="btnauto" onclick="doAuto()"><i class="fas fa-magic"></i> Auto Process <span style="opacity:.7;font-size:.78em">2 Coins</span></button>
|
| 228 |
+
|
| 229 |
+
<div class="pc" id="pc">
|
| 230 |
+
<div class="ph"><span class="ptit">โ๏ธ Processingโฆ</span><span class="ptmr" id="ptmr">โฑ 0s</span></div>
|
| 231 |
+
<div class="pb-bg"><div class="pb" id="pb"></div></div>
|
| 232 |
+
<div class="pmsg" id="pmsg">Startingโฆ</div>
|
| 233 |
+
<div class="psteps"><span class="ps" id="ps-dl">๐ฅ Download</span><span class="ps" id="ps-tr">๐๏ธ Transcribe</span><span class="ps" id="ps-ai">๐ค AI Script</span><span class="ps" id="ps-ts">๐ TTS</span><span class="ps" id="ps-vd">๐ฌ Render</span></div>
|
| 234 |
+
</div>
|
| 235 |
+
|
| 236 |
+
<div class="rc" id="rc">
|
| 237 |
+
<div class="rvw"><video id="rvid" controls playsinline></video></div>
|
| 238 |
+
<div class="rb"><div class="rtm" id="rtm" style="display:none"><i class="fas fa-clock"></i><span></span></div><div class="rtit" id="rtit" style="display:none"></div><div class="rtag" id="rtag" style="display:none"></div><div class="ract"><button class="rb-btn rb-g" onclick="dlVideo()"><i class="fas fa-download"></i> Download MP4</button><button class="rb-btn rb-b" onclick="copyCap()"><i class="fas fa-copy"></i> Copy Caption</button></div></div>
|
| 239 |
+
</div>
|
| 240 |
+
|
| 241 |
+
<div class="admp" id="admp"><div class="ch"><div class="ci ci-p"><i class="fas fa-crown"></i></div><div class="ct">Admin Panel</div><span class="admbadge">Admin</span></div>
|
| 242 |
+
<div class="admg"><div><div class="sil">Add Coins</div><div class="ai-row"><input class="ai" id="au-add" placeholder="username"><input class="ai" id="an-add" type="number" placeholder="n" style="width:60px"><button class="abtn ab-g" onclick="admCoins('add')">Add</button></div></div>
|
| 243 |
+
<div><div class="sil">Set Coins</div><div class="ai-row"><input class="ai" id="au-set" placeholder="username"><input class="ai" id="an-set" type="number" placeholder="n" style="width:60px"><button class="abtn ab-g" onclick="admCoins('set')">Set</button></div></div>
|
| 244 |
+
<div><div class="sil">Create User</div><div class="ai-row"><input class="ai" id="au-new" placeholder="name (blank=auto)"><button class="abtn ab-g" onclick="admCreate()">Create</button></div><div id="au-res" style="font-size:.71rem;color:var(--green);margin-top:3px"></div></div>
|
| 245 |
+
<div><div class="sil">Delete User</div><div class="ai-row"><input class="ai" id="au-del" placeholder="username"><button class="abtn ab-r" onclick="admDel()">Delete</button></div></div></div>
|
| 246 |
+
<div id="admmsg" class="admmsg"></div>
|
| 247 |
+
<button style="padding:8px 14px;background:var(--bg);border:1.5px solid var(--border);border-radius:8px;font-size:.75rem;cursor:pointer;margin-top:4px" onclick="loadUsers()"><i class="fas fa-users"></i> Load Users</button>
|
| 248 |
+
<div id="utw" style="overflow-x:auto"></div>
|
| 249 |
+
</div>
|
| 250 |
</div>
|
| 251 |
</div>
|
| 252 |
|
| 253 |
+
<div class="modal-ov" id="pkg-modal"><div class="modal-bg" onclick="closePkg()"></div><div class="modal-sheet"><button class="modal-close" onclick="closePkg()"><i class="fas fa-times"></i></button><h3>๐ฐ Buy Coins</h3><p>Package แแฝแฑแธแแผแฎแธ Admin แแญแฏ Telegram แแพ แแแบแแฝแแบแแซ</p><div class="pkg-grid"><div class="pkg-card" onclick="contactPkg(10,'10,000 MMK')"><div class="pkg-emoji">๐ฅ</div><div class="pkg-name">Starter</div><div class="pkg-coins">10 <span>coins</span></div></div><div class="pkg-card popular" onclick="contactPkg(30,'28,000 MMK')"><div class="pkg-pop-badge">โญ Popular</div><div class="pkg-emoji">๐ฅ</div><div class="pkg-name">Basic</div><div class="pkg-coins">30 <span>coins</span></div></div><div class="pkg-card" onclick="contactPkg(60,'58,000 MMK')"><div class="pkg-emoji">๐ฅ</div><div class="pkg-name">Pro</div><div class="pkg-coins">60 <span>coins</span></div></div><div class="pkg-card" onclick="contactPkg(100,'95,000 MMK')"><div class="pkg-emoji">๐</div><div class="pkg-name">Unlimited</div><div class="pkg-coins">100 <span>coins</span></div></div></div><div class="pkg-contact">Account: <b id="pkg-uname">โ</b> ยท <a href="https://t.me/PhoeShan2001" target="_blank">๐ฉ @PhoeShan2001 แแญแฏ Message แแญแฏแทแแแบ</a></div></div></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 254 |
|
| 255 |
+
<div id="toast"></div>
|
| 256 |
+
<audio id="pva"></audio>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
|
| 258 |
+
<script>
|
| 259 |
+
let U='',COINS=0,ISADM=false,OUT_URL='',OUT_CAP='',OUT_TAGS='',SSE=null,TICK=null,T0=0,FLIP_ON=false,COL_ON=false;
|
| 260 |
+
const EV={my:[{id:'my-MM-ThihaNeural',name:'Thiha (Male)'},{id:'my-MM-NilarNeural',name:'Nilar (Female)'}],th:[{id:'th-TH-NiwatNeural',name:'Niwat'},{id:'th-TH-PremwadeeNeural',name:'Premwadee'}],en:[{id:'en-US-GuyNeural',name:'Guy'},{id:'en-US-JennyNeural',name:'Jenny'}]};
|
| 261 |
+
let GV=[];
|
|
|
|
|
|
|
| 262 |
|
| 263 |
+
addEventListener('DOMContentLoaded',()=>{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 264 |
const saved=sessionStorage.getItem('recap_user');
|
| 265 |
+
if(!saved){window.location.href='/login';return;}
|
| 266 |
+
try{const sess=JSON.parse(saved);eApp(sess.u,sess.coins,sess.is_admin,sess.name);}catch{window.location.href='/login';}
|
| 267 |
+
onLang();fetch('/api/gemini_voices').then(r=>r.ok?r.json():null).then(d=>{if(d?.ok){GV=d.voices;onEng();}}).catch(()=>{});
|
| 268 |
});
|
| 269 |
+
|
| 270 |
+
function eApp(u,coins,isAdm,displayName){U=u;COINS=coins;ISADM=isAdm;updC(coins);const dn=displayName||u;document.getElementById('dun').textContent=dn;document.getElementById('drl').textContent=isAdm?'๐ Admin':'Member';document.getElementById('dav').textContent=dn[0].toUpperCase();if(isAdm){document.getElementById('admp').style.display='block';document.getElementById('adm-dlink').style.display='flex';document.getElementById('cpill').style.display='none';document.getElementById('dcoins').textContent='โ';}}
|
| 271 |
+
function doLogout(){U='';COINS=0;ISADM=false;sessionStorage.removeItem('recap_user');window.location.href='/login';}
|
| 272 |
+
function odw(){document.getElementById('dcoins').textContent=ISADM?'โ':COINS;document.getElementById('dov').classList.add('on');}
|
| 273 |
+
function cdw(){document.getElementById('dov').classList.remove('on');}
|
| 274 |
+
function scrollToAdmin(){document.getElementById('admp').scrollIntoView({behavior:'smooth'});}
|
| 275 |
+
function updC(n){if(n===-1||ISADM)return;COINS=n;document.getElementById('hcoins').textContent=n;}
|
| 276 |
+
function onLang(){renderV();}
|
| 277 |
+
function onEng(){renderV();const g=document.getElementById('engine').value==='gemini';document.getElementById('pvbtn').style.display=g?'none':'flex';}
|
| 278 |
+
function renderV(){const lang=document.getElementById('vlang').value,eng=document.getElementById('engine').value;const sel=document.getElementById('vsel');sel.innerHTML='';(eng==='gemini'?GV:(EV[lang]||EV.my)).forEach(v=>{const o=document.createElement('option');o.value=v.id;o.textContent=v.name||v.id;sel.appendChild(o);});}
|
| 279 |
+
async function doPrevVoice(){const voice=document.getElementById('vsel').value,speed=parseInt(document.getElementById('spd').value);const btn=document.getElementById('pvbtn');btn.innerHTML='<i class="fas fa-spinner sp"></i>';try{const r=await fetch('/api/preview_voice',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({voice,speed,engine:'ms'})});const d=await r.json();if(d.ok){const a=document.getElementById('pva');a.src=d.url;a.play();}else toast('โ Preview failed');}catch{toast('โ Preview failed');}btn.innerHTML='<i class="fas fa-play"></i>';}
|
| 280 |
+
function toggleOpt(k){if(k==='flip'){FLIP_ON=!FLIP_ON;const b=document.getElementById('btn-flip');b.className='icon-toggle'+(FLIP_ON?' on':'');b.innerHTML='<i class="fas fa-arrows-alt-h"></i> '+(FLIP_ON?'On':'Off');}else{COL_ON=!COL_ON;const b=document.getElementById('btn-col');b.className='icon-toggle'+(COL_ON?' on':'');b.innerHTML='<i class="fas fa-adjust"></i> '+(COL_ON?'On':'Off');}}
|
| 281 |
+
function onUrl(v){if(URL_DEBOUNCE)clearTimeout(URL_DEBOUNCE);if(v.startsWith('http')){URL_DEBOUNCE=setTimeout(()=>autoPreview(v),1200);}}
|
| 282 |
+
let URL_DEBOUNCE=null;
|
| 283 |
+
async function autoPreview(url){try{const r=await fetch('/api/thumb',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url})});const d=await r.json();if(d.ok&&d.width>0){const sel=document.getElementById('crop');const ratio=d.width/d.height;if(ratio>0.9&&ratio<1.1)sel.value='1:1';else if(ratio<0.7)sel.value='9:16';else if(ratio>1.4)sel.value='16:9';else sel.value='9:16';}}catch(e){console.log(e)}}
|
| 284 |
+
function onFile(inp){const f=inp.files[0];if(!f)return;document.getElementById('upzn').textContent=f.name;document.getElementById('upzn').style.display='block';document.getElementById('vurl').value='';}
|
| 285 |
+
function hasVid(){return document.getElementById('vurl').value.trim()||(document.getElementById('vfile').files||[]).length>0;}
|
| 286 |
+
function bfd(){const fd=new FormData();fd.append('username',U);fd.append('video_url',document.getElementById('vurl').value.trim());fd.append('voice',document.getElementById('vsel').value);fd.append('engine',document.getElementById('engine').value);fd.append('speed',document.getElementById('spd').value);fd.append('watermark','');fd.append('crop',document.getElementById('crop').value);fd.append('flip',FLIP_ON?'1':'0');fd.append('color',COL_ON?'1':'0');fd.append('content_type',document.getElementById('ctype').value);fd.append('ai_model',document.getElementById('aimodel').value);fd.append('vo_lang',document.getElementById('vlang').value);const vf=document.getElementById('vfile');if(vf&&vf.files[0])fd.append('video_file',vf.files[0]);return fd;}
|
| 287 |
+
function fmt(s){const m=Math.floor(s/60);return m>0?m+'m '+(s%60)+'s':s+'s';}
|
| 288 |
+
function showProg(on){document.getElementById('pc').style.display=on?'block':'none';if(on){document.getElementById('pb').style.width='0%';document.getElementById('pmsg').textContent='โณ Processing...';document.getElementById('ptmr').textContent='โฑ 0s';['ps-dl','ps-tr','ps-ai','ps-ts','ps-vd'].forEach(id=>document.getElementById(id).className='ps');}}
|
| 289 |
+
function updSteps(pct){const steps={8:'ps-dl',20:'ps-tr',45:'ps-ai',65:'ps-ts',78:'ps-vd'};let hit=false;Object.entries(steps).forEach(([p,id])=>{const el=document.getElementById(id);if(pct>=parseInt(p)){el.className='ps done';}else if(!hit){el.className='ps active';hit=true;}else el.className='ps';});}
|
| 290 |
+
function startTick(){T0=Date.now();if(TICK)clearInterval(TICK);TICK=setInterval(()=>{document.getElementById('ptmr').textContent='โฑ '+fmt(Math.floor((Date.now()-T0)/1000));},1000);}
|
| 291 |
+
function stopTick(){if(TICK){clearInterval(TICK);TICK=null;}return Math.floor((Date.now()-T0)/1000);}
|
| 292 |
+
function _resetBtn(){const b=document.getElementById('btnauto');b.disabled=false;b.innerHTML='<i class="fas fa-magic"></i> Auto Process <span style="opacity:.7;font-size:.78em">2 Coins</span>';}
|
| 293 |
+
function startSSE(tid){if(SSE)SSE.close();SSE=new EventSource('/api/progress/'+tid);SSE.onmessage=e=>{try{const p=JSON.parse(e.data);document.getElementById('pb').style.width=(p.pct||0)+'%';document.getElementById('pmsg').textContent=p.msg||'';updSteps(p.pct||0);if(p.done){SSE.close();SSE=null;const el=stopTick();_resetBtn();if(p.output_url){updC(p.coins!=null?p.coins:0);showRes(p.output_url,p.title,p.hashtags,p.caption,el);}else{showProg(false);toast('โ output not found');}}else if(p.error){SSE.close();SSE=null;stopTick();showProg(false);_resetBtn();toast(p.msg||'โ Process failed');}}catch(ex){}};}
|
| 294 |
+
async function doAuto(){if(!hasVid()){toast('โ Select video or URL');return;}const btn=document.getElementById('btnauto');btn.disabled=true;btn.innerHTML='<i class="fas fa-spinner sp"></i> Processingโฆ';showProg(true);startTick();const fd=bfd();const tid=uid8();fd.append('tid',tid);try{const ctrl=new AbortController(),tout=setTimeout(()=>ctrl.abort(),30000);const r=await fetch('/api/process_all',{method:'POST',body:fd,signal:ctrl.signal});clearTimeout(tout);if(!r.ok){stopTick();showProg(false);_resetBtn();toast('โ Server error');return;}const d=await r.json();if(!d.ok){stopTick();showProg(false);_resetBtn();toast(d.msg||'โ Process failed');return;}startSSE(tid);}catch(e){stopTick();showProg(false);_resetBtn();toast(e.name==='AbortError'?'โ Timeout':'โ '+e);}}
|
| 295 |
+
function showRes(url,title,tags,cap,el){showProg(false);OUT_URL=url;OUT_CAP=cap||title;OUT_TAGS=tags;const rc=document.getElementById('rc');const rvid=document.getElementById('rvid');rc.style.display='block';if(title){document.getElementById('rtit').textContent=title;document.getElementById('rtit').style.display='block';}if(tags){document.getElementById('rtag').textContent=tags;document.getElementById('rtag').style.display='block';}if(el>0){const rt=document.getElementById('rtm');rt.querySelector('span').textContent='Process time: '+fmt(el);rt.style.display='flex';}rc.scrollIntoView({behavior:'smooth'});let tries=0;const poll=setInterval(async()=>{tries++;try{const r=await fetch(url,{method:'HEAD'});if(r.ok){clearInterval(poll);rvid.src=url;toast('โ
Video ready!');return;}}catch(e){}if(tries>=20){clearInterval(poll);rvid.src=url;toast('โ
Done');}},1000);}
|
| 296 |
+
function dlVideo(){if(!OUT_URL)return;const a=document.createElement('a');a.href=OUT_URL;a.download='recap.mp4';a.click();}
|
| 297 |
+
function copyCap(){const t=[OUT_CAP,OUT_TAGS].filter(Boolean).join('\n\n');if(!t){toast('Nothing to copy');return;}navigator.clipboard.writeText(t).then(()=>toast('โ
Copied!')).catch(()=>toast('โ Copy failed'));}
|
| 298 |
+
async function admCoins(act){const u=document.getElementById('au-'+act).value.trim(),n=parseInt(document.getElementById('an-'+act).value)||0;if(!u){toast('โ Enter username');return;}const r=await fetch('/api/admin/coins',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u,amount:n,action:act})});const d=await r.json();document.getElementById('admmsg').textContent=d.msg||'';}
|
| 299 |
+
async function admCreate(){const u=document.getElementById('au-new').value.trim();const r=await fetch('/api/admin/create_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u,coins:0})});const d=await r.json();document.getElementById('au-res').textContent=d.msg+(d.username?' โ '+d.username:'');}
|
| 300 |
+
async function admDel(){const u=document.getElementById('au-del').value.trim();if(!u||!confirm('Delete '+u+'?'))return;const r=await fetch('/api/admin/delete_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u})});const d=await r.json();document.getElementById('admmsg').textContent=d.msg;if(d.ok)loadUsers();}
|
| 301 |
+
async function loadUsers(){const r=await fetch('/api/admin/users?caller='+encodeURIComponent(U));if(!r.ok)return;const d=await r.json();if(!d.ok)return;const w=document.getElementById('utw');if(!d.users.length){w.innerHTML='<div style="font-size:.75rem;color:var(--muted);padding:6px">No users</div>';return;}let h='<table class="ut"><tr><th>Username</th><th>Coins</th><th>Videos</th><th>Created</th><th></th></tr>';d.users.forEach(u=>{h+=`<tr><td>${u.username}</td><td>๐ช${u.coins}</td><td>${u.videos}</td><td>${u.created||''}</td><td><button class="delbtn" onclick="qDel('${u.username}')"><i class="fas fa-trash"></i></button></td></tr>`;});w.innerHTML=h+'</table>';}
|
| 302 |
+
async function qDel(u){if(!confirm('Delete '+u+'?'))return;const r=await fetch('/api/admin/delete_user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({caller:U,username:u})});const d=await r.json();toast(d.msg);if(d.ok)loadUsers();}
|
| 303 |
+
function toast(m){const e=document.getElementById('toast');e.textContent=m;e.classList.add('show');setTimeout(()=>e.classList.remove('show'),2800);}
|
| 304 |
+
function openPkg(){document.getElementById('pkg-uname').textContent=U||'โ';document.getElementById('pkg-modal').classList.add('on');}
|
| 305 |
+
function closePkg(){document.getElementById('pkg-modal').classList.remove('on');}
|
| 306 |
+
function contactPkg(n,price){const msg=encodeURIComponent('แแแบแนแแแฌแแซ! Coin แแแบแแปแแบแแซแแแบ\nPackage: '+n+' coins ('+price+')\nAccount: '+U);window.open('https://t.me/PhoeShan2001?text='+msg,'_blank');}
|
| 307 |
+
function uid8(){return([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,c=>(c^crypto.getRandomValues(new Uint8Array(1))[0]&15>>c/4).toString(16)).substring(0,8);}
|
| 308 |
+
async function doPaste(){try{const t=await navigator.clipboard.readText();if(t){document.getElementById('vurl').value=t;onUrl(t);toast('โ
Pasted!');}else toast('โ Clipboard empty');}catch(e){toast('โ Clipboard access denied');}}
|
| 309 |
</script>
|
| 310 |
</body>
|
| 311 |
</html>
|