Created
February 4, 2026 11:15
-
-
Save JLarky/04763e49840f0cefae24df98b2f9b63e to your computer and use it in GitHub Desktop.
script to remove unused files but leave some metadata after removing it
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bun | |
| import { existsSync, readdirSync, statSync, writeFileSync, unlinkSync, readFileSync } from 'node:fs' | |
| import { exit } from 'node:process' | |
| import { join } from 'node:path' | |
| import { $ } from 'bun' | |
| const targetDir = process.argv[2] | |
| if (!targetDir) { | |
| console.error('Error: No directory specified') | |
| exit(1) | |
| } | |
| if (!existsSync(targetDir)) { | |
| console.error(`Error: Directory '${targetDir}' does not exist`) | |
| exit(1) | |
| } | |
| async function getSHA256(filePath: string): Promise<string> { | |
| try { | |
| const result = await $`sha256sum "${filePath}"`.quiet() | |
| return result.stdout.toString().trim().split(' ')[0] | |
| } catch (error) { | |
| console.error(`SHA256 error for ${filePath}:`, error) | |
| return '' | |
| } | |
| } | |
| async function listFiles(dir: string, basePath: string = dir): Promise<string[]> { | |
| const files = readdirSync(dir) | |
| const jsonLines: string[] = [] | |
| for (const file of files) { | |
| const fullPath = join(dir, file) | |
| try { | |
| const stats = statSync(fullPath) | |
| if (stats.isFile() && file !== '_old_files_meta.txt') { | |
| const relativePath = './' + fullPath.replace(basePath + '/', '') | |
| const fileInfo = { | |
| path: relativePath, | |
| cdate: stats.birthtime.toISOString(), | |
| mdate: stats.mtime.toISOString(), | |
| size: stats.size, | |
| sha256: await getSHA256(fullPath) | |
| } | |
| jsonLines.push(JSON.stringify(fileInfo)) | |
| console.log(relativePath) | |
| } else if (stats.isDirectory()) { | |
| const subFiles = await listFiles(fullPath, basePath) | |
| jsonLines.push(...subFiles) | |
| } | |
| } catch (error) { | |
| console.error(`Error processing ${fullPath}:`, error) | |
| } | |
| } | |
| return jsonLines | |
| } | |
| async function deleteFilesFromMeta(metaFile: string): Promise<void> { | |
| try { | |
| const content = readFileSync(metaFile, 'utf-8') | |
| const lines = content.trim().split('\n').filter(line => line.trim()) | |
| for (const line of lines) { | |
| try { | |
| const fileInfo = JSON.parse(line) | |
| const fullPath = join(targetDir, fileInfo.path) | |
| if (existsSync(fullPath)) { | |
| unlinkSync(fullPath) | |
| console.log(`Deleted: ${fileInfo.path}`) | |
| } else { | |
| console.log(`File not found: ${fileInfo.path}`) | |
| } | |
| } catch (error) { | |
| console.error(`Error processing line: ${line}`, error) | |
| } | |
| } | |
| // Don't delete the meta file - keep it for reference | |
| console.log(`Finished deleting files. Meta file kept: ${metaFile}`) | |
| } catch (error) { | |
| console.error('Error deleting files:', error) | |
| } | |
| } | |
| async function promptUser(question: string): Promise<string> { | |
| console.log(question) | |
| const input = await new Promise<string>((resolve) => { | |
| process.stdin.resume() | |
| process.stdin.setEncoding('utf8') | |
| process.stdin.on('data', (data) => { | |
| process.stdin.pause() | |
| resolve(data.toString().trim().toLowerCase()) | |
| }) | |
| }) | |
| return input | |
| } | |
| async function main(): Promise<void> { | |
| const outputFile = join(targetDir, '_old_files_meta.txt') | |
| if (existsSync(outputFile)) { | |
| console.log(`Found existing ${outputFile}`) | |
| const answer = await promptUser('Choose an option:\n[r] Regenerate meta file\n[d] Delete files listed in meta file\n[c] Cancel\nYour choice: ') | |
| switch (answer) { | |
| case 'r': | |
| console.log('Regenerating meta file...') | |
| break | |
| case 'd': | |
| console.log('Deleting files...') | |
| await deleteFilesFromMeta(outputFile) | |
| return | |
| case 'c': | |
| console.log('Cancelled.') | |
| return | |
| default: | |
| console.log('Invalid choice. Cancelled.') | |
| return | |
| } | |
| } | |
| const jsonLines = await listFiles(targetDir) | |
| writeFileSync(outputFile, jsonLines.join('\n')) | |
| console.error(`\nWritten ${jsonLines.length} file entries to ${outputFile}`) | |
| } | |
| main().catch(error => { | |
| console.error('Error:', error) | |
| exit(1) | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment