Keep using Photos.app like you always do. Attic quietly backs up your originals and edits to an S3 bucket you control. One-way, append-only.
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add graceful SIGINT handling to save manifest on interrupt

+21 -4
+21 -4
cli/src/commands/backup.ts
··· 123 123 }; 124 124 125 125 let sinceLastSave = 0; 126 + let interrupted = false; 127 + 128 + // Save manifest on SIGINT (Ctrl+C) before exiting 129 + const onInterrupt = () => { interrupted = true; }; 130 + Deno.addSignalListener("SIGINT", onInterrupt); 126 131 127 132 // Process in batches 128 133 for (let i = 0; i < pending.length; i += options.batchSize) { 134 + if (interrupted) break; 135 + 129 136 const batch = pending.slice(i, i + options.batchSize); 130 137 const batchUuids = batch.map((a) => a.uuid); 131 138 const batchNum = Math.floor(i / options.batchSize) + 1; ··· 162 169 163 170 // 2. Upload each exported file to S3 164 171 for (const exported of batchResult.results) { 172 + if (interrupted) break; 165 173 const asset = assetByUuid.get(exported.uuid); 166 174 if (!asset) continue; 167 175 ··· 239 247 } 240 248 241 249 // Summary 242 - console.log(`\n ── Complete ──`); 243 - console.log(` Uploaded: ${report.uploaded.toLocaleString()}`); 244 - console.log(` Failed: ${report.failed.toLocaleString()}`); 245 - console.log(` Total: ${formatBytes(report.totalBytes)}\n`); 250 + Deno.removeSignalListener("SIGINT", onInterrupt); 251 + 252 + if (interrupted) { 253 + console.log(`\n\n ── Interrupted ──`); 254 + console.log(` Uploaded: ${report.uploaded.toLocaleString()} of ${pending.length.toLocaleString()}`); 255 + console.log(` Total: ${formatBytes(report.totalBytes)}`); 256 + console.log(` Manifest saved — will resume from here next run.\n`); 257 + } else { 258 + console.log(`\n ── Complete ──`); 259 + console.log(` Uploaded: ${report.uploaded.toLocaleString()}`); 260 + console.log(` Failed: ${report.failed.toLocaleString()}`); 261 + console.log(` Total: ${formatBytes(report.totalBytes)}\n`); 262 + } 246 263 247 264 return report; 248 265 }