Clean up: remove unused scripts, debug files, and mongodb dependency

This commit is contained in:
Michael Winter 2026-02-19 16:49:47 +01:00
parent 47993f76cb
commit b43b8e6eaf
5 changed files with 0 additions and 303 deletions

View file

@ -1,57 +0,0 @@
const { MongoClient, GridFSBucket } = require('mongodb');
const fs = require('fs');
const path = require('path');
async function exportGridFS() {
const client = new MongoClient('mongodb://localhost:27017/');
try {
await client.connect();
const db = client.db('portfolio');
const buckets = ['images', 'album_art', 'scores', 'pubs'];
for (const bucketName of buckets) {
const bucket = new GridFSBucket(db, { bucketName });
const outputDir = path.join(__dirname, 'public', bucketName);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
const cursor = bucket.find({});
const files = await cursor.toArray();
console.log(`Exporting ${files.length} files from ${bucketName}...`);
const promises = files.map(file => {
return new Promise((resolve, reject) => {
const outputPath = path.join(outputDir, file.filename);
const stream = bucket.openDownloadStreamByName(file.filename);
const writeStream = fs.createWriteStream(outputPath);
stream.pipe(writeStream);
stream.on('end', () => {
console.log(` Saved: ${file.filename}`);
resolve();
});
stream.on('error', (err) => {
console.error(` Error saving ${file.filename}:`, err.message);
reject(err);
});
});
});
await Promise.all(promises);
console.log(`Finished ${bucketName}`);
}
console.log('Done!');
} finally {
await client.close();
}
}
exportGridFS();

View file

@ -1,5 +1,3 @@
//import { defineNuxtConfig } from 'nuxt3'
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
modules: ['@nuxtjs/tailwindcss', '@nuxt/image', '@nuxt/icon', '@pinia/nuxt', 'nuxt-headlessui', 'nuxt-swiper', 'nuxt-umami'],

View file

@ -27,7 +27,6 @@
"@formkit/themes": "^1.7.2",
"@formkit/vue": "^1.7.2",
"@pinia/nuxt": "^0.11.3",
"mongodb": "^7.1.0",
"nuxt": "^4.3.1",
"nuxt-swiper": "^1.2.2",
"nuxt-umami": "^3.2.1",

View file

@ -1 +0,0 @@
\relax

View file

@ -1,242 +0,0 @@
const fs = require('fs')
const path = require('path')
const { execSync } = require('child_process')
const DATA_DIR = path.join(__dirname, '../server/data')
const PUBLIC_DIR = path.join(__dirname, '../public')
function readJson(filename) {
const data = fs.readFileSync(path.join(DATA_DIR, filename), 'utf-8')
const parsed = JSON.parse(data)
function cleanDates(obj) {
if (Array.isArray(obj)) return obj.map(cleanDates)
if (obj && typeof obj === 'object') {
if (obj.$date?.$numberLong) return new Date(parseInt(obj.$date.$numberLong)).toISOString()
const cleaned = {}
for (const [k, v] of Object.entries(obj)) cleaned[k] = cleanDates(v)
return cleaned
}
return obj
}
return cleanDates(parsed)
}
function formatMonth(dateStr) {
if (!dateStr) return 'Present'
const date = new Date(dateStr)
if (isNaN(date)) return dateStr
return date.toLocaleDateString('en-US', { month: 'short', year: 'numeric' })
}
function formatYear(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
if (isNaN(date)) return dateStr
return date.getFullYear()
}
function formatShortDate(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
if (isNaN(date)) return dateStr
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })
}
function escapeLatex(str) {
if (!str) return ''
str = str.replace(/[\u0300-\u036f]/g, '')
return str.replace(/[&%$#_{}]/g, '\\$&').replace(/~/g, '\\textasciitilde{}').replace(/\^/g, '\\textasciicircum{}').replace(/ä/g, '{\\"a}').replace(/ö/g, '{\\"o}').replace(/ü/g, '{\\"u}').replace(/Ä/g, '{\\"A}').replace(/Ö/g, '{\\"O}').replace(/Ü/g, '{\\"U}').replace(/á/g, "\\'a").replace(/é/g, "\\'e").replace(/í/g, "\\'i").replace(/ó/g, "\\'o").replace(/ú/g, "\\'u").replace(/à/g, "\\`a").replace(/è/g, "\\`e").replace(/ì/g, "\\`i").replace(/ò/g, "\\`o").replace(/ù/g, "\\`u").replace(/ã/g, '{\\~a}').replace(/ñ/g, '{\\~n}').replace(//g, '--').replace(/—/g, '---').replace(/ç/g, '\\c c')
}
function generateCvLatex(resume, talks) {
const basics = resume.basics || {}
const talksByYear = {}
for (const talk of talks || []) {
if (!talk.date) continue
const year = new Date(talk.date).getFullYear()
if (!talksByYear[year]) talksByYear[year] = []
talksByYear[year].push(talk)
}
const sortedYears = Object.keys(talksByYear).sort((a, b) => b - a)
let latex = '\\documentclass[11pt]{article}\n'
latex += '\\usepackage[utf8]{inputenc}\n'
latex += '\\usepackage[T1]{fontenc}\n'
latex += '\\usepackage{geometry}\n'
latex += '\\geometry{letterpaper, top=1in, bottom=1in, left=1in, right=1in}\n'
latex += '\\usepackage{enumitem}\n'
latex += '\\usepackage{titlesec}\n'
latex += '\\pagestyle{empty}\n'
latex += '\\titleformat{\\section}{\\bfseries\\Large}{\\thesection}{1em}{}\n'
latex += '\\titleformat{\\subsection}{\\bfseries\\large}{\\thesubsection}{1em}{}\n'
latex += '\\titlespacing{\\section}{0pt}{12pt}{6pt}\n'
latex += '\\titlespacing{\\subsection}{0pt}{8pt}{4pt}\n'
latex += '\\begin{document}\n'
// Header
latex += '\\begin{center}\n'
latex += '{\\LARGE\\bfseries ' + escapeLatex(basics.name || '') + '}\\\\[4pt]\n'
latex += '{\\large Curriculum Vitae}\\\\[8pt]\n'
latex += escapeLatex(basics.email || '') + ' \\quad ' + escapeLatex(basics.phone || '') + ' \\quad ' + escapeLatex(basics.website || '') + '\n'
latex += '\\end{center}\n'
latex += '\\hrulefill\\\\[12pt]\n'
// Education
latex += '\\section{Education}\n'
for (const edu of resume.education || []) {
latex += '{\\bfseries ' + escapeLatex(edu.studyType) + ' in ' + escapeLatex(edu.area) + '}, ' + escapeLatex(edu.institution) + ', ' + formatYear(edu.endDate) + '\\\\[4pt]\n'
}
// Teaching
latex += '\\section{Teaching}\n'
for (const teach of resume.teaching || []) {
latex += '{\\bfseries ' + escapeLatex(teach.company) + '}, \\textit{' + escapeLatex(teach.position) + '}\\\\[2pt]\n'
latex += escapeLatex(formatMonth(teach.startDate)) + ' -- ' + escapeLatex(formatMonth(teach.endDate)) + '\\\\[8pt]\n'
}
// Lectures
latex += '\\section{Lectures}\n'
for (const year of sortedYears) {
latex += '\\subsection{' + year + '}\n'
for (const talk of talksByYear[year]) {
latex += '{\\bfseries ' + escapeLatex(talk.location) + '}\\\\\n'
const titles = Array.isArray(talk.title) ? talk.title : [talk.title]
for (const t of titles) latex += '\\hspace{8pt}\\textit{' + escapeLatex(t) + '}\\\\\n'
}
latex += '\\\\[4pt]\n'
}
// Relevant Work
latex += '\\section{Relevant Work}\n'
for (const w of resume.work || []) {
latex += '{\\bfseries ' + escapeLatex(w.company) + '}, \\textit{' + escapeLatex(w.position) + '}\\\\[2pt]\n'
latex += escapeLatex(formatMonth(w.startDate)) + ' -- ' + escapeLatex(formatMonth(w.endDate)) + '\\\\[8pt]\n'
}
// Skills
latex += '\\section{Skills}\n'
latex += (resume.skills?.[0]?.keywords?.map(s => escapeLatex(s)).join(', ') || '') + '\\\\[8pt]\n'
// Languages
latex += '\\section{Languages}\n'
latex += (resume.languages || []).map(l => escapeLatex(l.language) + ' (' + escapeLatex(l.fluency) + ')').join(', ') + '\\\\[8pt]\n'
// Recordings
latex += '\\section{Recordings}\n'
latex += '\\subsection{Solo Albums}\n'
for (const rel of resume.solo_releases || []) {
latex += '{\\bfseries ' + escapeLatex(rel.title) + '}. ' + escapeLatex(rel.publisher) + '. ' + escapeLatex(rel.media_type) + '. ' + escapeLatex(rel.date) + '.\\\\[4pt]\n'
}
latex += '\\subsection{Compilation Albums}\n'
for (const rel of resume.compilation_releases || []) {
latex += '{\\bfseries ' + escapeLatex(rel.title) + '}. ' + escapeLatex(rel.publisher) + '. ' + escapeLatex(rel.media_type) + '. ' + escapeLatex(rel.date) + '. \\textit{featuring ' + escapeLatex(rel.work) + '}.\\\\[4pt]\n'
}
// Residencies
latex += '\\section{Residencies and Awards}\n'
for (const res of resume.residencies || []) {
latex += '{\\bfseries ' + escapeLatex(res.org) + '}, ' + escapeLatex(res.date) + '\\\\[4pt]\n'
}
// References
latex += '\\section{References}\n'
for (const ref of resume.references || []) {
latex += '{\\bfseries ' + escapeLatex(ref.name) + '}\\\\[2pt]\n'
latex += escapeLatex(ref.position) + '\\\\[2pt]\n'
latex += escapeLatex(ref.email) + '\\\\[8pt]\n'
}
latex += '\\end{document}\n'
return latex
}
function generateWorksListLatex(resume, works, events) {
const basics = resume.basics || {}
const worksByYear = {}
for (const work of works || []) {
const year = work.date ? new Date(work.date).getFullYear() : 'Unknown'
if (!worksByYear[year]) worksByYear[year] = []
const workEvents = (events || []).filter(e => e.program && e.program.some(p => p.work?.toLowerCase().includes(work.title.toLowerCase())))
worksByYear[year].push({ ...work, events: workEvents })
}
const sortedYears = Object.keys(worksByYear).sort((a, b) => b - a)
let latex = '\\documentclass[11pt]{article}\n'
latex += '\\usepackage[utf8]{inputenc}\n'
latex += '\\usepackage[T1]{fontenc}\n'
latex += '\\usepackage{geometry}\n'
latex += '\\geometry{letterpaper, top=1in, bottom=1in, left=1in, right=1in}\n'
latex += '\\usepackage{enumitem}\n'
latex += '\\usepackage{titlesec}\n'
latex += '\\pagestyle{empty}\n'
latex += '\\titleformat{\\section}{\\bfseries\\Large}{\\thesection}{1em}{}\n'
latex += '\\titlespacing{\\section}{0pt}{12pt}{6pt}\n'
latex += '\\begin{document}\n'
// Header
latex += '\\begin{center}\n'
latex += '{\\LARGE\\bfseries ' + escapeLatex(basics.name || '') + '}\\\\[4pt]\n'
latex += '{\\large Works List with Presentation History}\\\\[8pt]\n'
latex += escapeLatex(basics.email || '') + ' \\quad ' + escapeLatex(basics.phone || '') + ' \\quad ' + escapeLatex(basics.website || '') + '\n'
latex += '\\end{center}\n'
latex += '\\hrulefill\\\\[12pt]\n'
latex += 'A chronological performance / exhibition history, scores, and recordings are available at\\\\\n'
latex += 'www.unboundedpress.org.\\\\\n'
latex += 'All scores are also published or forthcoming through Frog Peak at\\\\\n'
latex += 'www.frogpeak.org/fpartists/fpwinter.html.\\\\[12pt]\n'
latex += '\\hrulefill\\\\[12pt]\n'
for (const year of sortedYears) {
latex += '\\section{' + year + '}\n'
for (const work of worksByYear[year]) {
latex += '{\\bfseries\\textit{' + escapeLatex(work.title) + '}}\\\\[-4pt]\n'
if (work.instrument_tags) latex += '\\hspace{8pt}' + escapeLatex(work.instrument_tags.join(', ')) + '\\\\[-4pt]\n'
for (const event of work.events || []) {
const venue = event.venue || {}
latex += '\\hspace{8pt}' + escapeLatex(venue.name) + '; ' + escapeLatex(venue.city) + ', ' + escapeLatex(venue.state) + ' -- ' + escapeLatex(formatShortDate(event.start_date)) + '\\\\\n'
}
latex += '\\\\[4pt]\n'
}
}
latex += '\\end{document}\n'
return latex
}
function compileLatex(latexContent, outputPath) {
const tempDir = path.join(__dirname, 'temp')
if (!fs.existsSync(tempDir)) fs.mkdirSync(tempDir, { recursive: true })
const texPath = path.join(tempDir, 'temp.tex')
fs.writeFileSync(texPath, latexContent)
try {
execSync('cd ' + tempDir + ' && pdflatex temp.tex', { stdio: 'pipe' })
const pdfPath = path.join(tempDir, 'temp.pdf')
if (fs.existsSync(pdfPath)) {
fs.copyFileSync(pdfPath, outputPath)
console.log('Generated:', outputPath)
}
} catch (e) {
fs.writeFileSync(path.join(PUBLIC_DIR, 'debug.tex'), latexContent)
console.error('Error generating PDF')
}
}
const resume = readJson('resume.json')[0]
const talks = readJson('talks.json')
const works = readJson('works.json')
const events = readJson('events.json')
console.log('Generating CV...')
compileLatex(generateCvLatex(resume, talks), path.join(PUBLIC_DIR, 'cv.pdf'))
console.log('Generating Works List...')
compileLatex(generateWorksListLatex(resume, works, events), path.join(PUBLIC_DIR, 'works_list.pdf'))
console.log('Done!')