← back to Sdcc Images
scripts/refresh.js
118 lines
#!/usr/bin/env node
/**
* Refresh data/files.json by querying Steve's personal Drive (via George tailnet).
* - Find every file or folder whose name contains 'sdcc' (case-insensitive)
* - Recurse into matching folders, pull all image files
* - Write data/files.json: { generatedAt, query, files: [{id, name, webViewLink, thumbnailUrl, parentName}] }
*/
const http = require('http');
const fs = require('fs');
const path = require('path');
const GEORGE = '100.107.67.67';
const PORT = 9850;
const ACCOUNT = 'steve-personal';
const AUTH = 'Basic ' + Buffer.from('admin:DWSecure2024!').toString('base64');
function get(path) {
return new Promise((resolve, reject) => {
const req = http.request(
{ hostname: GEORGE, port: PORT, method: 'GET', path, headers: { 'Authorization': AUTH } },
res => { let c = ''; res.on('data', d => c += d); res.on('end', () => { try { resolve(JSON.parse(c)); } catch { resolve({ raw: c }); } }); }
);
req.on('error', reject);
req.setTimeout(45000, () => { req.destroy(); reject(new Error('timeout')); });
req.end();
});
}
const enc = s => encodeURIComponent(s);
async function listAll(query) {
const all = [];
let pageSize = 200;
// George doesn't support pageToken — single page up to 200. We'll do multiple narrow queries instead.
const url = `/api/drive/list?account=${ACCOUNT}&pageSize=${pageSize}&q=${enc(query)}`;
const r = await get(url);
if (r.error) throw new Error('George error: ' + r.error);
return r.files || [];
}
const FOLDER_MIME = 'application/vnd.google-apps.folder';
const IMAGE_MIMES = ['image/jpeg','image/jpg','image/png','image/gif','image/webp','image/heic','image/heif','image/vnd.adobe.photoshop','image/tiff'];
// Extra folders to recurse even if their name doesn't contain 'sdcc'.
// Add { id, label } here to include any shared Drive folder.
const EXTRA_FOLDERS = [
{ id: '0ByWfbpWMJPXkM0xrTFVadmVvSlU', label: 'SDCC (shared)' },
];
async function refresh() {
console.log('Finding all SDCC-named folders + image files in Drive...');
// 1. Top-level matches: anything with "sdcc" in name
const topMatches = await listAll(`name contains 'sdcc' and trashed=false`);
console.log(`top-level sdcc-named: ${topMatches.length}`);
const folders = topMatches.filter(f => f.mimeType === FOLDER_MIME);
const directImages = topMatches.filter(f => f.mimeType && f.mimeType.startsWith('image/'));
console.log(` folders: ${folders.length}`);
console.log(` direct images: ${directImages.length}`);
// 2. Recurse into folders — list children of each folder
// Drive query: 'PARENT_ID' in parents
const collected = new Map();
for (const img of directImages) collected.set(img.id, { ...img, parentName: '(root match)' });
async function recurse(folderId, folderName, depth) {
if (depth > 4) return; // safety
let q = `'${folderId}' in parents and trashed=false`;
const items = await listAll(q);
for (const item of items) {
if (item.mimeType === FOLDER_MIME) {
await recurse(item.id, `${folderName} / ${item.name}`, depth + 1);
} else if (item.mimeType && item.mimeType.startsWith('image/')) {
if (!collected.has(item.id)) collected.set(item.id, { ...item, parentName: folderName });
}
}
}
for (const folder of folders) {
console.log(` recursing: ${folder.name}`);
await recurse(folder.id, folder.name, 0);
console.log(` running total: ${collected.size}`);
}
for (const extra of EXTRA_FOLDERS) {
console.log(` recursing extra: ${extra.label} (${extra.id})`);
await recurse(extra.id, extra.label, 0);
console.log(` running total: ${collected.size}`);
}
// 3. Build output
const files = [...collected.values()].map(f => ({
id: f.id,
name: f.name,
mimeType: f.mimeType,
size: f.size ? parseInt(f.size) : null,
modifiedTime: f.modifiedTime,
parentName: f.parentName,
webViewLink: f.webViewLink || `https://drive.google.com/file/d/${f.id}/view`,
thumbnailLink: `https://drive.google.com/thumbnail?id=${f.id}&sz=w400`,
})).sort((a, b) => (a.parentName + a.name).localeCompare(b.parentName + b.name));
const out = {
generatedAt: new Date().toISOString(),
query: "name contains 'sdcc' (recursive)",
account: ACCOUNT,
fileCount: files.length,
files,
};
const outPath = path.join(__dirname, '..', 'data', 'files.json');
fs.mkdirSync(path.dirname(outPath), { recursive: true });
fs.writeFileSync(outPath, JSON.stringify(out, null, 2));
console.log(`\nDONE — ${files.length} images written to ${outPath}`);
}
refresh().catch(e => { console.error('FATAL', e.message); process.exit(1); });