@officexapp/vidfarm-devcli 0.21.15 → 0.21.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/vidfarm-director/SKILL.md +19 -4
- package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +6 -0
- package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +19 -4
- package/.agents/skills/vidfarm-director/references/core-workflows.md +2 -2
- package/.agents/skills/vidfarm-director/references/editor-workflows.md +29 -2
- package/SKILL.director.md +75 -12
- package/demo/dist/app.js +207 -207
- package/dist/src/cli.js +217 -10
- package/dist/src/devcli/cost-mode.js +22 -7
- package/dist/src/services/clip-curation/hunt.js +5 -4
- package/dist/src/services/clip-curation/media-select.js +76 -30
- package/package.json +1 -1
- package/public/serve-shells/editor.html +15 -5
- package/public/serve-shells/library-files.html +87 -3
- package/public/serve-shells/library-raws.html +222 -16
- package/public/serve-shells/tools-clipper.html +73 -4
- package/public/serve-shells/tools-image.html +172 -5
- package/public/serve-shells/tools-video.html +102 -4
|
@@ -382,7 +382,10 @@
|
|
|
382
382
|
/* chat column */
|
|
383
383
|
.rk-aichat-main{flex:1;min-width:0;display:flex;flex-direction:column}
|
|
384
384
|
.rk-aichat-head{display:flex;align-items:center;gap:8px;padding:14px 14px;border-bottom:1px solid var(--rk-border);flex:none}
|
|
385
|
-
.rk-aichat-head-main{flex:1;min-width:0;display:
|
|
385
|
+
.rk-aichat-head-main{flex:1;min-width:0;display:flex;align-items:center;gap:10px}
|
|
386
|
+
.rk-aichat-head-titles{display:grid;gap:1px;min-width:0}
|
|
387
|
+
.rk-aichat-watch{display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;color:var(--rk-text-muted);font-size:12px;font-weight:400;font-family:inherit;cursor:pointer;padding:3px 8px;border-radius:8px;white-space:nowrap;transition:color .15s,background .15s}
|
|
388
|
+
.rk-aichat-watch:hover{color:var(--rk-ink);background:var(--rk-n-100)}
|
|
386
389
|
.rk-aichat-title{font-family:var(--rk-font-display);font-weight:800;font-size:15px;color:var(--rk-ink);letter-spacing:-.01em}
|
|
387
390
|
.rk-aichat-sub{font-size:11.5px;color:var(--rk-text-muted)}
|
|
388
391
|
.rk-aichat-back{flex:1;min-width:0;display:inline-flex;align-items:center;gap:8px;padding:7px 12px 7px 9px;
|
|
@@ -1195,11 +1198,15 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1195
1198
|
.rk-ip-gen-box{background:#fff;border:1.5px solid var(--rk-border-strong);border-radius:var(--rk-r-2xl);padding:10px 10px 8px;display:grid;gap:8px;
|
|
1196
1199
|
box-shadow:var(--rk-shadow-sm);transition:border-color var(--rk-dur) var(--rk-ease),box-shadow var(--rk-dur) var(--rk-ease);text-align:left}
|
|
1197
1200
|
.rk-ip-gen-box:focus-within{border-color:var(--rk-gold-600);box-shadow:0 0 0 3px var(--rk-gold-tint)}
|
|
1201
|
+
.rk-ip-gen.is-dragref .rk-ip-gen-box{border-color:var(--rk-gold-600);border-style:dashed;background:var(--rk-gold-tint)}
|
|
1198
1202
|
.rk-ip-gen.is-busy .rk-ip-gen-box{opacity:.75}
|
|
1199
1203
|
.rk-ip-gen-input{width:100%;border:0;outline:0;resize:none;background:transparent;font:inherit;font-size:14px;line-height:1.45;color:var(--rk-ink);min-height:44px;padding:2px 4px}
|
|
1200
1204
|
.rk-ip-gen-input::placeholder{color:var(--rk-text-faint)}
|
|
1201
1205
|
.rk-ip-gen-input:disabled{cursor:not-allowed;color:var(--rk-text-muted)}
|
|
1202
1206
|
.rk-ip-gen-clip:disabled{opacity:.5;cursor:not-allowed}
|
|
1207
|
+
.rk-ip-gen-presets{display:flex;flex-wrap:wrap;gap:6px}
|
|
1208
|
+
.rk-ip-preset{flex:none;border:1px dashed var(--rk-border-strong,var(--rk-border));background:var(--rk-n-50);color:var(--rk-n-700);border-radius:999px;padding:4px 10px;font-size:11.5px;font-weight:600;cursor:pointer;transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease)}
|
|
1209
|
+
.rk-ip-preset:hover{background:var(--rk-gold-tint);color:var(--rk-gold-700);border-color:var(--rk-gold-600)}
|
|
1203
1210
|
.rk-ip-gen-refs{display:flex;flex-wrap:wrap;gap:6px}
|
|
1204
1211
|
.rk-ip-gen-refs[hidden]{display:none}
|
|
1205
1212
|
.rk-ip-gen-ref{display:inline-flex;align-items:center;gap:6px;padding:3px 4px 3px 6px;border:1px solid var(--rk-border);border-radius:var(--rk-r-lg);background:var(--rk-n-50);font-size:11.5px;color:var(--rk-n-700);max-width:180px}
|
|
@@ -1227,6 +1234,10 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1227
1234
|
.rk-ip-filemodal-panel{width:min(560px,100%);max-height:min(80vh,680px);display:flex;flex-direction:column;background:var(--rk-surface);border:1px solid var(--rk-border);border-radius:var(--rk-r-3xl);box-shadow:var(--rk-shadow-lg,var(--rk-shadow-card));overflow:hidden}
|
|
1228
1235
|
.rk-ip-filemodal-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;border-bottom:1px solid var(--rk-border)}
|
|
1229
1236
|
.rk-ip-filemodal-title{font-family:var(--rk-font-display);font-weight:800;font-size:var(--rk-text-md,15px);color:var(--rk-ink)}
|
|
1237
|
+
.rk-ip-filemodal-actions{display:flex;align-items:center;gap:10px}
|
|
1238
|
+
.rk-ip-filemodal-upload{border:1px solid var(--rk-border-strong,var(--rk-border));background:var(--rk-n-50);color:var(--rk-n-700);border-radius:999px;padding:5px 12px;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap;transition:background var(--rk-dur) var(--rk-ease),color var(--rk-dur) var(--rk-ease),border-color var(--rk-dur) var(--rk-ease)}
|
|
1239
|
+
.rk-ip-filemodal-upload:hover:not(:disabled){background:var(--rk-gold-tint);color:var(--rk-gold-700);border-color:var(--rk-gold-600)}
|
|
1240
|
+
.rk-ip-filemodal-upload:disabled{opacity:.6;cursor:default}
|
|
1230
1241
|
.rk-ip-filemodal-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted);cursor:pointer;padding:0 4px}
|
|
1231
1242
|
.rk-ip-filemodal-close:hover{color:var(--rk-ink)}
|
|
1232
1243
|
.rk-ip-filemodal-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}
|
|
@@ -1457,6 +1468,10 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1457
1468
|
<span class="rk-ip-gen-or">or</span>
|
|
1458
1469
|
<div class="rk-ip-gen-box">
|
|
1459
1470
|
<textarea id="rk-ip-genprompt" class="rk-ip-gen-input" rows="2" placeholder="Or type your image prompt"></textarea>
|
|
1471
|
+
<div class="rk-ip-gen-presets" id="rk-ip-genpresets">
|
|
1472
|
+
<button type="button" class="rk-ip-preset" data-preset="character-card" title="Fill the prompt with a character reference sheet (multi-angle, expressions, poses)">+ Character card</button>
|
|
1473
|
+
<button type="button" class="rk-ip-preset" data-preset="storyboard" title="Fill the prompt with a numbered storyboard (sequential shot panels)">+ Storyboard</button>
|
|
1474
|
+
</div>
|
|
1460
1475
|
<div class="rk-ip-gen-refs" id="rk-ip-genrefs" hidden></div>
|
|
1461
1476
|
<div class="rk-ip-gen-bar">
|
|
1462
1477
|
<button type="button" class="rk-ip-gen-clip" id="rk-ip-genclip" aria-label="Attach reference images from your files" title="Attach reference images from your files"><svg width="18" height="18" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="m8.1 10.7 4.8-4.8a2.5 2.5 0 0 1 3.5 3.5l-6.1 6.1a4 4 0 0 1-5.7-5.7l6.3-6.3"/><path d="m10 8.8-4.1 4.1a1.6 1.6 0 0 0 2.3 2.3l5.6-5.6"/></svg></button>
|
|
@@ -1596,8 +1611,13 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1596
1611
|
<header class="rk-aichat-head">
|
|
1597
1612
|
<span class="rk-brand-mark">V</span>
|
|
1598
1613
|
<div class="rk-aichat-head-main">
|
|
1599
|
-
<div class="rk-aichat-
|
|
1600
|
-
|
|
1614
|
+
<div class="rk-aichat-head-titles">
|
|
1615
|
+
<div class="rk-aichat-title">VidFarm AI</div>
|
|
1616
|
+
<div class="rk-aichat-sub">on your own AI keys</div>
|
|
1617
|
+
</div>
|
|
1618
|
+
<button class="rk-aichat-watch" id="rkWatchPoppanel" type="button" title="Watch Tutorial" aria-label="Watch Tutorial">
|
|
1619
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M10 8.5l6 3.5-6 3.5z" fill="currentColor" stroke="none"></path></svg><span>Watch Tutorial</span>
|
|
1620
|
+
</button>
|
|
1601
1621
|
</div>
|
|
1602
1622
|
<button class="rk-aichat-tool" id="rkHistoryToggle" type="button" title="Chat history" aria-label="Toggle chat history" aria-pressed="false">
|
|
1603
1623
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l3 2"/></svg>
|
|
@@ -3612,8 +3632,35 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
3612
3632
|
var panel = document.createElement('div'); panel.className = 'rk-ip-filemodal-panel';
|
|
3613
3633
|
var head = document.createElement('div'); head.className = 'rk-ip-filemodal-head';
|
|
3614
3634
|
var title = document.createElement('span'); title.className = 'rk-ip-filemodal-title'; title.textContent = 'Attach reference images';
|
|
3635
|
+
var headActions = document.createElement('div'); headActions.className = 'rk-ip-filemodal-actions';
|
|
3636
|
+
var uploadBtn = document.createElement('button'); uploadBtn.type = 'button'; uploadBtn.className = 'rk-ip-filemodal-upload'; uploadBtn.textContent = '\u2191 Upload from computer';
|
|
3637
|
+
var uploadInput = document.createElement('input'); uploadInput.type = 'file'; uploadInput.accept = 'image/png,image/jpeg,image/webp,image/gif,image/avif'; uploadInput.multiple = true; uploadInput.hidden = true;
|
|
3615
3638
|
var close = document.createElement('button'); close.type = 'button'; close.className = 'rk-ip-filemodal-close'; close.setAttribute('aria-label', 'Close'); close.innerHTML = '×';
|
|
3616
|
-
|
|
3639
|
+
headActions.appendChild(uploadBtn); headActions.appendChild(close);
|
|
3640
|
+
head.appendChild(title); head.appendChild(headActions); head.appendChild(uploadInput);
|
|
3641
|
+
uploadBtn.addEventListener('click', function(){ if(!uploadBtn.disabled) uploadInput.click(); });
|
|
3642
|
+
uploadInput.addEventListener('change', function(){
|
|
3643
|
+
var files = Array.prototype.slice.call(uploadInput.files || []).filter(function(f){ return /^image\//i.test(f.type || '') || /\.(png|jpe?g|gif|webp|avif)$/i.test(f.name || ''); });
|
|
3644
|
+
uploadInput.value = '';
|
|
3645
|
+
if(!files.length){ setGenStatus('Pick an image file to upload as a reference.', 'error'); return; }
|
|
3646
|
+
uploadBtn.disabled = true; var original = uploadBtn.textContent; uploadBtn.textContent = 'Uploading\u2026';
|
|
3647
|
+
setGenStatus('Uploading ' + files.length + ' reference' + (files.length > 1 ? 's' : '') + '\u2026', '');
|
|
3648
|
+
var added = 0;
|
|
3649
|
+
files.reduce(function(chain, f){
|
|
3650
|
+
return chain.then(function(){
|
|
3651
|
+
return uploadTemporaryBlob(f, f.name || 'reference.png', f.type || 'image/png').then(function(url){
|
|
3652
|
+
if(url && genRefs.indexOf(url) === -1){ genRefs.push(url); added++; renderGenRefs(); }
|
|
3653
|
+
});
|
|
3654
|
+
});
|
|
3655
|
+
}, Promise.resolve()).then(function(){
|
|
3656
|
+
uploadBtn.disabled = false; uploadBtn.textContent = original;
|
|
3657
|
+
if(added){ setGenStatus(added + ' reference' + (added > 1 ? 's' : '') + ' uploaded.', 'success'); closeGenFilePanel(); }
|
|
3658
|
+
else setGenStatus('Those files were already attached.', '');
|
|
3659
|
+
}).catch(function(err){
|
|
3660
|
+
uploadBtn.disabled = false; uploadBtn.textContent = original;
|
|
3661
|
+
setGenStatus((err && err.message) ? err.message : 'Upload failed.', 'error');
|
|
3662
|
+
});
|
|
3663
|
+
});
|
|
3617
3664
|
var mountEl = document.createElement('div'); mountEl.className = 'rk-ip-filemodal-mount';
|
|
3618
3665
|
panel.appendChild(head); panel.appendChild(mountEl); overlay.appendChild(panel);
|
|
3619
3666
|
document.body.appendChild(overlay); genFileModal = overlay;
|
|
@@ -3639,6 +3686,30 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
3639
3686
|
}
|
|
3640
3687
|
}
|
|
3641
3688
|
|
|
3689
|
+
// Paste or drop image files straight into the composer -> temp upload -> reference.
|
|
3690
|
+
function addGenReferenceFiles(fileList){
|
|
3691
|
+
var files = Array.prototype.slice.call(fileList || []).filter(function(f){ return /^image\//i.test(f.type || '') || /\.(png|jpe?g|gif|webp|avif)$/i.test(f.name || ''); });
|
|
3692
|
+
if(!files.length) return Promise.resolve(0);
|
|
3693
|
+
setGenStatus('Uploading ' + files.length + ' reference' + (files.length > 1 ? 's' : '') + '\u2026', '');
|
|
3694
|
+
var added = 0;
|
|
3695
|
+
return files.reduce(function(chain, f){
|
|
3696
|
+
return chain.then(function(){
|
|
3697
|
+
return uploadTemporaryBlob(f, f.name || 'pasted-image.png', f.type || 'image/png').then(function(url){
|
|
3698
|
+
if(url && genRefs.indexOf(url) === -1){ genRefs.push(url); added++; renderGenRefs(); }
|
|
3699
|
+
});
|
|
3700
|
+
});
|
|
3701
|
+
}, Promise.resolve()).then(function(){
|
|
3702
|
+
if(added) setGenStatus(added + ' reference' + (added > 1 ? 's' : '') + ' attached.', 'success');
|
|
3703
|
+
return added;
|
|
3704
|
+
}).catch(function(err){ setGenStatus((err && err.message) ? err.message : 'Upload failed.', 'error'); return added; });
|
|
3705
|
+
}
|
|
3706
|
+
function imagesFromClipboard(e){
|
|
3707
|
+
var items = (e.clipboardData && e.clipboardData.items) || []; var out = [];
|
|
3708
|
+
for(var i = 0; i < items.length; i++){ if(items[i].kind === 'file'){ var f = items[i].getAsFile(); if(f && /^image\//i.test(f.type || '')) out.push(f); } }
|
|
3709
|
+
return out;
|
|
3710
|
+
}
|
|
3711
|
+
function dtHasFiles(e){ var t = (e.dataTransfer && e.dataTransfer.types) || []; return Array.prototype.indexOf.call(t, 'Files') !== -1; }
|
|
3712
|
+
|
|
3642
3713
|
function pollImageGenerateJob(jobId){
|
|
3643
3714
|
var attempt = 0;
|
|
3644
3715
|
function step(){
|
|
@@ -3661,8 +3732,41 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
3661
3732
|
return step();
|
|
3662
3733
|
}
|
|
3663
3734
|
|
|
3735
|
+
// "character card" / "storyboard" shorthand — spell out the full layout
|
|
3736
|
+
// so the image model produces a reference sheet / numbered shot board
|
|
3737
|
+
// instead of a single picture. Snippets are shared with the AI chat +
|
|
3738
|
+
// SKILL.md via src/services/image-prompt-presets.ts.
|
|
3739
|
+
var CHAR_CARD_SNIPPET = "Render this as a CHARACTER REFERENCE SHEET (a.k.a. character card / model sheet / sprite card) on a plain neutral light-gray studio background — ONE single consistent character laid out as a clean labeled grid of views: BODY SHOTS (full body, three-quarter body, half body, and a head-and-shoulders 'original expression'); a CHARACTER TURNAROUND standing in a row (front, side profile, back view); an EXPRESSION SHEET of face close-ups (happy, sad, angry, blank / dazed); and a POSE SHEET of 2-3 dynamic action poses. Keep the SAME face, hairstyle, wardrobe, colors, body proportions and art style IDENTICAL across every panel so the character stays perfectly consistent. Small text label under each view, even flat studio lighting, no background scenery.";
|
|
3740
|
+
var STORYBOARD_SNIPPET = "Render this as a STORYBOARD: a single sheet of sequential NUMBERED panels laid out in a grid (e.g. 3x3), each panel a framed still of one shot / scene in order, with a short caption UNDER each frame describing the action, the camera move (pan / zoom / cut) and any voiceover or sound. Keep the same characters and setting consistent from panel to panel; add small arrows to show motion or camera moves where useful; read left-to-right, top-to-bottom like a film / animation pre-viz board. IMPORTANT: this storyboard is ALSO a look / style fit-check, so render every panel in the SAME visual style intended for the final piece — match whatever style the subject implies (photoreal, cinematic, 3D, anime, flat illustration, etc.); only fall back to a clean pencil / line sketch if the user gave no style at all.";
|
|
3741
|
+
function shorthandAlreadyExpanded(t){ var l=(t||'').toLowerCase(); return l.indexOf('character reference sheet')>=0 || l.indexOf('sequential numbered panels')>=0; }
|
|
3742
|
+
function expandShorthand(t){
|
|
3743
|
+
var text=(t||'').trim(); if(!text) return t;
|
|
3744
|
+
if(shorthandAlreadyExpanded(text)) return text;
|
|
3745
|
+
var cc=/\bcharacter\s+(card|sheet|reference\s+sheet|model\s+sheet)\b|\bmodel\s+sheet\b|\bsprite\s+card\b/i.test(text);
|
|
3746
|
+
var sb=/\bstory\s?boards?\b/i.test(text);
|
|
3747
|
+
if(!cc && !sb) return text;
|
|
3748
|
+
var snip = cc ? CHAR_CARD_SNIPPET : STORYBOARD_SNIPPET;
|
|
3749
|
+
var sep = /[.!?]\s*$/.test(text) ? ' ' : '. ';
|
|
3750
|
+
return text + sep + snip;
|
|
3751
|
+
}
|
|
3752
|
+
function applyGenPreset(kind){
|
|
3753
|
+
if(!genPrompt) return;
|
|
3754
|
+
var snip = kind === 'storyboard' ? STORYBOARD_SNIPPET : CHAR_CARD_SNIPPET;
|
|
3755
|
+
var cur = (genPrompt.value || '').split(CHAR_CARD_SNIPPET).join('').split(STORYBOARD_SNIPPET).join('').replace(/[\s.]+$/, '').trim();
|
|
3756
|
+
var caret;
|
|
3757
|
+
if(cur){ var sep = /[.!?]$/.test(cur) ? ' ' : '. '; genPrompt.value = cur + sep + snip; caret = cur.length; }
|
|
3758
|
+
else { var lead = kind === 'storyboard' ? 'A storyboard for ' : 'A character card of '; genPrompt.value = lead + snip; caret = lead.length; }
|
|
3759
|
+
genPrompt.focus();
|
|
3760
|
+
try{ genPrompt.setSelectionRange(caret, caret); }catch(_){}
|
|
3761
|
+
setGenStatus(kind === 'storyboard' ? 'Storyboard layout added \u2014 describe your scenes, then Generate.' : 'Character-card layout added \u2014 describe your character, then Generate.', '');
|
|
3762
|
+
syncGenSend();
|
|
3763
|
+
}
|
|
3764
|
+
Array.prototype.forEach.call(document.querySelectorAll('#rk-ip-genpresets .rk-ip-preset'), function(btn){
|
|
3765
|
+
btn.addEventListener('click', function(){ applyGenPreset(btn.getAttribute('data-preset') || 'character-card'); });
|
|
3766
|
+
});
|
|
3767
|
+
|
|
3664
3768
|
function submitGenerate(){
|
|
3665
|
-
var p = (genPrompt && genPrompt.value || '').trim();
|
|
3769
|
+
var p = expandShorthand((genPrompt && genPrompt.value || '').trim());
|
|
3666
3770
|
if(!p){ setGenStatus('Type a prompt to generate an image.', 'error'); if(genPrompt) genPrompt.focus(); return; }
|
|
3667
3771
|
if(genBusy) return;
|
|
3668
3772
|
genBusy = true; syncGenSend(); if(genWrap) genWrap.classList.add('is-busy');
|
|
@@ -3691,6 +3795,12 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
3691
3795
|
if(genPrompt){
|
|
3692
3796
|
genPrompt.addEventListener('input', syncGenSend);
|
|
3693
3797
|
genPrompt.addEventListener('keydown', function(e){ if(e.key === 'Enter' && !e.shiftKey){ e.preventDefault(); submitGenerate(); } });
|
|
3798
|
+
genPrompt.addEventListener('paste', function(e){ var imgs = imagesFromClipboard(e); if(imgs.length){ e.preventDefault(); addGenReferenceFiles(imgs); } });
|
|
3799
|
+
}
|
|
3800
|
+
if(genWrap){
|
|
3801
|
+
['dragenter', 'dragover'].forEach(function(ev){ genWrap.addEventListener(ev, function(e){ if(dtHasFiles(e)){ e.preventDefault(); e.stopPropagation(); genWrap.classList.add('is-dragref'); } }); });
|
|
3802
|
+
['dragleave', 'dragend'].forEach(function(ev){ genWrap.addEventListener(ev, function(){ genWrap.classList.remove('is-dragref'); }); });
|
|
3803
|
+
genWrap.addEventListener('drop', function(e){ if(dtHasFiles(e)){ e.preventDefault(); e.stopPropagation(); genWrap.classList.remove('is-dragref'); addGenReferenceFiles(e.dataTransfer.files); } });
|
|
3694
3804
|
}
|
|
3695
3805
|
if(genClip) genClip.addEventListener('click', openGenFilePanel);
|
|
3696
3806
|
if(genSend) genSend.addEventListener('click', submitGenerate);
|
|
@@ -5641,6 +5751,63 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
5641
5751
|
document.querySelectorAll("[data-skill-menu]").forEach((panel) => { panel.hidden = true; });
|
|
5642
5752
|
});
|
|
5643
5753
|
})();</script>
|
|
5754
|
+
<script>window.__vidfarmTutorials=[["/discover/templates/categories","/assets/blog/tutorial-videos/page-categories.mp4"],["/discover/templates/swipe","/assets/blog/tutorial-videos/page-swipe.mp4"],["/discover","/assets/blog/tutorial-videos/page-discover.mp4"],["/tools/image","/assets/blog/tutorial-videos/tools-image.mp4"],["/tools/video","/assets/blog/tutorial-videos/tools-video.mp4"],["/tools/clipper","/assets/blog/tutorial-videos/tools-clipper.mp4"],["/chat","/assets/blog/tutorial-videos/page-chat.mp4"],["/calendar","/assets/blog/tutorial-videos/page-calendar.mp4"],["/settings/profile","/assets/blog/tutorial-videos/page-profile.mp4"],["/settings/wallet","/assets/blog/tutorial-videos/page-wallet.mp4"],["/settings/channels","/assets/blog/tutorial-videos/page-channels.mp4"],["/settings/developer","/assets/blog/tutorial-videos/page-developer.mp4"],["/library","/assets/blog/tutorial-videos/page-library.mp4"]];window.__vfPoppanelVideo="/assets/blog/tutorial-videos/page-poppanel.mp4";</script>
|
|
5755
|
+
<script>(() => {
|
|
5756
|
+
try {
|
|
5757
|
+
function findTitle() {
|
|
5758
|
+
var hs = document.querySelectorAll('.rk-content h1');
|
|
5759
|
+
for (var i = 0; i < hs.length; i++) { var t = (hs[i].textContent || '').trim(); if (t && t.toLowerCase() !== 'vidfarm') return hs[i]; }
|
|
5760
|
+
return null;
|
|
5761
|
+
}
|
|
5762
|
+
function openModal(url) {
|
|
5763
|
+
if (document.getElementById('vf-tut-modal')) return;
|
|
5764
|
+
var ov = document.createElement('div');
|
|
5765
|
+
ov.id = 'vf-tut-modal';
|
|
5766
|
+
ov.style.cssText = 'position:fixed;inset:0;z-index:2147483000;background:rgba(0,0,0,.72);display:flex;align-items:center;justify-content:center;padding:24px;';
|
|
5767
|
+
var box = document.createElement('div');
|
|
5768
|
+
box.style.cssText = 'position:relative;width:min(900px,92vw);';
|
|
5769
|
+
var vid = document.createElement('video');
|
|
5770
|
+
vid.src = url; vid.controls = true; vid.autoplay = true; vid.playsInline = true;
|
|
5771
|
+
vid.style.cssText = 'width:100%;max-height:86vh;border-radius:14px;box-shadow:0 24px 80px rgba(0,0,0,.5);background:#000;display:block;';
|
|
5772
|
+
var x = document.createElement('button');
|
|
5773
|
+
x.type = 'button'; x.setAttribute('aria-label', 'Close'); x.innerHTML = '×';
|
|
5774
|
+
x.style.cssText = 'position:absolute;top:-16px;right:-16px;width:40px;height:40px;border-radius:50%;border:0;background:#fff;color:#111;font-size:26px;line-height:1;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.3);display:flex;align-items:center;justify-content:center;';
|
|
5775
|
+
function close() { try { vid.pause(); } catch (e) {} ov.remove(); document.removeEventListener('keydown', onKey); }
|
|
5776
|
+
function onKey(e) { if (e.key === 'Escape') close(); }
|
|
5777
|
+
x.onclick = close;
|
|
5778
|
+
ov.onclick = function (e) { if (e.target === ov) close(); };
|
|
5779
|
+
document.addEventListener('keydown', onKey);
|
|
5780
|
+
box.appendChild(vid); box.appendChild(x); ov.appendChild(box); document.body.appendChild(ov);
|
|
5781
|
+
}
|
|
5782
|
+
window.__vfOpenTutorial = openModal;
|
|
5783
|
+
// Pop-panel (agent dock) tutorial button — present on every full-chrome page,
|
|
5784
|
+
// next to the "VidFarm AI" title. Retry briefly in case the dock mounts late.
|
|
5785
|
+
var pt = 0;
|
|
5786
|
+
(function wirePop() {
|
|
5787
|
+
var pv = document.getElementById('rkWatchPoppanel');
|
|
5788
|
+
if (pv && window.__vfPoppanelVideo) { pv.onclick = function () { openModal(window.__vfPoppanelVideo); }; return; }
|
|
5789
|
+
if (pt++ < 20) setTimeout(wirePop, 300);
|
|
5790
|
+
})();
|
|
5791
|
+
// Page-title tutorial button — only when this route has a matching video.
|
|
5792
|
+
var routes = window.__vidfarmTutorials || [];
|
|
5793
|
+
var path = location.pathname, hit = null;
|
|
5794
|
+
for (var i = 0; i < routes.length; i++) { if (path === routes[i][0] || path.indexOf(routes[i][0]) === 0) { hit = routes[i][1]; break; } }
|
|
5795
|
+
function inject() {
|
|
5796
|
+
if (document.getElementById('vf-watch-tut')) return true;
|
|
5797
|
+
var h1 = findTitle(); if (!h1) return false;
|
|
5798
|
+
var btn = document.createElement('button');
|
|
5799
|
+
btn.id = 'vf-watch-tut'; btn.type = 'button'; btn.setAttribute('aria-label', 'Watch Tutorial');
|
|
5800
|
+
btn.style.cssText = 'display:inline-flex;align-items:center;gap:6px;margin-left:16px;padding:4px 10px;border:0;background:transparent;color:#9aa0a6;font-size:13px;font-weight:400;font-family:inherit;letter-spacing:0;cursor:pointer;vertical-align:middle;border-radius:8px;transition:color .15s,background .15s;';
|
|
5801
|
+
btn.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M10 8.5l6 3.5-6 3.5z" fill="currentColor" stroke="none"></path></svg><span>Watch Tutorial</span>';
|
|
5802
|
+
btn.onmouseenter = function () { btn.style.color = '#3c4043'; btn.style.background = 'rgba(0,0,0,.05)'; };
|
|
5803
|
+
btn.onmouseleave = function () { btn.style.color = '#9aa0a6'; btn.style.background = 'transparent'; };
|
|
5804
|
+
btn.onclick = function () { openModal(hit); };
|
|
5805
|
+
h1.appendChild(btn);
|
|
5806
|
+
return true;
|
|
5807
|
+
}
|
|
5808
|
+
if (hit) { var tries = 0; (function loop() { if (inject()) return; if (tries++ > 40) return; setTimeout(loop, 250); })(); }
|
|
5809
|
+
} catch (e) {}
|
|
5810
|
+
})();</script>
|
|
5644
5811
|
<script type="module" src="/assets/file-directory-app.js"></script>
|
|
5645
5812
|
</body>
|
|
5646
5813
|
</html>
|
|
@@ -382,7 +382,10 @@
|
|
|
382
382
|
/* chat column */
|
|
383
383
|
.rk-aichat-main{flex:1;min-width:0;display:flex;flex-direction:column}
|
|
384
384
|
.rk-aichat-head{display:flex;align-items:center;gap:8px;padding:14px 14px;border-bottom:1px solid var(--rk-border);flex:none}
|
|
385
|
-
.rk-aichat-head-main{flex:1;min-width:0;display:
|
|
385
|
+
.rk-aichat-head-main{flex:1;min-width:0;display:flex;align-items:center;gap:10px}
|
|
386
|
+
.rk-aichat-head-titles{display:grid;gap:1px;min-width:0}
|
|
387
|
+
.rk-aichat-watch{display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;color:var(--rk-text-muted);font-size:12px;font-weight:400;font-family:inherit;cursor:pointer;padding:3px 8px;border-radius:8px;white-space:nowrap;transition:color .15s,background .15s}
|
|
388
|
+
.rk-aichat-watch:hover{color:var(--rk-ink);background:var(--rk-n-100)}
|
|
386
389
|
.rk-aichat-title{font-family:var(--rk-font-display);font-weight:800;font-size:15px;color:var(--rk-ink);letter-spacing:-.01em}
|
|
387
390
|
.rk-aichat-sub{font-size:11.5px;color:var(--rk-text-muted)}
|
|
388
391
|
.rk-aichat-back{flex:1;min-width:0;display:inline-flex;align-items:center;gap:8px;padding:7px 12px 7px 9px;
|
|
@@ -1196,6 +1199,7 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1196
1199
|
.rk-ip-gen-or::before{left:0}.rk-ip-gen-or::after{right:0}
|
|
1197
1200
|
.rk-ip-gen-box{background:#fff;border:1.5px solid var(--rk-border-strong);border-radius:var(--rk-r-2xl);padding:10px 10px 8px;display:grid;gap:8px;box-shadow:var(--rk-shadow-sm);text-align:left}
|
|
1198
1201
|
.rk-ip-gen-box:focus-within{border-color:var(--rk-gold-600);box-shadow:0 0 0 3px var(--rk-gold-tint)}
|
|
1202
|
+
.rk-ip-gen.is-dragref .rk-ip-gen-box{border-color:var(--rk-gold-600);border-style:dashed;background:var(--rk-gold-tint)}
|
|
1199
1203
|
.rk-ip-gen.is-busy .rk-ip-gen-box{opacity:.75}
|
|
1200
1204
|
.rk-ip-gen-input{width:100%;border:0;outline:0;resize:none;background:transparent;font:inherit;font-size:14px;line-height:1.45;color:var(--rk-ink);min-height:44px;padding:2px 4px}
|
|
1201
1205
|
.rk-ip-gen-input::placeholder{color:var(--rk-text-faint)}
|
|
@@ -1629,8 +1633,13 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
1629
1633
|
<header class="rk-aichat-head">
|
|
1630
1634
|
<span class="rk-brand-mark">V</span>
|
|
1631
1635
|
<div class="rk-aichat-head-main">
|
|
1632
|
-
<div class="rk-aichat-
|
|
1633
|
-
|
|
1636
|
+
<div class="rk-aichat-head-titles">
|
|
1637
|
+
<div class="rk-aichat-title">VidFarm AI</div>
|
|
1638
|
+
<div class="rk-aichat-sub">on your own AI keys</div>
|
|
1639
|
+
</div>
|
|
1640
|
+
<button class="rk-aichat-watch" id="rkWatchPoppanel" type="button" title="Watch Tutorial" aria-label="Watch Tutorial">
|
|
1641
|
+
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M10 8.5l6 3.5-6 3.5z" fill="currentColor" stroke="none"></path></svg><span>Watch Tutorial</span>
|
|
1642
|
+
</button>
|
|
1634
1643
|
</div>
|
|
1635
1644
|
<button class="rk-aichat-tool" id="rkHistoryToggle" type="button" title="Chat history" aria-label="Toggle chat history" aria-pressed="false">
|
|
1636
1645
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/><path d="M12 7v5l3 2"/></svg>
|
|
@@ -2479,6 +2488,29 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
2479
2488
|
dir.pick({ select: "file", roots: ["files","temp","raws"], title: "Attach reference images", hint: "Pick one or more images to guide the generation.", confirmLabel: "Attach", multiple: true,
|
|
2480
2489
|
onPick: function(picked){ var arr = Array.isArray(picked) ? picked : [picked]; arr.forEach(function(f){ var url = f && (f.url || f.viewUrl); if(url){ try { genRefs.push(absoluteUrl(url)); } catch(_){} } }); renderGenRefs(); } });
|
|
2481
2490
|
}
|
|
2491
|
+
// Paste or drop image files straight into the composer -> temp upload -> reference.
|
|
2492
|
+
function addGenReferenceFiles(fileList){
|
|
2493
|
+
var files = Array.prototype.slice.call(fileList || []).filter(function(f){ return /^image\//i.test(f.type || "") || /\.(png|jpe?g|gif|webp|avif)$/i.test(f.name || ""); });
|
|
2494
|
+
if(!files.length) return Promise.resolve(0);
|
|
2495
|
+
setGenStatus("Uploading " + files.length + " reference" + (files.length > 1 ? "s" : "") + "\u2026", "");
|
|
2496
|
+
var added = 0;
|
|
2497
|
+
return files.reduce(function(chain, f){
|
|
2498
|
+
return chain.then(function(){
|
|
2499
|
+
return uploadTemporaryBlob(f, f.name || ("pasted-image.png"), f.type || "image/png").then(function(uploaded){
|
|
2500
|
+
if(uploaded){ var url = absoluteUrl(uploaded); if(genRefs.indexOf(url) === -1){ genRefs.push(url); added++; renderGenRefs(); } }
|
|
2501
|
+
});
|
|
2502
|
+
});
|
|
2503
|
+
}, Promise.resolve()).then(function(){
|
|
2504
|
+
if(added) setGenStatus(added + " reference" + (added > 1 ? "s" : "") + " attached.", "success");
|
|
2505
|
+
return added;
|
|
2506
|
+
}).catch(function(err){ setGenStatus((err && err.message) ? err.message : "Upload failed.", "error"); return added; });
|
|
2507
|
+
}
|
|
2508
|
+
function imagesFromClipboard(e){
|
|
2509
|
+
var items = (e.clipboardData && e.clipboardData.items) || []; var out = [];
|
|
2510
|
+
for(var i = 0; i < items.length; i++){ if(items[i].kind === "file"){ var f = items[i].getAsFile(); if(f && /^image\//i.test(f.type || "")) out.push(f); } }
|
|
2511
|
+
return out;
|
|
2512
|
+
}
|
|
2513
|
+
function dtHasFiles(e){ var t = (e.dataTransfer && e.dataTransfer.types) || []; return Array.prototype.indexOf.call(t, "Files") !== -1; }
|
|
2482
2514
|
function pollGenerateJob(jobId){
|
|
2483
2515
|
var attempt = 0;
|
|
2484
2516
|
function step(){
|
|
@@ -2513,7 +2545,16 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
2513
2545
|
.catch(function(err){ var msg = (err && err.message) ? err.message : "Unable to generate video."; if(/401|403|sign in|unauth/i.test(msg)) msg = "Sign in to generate videos."; setGenStatus(msg, "error"); })
|
|
2514
2546
|
.then(function(){ genBusy = false; if(genWrap) genWrap.classList.remove("is-busy"); syncGenSend(); });
|
|
2515
2547
|
}
|
|
2516
|
-
if(genPrompt){
|
|
2548
|
+
if(genPrompt){
|
|
2549
|
+
genPrompt.addEventListener("input", syncGenSend);
|
|
2550
|
+
genPrompt.addEventListener("keydown", function(e){ if(e.key === "Enter" && !e.shiftKey){ e.preventDefault(); submitGenerateNew(); } });
|
|
2551
|
+
genPrompt.addEventListener("paste", function(e){ var imgs = imagesFromClipboard(e); if(imgs.length){ e.preventDefault(); addGenReferenceFiles(imgs); } });
|
|
2552
|
+
}
|
|
2553
|
+
if(genWrap){
|
|
2554
|
+
["dragenter","dragover"].forEach(function(ev){ genWrap.addEventListener(ev, function(e){ if(dtHasFiles(e)){ e.preventDefault(); e.stopPropagation(); genWrap.classList.add("is-dragref"); } }); });
|
|
2555
|
+
["dragleave","dragend"].forEach(function(ev){ genWrap.addEventListener(ev, function(){ genWrap.classList.remove("is-dragref"); }); });
|
|
2556
|
+
genWrap.addEventListener("drop", function(e){ if(dtHasFiles(e)){ e.preventDefault(); e.stopPropagation(); genWrap.classList.remove("is-dragref"); addGenReferenceFiles(e.dataTransfer.files); } });
|
|
2557
|
+
}
|
|
2517
2558
|
if(genClip) genClip.addEventListener("click", openGenFilePanel);
|
|
2518
2559
|
if(genSend) genSend.addEventListener("click", submitGenerateNew);
|
|
2519
2560
|
renderGenRefs(); syncGenSend();
|
|
@@ -4461,6 +4502,63 @@ body.vf-has-topbanner.rk-has-sidebar .rk-content{padding-top:var(--vf-topbanner-
|
|
|
4461
4502
|
document.querySelectorAll("[data-skill-menu]").forEach((panel) => { panel.hidden = true; });
|
|
4462
4503
|
});
|
|
4463
4504
|
})();</script>
|
|
4505
|
+
<script>window.__vidfarmTutorials=[["/discover/templates/categories","/assets/blog/tutorial-videos/page-categories.mp4"],["/discover/templates/swipe","/assets/blog/tutorial-videos/page-swipe.mp4"],["/discover","/assets/blog/tutorial-videos/page-discover.mp4"],["/tools/image","/assets/blog/tutorial-videos/tools-image.mp4"],["/tools/video","/assets/blog/tutorial-videos/tools-video.mp4"],["/tools/clipper","/assets/blog/tutorial-videos/tools-clipper.mp4"],["/chat","/assets/blog/tutorial-videos/page-chat.mp4"],["/calendar","/assets/blog/tutorial-videos/page-calendar.mp4"],["/settings/profile","/assets/blog/tutorial-videos/page-profile.mp4"],["/settings/wallet","/assets/blog/tutorial-videos/page-wallet.mp4"],["/settings/channels","/assets/blog/tutorial-videos/page-channels.mp4"],["/settings/developer","/assets/blog/tutorial-videos/page-developer.mp4"],["/library","/assets/blog/tutorial-videos/page-library.mp4"]];window.__vfPoppanelVideo="/assets/blog/tutorial-videos/page-poppanel.mp4";</script>
|
|
4506
|
+
<script>(() => {
|
|
4507
|
+
try {
|
|
4508
|
+
function findTitle() {
|
|
4509
|
+
var hs = document.querySelectorAll('.rk-content h1');
|
|
4510
|
+
for (var i = 0; i < hs.length; i++) { var t = (hs[i].textContent || '').trim(); if (t && t.toLowerCase() !== 'vidfarm') return hs[i]; }
|
|
4511
|
+
return null;
|
|
4512
|
+
}
|
|
4513
|
+
function openModal(url) {
|
|
4514
|
+
if (document.getElementById('vf-tut-modal')) return;
|
|
4515
|
+
var ov = document.createElement('div');
|
|
4516
|
+
ov.id = 'vf-tut-modal';
|
|
4517
|
+
ov.style.cssText = 'position:fixed;inset:0;z-index:2147483000;background:rgba(0,0,0,.72);display:flex;align-items:center;justify-content:center;padding:24px;';
|
|
4518
|
+
var box = document.createElement('div');
|
|
4519
|
+
box.style.cssText = 'position:relative;width:min(900px,92vw);';
|
|
4520
|
+
var vid = document.createElement('video');
|
|
4521
|
+
vid.src = url; vid.controls = true; vid.autoplay = true; vid.playsInline = true;
|
|
4522
|
+
vid.style.cssText = 'width:100%;max-height:86vh;border-radius:14px;box-shadow:0 24px 80px rgba(0,0,0,.5);background:#000;display:block;';
|
|
4523
|
+
var x = document.createElement('button');
|
|
4524
|
+
x.type = 'button'; x.setAttribute('aria-label', 'Close'); x.innerHTML = '×';
|
|
4525
|
+
x.style.cssText = 'position:absolute;top:-16px;right:-16px;width:40px;height:40px;border-radius:50%;border:0;background:#fff;color:#111;font-size:26px;line-height:1;cursor:pointer;box-shadow:0 4px 16px rgba(0,0,0,.3);display:flex;align-items:center;justify-content:center;';
|
|
4526
|
+
function close() { try { vid.pause(); } catch (e) {} ov.remove(); document.removeEventListener('keydown', onKey); }
|
|
4527
|
+
function onKey(e) { if (e.key === 'Escape') close(); }
|
|
4528
|
+
x.onclick = close;
|
|
4529
|
+
ov.onclick = function (e) { if (e.target === ov) close(); };
|
|
4530
|
+
document.addEventListener('keydown', onKey);
|
|
4531
|
+
box.appendChild(vid); box.appendChild(x); ov.appendChild(box); document.body.appendChild(ov);
|
|
4532
|
+
}
|
|
4533
|
+
window.__vfOpenTutorial = openModal;
|
|
4534
|
+
// Pop-panel (agent dock) tutorial button — present on every full-chrome page,
|
|
4535
|
+
// next to the "VidFarm AI" title. Retry briefly in case the dock mounts late.
|
|
4536
|
+
var pt = 0;
|
|
4537
|
+
(function wirePop() {
|
|
4538
|
+
var pv = document.getElementById('rkWatchPoppanel');
|
|
4539
|
+
if (pv && window.__vfPoppanelVideo) { pv.onclick = function () { openModal(window.__vfPoppanelVideo); }; return; }
|
|
4540
|
+
if (pt++ < 20) setTimeout(wirePop, 300);
|
|
4541
|
+
})();
|
|
4542
|
+
// Page-title tutorial button — only when this route has a matching video.
|
|
4543
|
+
var routes = window.__vidfarmTutorials || [];
|
|
4544
|
+
var path = location.pathname, hit = null;
|
|
4545
|
+
for (var i = 0; i < routes.length; i++) { if (path === routes[i][0] || path.indexOf(routes[i][0]) === 0) { hit = routes[i][1]; break; } }
|
|
4546
|
+
function inject() {
|
|
4547
|
+
if (document.getElementById('vf-watch-tut')) return true;
|
|
4548
|
+
var h1 = findTitle(); if (!h1) return false;
|
|
4549
|
+
var btn = document.createElement('button');
|
|
4550
|
+
btn.id = 'vf-watch-tut'; btn.type = 'button'; btn.setAttribute('aria-label', 'Watch Tutorial');
|
|
4551
|
+
btn.style.cssText = 'display:inline-flex;align-items:center;gap:6px;margin-left:16px;padding:4px 10px;border:0;background:transparent;color:#9aa0a6;font-size:13px;font-weight:400;font-family:inherit;letter-spacing:0;cursor:pointer;vertical-align:middle;border-radius:8px;transition:color .15s,background .15s;';
|
|
4552
|
+
btn.innerHTML = '<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="10"></circle><path d="M10 8.5l6 3.5-6 3.5z" fill="currentColor" stroke="none"></path></svg><span>Watch Tutorial</span>';
|
|
4553
|
+
btn.onmouseenter = function () { btn.style.color = '#3c4043'; btn.style.background = 'rgba(0,0,0,.05)'; };
|
|
4554
|
+
btn.onmouseleave = function () { btn.style.color = '#9aa0a6'; btn.style.background = 'transparent'; };
|
|
4555
|
+
btn.onclick = function () { openModal(hit); };
|
|
4556
|
+
h1.appendChild(btn);
|
|
4557
|
+
return true;
|
|
4558
|
+
}
|
|
4559
|
+
if (hit) { var tries = 0; (function loop() { if (inject()) return; if (tries++ > 40) return; setTimeout(loop, 250); })(); }
|
|
4560
|
+
} catch (e) {}
|
|
4561
|
+
})();</script>
|
|
4464
4562
|
<script type="module" src="/assets/file-directory-app.js"></script>
|
|
4465
4563
|
</body>
|
|
4466
4564
|
</html>
|