This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/h5p-service/server-simple.js
Benjamin Admin 21a844cb8a fix: Restore all files lost during destructive rebase
A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.

This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).

Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 09:51:32 +01:00

378 lines
12 KiB
JavaScript

/**
* BreakPilot H5P Service - Simplified Version
* Minimal H5P integration without h5p-express complexity
*/
import express from 'express';
import cors from 'cors';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const app = express();
const PORT = process.env.PORT || 8080;
// Middleware
app.use(cors());
app.use(express.json({ limit: '500mb' }));
app.use(express.urlencoded({ extended: true, limit: '500mb' }));
// Serve static H5P files
app.use('/h5p/core', express.static(path.join(__dirname, 'h5p-core')));
app.use('/h5p/libraries', express.static(path.join(__dirname, 'h5p-libraries')));
app.use('/h5p/content', express.static(path.join(__dirname, 'h5p-content')));
// Serve editors
app.use('/h5p/editors', express.static(path.join(__dirname, 'editors')));
// Serve players
app.use('/h5p/players', express.static(path.join(__dirname, 'players')));
// Content type specific editors
app.get('/h5p/editor/quiz', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'quiz-editor.html'));
});
app.get('/h5p/player/quiz', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'quiz-player.html'));
});
app.get('/h5p/editor/flashcards', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'flashcards-editor.html'));
});
app.get('/h5p/editor/fill-blanks', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'fill-blanks-editor.html'));
});
app.get('/h5p/player/fill-blanks', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'fill-blanks-player.html'));
});
app.get('/h5p/editor/memory', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'memory-editor.html'));
});
app.get('/h5p/player/memory', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'memory-player.html'));
});
app.get('/h5p/editor/drag-drop', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'drag-drop-editor.html'));
});
app.get('/h5p/player/drag-drop', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'drag-drop-player.html'));
});
app.get('/h5p/editor/timeline', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'timeline-editor.html'));
});
app.get('/h5p/player/timeline', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'timeline-player.html'));
});
app.get('/h5p/editor/interactive-video', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'interactive-video-editor.html'));
});
app.get('/h5p/player/interactive-video', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'interactive-video-player.html'));
});
app.get('/h5p/editor/course-presentation', (req, res) => {
res.sendFile(path.join(__dirname, 'editors', 'course-presentation-editor.html'));
});
app.get('/h5p/player/course-presentation', (req, res) => {
res.sendFile(path.join(__dirname, 'players', 'course-presentation-player.html'));
});
// Main H5P Editor Selection Page
app.get('/h5p/editor/new', (req, res) => {
res.send(`<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>H5P Editor - BreakPilot</title>
<!-- H5P Core Styles -->
<link rel="stylesheet" href="/h5p/core/styles/h5p.css">
<link rel="stylesheet" href="/h5p/core/styles/h5p-confirmation-dialog.css">
<link rel="stylesheet" href="/h5p/core/styles/h5p-core-button.css">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #f5f5f5;
padding: 20px;
}
.container {
background: white;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
padding: 30px;
max-width: 1400px;
margin: 0 auto;
}
h1 {
color: #333;
margin-bottom: 20px;
font-size: 24px;
display: flex;
align-items: center;
gap: 10px;
}
.status {
display: inline-block;
background: #10b981;
color: white;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 600;
}
.info-box {
background: #f0f9ff;
border-left: 4px solid #3b82f6;
padding: 16px;
margin: 20px 0;
border-radius: 4px;
}
.info-box h3 {
color: #1e40af;
margin-bottom: 8px;
font-size: 16px;
}
.info-box p {
color: #475569;
line-height: 1.6;
margin: 0;
}
.content-types {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
margin-top: 24px;
}
.content-type-card {
background: #fff;
border: 2px solid #e5e7eb;
border-radius: 8px;
padding: 20px;
cursor: pointer;
transition: all 0.2s;
}
.content-type-card:hover {
border-color: #667eea;
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.15);
transform: translateY(-2px);
}
.content-type-card h4 {
color: #1e293b;
margin-bottom: 8px;
font-size: 16px;
}
.content-type-card p {
color: #64748b;
font-size: 14px;
line-height: 1.5;
}
.icon {
font-size: 32px;
margin-bottom: 12px;
display: block;
}
</style>
</head>
<body>
<div class="container">
<h1>
🎓 H5P Content Creator
<span class="status">Beta</span>
</h1>
<div class="info-box">
<h3>📚 Willkommen im H5P Content Creator!</h3>
<p>
Erstelle interaktive Lerninhalte wie Quizze, Videos mit Fragen, Präsentationen und vieles mehr.
H5P (HTML5 Package) ermöglicht es, ansprechende und interaktive Bildungsinhalte zu erstellen,
die auf allen Geräten funktionieren.
</p>
</div>
<h2 style="margin: 32px 0 16px 0; color: #334155; font-size: 20px;">Beliebte Content-Typen</h2>
<div class="content-types">
<div class="content-type-card" onclick="window.location.href='/h5p/editor/quiz'">
<span class="icon">✍️</span>
<h4>Quiz (Question Set)</h4>
<p>Multiple-Choice-Tests mit sofortigem Feedback und Punktebewertung</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/interactive-video'">
<span class="icon">🎬</span>
<h4>Interactive Video</h4>
<p>Videos mit eingebetteten Fragen, Links und anderen interaktiven Elementen</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/course-presentation'">
<span class="icon">📊</span>
<h4>Course Presentation</h4>
<p>Präsentationen mit interaktiven Folien, Fragen und Multimedia-Inhalten</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/flashcards'">
<span class="icon">🃏</span>
<h4>Flashcards</h4>
<p>Lernkarten zum Üben und Wiederholen von Vokabeln und Konzepten</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/timeline'">
<span class="icon">📅</span>
<h4>Timeline</h4>
<p>Interaktive Zeitstrahle mit Bildern, Videos und Beschreibungen</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/drag-drop'">
<span class="icon">🎯</span>
<h4>Drag and Drop</h4>
<p>Elemente ziehen und an der richtigen Stelle ablegen - ideal für Zuordnungsaufgaben</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/fill-blanks'">
<span class="icon">📝</span>
<h4>Fill in the Blanks</h4>
<p>Lückentexte mit automatischer Korrektur und Hinweisen</p>
</div>
<div class="content-type-card" onclick="window.location.href='/h5p/editor/memory'">
<span class="icon">🧠</span>
<h4>Memory Game</h4>
<p>Klassisches Memory-Spiel mit Bildern oder Text-Paaren</p>
</div>
</div>
<div class="info-box" style="margin-top: 32px; background: #d1fae5; border-color: #10b981;">
<h3 style="color: #065f46;">✅ Alle Editoren verfügbar!</h3>
<p style="color: #047857;">
Alle 8 Content-Typen sind jetzt verfügbar: <strong>Quiz</strong>, <strong>Interactive Video</strong>, <strong>Course Presentation</strong>, <strong>Flashcards</strong>, <strong>Timeline</strong>, <strong>Drag and Drop</strong>, <strong>Fill in the Blanks</strong> und <strong>Memory Game</strong>!
Klicke auf eine Kachel, um den Editor zu öffnen.
</p>
</div>
</div>
<!-- H5P Core JavaScript -->
<script src="/h5p/core/jquery.js"></script>
<script src="/h5p/core/h5p.js"></script>
<script src="/h5p/core/h5p-event-dispatcher.js"></script>
<script src="/h5p/core/h5p-x-api-event.js"></script>
<script src="/h5p/core/h5p-x-api.js"></script>
<script src="/h5p/core/h5p-content-type.js"></script>
<script src="/h5p/core/h5p-confirmation-dialog.js"></script>
<script src="/h5p/core/h5p-action-bar.js"></script>
<script>
console.log('H5P Editor page loaded');
console.log('H5P Core version:', typeof H5P !== 'undefined' ? 'loaded' : 'not loaded');
</script>
</body>
</html>`);
});
// Health & Info
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BreakPilot H5P Service</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
.container {
background: white;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
padding: 40px;
max-width: 600px;
width: 100%;
}
h1 { color: #333; margin-bottom: 10px; font-size: 32px; }
.status {
display: inline-block;
background: #10b981;
color: white;
padding: 6px 16px;
border-radius: 20px;
font-size: 14px;
margin: 20px 0;
}
.btn {
display: block;
padding: 12px 24px;
background: #667eea;
color: white;
text-decoration: none;
border-radius: 8px;
text-align: center;
font-weight: 600;
margin: 10px 0;
}
.btn:hover { background: #5568d3; }
</style>
</head>
<body>
<div class="container">
<h1>🎓 H5P Service</h1>
<div class="status">✅ Running (Simplified)</div>
<p style="color: #64748b; margin: 20px 0;">
Vereinfachte H5P-Integration für BreakPilot Studio
</p>
<a href="/h5p/editor/new" class="btn">H5P Editor öffnen</a>
<a href="/health" class="btn" style="background: #e2e8f0; color: #4a5568;">Health Check</a>
</div>
</body>
</html>
`);
});
app.get('/health', (req, res) => {
res.json({
status: 'healthy',
service: 'h5p-service-simplified',
version: '1.0.0-simple'
});
});
// Export app for testing
export { app };
// Start server only when run directly (not imported for tests)
const isMainModule = import.meta.url === `file://${process.argv[1]}`;
if (isMainModule) {
app.listen(PORT, () => {
console.log(`
╔════════════════════════════════════════════════════╗
║ 🎓 BreakPilot H5P Service (Simplified) ║
║ 📍 http://localhost:${PORT}
║ ✅ Ready to serve H5P content! ║
╚════════════════════════════════════════════════════╝
`);
});
}