- isEnglishContent() fetches each job page and drops descriptions with ≥6 German or French indicator words; called for every new job in index.ts before writing to CSV - New `bun recheck` command (recheck.ts) runs searches in raw mode, lists filtered-out jobs, and prints word-frequency suggestions for SOFTWARE_TITLE_RE - Expanded KEYWORDS and SOFTWARE_TITLE_RE to cover ML/AI, system/applications engineer, director, informatics, and more title variants - Added `raw` flag to fetchJobs() to bypass the software-role filter - Add CLAUDE.md with project workflow docs; add CV files and city temp scripts
74 lines
1.9 KiB
TypeScript
74 lines
1.9 KiB
TypeScript
#!/usr/bin/env bun
|
|
import { searches } from "./config.ts";
|
|
import { fetchJobs, isEnglishContent } from "./fetch.ts";
|
|
|
|
const CSV = "./jobs.csv";
|
|
const HEADER = "date_found,posted_at,search,title,company,link";
|
|
|
|
// Load existing IDs from CSV to deduplicate across runs
|
|
const existingIds = new Set<string>();
|
|
try {
|
|
const text = await Bun.file(CSV).text();
|
|
for (const line of text.split("\n").slice(1)) {
|
|
const id = line.match(/\/jobs\/view\/(\d+)\//)?.[1];
|
|
if (id) existingIds.add(id);
|
|
}
|
|
} catch {
|
|
// first run — file doesn't exist yet
|
|
}
|
|
|
|
const date = new Date().toISOString().slice(0, 10);
|
|
const newRows: string[] = [];
|
|
|
|
function csvCell(val: string): string {
|
|
return `"${val.replace(/"/g, '""')}"`;
|
|
}
|
|
|
|
for (const config of searches) {
|
|
console.log(`\n[${config.label}]`);
|
|
const jobs = await fetchJobs(config);
|
|
|
|
if (jobs.length === 0) {
|
|
console.log(" No jobs found.");
|
|
continue;
|
|
}
|
|
|
|
let added = 0;
|
|
let langDropped = 0;
|
|
for (const job of jobs) {
|
|
if (!existingIds.has(job.id)) {
|
|
process.stdout.write(` checking content: ${job.title} … `);
|
|
const english = await isEnglishContent(job.id);
|
|
if (!english) {
|
|
console.log("dropped (non-English)");
|
|
langDropped++;
|
|
continue;
|
|
}
|
|
console.log("ok");
|
|
existingIds.add(job.id);
|
|
newRows.push(
|
|
[date, job.postedAt, config.label, job.title, job.company, job.link]
|
|
.map(csvCell)
|
|
.join(",")
|
|
);
|
|
added++;
|
|
}
|
|
}
|
|
console.log(` ${jobs.length} found, ${added} new, ${langDropped} non-English dropped`);
|
|
}
|
|
|
|
if (newRows.length === 0) {
|
|
console.log("\nNo new jobs.");
|
|
process.exit(0);
|
|
}
|
|
|
|
// Append to CSV (write header if first run)
|
|
const existing = await Bun.file(CSV).exists();
|
|
const append = existing
|
|
? await Bun.file(CSV).text()
|
|
: HEADER + "\n";
|
|
|
|
await Bun.write(CSV, append + newRows.join("\n") + "\n");
|
|
|
|
console.log(`\n${newRows.length} new jobs → ${CSV}`);
|