File size: 2,917 Bytes
8d0498c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
const $ = (id)=>document.getElementById(id);

async function api(path, opts){
  const res = await fetch(path, opts);
  if(!res.ok){
    const t = await res.text();
    throw new Error(`${res.status} ${res.statusText}: ${t}`);
  }
  return res;
}

async function refresh(){
  const res = await api('/api/templates');
  const items = await res.json();
  const list = $('list');
  list.innerHTML = '';
  for(const t of items){
    const li = document.createElement('li');
    const name = document.createElement('span');
    name.textContent = `${t.id}${t.name ?? ''}`;
    const loadBtn = document.createElement('button');
    loadBtn.textContent = 'Load';
    loadBtn.onclick = ()=>loadTemplate(t.id);
    li.appendChild(name);
    li.appendChild(loadBtn);
    list.appendChild(li);
  }
}

async function loadTemplate(id){
  const res = await api(`/api/templates/${encodeURIComponent(id)}`);
  const tpl = await res.json();
  $('tplId').value = tpl.id;
  $('json').value = JSON.stringify(tpl, null, 2);
}

function newTemplate(){
  const id = `tpl_${Math.random().toString(16).slice(2,8)}`;
  $('tplId').value = id;
  $('json').value = JSON.stringify({
    id,
    name: "My Template",
    width: 1280,
    height: 720,
    fps: 30,
    duration_sec: 5,
    bg_color: "#111827",
    text: { value: "{name}", x: 80, y: 600, fontsize: 48 }
  }, null, 2);
}

async function saveTemplate(){
  const id = $('tplId').value.trim();
  if(!id) return alert('Template id required');
  let body;
  try{ body = JSON.parse($('json').value); }
  catch(e){ return alert('Invalid JSON'); }
  body.id = id;
  await api(`/api/templates/${encodeURIComponent(id)}`, {
    method:'POST',
    headers:{'Content-Type':'application/json'},
    body: JSON.stringify(body)
  });
  await refresh();
}

async function render(){
  const tplId = $('tplId').value.trim();
  if(!tplId) return alert('Load or create a template first');
  const name = $('name').value || 'Friend';
  $('renderStatus').textContent = 'Queued…';
  const res = await api('/api/render', {
    method:'POST',
    headers:{'Content-Type':'application/json'},
    body: JSON.stringify({ template_id: tplId, variables: { name } })
  });
  const job = await res.json();
  poll(job.job_id);
}

async function poll(jobId){
  while(true){
    const res = await api(`/api/jobs/${encodeURIComponent(jobId)}`);
    const job = await res.json();
    $('renderStatus').textContent = `${job.status}${job.detail?` — ${job.detail}`:''}`;
    if(job.status === 'done'){
      const url = `/api/jobs/${encodeURIComponent(jobId)}/download`;
      $('player').src = url;
      break;
    }
    if(job.status === 'error') break;
    await new Promise(r=>setTimeout(r, 1200));
  }
}

$('refresh').onclick = refresh;
$('new').onclick = ()=>{ newTemplate(); };
$('save').onclick = saveTemplate;
$('render').onclick = render;

refresh().catch(e=>$('renderStatus').textContent = e.message);