87 lines
2.5 KiB
JavaScript
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);
|
|
});
|