0, 'cards' => 0, 'tutorials' => 0, 'cheatsheets' => 0]; $flashcard_dir = CONTENT_DIR . '/flashcards'; if (is_dir($flashcard_dir)) { $sort = 0; foreach (glob($flashcard_dir . '/deck-*.md') as $file) { $count = import_flashcard_deck($pdo, $file, $sort++); $stats['decks']++; $stats['cards'] += $count; } } $tutorial_dir = CONTENT_DIR . '/tutorials'; if (is_dir($tutorial_dir)) { $sort = 0; foreach (glob($tutorial_dir . '/*.md') as $file) { $basename = basename($file); if ($basename === 'onboarding-path.md' || $basename === 'progress.md') continue; import_tutorial($pdo, $file, $sort++); $stats['tutorials']++; } } $cheatsheet_dir = CONTENT_DIR . '/cheatsheets'; if (is_dir($cheatsheet_dir)) { foreach (glob($cheatsheet_dir . '/*-cheatsheet.md') as $file) { import_cheatsheet($pdo, $file); $stats['cheatsheets']++; } } return $stats; } function import_flashcard_deck($pdo, $filepath, $deck_sort) { $content = file_get_contents($filepath); $basename = basename($filepath); preg_match('/^# Flashcard Deck: (.+)$/m', $content, $m); $deck_name = $m[1] ?? str_replace(['deck-', '.md'], '', $basename); $slug = slugify($deck_name); $stmt = $pdo->prepare(" INSERT INTO decks (slug, name, sort_order, source_file, updated_at) VALUES (:slug, :name, :sort, :src, NOW()) ON CONFLICT (slug) DO UPDATE SET name = :name, sort_order = :sort, source_file = :src, updated_at = NOW() RETURNING id "); $stmt->execute([':slug' => $slug, ':name' => $deck_name, ':sort' => $deck_sort, ':src' => $basename]); $deck_id = $stmt->fetchColumn(); // Parse cards preg_match_all( '/## Karte (\d+) \| (\w+)\s*\n\*\*Q:\*\*\s*(.+?)(?:\n)\*\*A:\*\*\s*(.+?)(?=\n---|\n## Karte|\n## Spaced|\Z)/s', $content, $matches, PREG_SET_ORDER ); // Delete old cards for this deck, then re-insert $pdo->prepare("DELETE FROM cards WHERE deck_id = :did")->execute([':did' => $deck_id]); $card_count = 0; foreach ($matches as $i => $match) { $level = strtolower(trim($match[2])); $question = trim($match[3]); $answer = trim($match[4]); $stmt = $pdo->prepare(" INSERT INTO cards (deck_id, question, answer, level, sort_order, source_file) VALUES (:did, :q, :a, :lvl, :sort, :src) "); $stmt->execute([ ':did' => $deck_id, ':q' => $question, ':a' => $answer, ':lvl' => $level, ':sort' => $i, ':src' => $basename ]); $card_count++; } $pdo->prepare("UPDATE decks SET card_count = :c WHERE id = :id") ->execute([':c' => $card_count, ':id' => $deck_id]); return $card_count; } function import_tutorial($pdo, $filepath, $sort_order) { $content = file_get_contents($filepath); $basename = basename($filepath); preg_match('/^# (.+)$/m', $content, $m); $title = $m[1] ?? str_replace('.md', '', $basename); $slug = slugify($basename); preg_match('/\*\*Dauer\*\*:\s*ca\.\s*(\d+)/i', $content, $dm); $duration = $dm[1] ?? null; preg_match('/\*\*Ziel\*\*:\s*(.+)$/m', $content, $desc); $description = $desc[1] ?? ''; $stmt = $pdo->prepare(" INSERT INTO tutorials (slug, title, description, content_md, duration_min, sort_order, source_file, updated_at) VALUES (:slug, :title, :desc, :content, :dur, :sort, :src, NOW()) ON CONFLICT (slug) DO UPDATE SET title = :title, description = :desc, content_md = :content, duration_min = :dur, sort_order = :sort, source_file = :src, updated_at = NOW() "); $stmt->execute([ ':slug' => $slug, ':title' => $title, ':desc' => $description, ':content' => $content, ':dur' => $duration, ':sort' => $sort_order, ':src' => $basename ]); } function import_cheatsheet($pdo, $filepath) { $content = file_get_contents($filepath); $basename = basename($filepath); preg_match('/^# (.+)$/m', $content, $m); $title = $m[1] ?? str_replace(['-cheatsheet', '.md'], ['', ''], $basename); $slug = slugify($basename); $category = ucfirst(str_replace(['-cheatsheet.md', '-'], ['', ' '], $basename)); $stmt = $pdo->prepare(" INSERT INTO cheatsheets (slug, title, category, content_md, source_file, updated_at) VALUES (:slug, :title, :cat, :content, :src, NOW()) ON CONFLICT (slug) DO UPDATE SET title = :title, category = :cat, content_md = :content, source_file = :src, updated_at = NOW() "); $stmt->execute([ ':slug' => $slug, ':title' => $title, ':cat' => $category, ':content' => $content, ':src' => $basename ]); } function slugify($text) { $text = str_replace(['.md', 'deck-'], '', $text); $text = strtolower($text); $text = preg_replace('/[^a-z0-9\-]/', '-', $text); $text = preg_replace('/-+/', '-', $text); return trim($text, '-'); }