fp/services/pocketbase/utils/data_migrations/2025-11-09-copy-video-src-b2.js
2025-11-12 07:54:01 -08:00

87 lines
2.5 KiB
JavaScript

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);
});