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>
378 lines
12 KiB
JavaScript
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! ║
|
|
╚════════════════════════════════════════════════════╝
|
|
`);
|
|
});
|
|
}
|