import { basename } from 'node:path'; import PocketBase from 'pocketbase'; import { env } from 'node:process'; import spawn from 'nano-spawn'; // Config const PB_URL = env.PB_URL || 'http://127.0.0.1:8090'; const B2_BUCKET_FROM = env.B2_BUCKET_FROM; const B2_BUCKET_TO = env.B2_BUCKET_TO; const USERNAME = env.PB_USERNAME; const PASSWORD = env.PB_PASSWORD; const vodsCollectionName = 'pbc_144770472'; const pb = new PocketBase(PB_URL); // retry wrapper for async tasks async function retryAsync(fn, retries = 6, delayMs = 2000) { for (let attempt = 1; attempt <= retries; attempt++) { try { return await fn(); } catch (err) { console.warn(`Attempt ${attempt}/${retries} failed: ${err.message}`, err); if (attempt === retries) throw err; await new Promise(r => setTimeout(r, delayMs * attempt)); // exponential-ish backoff } } } async function main() { console.log('Authenticating with PocketBase...'); await retryAsync(() => pb.collection('_superusers').authWithPassword(USERNAME, PASSWORD) ); console.log('Fetching all VODs...'); const vods = await retryAsync(() => pb.collection('vods').getFullList()); console.log(`Found ${vods.length} VODs. Updating sourceVideo fields...`); for (const vod of vods) { const oldSource = vod.sourceVideo; if (!oldSource) continue; const filename = basename(oldSource); const newSource = `${vodsCollectionName}/${vod.id}/${filename}`; if (newSource === oldSource) { console.log(`Skipping VOD ${vod.id}, already updated.`); continue; } if (!oldSource.includes('content/')) { console.log(`Skipping VOD ${vod.id}, already copied.`); continue; } const from = `b2://${B2_BUCKET_FROM}/${oldSource.replace('content/', '')}`; const to = `b2://${B2_BUCKET_TO}/${newSource}`; console.log(`Copying ${from} -> ${to}`); try { await retryAsync(() => spawn('b2', ['file', 'server-side-copy', from, to])); } catch (err) { console.error(`Failed to copy for VOD ${vod.id}: ${err.message}`, err); continue; // skip to next vod } console.log(`Updating VOD ${vod.id} record...`); try { await retryAsync(() => pb.collection('vods').update(vod.id, { sourceVideo: newSource }) ); } catch (err) { console.error(`Failed to update VOD ${vod.id}: ${err.message}`); continue; } console.log(`✅ Updated VOD ${vod.id}: ${oldSource} → ${newSource}`); } console.log('🎉 All done.'); } main().catch(err => { console.error('Fatal error:', err); process.exit(1); });