@mevdragon/vidfarm-devcli 0.19.1 → 0.20.1
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/music/SKILL.md +416 -0
- package/.agents/skills/music/references/api_reference.md +519 -0
- package/.agents/skills/music/references/installation.md +65 -0
- package/.agents/skills/text-to-speech/SKILL.md +226 -0
- package/.agents/skills/text-to-speech/references/installation.md +90 -0
- package/.agents/skills/text-to-speech/references/streaming.md +307 -0
- package/.agents/skills/text-to-speech/references/voice-settings.md +115 -0
- package/.agents/skills/vidfarm-media/SKILL.md +25 -11
- package/.agents/skills/vidfarm-media/references/tts.md +41 -3
- package/SKILL.director.md +31 -13
- package/SKILL.platform.md +2 -2
- package/demo/dist/app.css +1 -1
- package/demo/dist/app.js +75 -75
- package/dist/src/app.js +129 -41
- package/dist/src/cli.js +162 -5
- package/dist/src/config.js +12 -0
- package/dist/src/devcli/clips.js +7 -2
- package/dist/src/domain.js +3 -0
- package/dist/src/editor-chat.js +5 -1
- package/dist/src/frontend/file-directory.js +41 -18
- package/dist/src/primitive-context.js +14 -0
- package/dist/src/primitive-registry.js +140 -18
- package/dist/src/reskin/chat-page.js +1 -1
- package/dist/src/reskin/inpaint-clipper-page.js +446 -205
- package/dist/src/reskin/library-page.js +7 -1
- package/dist/src/reskin/portfolio-page.js +9 -9
- package/dist/src/reskin/settings-page.js +4 -4
- package/dist/src/reskin/theme.js +8 -4
- package/dist/src/services/billing.js +5 -0
- package/dist/src/services/clip-curation/ffmpeg.js +48 -0
- package/dist/src/services/clip-curation/hunt.js +2 -0
- package/dist/src/services/clip-curation/index.js +1 -1
- package/dist/src/services/clip-curation/scan.js +29 -16
- package/dist/src/services/elevenlabs.js +222 -0
- package/dist/src/services/providers.js +216 -2
- package/dist/src/services/swipe-customize.js +5 -2
- package/package.json +1 -1
- package/public/assets/file-directory-app.js +3 -2
|
@@ -7,6 +7,7 @@ import { ServerlessProviderKeyService } from "./serverless-provider-keys.js";
|
|
|
7
7
|
import sharp from "sharp";
|
|
8
8
|
import { ProviderAuthError, ProviderKeyUnavailableError, ProviderLeaseTimeoutError, ProviderQuotaExceededError, ProviderRateLimitError, ProviderTransientError, ProviderWaitExceededError, SpeechVoiceMismatchError, conciseProviderDetails, parseRetryAfterSeconds, rateLimitOrQuotaError } from "./provider-errors.js";
|
|
9
9
|
import { SUPPORTED_STT_MODELS, SUPPORTED_TTS_MODELS, defaultSpeechModelFor, generateSpeechWithKey, inferSpeechContentType, speechVoiceFamilyFor, speechVoiceMismatch, transcribeSpeechWithKey } from "./speech.js";
|
|
10
|
+
import { DEFAULT_ELEVENLABS_STT_MODEL, DEFAULT_ELEVENLABS_TTS_MODEL, elevenLabsListVoices, elevenLabsMusicCompose, elevenLabsSpeechToText, elevenLabsTextToSpeech, validateElevenLabsKey } from "./elevenlabs.js";
|
|
10
11
|
export { ProviderAuthError, ProviderKeyUnavailableError, ProviderLeaseTimeoutError, ProviderQuotaExceededError, ProviderRateLimitError, ProviderTransientError, ProviderWaitExceededError } from "./provider-errors.js";
|
|
11
12
|
const SUPPORTED_TEXT_MODELS = {
|
|
12
13
|
openai: new Set(["gpt-5.4"]),
|
|
@@ -70,6 +71,8 @@ const OPENAI_IMAGE_SIZES = new Set([
|
|
|
70
71
|
"auto"
|
|
71
72
|
]);
|
|
72
73
|
const GEMINI_IMAGE_ASPECT_RATIOS = new Set(["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "9:21"]);
|
|
74
|
+
// elevenlabs is intentionally absent — it validates against its own /v1/user
|
|
75
|
+
// endpoint (see validateProviderKey), not a chat-completion probe.
|
|
73
76
|
const PROVIDER_KEY_VALIDATION_MODELS = {
|
|
74
77
|
openai: "gpt-4.1-mini",
|
|
75
78
|
gemini: "gemini-3.1-flash-lite-preview",
|
|
@@ -334,6 +337,20 @@ export class ProviderService {
|
|
|
334
337
|
return [...new Set(providers)];
|
|
335
338
|
}
|
|
336
339
|
async validateProviderKey(input) {
|
|
340
|
+
// ElevenLabs is audio-only: validate against its own account endpoint, not a
|
|
341
|
+
// chat-completion probe.
|
|
342
|
+
if (input.provider === "elevenlabs") {
|
|
343
|
+
if (config.mockProviders) {
|
|
344
|
+
return { provider: input.provider, model: "elevenlabs", mock: true };
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
347
|
+
await validateElevenLabsKey(input.secret);
|
|
348
|
+
return { provider: input.provider, model: "elevenlabs", mock: false };
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
throw new Error(toProviderValidationMessage(input.provider, error));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
337
354
|
const model = PROVIDER_KEY_VALIDATION_MODELS[input.provider];
|
|
338
355
|
if (!model) {
|
|
339
356
|
throw new Error(`Provider ${input.provider} does not support validation.`);
|
|
@@ -541,7 +558,123 @@ export class ProviderService {
|
|
|
541
558
|
await this.releaseLease(lease);
|
|
542
559
|
}
|
|
543
560
|
}
|
|
561
|
+
// --- Audio (music / TTS / STT): platform-key + wallet vs BYOK routing ---
|
|
562
|
+
async resolveCustomerElevenLabsKey(customerId) {
|
|
563
|
+
const now = new Date().toISOString();
|
|
564
|
+
const secret = (await this.serverlessProviderKeys.listProviderKeysWithSecrets(customerId))
|
|
565
|
+
.filter((entry) => String(entry.provider) === "elevenlabs")
|
|
566
|
+
.filter((entry) => String(entry.status) === "active")
|
|
567
|
+
.filter((entry) => !entry.cooldown_until || String(entry.cooldown_until) <= now)
|
|
568
|
+
.map((entry) => readStoredProviderSecret(String(entry.secret ?? "")))
|
|
569
|
+
.find((value) => value.trim().length > 0);
|
|
570
|
+
return secret ?? null;
|
|
571
|
+
}
|
|
572
|
+
async customerHasByokAudioKey(customerId) {
|
|
573
|
+
const providers = await this.listAvailableProvidersAsync(customerId);
|
|
574
|
+
return providers.some((provider) => provider === "openai" || provider === "gemini" || provider === "openrouter");
|
|
575
|
+
}
|
|
576
|
+
/**
|
|
577
|
+
* Decide how an audio call is authorized. Default (`use_wallet_credits` unset
|
|
578
|
+
* or true): the platform ElevenLabs key, billed to the wallet. Explicit
|
|
579
|
+
* `false`: the customer's own ElevenLabs key, else a BYOK openai/gemini/
|
|
580
|
+
* openrouter key (TTS/STT only), else fall back to the platform key + wallet.
|
|
581
|
+
*/
|
|
582
|
+
async resolveAudioAuthPlan(input) {
|
|
583
|
+
// `undefined` = legacy BYOK-only. Internal callers (captions, voice-matched
|
|
584
|
+
// regenerate-speech) never pass the flag, so they keep their exact behavior
|
|
585
|
+
// and never silently draw on the platform key or the wallet. Only surfaces
|
|
586
|
+
// that explicitly opt in (the music/tts/stt primitives) reach ElevenLabs.
|
|
587
|
+
if (input.useWalletCredits === undefined) {
|
|
588
|
+
return { mode: "byok" };
|
|
589
|
+
}
|
|
590
|
+
const platformKey = config.ELEVENLABS_API_KEY?.trim() || null;
|
|
591
|
+
if (input.useWalletCredits) {
|
|
592
|
+
if (platformKey) {
|
|
593
|
+
return { mode: "elevenlabs", apiKey: platformKey, walletBilled: true, scope: "platform" };
|
|
594
|
+
}
|
|
595
|
+
// Operator hasn't wired a platform key — honor the intent with the user's
|
|
596
|
+
// own ElevenLabs key (no charge) or a BYOK audio key before failing.
|
|
597
|
+
const userKey = await this.resolveCustomerElevenLabsKey(input.customerId);
|
|
598
|
+
if (userKey) {
|
|
599
|
+
return { mode: "elevenlabs", apiKey: userKey, walletBilled: false, scope: "user" };
|
|
600
|
+
}
|
|
601
|
+
if (input.byokFallback && (await this.customerHasByokAudioKey(input.customerId))) {
|
|
602
|
+
return { mode: "byok" };
|
|
603
|
+
}
|
|
604
|
+
throw new ProviderKeyUnavailableError("use_wallet_credits is on but no platform ElevenLabs key is configured, and you have no usable audio key. Ask the operator to set ELEVENLABS_API_KEY or save your own key.");
|
|
605
|
+
}
|
|
606
|
+
// use_wallet_credits === false: prefer the user's OWN key, then a BYOK audio
|
|
607
|
+
// key (TTS/STT), and only then fall back to the platform key + wallet.
|
|
608
|
+
const userKey = await this.resolveCustomerElevenLabsKey(input.customerId);
|
|
609
|
+
if (userKey) {
|
|
610
|
+
return { mode: "elevenlabs", apiKey: userKey, walletBilled: false, scope: "user" };
|
|
611
|
+
}
|
|
612
|
+
if (input.byokFallback && (await this.customerHasByokAudioKey(input.customerId))) {
|
|
613
|
+
return { mode: "byok" };
|
|
614
|
+
}
|
|
615
|
+
if (platformKey) {
|
|
616
|
+
return { mode: "elevenlabs", apiKey: platformKey, walletBilled: true, scope: "platform" };
|
|
617
|
+
}
|
|
618
|
+
throw new ProviderKeyUnavailableError(input.capability === "music"
|
|
619
|
+
? "Music needs ElevenLabs: save an ElevenLabs key in Settings, or ask the operator to configure the platform ELEVENLABS_API_KEY (use_wallet_credits)."
|
|
620
|
+
: `No audio provider available for ${input.capability}. Enable use_wallet_credits (platform ElevenLabs key), save your own ElevenLabs key, or add an OpenAI/Gemini/OpenRouter key.`);
|
|
621
|
+
}
|
|
622
|
+
/** Voices available to whichever ElevenLabs account will serve this customer. */
|
|
623
|
+
async listElevenLabsVoices(input) {
|
|
624
|
+
const plan = await this.resolveAudioAuthPlan({
|
|
625
|
+
customerId: input.customerId,
|
|
626
|
+
useWalletCredits: input.useWalletCredits,
|
|
627
|
+
byokFallback: false,
|
|
628
|
+
capability: "tts"
|
|
629
|
+
});
|
|
630
|
+
if (plan.mode !== "elevenlabs") {
|
|
631
|
+
throw new ProviderKeyUnavailableError("No ElevenLabs account is available to list voices.");
|
|
632
|
+
}
|
|
633
|
+
return { scope: plan.scope, voices: await elevenLabsListVoices(plan.apiKey) };
|
|
634
|
+
}
|
|
544
635
|
async generateSpeech(input) {
|
|
636
|
+
const plan = await this.resolveAudioAuthPlan({
|
|
637
|
+
customerId: input.customerId,
|
|
638
|
+
useWalletCredits: input.useWalletCredits,
|
|
639
|
+
byokFallback: true,
|
|
640
|
+
capability: "tts"
|
|
641
|
+
});
|
|
642
|
+
if (plan.mode === "elevenlabs") {
|
|
643
|
+
const model = /^eleven/i.test(input.model || "") ? input.model : DEFAULT_ELEVENLABS_TTS_MODEL;
|
|
644
|
+
const generated = await elevenLabsTextToSpeech({
|
|
645
|
+
apiKey: plan.apiKey,
|
|
646
|
+
text: input.text,
|
|
647
|
+
voice: input.voice,
|
|
648
|
+
model,
|
|
649
|
+
responseFormat: input.responseFormat
|
|
650
|
+
});
|
|
651
|
+
const billing = plan.walletBilled
|
|
652
|
+
? {
|
|
653
|
+
costUsd: Number(((generated.characterCount / 1000) * config.ELEVENLABS_TTS_USD_PER_1K_CHARS).toFixed(4)),
|
|
654
|
+
costCenterSlug: "elevenlabs_tts",
|
|
655
|
+
metadata: {
|
|
656
|
+
operation: "tts",
|
|
657
|
+
provider: "elevenlabs",
|
|
658
|
+
model,
|
|
659
|
+
character_count: generated.characterCount,
|
|
660
|
+
wallet_billed: true,
|
|
661
|
+
scope: plan.scope
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
: null;
|
|
665
|
+
return {
|
|
666
|
+
bytes: generated.bytes,
|
|
667
|
+
contentType: generated.contentType,
|
|
668
|
+
usage: generated.usage,
|
|
669
|
+
effectiveProvider: "elevenlabs",
|
|
670
|
+
effectiveModel: model,
|
|
671
|
+
billing
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
const byok = await this.generateSpeechByok(input);
|
|
675
|
+
return { ...byok.result, effectiveProvider: byok.provider, effectiveModel: byok.model, billing: null };
|
|
676
|
+
}
|
|
677
|
+
async generateSpeechByok(input) {
|
|
545
678
|
// Provider fallback must stay voice-aware: a Gemini preset routed to an
|
|
546
679
|
// OpenAI key (or the reverse) would 400 opaquely at the provider.
|
|
547
680
|
const attempts = (await providerAttempts({
|
|
@@ -562,11 +695,12 @@ export class ProviderService {
|
|
|
562
695
|
let lastError = null;
|
|
563
696
|
for (const attempt of attempts) {
|
|
564
697
|
try {
|
|
565
|
-
|
|
698
|
+
const result = await this.generateSpeechWithProvider({
|
|
566
699
|
...input,
|
|
567
700
|
provider: attempt.provider,
|
|
568
701
|
model: attempt.model
|
|
569
702
|
});
|
|
703
|
+
return { result, provider: attempt.provider, model: attempt.model };
|
|
570
704
|
}
|
|
571
705
|
catch (error) {
|
|
572
706
|
lastError = error;
|
|
@@ -581,6 +715,42 @@ export class ProviderService {
|
|
|
581
715
|
throw lastError instanceof Error ? lastError : new ProviderLeaseTimeoutError("No eligible AI speech provider key became available in time.");
|
|
582
716
|
}
|
|
583
717
|
}
|
|
718
|
+
/** ElevenLabs music generation. Platform key + wallet by default; the
|
|
719
|
+
* customer's own ElevenLabs key when use_wallet_credits is false. */
|
|
720
|
+
async generateMusic(input) {
|
|
721
|
+
const plan = await this.resolveAudioAuthPlan({
|
|
722
|
+
customerId: input.customerId,
|
|
723
|
+
useWalletCredits: input.useWalletCredits,
|
|
724
|
+
byokFallback: false,
|
|
725
|
+
capability: "music"
|
|
726
|
+
});
|
|
727
|
+
if (plan.mode !== "elevenlabs") {
|
|
728
|
+
throw new ProviderKeyUnavailableError("Music generation requires an ElevenLabs key.");
|
|
729
|
+
}
|
|
730
|
+
const generated = await elevenLabsMusicCompose({
|
|
731
|
+
apiKey: plan.apiKey,
|
|
732
|
+
prompt: input.prompt,
|
|
733
|
+
musicLengthMs: input.musicLengthMs,
|
|
734
|
+
compositionPlan: input.compositionPlan,
|
|
735
|
+
model: input.model,
|
|
736
|
+
outputFormat: input.outputFormat
|
|
737
|
+
});
|
|
738
|
+
const minutes = Math.max(0, generated.musicLengthMs) / 60000;
|
|
739
|
+
const billing = plan.walletBilled
|
|
740
|
+
? {
|
|
741
|
+
costUsd: Number((minutes * config.ELEVENLABS_MUSIC_USD_PER_MIN).toFixed(4)),
|
|
742
|
+
costCenterSlug: "elevenlabs_music",
|
|
743
|
+
metadata: {
|
|
744
|
+
operation: "music",
|
|
745
|
+
provider: "elevenlabs",
|
|
746
|
+
music_length_ms: generated.musicLengthMs,
|
|
747
|
+
wallet_billed: true,
|
|
748
|
+
scope: plan.scope
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
: null;
|
|
752
|
+
return { ...generated, scope: plan.scope, billing };
|
|
753
|
+
}
|
|
584
754
|
async generateSpeechWithProvider(input) {
|
|
585
755
|
assertSupportedSpeechModel("tts", input.provider, input.model);
|
|
586
756
|
const lease = await this.leaseCustomerKey({
|
|
@@ -1475,6 +1645,45 @@ export class ProviderService {
|
|
|
1475
1645
|
}
|
|
1476
1646
|
}
|
|
1477
1647
|
async transcribeSpeech(input) {
|
|
1648
|
+
const plan = await this.resolveAudioAuthPlan({
|
|
1649
|
+
customerId: input.customerId,
|
|
1650
|
+
useWalletCredits: input.useWalletCredits,
|
|
1651
|
+
byokFallback: true,
|
|
1652
|
+
capability: "stt"
|
|
1653
|
+
});
|
|
1654
|
+
if (plan.mode === "elevenlabs") {
|
|
1655
|
+
const model = /^scribe/i.test(input.model || "") ? input.model : DEFAULT_ELEVENLABS_STT_MODEL;
|
|
1656
|
+
const transcription = await elevenLabsSpeechToText({
|
|
1657
|
+
apiKey: plan.apiKey,
|
|
1658
|
+
audio: input.audio,
|
|
1659
|
+
contentType: input.contentType,
|
|
1660
|
+
model,
|
|
1661
|
+
diarize: input.diarize,
|
|
1662
|
+
languageCode: input.language
|
|
1663
|
+
});
|
|
1664
|
+
const minutes = Math.max(0, transcription.audioDurationSec ?? 0) / 60;
|
|
1665
|
+
const billing = plan.walletBilled
|
|
1666
|
+
? {
|
|
1667
|
+
costUsd: Number((minutes * config.ELEVENLABS_STT_USD_PER_MIN).toFixed(4)),
|
|
1668
|
+
costCenterSlug: "elevenlabs_stt",
|
|
1669
|
+
metadata: {
|
|
1670
|
+
operation: "stt",
|
|
1671
|
+
provider: "elevenlabs",
|
|
1672
|
+
model,
|
|
1673
|
+
audio_duration_sec: transcription.audioDurationSec,
|
|
1674
|
+
wallet_billed: true,
|
|
1675
|
+
scope: plan.scope
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1678
|
+
: null;
|
|
1679
|
+
const { audioDurationSec, ...rest } = transcription;
|
|
1680
|
+
void audioDurationSec;
|
|
1681
|
+
return { ...rest, effectiveProvider: "elevenlabs", effectiveModel: model, billing };
|
|
1682
|
+
}
|
|
1683
|
+
const byok = await this.transcribeSpeechByok(input);
|
|
1684
|
+
return { ...byok.result, effectiveProvider: byok.provider, effectiveModel: byok.model, billing: null };
|
|
1685
|
+
}
|
|
1686
|
+
async transcribeSpeechByok(input) {
|
|
1478
1687
|
const attempts = await providerAttempts({
|
|
1479
1688
|
providerKeyService: this.serverlessProviderKeys,
|
|
1480
1689
|
customerId: input.customerId,
|
|
@@ -1489,11 +1698,12 @@ export class ProviderService {
|
|
|
1489
1698
|
let lastError = null;
|
|
1490
1699
|
for (const attempt of attempts) {
|
|
1491
1700
|
try {
|
|
1492
|
-
|
|
1701
|
+
const result = await this.transcribeSpeechWithProvider({
|
|
1493
1702
|
...input,
|
|
1494
1703
|
provider: attempt.provider,
|
|
1495
1704
|
model: attempt.model
|
|
1496
1705
|
});
|
|
1706
|
+
return { result, provider: attempt.provider, model: attempt.model };
|
|
1497
1707
|
}
|
|
1498
1708
|
catch (error) {
|
|
1499
1709
|
lastError = error;
|
|
@@ -2041,6 +2251,10 @@ function formatProviderLabel(provider) {
|
|
|
2041
2251
|
return "OpenRouter";
|
|
2042
2252
|
case "perplexity":
|
|
2043
2253
|
return "Perplexity";
|
|
2254
|
+
case "elevenlabs":
|
|
2255
|
+
return "ElevenLabs";
|
|
2256
|
+
default:
|
|
2257
|
+
return provider;
|
|
2044
2258
|
}
|
|
2045
2259
|
}
|
|
2046
2260
|
function readStringField(value, field) {
|
|
@@ -66,6 +66,7 @@ export async function reconcileSwipeRows(customerId, rows) {
|
|
|
66
66
|
}
|
|
67
67
|
return out;
|
|
68
68
|
}
|
|
69
|
+
// Text generation only — the audio-only elevenlabs provider never appears here.
|
|
69
70
|
const TEXT_MODEL_DEFAULTS = {
|
|
70
71
|
openai: "gpt-5.4-mini",
|
|
71
72
|
gemini: "gemini-2.5-flash",
|
|
@@ -246,7 +247,9 @@ function parseJsonLoose(text) {
|
|
|
246
247
|
}
|
|
247
248
|
async function generateRecaption(input) {
|
|
248
249
|
const available = await providers.listAvailableProvidersAsync(input.customerId);
|
|
249
|
-
|
|
250
|
+
// Text generation only — never fall back to a non-text provider (e.g. the
|
|
251
|
+
// audio-only elevenlabs key), which has no text model.
|
|
252
|
+
const provider = TEXT_PROVIDER_PRIORITY.find((p) => available.includes(p));
|
|
250
253
|
if (!provider)
|
|
251
254
|
throw new NoProviderKeyError();
|
|
252
255
|
const generated = await providers.generateText({
|
|
@@ -254,7 +257,7 @@ async function generateRecaption(input) {
|
|
|
254
257
|
jobId: input.jobId,
|
|
255
258
|
workerId: "swipe-customize",
|
|
256
259
|
provider,
|
|
257
|
-
model: TEXT_MODEL_DEFAULTS[provider],
|
|
260
|
+
model: TEXT_MODEL_DEFAULTS[provider] ?? "gpt-5.4-mini",
|
|
258
261
|
prompt: input.prompt,
|
|
259
262
|
temperature: 0.7,
|
|
260
263
|
responseFormat: "json"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mevdragon/vidfarm-devcli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.20.1",
|
|
4
4
|
"description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
var Me=["files","temp","raws","projects","approved"],pe=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."},{key:"projects",label:"Projects",description:"Your video-editing projects \u2014 one folder per fork, holding that composition's working files (composition.html/json, cast, media) and saved versions. Read-only: browse to reference or study another fork."},{key:"approved",label:"Approved",description:"Finished, ready-to-post cuts, organized into folders (defaults to a folder per tracer/campaign)."}];function qe(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function ue(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function J(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[s,...a]=n;return qe(s)?{root:s,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function Z(r,n,s){let a=[r,ue(n)];return s&&a.push(String(s).trim()),"/"+a.filter(Boolean).join("/")}var We="/api/v1/user/me";function i(r,n,s){let a=document.createElement(r);return n&&(a.className=n),s!=null&&(a.textContent=s),a}function Je(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],s=r,a=0;for(;s>=1024&&a<n.length-1;)s/=1024,a++;return(s>=10||a===0?Math.round(s):s.toFixed(1))+" "+n[a]}function Ve(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),s=r%60;return n+":"+(s<10?"0"+s:s)}function Se(r){let n=i("span","rk-aichat-fic "+(r.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(r.kind==="folder")return n.textContent="/",n;if(r.thumbUrl){let a=i("img");return a.src=r.thumbUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}let s=r.contentType||"";if(r.viewUrl&&s.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&s.indexOf("video/")===0){let a=i("video");return a.src=r.viewUrl,a.muted=!0,a.playsInline=!0,n.appendChild(a),n}return n.textContent=(r.name.split(".").pop()||r.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var fe;function he(r){let n=document.getElementById("rk-dir-toast");n||(n=i("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=r,n.classList.add("is-on"),fe&&window.clearTimeout(fe),fe=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function $e(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,s)=>{try{let a=i("textarea");a.value=r,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),n()}catch(a){s(a)}})}var q=null;function Re(r,n){q&&q();let s=i("div","rk-dir-menu");n.forEach(f=>{let L=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);L.type="button",L.addEventListener("click",N=>{N.stopPropagation(),x(),f.run()}),s.appendChild(L)}),document.body.appendChild(s);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=s.offsetWidth,v=s.offsetHeight,S=a.bottom+4,w=a.right-h;w<8&&(w=a.left),S+v>window.innerHeight-8&&(S=Math.max(8,a.top-v-4)),s.style.top=S+"px",s.style.left=Math.max(8,w)+"px";function x(){s.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",D,!0),window.removeEventListener("scroll",x,!0),q===x&&(q=null)}function m(f){s.contains(f.target)||x()}function D(f){f.key==="Escape"&&x()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",D,!0),window.addEventListener("scroll",x,!0)},0),q=x}function me(r,n={}){let s=n.apiBase||We,a=n.roots&&n.roots.length?n.roots:Me.slice(),h=a.length===1?a[0]:null,v=n.mode||"attach",S=n.showSearch!==!1,w=n.showMultiSelect!==!1,x=n.showUpload!=null?n.showUpload:v==="attach",m=n.primaryClick||"copyPath",D=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},L=e=>(n.onAttach||f.onAttach||(()=>he("Attached "+e.length+" item(s)")))(e),N=(e,t)=>{let o=n.onPreview||f.onPreview;o?o(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},T=e=>(n.onToast||f.onToast||he)(e),R=e=>$e(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=He(n.initialPath,h),u="idle",g=[],P=[],V=null,W=!1,k=new Map,$=!1,I=[],X="idle",H=!1,le="local";function ge(){return le==="cloud"?"/cloud":""}function He(e,t){let o=J(e||"");return o.root?Z(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let be=i("div","rk-dir-search"),z=i("input","rk-dir-search-input");z.type="search",z.placeholder="Search files \u2014 meaning, name, or path\u2026",be.appendChild(z);let O=i("div","rk-aichat-crumbs rk-dir-crumbs"),_=i("div","rk-dir-selbar");_.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),y=i("label","rk-aichat-drop rk-dir-drop");y.hidden=!0;let ee=i("span","rk-aichat-drop-text","Drop files here"),B=i("input");B.type="file",B.multiple=!0,B.hidden=!0,y.appendChild(ee),y.appendChild(B);let de=i("div","rk-dir-space"),te=i("button","rk-dir-space-btn is-on","Local"),ne=i("button","rk-dir-space-btn","Cloud");te.type="button",ne.type="button",de.appendChild(te),de.appendChild(ne);function ke(e){le!==e&&(le=e,te.classList.toggle("is-on",e==="local"),ne.classList.toggle("is-on",e==="cloud"),$=!1,I=[],z.value="",k.clear(),p=h?"/"+h:"/",u="idle",F(!0))}te.addEventListener("click",()=>ke("local")),ne.addEventListener("click",()=>ke("cloud")),D&&r.appendChild(de),S&&r.appendChild(be),r.appendChild(O),w&&r.appendChild(_),r.appendChild(b),x&&r.appendChild(y);function ye(e,t){let o=new URL(s+ge()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function F(e){if(!H){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(ye(p),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return u="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!H){if(!t){C();return}g=Oe(t.folders||[]),P=t.files||[],V=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{H||(u="error",C())})}}function Oe(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function _e(){V==null||W||(W=!0,C(),fetch(ye(p,V),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(W=!1,H||!e){C();return}P=P.concat(e.files||[]),V=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{W=!1,C()}))}let ce;function Be(){let e=z.value.trim();if(ce&&window.clearTimeout(ce),!e){$=!1,I=[],C();return}ce=window.setTimeout(()=>Ue(e),260)}function Ue(e){$=!0,X="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(s+ge()+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(o=>o.ok?o.json():null).then(o=>{H||(I=o&&o.results||[],X="ready",C())}).catch(()=>{H||(X="error",C())})}function U(e){let t=J(e);p=t.root?Z(t.root,t.folderPath):"/",u="idle",$=!1,z.value="",(n.onNavigate||(()=>{}))(p),F(!0)}function j(){return J(p).root}function re(){return J(p).folderPath}function Y(e){return!!e&&e!=="projects"}function oe(e){let t=j();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!Y(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let d=ue(e??re()),c=Z(t,d?d+"/"+o:o);fetch(s+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:c})}).then(l=>l.ok?l.json():l.json().then(E=>Promise.reject(new Error(E.error||"http "+l.status)))).then(l=>{U(l.path||(t===j()?p:"/"+t)),T("Created "+(l.path||o))}).catch(l=>T(l.message||"Couldn't create folder"))}function ie(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(s+"/directory/rename",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:e.path,new_name:o,...t?{}:{file_id:e.id}})}).then(d=>d.ok?d.json():d.json().then(c=>Promise.reject(new Error(c.error||"http "+d.status)))).then(()=>{k.has(e.path)&&(k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values()))),F(!0),T("Renamed to "+o)}).catch(d=>T(d.message||"Couldn't rename"))}function je(e,t){t?k.set(e.path,e):k.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(k.values())),Ce();let o=b.querySelector('[data-path="'+Xe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function ve(){k.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function se(e,t,o){let d=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return d.type="button",d.addEventListener("click",o),d}function Ne(){O.innerHTML="";let e=j(),t=re();if(h||O.appendChild(se("Files",p==="/",()=>U("/"))),!e)return;let o=(pe.find(c=>c.key===e)||{label:e}).label;h||O.appendChild(we()),O.appendChild(se(o,!t,()=>U("/"+e)));let d="";if(t.split("/").filter(Boolean).forEach((c,l,E)=>{O.appendChild(we()),d=d?d+"/"+c:c;let M="/"+e+"/"+d;O.appendChild(se(c,l===E.length-1,()=>U(M)))}),Y(e)){let c=i("button","rk-dir-newfolder","+ Folder");c.type="button",c.title="New folder here (or right-click)",c.addEventListener("click",()=>oe()),O.appendChild(c)}}function we(){return i("span","rk-aichat-crumb-sep","/")}function Ce(){if(!w)return;let e=k.size;if(_.hidden=e===0,e===0)return;if(_.innerHTML="",_.appendChild(i("span","rk-dir-selcount",e+" selected")),v==="attach"){let d=i("button","rk-dir-selbtn","Attach");d.type="button",d.addEventListener("click",()=>{L(Array.from(k.values())),ve()}),_.appendChild(d)}let t=i("button","rk-dir-selbtn","Copy paths");t.type="button",t.addEventListener("click",()=>R(Array.from(k.values()).map(d=>d.path).join(`
|
|
2
|
-
`)));let o=i("button","rk-dir-selbtn is-ghost","Clear");o.type="button",o.addEventListener("click",ve),_.appendChild(t),_.appendChild(o)}function xe(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=k.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>je(e,t.checked)),t}function Ee(e){let t=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),w&&t.appendChild(xe(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(Se(e));let d=i("span","rk-aichat-fmain");d.appendChild(i("span","rk-aichat-fname",e.name));let c=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";d.appendChild(i("span","rk-aichat-fmeta",c||"folder")),o.appendChild(d),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let l=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");l.type="button",l.title="Open folder",l.addEventListener("click",M=>{M.stopPropagation(),U(e.path)}),t.appendChild(l);let E=[{label:"Open folder",run:()=>U(e.path)}];return Y(e.root)&&(E.push({label:"New subfolder",run:()=>oe(e.folderPath)}),E.push({label:"Rename",run:()=>ie(e)})),E.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Le(e,E)),t}function De(e,t,o,d){let c=i("div","rk-aichat-frow rk-dir-row"+(k.has(e.path)?" is-selected":""));c.setAttribute("data-path",e.path),w&&c.appendChild(xe(e));let l=i("button","rk-aichat-fmainbtn");l.type="button";let E=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";l.title=E+e.name,l.appendChild(Se(e));let M=i("span","rk-aichat-fmain");M.appendChild(i("span","rk-aichat-fname",e.name));let G=d?e.path:Ve(e.durationSec)||Je(e.sizeBytes)||e.contentType||"file";if(M.appendChild(i("span","rk-aichat-fmeta",G)),l.appendChild(M),l.addEventListener("click",()=>{m==="attach"?L([e]):m==="preview"?N(t,o):R(e.path)}),c.appendChild(l),v==="attach"&&m==="preview"){let Q=i("button","rk-aichat-fadd rk-dir-attach","+");Q.type="button",Q.title="Attach "+e.name,Q.setAttribute("aria-label","Attach "+e.name),Q.addEventListener("click",Ke=>{Ke.stopPropagation(),L([e])}),c.appendChild(Q)}let A=[];return v==="attach"&&A.push({label:"Attach",run:()=>L([e])}),e.viewUrl&&A.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&A.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&A.push({label:"Rename",run:()=>ie(e)}),A.push({label:"Copy path",run:()=>R(e.path)}),c.appendChild(Le(e,A)),c}function Le(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",d=>{d.stopPropagation(),Re(o,t)}),o}function K(e,t,o){let d=i("div","rk-aichat-fstate");if(d.appendChild(i("div",void 0,e)),t){let c=i("a");c.href=t.href,c.textContent=t.label,d.appendChild(c)}if(o){let c=i("button",void 0,"Try again");c.type="button",c.addEventListener("click",()=>F(!0)),d.appendChild(c)}return d}function C(){if(!H){if(Ne(),Ce(),Fe(),b.innerHTML="",$){ze();return}if(u==="loading"&&!P.length&&!g.length){b.appendChild(K("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(K("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(K("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!P.length){b.appendChild(K(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Ee(e))),P.forEach((e,t)=>b.appendChild(De(e,P,t))),V!=null){let e=i("button","rk-aichat-loadmore",W?"Loading\u2026":"Load more");e.type="button",e.disabled=W,e.addEventListener("click",_e),b.appendChild(e)}}}function ze(){if(X==="loading"&&!I.length){b.appendChild(K("Searching\u2026"));return}if(X==="error"){b.appendChild(K("Search failed."));return}if(!I.length){b.appendChild(K("No matches."));return}let e=I.filter(t=>t.kind!=="folder");I.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Ee(t)):b.appendChild(De(t,e,e.indexOf(t),!0))})}let ae=!1;function Te(){let e=j();return e==="files"?s+"/attachments/upload":e==="temp"?s+"/temporary-files/upload":null}function Fe(){if(!x)return;let e=Te();if(y.hidden=!e||u==="auth",!y.hidden&&!ae){let t=re(),o=j()?(pe.find(d=>d.key===j())||{label:""}).label:"";ee.textContent="Drop files into "+o+(t?" / "+t:"")}}function Pe(e){let t=Te();if(!t||ae||!e||!e.length)return;ae=!0;let o=re(),d=Array.from(e),c=0,l=0;ee.textContent="Uploading "+d.length+" file(s)\u2026";let E=M=>{if(M>=d.length){ae=!1,l&&T(l+" of "+d.length+" failed"),F(!0);return}let G=new FormData;G.append("file",d[M]),G.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:G}).then(A=>{if(!A.ok)throw new Error("http "+A.status);c++}).catch(()=>{l++}).then(()=>E(M+1))};E(0)}function Ye(e){return g.concat(P,I).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!j(),o=e.target.closest(".rk-dir-row"),d={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},c=[],l=o?Ye(o.getAttribute("data-path")||""):void 0;l&&l.kind==="folder"?(c.push({label:"Open folder",run:()=>U(l.path)}),Y(l.root)&&c.push({label:"New subfolder",run:()=>oe(l.folderPath)}),Y(l.root)&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})):l&&(v==="attach"&&c.push({label:"Attach",run:()=>L([l])}),l.viewUrl&&c.push({label:"View",run:()=>window.open(l.viewUrl,"_blank","noopener")}),l.viewUrl&&c.push({label:"Preview",run:()=>N(P,P.indexOf(l))}),l.root!=="raws"&&Y(l.root)&&l.id&&c.push({label:"Rename",run:()=>ie(l)}),c.push({label:"Copy path",run:()=>R(l.path)})),t&&Y(j())&&c.push({label:"New folder here",run:()=>oe()}),c.length&&(e.preventDefault(),Re(d,c))}),z.addEventListener("input",Be),y.addEventListener("click",e=>{(e.target===y||e.target===ee)&&B.click()}),B.addEventListener("change",()=>{Pe(B.files),B.value=""}),y.addEventListener("dragover",e=>{e.preventDefault(),y.classList.add("is-drag")}),y.addEventListener("dragleave",e=>{e.target===y&&y.classList.remove("is-drag")}),y.addEventListener("drop",e=>{e.preventDefault(),y.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Pe(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),F(!0),{refresh:()=>F(!0),navigate:U,getSelection:()=>Array.from(k.values()),getCurrentPath:()=>p,destroy:()=>{H=!0,q&&q(),r.innerHTML=""}}}function Xe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Ae="rk-dirpick-style";function Ge(){if(document.getElementById(Ae))return;let r=document.createElement("style");r.id=Ae,r.textContent=[".rk-dirpick{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:20px;","background:rgba(28,25,23,.44);backdrop-filter:blur(2px);animation:rk-dirpick-fade .16s ease}","@keyframes rk-dirpick-fade{from{opacity:0}to{opacity:1}}",".rk-dirpick-panel{width:min(560px,100%);max-height:min(82vh,700px);display:flex;flex-direction:column;","background:var(--rk-surface,#fff);border:1px solid var(--rk-border,#e6e0d6);border-radius:var(--rk-r-3xl,20px);","box-shadow:var(--rk-shadow-lg,0 24px 60px rgba(28,25,23,.28));overflow:hidden}",".rk-dirpick-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;","border-bottom:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-title{font-family:var(--rk-font-display,inherit);font-weight:800;font-size:15px;color:var(--rk-ink,#1c1917)}",".rk-dirpick-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted,#78716c);cursor:pointer;padding:0 4px}",".rk-dirpick-close:hover{color:var(--rk-ink,#1c1917)}",".rk-dirpick-hint{padding:10px 18px 0;font-size:12.5px;line-height:1.4;color:var(--rk-text-muted,#78716c)}",".rk-dirpick-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}",".rk-dirpick-foot{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-dest{flex:1;min-width:0;font-size:12.5px;color:var(--rk-text-muted,#78716c);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",".rk-dirpick-dest b{color:var(--rk-ink,#1c1917);font-weight:700}",".rk-dirpick-btn{flex:none;min-height:36px;padding:0 16px;border-radius:999px;border:0;cursor:pointer;","font:inherit;font-size:13px;font-weight:800;background:var(--rk-gold-500,var(--rk-gold-600,#fcb900));color:var(--rk-ink,#1c1917)}",".rk-dirpick-btn:hover:not(:disabled){background:var(--rk-gold-600,#e0a500)}",".rk-dirpick-btn:disabled{opacity:.5;cursor:default}",".rk-dirpick-btn.is-ghost{background:transparent;border:1px solid var(--rk-border,#e6e0d6);color:var(--rk-ink,#1c1917)}"].join(""),document.head.appendChild(r)}function Qe(r={}){Ge();let n=r.select==="folder"?"folder":"file",s=!1,a=null,h=i("div","rk-dirpick"),v=i("div","rk-dirpick-panel"),S=i("div","rk-dirpick-head");S.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let w=i("button","rk-dirpick-close");w.type="button",w.setAttribute("aria-label","Close"),w.innerHTML="×",S.appendChild(w),v.appendChild(S),r.hint&&v.appendChild(i("div","rk-dirpick-hint",r.hint));let x=i("div","rk-dirpick-mount");v.appendChild(x);let m=null,D=null;function f(p){s||(s=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function L(p){let u=J(p);if(!u.root)return null;let g=u.folderPath||"",P=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:Z(u.root,g),root:u.root,folderPath:g,name:P,kind:"folder"}}function N(p){if(!m||!D)return;let u=L(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),D.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",D.disabled=!0}if(n==="folder"){let p=i("div","rk-dirpick-foot");m=i("div","rk-dirpick-dest");let u=i("button","rk-dirpick-btn is-ghost","Cancel");u.type="button",u.addEventListener("click",()=>f(null)),D=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),D.type="button",D.addEventListener("click",()=>{let g=a?L(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(D),v.appendChild(p)}h.appendChild(v),document.body.appendChild(h);function T(p){p.key==="Escape"&&f(null)}function R(){document.removeEventListener("keydown",T,!0);try{a&&a.destroy()}catch{}h.remove()}return w.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=me(x,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:!1,primaryClick:n==="file"?"attach":"copyPath",onNavigate:p=>N(p),onAttach:p=>{if(n!=="file")return;let u=p&&p[0];if(u){if(r.accept&&!r.accept(u)){he(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function Ze(r){let n=r.dataset,s=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:s.length?s:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath",cloudAvailable:n.cloudAvailable!=null?n.cloudAvailable==="true":void 0}}function Ie(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=me(n,Ze(n)))})}window.__vidfarmDirectory={mount:me,pick:Qe};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",Ie):Ie();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{me as createDirectoryExplorer,Qe as openDirectoryPicker};
|
|
1
|
+
var Ie=["files","temp","raws","projects","approved"],fe=[{key:"files",label:"My Files",description:"Durable personal files \u2014 brand assets, characters, saved context. Vector-searchable via notes."},{key:"temp",label:"Temp",description:"Scratch space, auto-organized by date (YYYY-MM-DD) and auto-deleted after 30 days."},{key:"raws",label:"Raws",description:"The reusable clip / source-footage library, organized into folders by source."},{key:"projects",label:"Projects",description:"Your video-editing projects \u2014 one folder per fork, holding that composition's working files (composition.html/json, cast, media) and saved versions. Read-only: browse to reference or study another fork."},{key:"approved",label:"Approved",description:"Finished, ready-to-post cuts, organized into folders (defaults to a folder per tracer/campaign)."}];function Je(r){return r==="files"||r==="temp"||r==="raws"||r==="projects"||r==="approved"}function he(r){return String(r??"").split("/").map(n=>n.trim()).filter(Boolean).join("/")}function $(r){let n=String(r??"").split("/").map(h=>h.trim()).filter(Boolean);if(n.length===0)return{root:null,folderPath:"",segments:[]};let[c,...a]=n;return Je(c)?{root:c,folderPath:a.join("/"),segments:a}:{root:null,folderPath:"",segments:n}}function X(r,n,c){let a=[r,he(n)];return c&&a.push(String(c).trim()),"/"+a.filter(Boolean).join("/")}var Ve="/api/v1/user/me";function i(r,n,c){let a=document.createElement(r);return n&&(a.className=n),c!=null&&(a.textContent=c),a}function $e(r){if(!r||r<=0)return"";let n=["B","KB","MB","GB"],c=r,a=0;for(;c>=1024&&a<n.length-1;)c/=1024,a++;return(c>=10||a===0?Math.round(c):c.toFixed(1))+" "+n[a]}function Xe(r){if(typeof r!="number"||!(r>0))return"";r=Math.round(r);let n=Math.floor(r/60),c=r%60;return n+":"+(c<10?"0"+c:c)}function He(r){let n=i("span","rk-aichat-fic "+(r.kind==="folder"?"rk-aichat-fic-folder":"rk-aichat-fic-file"));if(r.kind==="folder")return n.textContent="/",n;if(r.thumbUrl){let a=i("img");return a.src=r.thumbUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}let c=r.contentType||"";if(r.viewUrl&&c.indexOf("image/")===0){let a=i("img");return a.src=r.viewUrl,a.alt="",a.loading="lazy",n.appendChild(a),n}if(r.viewUrl&&c.indexOf("video/")===0){let a=i("video");return a.src=r.viewUrl,a.muted=!0,a.playsInline=!0,n.appendChild(a),n}return n.textContent=(r.name.split(".").pop()||r.name.slice(0,1)||"?").slice(0,3).toUpperCase(),n}var me;function be(r){let n=document.getElementById("rk-dir-toast");n||(n=i("div"),n.id="rk-dir-toast",n.className="rk-dir-toast",document.body.appendChild(n)),n.textContent=r,n.classList.add("is-on"),me&&window.clearTimeout(me),me=window.setTimeout(()=>n&&n.classList.remove("is-on"),1800)}function Ge(r){return navigator.clipboard&&navigator.clipboard.writeText?navigator.clipboard.writeText(r):new Promise((n,c)=>{try{let a=i("textarea");a.value=r,a.style.position="fixed",a.style.opacity="0",document.body.appendChild(a),a.select(),document.execCommand("copy"),document.body.removeChild(a),n()}catch(a){c(a)}})}var J=null;function ge(r,n){J&&J();let c=i("div","rk-dir-menu");n.forEach(f=>{let P=i("button","rk-dir-menuitem"+(f.danger?" is-danger":""),f.label);P.type="button",P.addEventListener("click",N=>{N.stopPropagation(),E(),f.run()}),c.appendChild(P)}),document.body.appendChild(c);let a=r instanceof HTMLElement?r.getBoundingClientRect():r,h=c.offsetWidth,y=c.offsetHeight,A=a.bottom+4,v=a.right-h;v<8&&(v=a.left),A+y>window.innerHeight-8&&(A=Math.max(8,a.top-y-4)),c.style.top=A+"px",c.style.left=Math.max(8,v)+"px";function E(){c.remove(),document.removeEventListener("click",m,!0),document.removeEventListener("keydown",L,!0),window.removeEventListener("scroll",E,!0),J===E&&(J=null)}function m(f){c.contains(f.target)||E()}function L(f){f.key==="Escape"&&E()}setTimeout(()=>{document.addEventListener("click",m,!0),document.addEventListener("keydown",L,!0),window.addEventListener("scroll",E,!0)},0),J=E}function ke(r,n={}){let c=n.apiBase||Ve,a=n.roots&&n.roots.length?n.roots:Ie.slice(),h=a.length===1?a[0]:null,y=n.mode||"attach",A=n.showSearch!==!1,v=n.showMultiSelect!==!1,E=n.showUpload!=null?n.showUpload:y==="attach",m=n.primaryClick||"copyPath",L=n.cloudAvailable!=null?n.cloudAvailable:typeof window<"u"&&window.__vidfarmCloudSpace===!0,f=window.__rkDirectoryHost||{},P=e=>(n.onAttach||f.onAttach||(()=>be("Attached "+e.length+" item(s)")))(e),N=(e,t)=>{let o=n.onPreview||f.onPreview;o?o(e,t):e[t]&&e[t].viewUrl&&window.open(e[t].viewUrl,"_blank","noopener")},T=e=>(n.onToast||f.onToast||be)(e),R=e=>Ge(e).then(()=>T("Copied "+e)).catch(()=>T("Couldn't copy path")),p=Be(n.initialPath,h),u="idle",g=[],M=[],G=null,V=!1,w=new Map,Q=!1,B=[],Z="idle",U=!1,de="local";function ye(){return de==="cloud"?"/cloud":""}function Be(e,t){let o=$(e||"");return o.root?X(o.root,o.folderPath):t?"/"+t:"/"}r.classList.add("rk-dir"),r.innerHTML="";let ve=i("div","rk-dir-search"),z=i("input","rk-dir-search-input");z.type="search",z.placeholder="Search files \u2014 meaning, name, or path\u2026",ve.appendChild(z);let j=i("div","rk-aichat-crumbs rk-dir-crumbs"),Y=i("div","rk-dir-selbar");Y.hidden=!0;let b=i("div","rk-aichat-files-body rk-dir-body"),k=i("label","rk-aichat-drop rk-dir-drop");k.hidden=!0;let te=i("span","rk-aichat-drop-text","Drop files here"),F=i("input");F.type="file",F.multiple=!0,F.hidden=!0,k.appendChild(te),k.appendChild(F);let ce=i("div","rk-dir-space"),ne=i("button","rk-dir-space-btn is-on","Local"),re=i("button","rk-dir-space-btn","Cloud");ne.type="button",re.type="button",ce.appendChild(ne),ce.appendChild(re);function we(e){de!==e&&(de=e,ne.classList.toggle("is-on",e==="local"),re.classList.toggle("is-on",e==="cloud"),Q=!1,B=[],z.value="",w.clear(),p=h?"/"+h:"/",u="idle",K(!0))}ne.addEventListener("click",()=>we("local")),re.addEventListener("click",()=>we("cloud")),L&&r.appendChild(ce),A&&r.appendChild(ve),r.appendChild(j),v&&r.appendChild(Y),r.appendChild(b),E&&r.appendChild(k);function Ce(e,t){let o=new URL(c+ye()+"/directory",window.location.href);return o.searchParams.set("path",e),t&&o.searchParams.set("offset",String(t)),o.toString()}function K(e){if(!U){if(!e&&u==="ready"){C();return}u="loading",C(),fetch(Ce(p),{credentials:"same-origin",headers:{accept:"application/json"}}).then(t=>{if(t.status===401||t.status===403)return u="auth",null;if(!t.ok)throw new Error("http "+t.status);return t.json()}).then(t=>{if(!U){if(!t){C();return}g=Ue(t.folders||[]),M=t.files||[],G=typeof t.next_offset=="number"?t.next_offset:null,u="ready",C()}}).catch(()=>{U||(u="error",C())})}}function Ue(e){return p!=="/"?e:e.filter(t=>a.indexOf(t.root)!==-1)}function je(){G==null||V||(V=!0,C(),fetch(Ce(p,G),{credentials:"same-origin",headers:{accept:"application/json"}}).then(e=>e.ok?e.json():null).then(e=>{if(V=!1,U||!e){C();return}M=M.concat(e.files||[]),G=typeof e.next_offset=="number"?e.next_offset:null,C()}).catch(()=>{V=!1,C()}))}let se;function Fe(){let e=z.value.trim();if(se&&window.clearTimeout(se),!e){Q=!1,B=[],C();return}se=window.setTimeout(()=>Ne(e),260)}function Ne(e){Q=!0,Z="loading",C();let t=h?"/"+h:p!=="/"?p:"";fetch(c+ye()+"/directory/search",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({query:e,path:t,mode:"auto",limit:40})}).then(o=>o.ok?o.json():null).then(o=>{U||(B=o&&o.results||[],Z="ready",C())}).catch(()=>{U||(Z="error",C())})}function I(e){let t=$(e);p=t.root?X(t.root,t.folderPath):"/",u="idle",Q=!1,z.value="",(n.onNavigate||(()=>{}))(p),K(!0)}function H(){return $(p).root}function oe(){return $(p).folderPath}function q(e){return!!e&&e!=="projects"}function ie(e){let t=H();if(!t){T("Open a root (/files, /temp, /raws) first");return}if(!q(t)){T("/projects is read-only");return}let o=(window.prompt("New folder name")||"").trim();if(!o)return;let s=he(e??oe()),l=X(t,s?s+"/"+o:o);fetch(c+"/directory/folders",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:l})}).then(d=>d.ok?d.json():d.json().then(x=>Promise.reject(new Error(x.error||"http "+d.status)))).then(d=>{I(d.path||(t===H()?p:"/"+t)),T("Created "+(d.path||o))}).catch(d=>T(d.message||"Couldn't create folder"))}function ae(e){let t=e.kind==="folder",o=(window.prompt(t?"Rename folder":"Rename file",e.name)||"").trim();!o||o===e.name||fetch(c+"/directory/rename",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json",accept:"application/json"},body:JSON.stringify({path:e.path,new_name:o,...t?{}:{file_id:e.id}})}).then(s=>s.ok?s.json():s.json().then(l=>Promise.reject(new Error(l.error||"http "+s.status)))).then(()=>{w.has(e.path)&&(w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values()))),K(!0),T("Renamed to "+o)}).catch(s=>T(s.message||"Couldn't rename"))}function ze(e,t){t?w.set(e.path,e):w.delete(e.path),(n.onSelectionChange||(()=>{}))(Array.from(w.values())),De();let o=b.querySelector('[data-path="'+Qe(e.path)+'"]');o&&o.classList.toggle("is-selected",t)}function xe(){w.clear(),(n.onSelectionChange||(()=>{}))([]),C()}function pe(e,t,o){let s=i("button","rk-aichat-crumb"+(t?" is-current":""),e);return s.type="button",s.addEventListener("click",o),s}function Ye(){j.innerHTML="";let e=H(),t=oe();if(h||j.appendChild(pe("Files",p==="/",()=>I("/"))),!e)return;let o=(fe.find(l=>l.key===e)||{label:e}).label;h||j.appendChild(Ee()),j.appendChild(pe(o,!t,()=>I("/"+e)));let s="";if(t.split("/").filter(Boolean).forEach((l,d,x)=>{j.appendChild(Ee()),s=s?s+"/"+l:l;let S="/"+e+"/"+s;j.appendChild(pe(l,d===x.length-1,()=>I(S)))}),q(e)){let l=i("button","rk-dir-newfolder","+ Folder");l.type="button",l.title="New folder here (or right-click)",l.addEventListener("click",()=>ie()),j.appendChild(l)}}function Ee(){return i("span","rk-aichat-crumb-sep","/")}function De(){if(!v)return;let e=w.size;if(Y.hidden=e===0,e===0)return;Y.innerHTML="",Y.appendChild(i("span","rk-dir-selcount",e+" selected"));let t=()=>Array.from(w.values()),o=i("button","rk-dir-selbtn is-primary","Copy paths");o.type="button",o.addEventListener("click",()=>R(t().map(d=>d.path).join(`
|
|
2
|
+
`))),Y.appendChild(o);let s=[];y==="attach"&&s.push({label:"Attach",run:()=>{P(t()),xe()}}),s.push({label:"Copy paths",run:()=>R(t().map(d=>d.path).join(`
|
|
3
|
+
`))}),s.push({label:"Clear selection",run:xe});let l=i("button","rk-dir-selbtn is-ghost rk-dir-selmore","\u22EF");l.type="button",l.setAttribute("aria-label","More actions"),l.addEventListener("click",d=>{d.stopPropagation(),ge(l,s)}),Y.appendChild(l)}function Le(e){let t=i("input","rk-dir-check");return t.type="checkbox",t.checked=w.has(e.path),t.setAttribute("aria-label","Select "+e.name),t.addEventListener("click",o=>o.stopPropagation()),t.addEventListener("change",()=>ze(e,t.checked)),t}function Pe(e){let t=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));t.setAttribute("data-path",e.path),v&&t.appendChild(Le(e));let o=i("button","rk-aichat-fmainbtn");o.type="button",o.title="Copy path "+e.path,o.appendChild(He(e));let s=i("span","rk-aichat-fmain");s.appendChild(i("span","rk-aichat-fname",e.name));let l=e.meta&&typeof e.meta.description=="string"?e.meta.description:"";s.appendChild(i("span","rk-aichat-fmeta",l||"folder")),o.appendChild(s),o.addEventListener("click",()=>R(e.path)),t.appendChild(o);let d=i("button","rk-aichat-fadd rk-dir-open","Open \u203A");d.type="button",d.title="Open folder",d.addEventListener("click",S=>{S.stopPropagation(),I(e.path)}),t.appendChild(d);let x=[{label:"Open folder",run:()=>I(e.path)}];return q(e.root)&&(x.push({label:"New subfolder",run:()=>ie(e.folderPath)}),x.push({label:"Rename",run:()=>ae(e)})),x.push({label:"Copy path",run:()=>R(e.path)}),t.appendChild(Me(e,x)),t}function Te(e,t,o,s){let l=i("div","rk-aichat-frow rk-dir-row"+(w.has(e.path)?" is-selected":""));l.setAttribute("data-path",e.path),v&&l.appendChild(Le(e));let d=i("button","rk-aichat-fmainbtn");d.type="button";let x=m==="copyPath"?"Copy path ":m==="attach"?"Attach ":"Preview ";d.title=x+e.name,d.appendChild(He(e));let S=i("span","rk-aichat-fmain");S.appendChild(i("span","rk-aichat-fname",e.name));let ue=s?e.path:Xe(e.durationSec)||$e(e.sizeBytes)||e.contentType||"file";if(S.appendChild(i("span","rk-aichat-fmeta",ue)),d.appendChild(S),d.addEventListener("click",()=>{m==="attach"?P([e]):m==="preview"?N(t,o):R(e.path)}),l.appendChild(d),y==="attach"&&m==="preview"){let D=i("button","rk-aichat-fadd rk-dir-attach","+");D.type="button",D.title="Attach "+e.name,D.setAttribute("aria-label","Attach "+e.name),D.addEventListener("click",ee=>{ee.stopPropagation(),P([e])}),l.appendChild(D)}let O=[];return y==="attach"&&O.push({label:"Attach",run:()=>P([e])}),e.viewUrl&&O.push({label:"View",run:()=>window.open(e.viewUrl,"_blank","noopener")}),e.viewUrl&&O.push({label:"Preview",run:()=>N(t,o)}),(e.root==="files"||e.root==="temp")&&e.id&&O.push({label:"Rename",run:()=>ae(e)}),O.push({label:"Copy path",run:()=>R(e.path)}),l.appendChild(Me(e,O)),l}function Me(e,t){let o=i("button","rk-dir-kebab","\u22EF");return o.type="button",o.setAttribute("aria-label","More actions"),o.addEventListener("click",s=>{s.stopPropagation(),ge(o,t)}),o}function W(e,t,o){let s=i("div","rk-aichat-fstate");if(s.appendChild(i("div",void 0,e)),t){let l=i("a");l.href=t.href,l.textContent=t.label,s.appendChild(l)}if(o){let l=i("button",void 0,"Try again");l.type="button",l.addEventListener("click",()=>K(!0)),s.appendChild(l)}return s}function C(){if(!U){if(Ye(),De(),qe(),b.innerHTML="",Q){Ke();return}if(u==="loading"&&!M.length&&!g.length){b.appendChild(W("Loading your files\u2026"));return}if(u==="auth"){b.appendChild(W("Sign in to browse your files.",{href:"/login",label:"Sign in"}));return}if(u==="error"){b.appendChild(W("Couldn't reach your files.",void 0,!0));return}if(!g.length&&!M.length){b.appendChild(W(p==="/"?"No files yet.":"This folder is empty."));return}if(g.forEach(e=>b.appendChild(Pe(e))),M.forEach((e,t)=>b.appendChild(Te(e,M,t))),G!=null){let e=i("button","rk-aichat-loadmore",V?"Loading\u2026":"Load more");e.type="button",e.disabled=V,e.addEventListener("click",je),b.appendChild(e)}}}function Ke(){if(Z==="loading"&&!B.length){b.appendChild(W("Searching\u2026"));return}if(Z==="error"){b.appendChild(W("Search failed."));return}if(!B.length){b.appendChild(W("No matches."));return}let e=B.filter(t=>t.kind!=="folder");B.forEach((t,o)=>{t.kind==="folder"?b.appendChild(Pe(t)):b.appendChild(Te(t,e,e.indexOf(t),!0))})}let le=!1;function Se(){let e=H();return e==="files"?c+"/attachments/upload":e==="temp"?c+"/temporary-files/upload":null}function qe(){if(!E)return;let e=Se();if(k.hidden=!e||u==="auth",!k.hidden&&!le){let t=oe(),o=H()?(fe.find(s=>s.key===H())||{label:""}).label:"";te.textContent="Drop files into "+o+(t?" / "+t:"")}}function Re(e){let t=Se();if(!t||le||!e||!e.length)return;le=!0;let o=oe(),s=H(),l=Array.from(e),d=0,x=0,S=null;te.textContent="Uploading "+l.length+" file(s)\u2026";let ue=()=>{le=!1,x&&T(x+" of "+l.length+" failed");let D=s&&S!=null?X(s,S):null;D&&D!==p?I(D):K(!0)},O=D=>{if(D>=l.length){ue();return}let ee=new FormData;ee.append("file",l[D]),ee.append("folder_path",o),fetch(t,{method:"POST",credentials:"same-origin",body:ee}).then(_=>{if(!_.ok)throw new Error("http "+_.status);return _.json().catch(()=>null)}).then(_=>{d++;let Ae=_&&((_.file&&_.file.folderPath)??(_.attachment&&_.attachment.folderPath));typeof Ae=="string"&&S==null&&(S=Ae)}).catch(()=>{x++}).then(()=>O(D+1))};O(0)}function We(e){return g.concat(M,B).find(t=>t.path===e)}return b.addEventListener("contextmenu",e=>{let t=!!H(),o=e.target.closest(".rk-dir-row"),s={top:e.clientY,bottom:e.clientY,left:e.clientX,right:e.clientX},l=[],d=o?We(o.getAttribute("data-path")||""):void 0;d&&d.kind==="folder"?(l.push({label:"Open folder",run:()=>I(d.path)}),q(d.root)&&l.push({label:"New subfolder",run:()=>ie(d.folderPath)}),q(d.root)&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})):d&&(y==="attach"&&l.push({label:"Attach",run:()=>P([d])}),d.viewUrl&&l.push({label:"View",run:()=>window.open(d.viewUrl,"_blank","noopener")}),d.viewUrl&&l.push({label:"Preview",run:()=>N(M,M.indexOf(d))}),d.root!=="raws"&&q(d.root)&&d.id&&l.push({label:"Rename",run:()=>ae(d)}),l.push({label:"Copy path",run:()=>R(d.path)})),t&&q(H())&&l.push({label:"New folder here",run:()=>ie()}),l.length&&(e.preventDefault(),ge(s,l))}),z.addEventListener("input",Fe),k.addEventListener("click",e=>{(e.target===k||e.target===te)&&F.click()}),F.addEventListener("change",()=>{Re(F.files),F.value=""}),k.addEventListener("dragover",e=>{e.preventDefault(),k.classList.add("is-drag")}),k.addEventListener("dragleave",e=>{e.target===k&&k.classList.remove("is-drag")}),k.addEventListener("drop",e=>{e.preventDefault(),k.classList.remove("is-drag"),e.dataTransfer&&e.dataTransfer.files&&Re(e.dataTransfer.files)}),(n.onNavigate||(()=>{}))(p),K(!0),{refresh:()=>K(!0),navigate:I,getSelection:()=>Array.from(w.values()),getCurrentPath:()=>p,destroy:()=>{U=!0,J&&J(),r.innerHTML=""}}}function Qe(r){return window.CSS&&window.CSS.escape?window.CSS.escape(r):r.replace(/["\\]/g,"\\$&")}var Oe="rk-dirpick-style";function Ze(){if(document.getElementById(Oe))return;let r=document.createElement("style");r.id=Oe,r.textContent=[".rk-dirpick{position:fixed;inset:0;z-index:1200;display:grid;place-items:center;padding:20px;","background:rgba(28,25,23,.44);backdrop-filter:blur(2px);animation:rk-dirpick-fade .16s ease}","@keyframes rk-dirpick-fade{from{opacity:0}to{opacity:1}}",".rk-dirpick-panel{width:min(560px,100%);max-height:min(82vh,700px);display:flex;flex-direction:column;","background:var(--rk-surface,#fff);border:1px solid var(--rk-border,#e6e0d6);border-radius:var(--rk-r-3xl,20px);","box-shadow:var(--rk-shadow-lg,0 24px 60px rgba(28,25,23,.28));overflow:hidden}",".rk-dirpick-head{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:14px 18px;","border-bottom:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-title{font-family:var(--rk-font-display,inherit);font-weight:800;font-size:15px;color:var(--rk-ink,#1c1917)}",".rk-dirpick-close{border:0;background:transparent;font-size:22px;line-height:1;color:var(--rk-text-muted,#78716c);cursor:pointer;padding:0 4px}",".rk-dirpick-close:hover{color:var(--rk-ink,#1c1917)}",".rk-dirpick-hint{padding:10px 18px 0;font-size:12.5px;line-height:1.4;color:var(--rk-text-muted,#78716c)}",".rk-dirpick-mount{padding:12px 14px;overflow:auto;flex:1;min-height:0}",".rk-dirpick-foot{display:flex;align-items:center;gap:10px;padding:12px 18px;border-top:1px solid var(--rk-border,#e6e0d6)}",".rk-dirpick-dest{flex:1;min-width:0;font-size:12.5px;color:var(--rk-text-muted,#78716c);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",".rk-dirpick-dest b{color:var(--rk-ink,#1c1917);font-weight:700}",".rk-dirpick-btn{flex:none;min-height:36px;padding:0 16px;border-radius:999px;border:0;cursor:pointer;","font:inherit;font-size:13px;font-weight:800;background:var(--rk-gold-500,var(--rk-gold-600,#fcb900));color:var(--rk-ink,#1c1917)}",".rk-dirpick-btn:hover:not(:disabled){background:var(--rk-gold-600,#e0a500)}",".rk-dirpick-btn:disabled{opacity:.5;cursor:default}",".rk-dirpick-btn.is-ghost{background:transparent;border:1px solid var(--rk-border,#e6e0d6);color:var(--rk-ink,#1c1917)}"].join(""),document.head.appendChild(r)}function et(r={}){Ze();let n=r.select==="folder"?"folder":"file",c=!1,a=null,h=i("div","rk-dirpick"),y=i("div","rk-dirpick-panel"),A=i("div","rk-dirpick-head");A.appendChild(i("span","rk-dirpick-title",r.title||(n==="folder"?"Choose a folder":"Choose a file")));let v=i("button","rk-dirpick-close");v.type="button",v.setAttribute("aria-label","Close"),v.innerHTML="×",A.appendChild(v),y.appendChild(A),r.hint&&y.appendChild(i("div","rk-dirpick-hint",r.hint));let E=i("div","rk-dirpick-mount");y.appendChild(E);let m=null,L=null;function f(p){c||(c=!0,R(),p?(r.onPick||(()=>{}))(p):(r.onCancel||(()=>{}))())}function P(p){let u=$(p);if(!u.root)return null;let g=u.folderPath||"",M=g?g.split("/").filter(Boolean).pop()||g:u.root;return{path:X(u.root,g),root:u.root,folderPath:g,name:M,kind:"folder"}}function N(p){if(!m||!L)return;let u=P(p);if(u){m.innerHTML="",m.appendChild(document.createTextNode("Save to "));let g=i("b",void 0,u.path);m.appendChild(g),L.disabled=!1}else m.textContent="Open a folder (Files, Temp, \u2026) to choose a destination.",L.disabled=!0}if(n==="folder"){let p=i("div","rk-dirpick-foot");m=i("div","rk-dirpick-dest");let u=i("button","rk-dirpick-btn is-ghost","Cancel");u.type="button",u.addEventListener("click",()=>f(null)),L=i("button","rk-dirpick-btn",r.confirmLabel||"Use this folder"),L.type="button",L.addEventListener("click",()=>{let g=a?P(a.getCurrentPath()):null;g&&f(g)}),p.appendChild(m),p.appendChild(u),p.appendChild(L),y.appendChild(p)}h.appendChild(y),document.body.appendChild(h);function T(p){p.key==="Escape"&&f(null)}function R(){document.removeEventListener("keydown",T,!0);try{a&&a.destroy()}catch{}h.remove()}return v.addEventListener("click",()=>f(null)),h.addEventListener("click",p=>{p.target===h&&f(null)}),document.addEventListener("keydown",T,!0),a=ke(E,{roots:r.roots,initialPath:r.initialPath,apiBase:r.apiBase,mode:"standalone",showSearch:!0,showMultiSelect:!1,showUpload:r.allowUpload===!0,primaryClick:n==="file"?"attach":"copyPath",onNavigate:p=>N(p),onAttach:p=>{if(n!=="file")return;let u=p&&p[0];if(u){if(r.accept&&!r.accept(u)){be(r.rejectMessage||"That file can't be used here.");return}f(u)}}}),{close:()=>f(null)}}function tt(r){let n=r.dataset,c=(n.roots||"").split(",").map(a=>a.trim()).filter(Boolean);return{roots:c.length?c:void 0,initialPath:n.initialPath||void 0,mode:n.mode==="standalone"?"standalone":"attach",showSearch:n.showSearch!=="false",showMultiSelect:n.showMultiselect!=="false",showUpload:n.showUpload!=null?n.showUpload==="true":void 0,primaryClick:n.primaryClick||"copyPath",cloudAvailable:n.cloudAvailable!=null?n.cloudAvailable==="true":void 0}}function _e(){Array.prototype.slice.call(document.querySelectorAll("[data-rk-directory]")).forEach(n=>{n.getAttribute("data-rk-dir-mounted")!=="1"&&(n.setAttribute("data-rk-dir-mounted","1"),window.__rkDirectoryInstance=ke(n,tt(n)))})}window.__vidfarmDirectory={mount:ke,pick:et};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",_e):_e();window.dispatchEvent(new CustomEvent("vidfarm:directory-ready"));export{ke as createDirectoryExplorer,et as openDirectoryPicker};
|