Scrapt Lehrstoff vollautomatisch von den einzelnen Unterrichtsstunden
// ==UserScript==
// @name WebUntis Topic Scraper
// @namespace http://tampermonkey.net/
// @namespace https://github.com/dein-username
// @license MIT
// @homepageURL https://greasyfork.org/
// @version 0.1.0
// @description Scrapt Lehrstoff vollautomatisch von den einzelnen Unterrichtsstunden
// @author Whiztech
// @match https://gds2.webuntis.com/timetable/my-student*
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function () {
'use strict';
function icon(paths, size) {
size = size || 15;
var ns = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(ns, 'svg');
svg.setAttribute('width', size);
svg.setAttribute('height', size);
svg.setAttribute('viewBox', '0 0 24 24');
svg.setAttribute('fill', 'none');
svg.setAttribute('stroke', 'currentColor');
svg.setAttribute('stroke-width', '2');
svg.setAttribute('stroke-linecap', 'round');
svg.setAttribute('stroke-linejoin', 'round');
svg.style.cssText = 'display:inline-block;vertical-align:middle;flex-shrink:0;';
paths.forEach(function(d) {
var p = document.createElementNS(ns, 'path');
p.setAttribute('d', d);
svg.appendChild(p);
});
return svg;
}
var ICONS = {
play: ['M5 3l14 9-14 9V3z'],
copy: ['M8 4H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-2','M16 2H8a2 2 0 0 0-2 2v0a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v0a2 2 0 0 0-2-2z'],
eye: ['M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z','M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z'],
trash: ['M3 6h18','M19 6l-1 14H6L5 6','M8 6V4h8v2','M10 11v6','M14 11v6'],
check: ['M20 6L9 17l-5-5'],
xmark: ['M18 6 6 18','M6 6l12 12'],
clipboard: ['M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2','M9 2h6a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1H9a1 1 0 0 1-1-1V3a1 1 0 0 1 1-1z'],
loader: ['M12 2v4','M12 18v4','M4.93 4.93l2.83 2.83','M16.24 16.24l2.83 2.83','M2 12h4','M18 12h4','M4.93 19.07l2.83-2.83','M16.24 7.76l2.83-2.83'],
};
function makeBtn(labelText, iconName, bg, bgHover) {
var btn = document.createElement('button');
btn.style.cssText = [
'width:100%;padding:8px 10px;background:' + bg + ';color:#fff;',
'border:none;border-radius:8px;font-size:12.5px;font-weight:600;cursor:pointer;',
'transition:background .15s;margin-bottom:6px;',
'display:flex;align-items:center;gap:7px;',
].join('');
btn.appendChild(icon(ICONS[iconName], 14));
var span = document.createElement('span');
span.textContent = labelText;
btn.appendChild(span);
btn.addEventListener('mouseenter', function() { btn.style.background = bgHover; });
btn.addEventListener('mouseleave', function() { btn.style.background = bg; });
btn._span = span;
return btn;
}
function sep() {
var hr = document.createElement('hr');
hr.style.cssText = 'border:none;border-top:1px solid rgba(0,0,0,0.08);margin:10px 0;';
return hr;
}
function showModal(title, message, buttons) {
var overlay = document.createElement('div');
overlay.style.cssText = [
'position:fixed;inset:0;z-index:10000001;',
'background:rgba(0,0,0,0.45);',
'backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);',
'display:flex;align-items:center;justify-content:center;',
].join('');
var card = document.createElement('div');
card.style.cssText = [
'background:rgba(255,255,255,0.92);',
'backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);',
'border:1px solid rgba(255,255,255,0.6);',
'border-radius:16px;padding:24px 28px;',
'box-shadow:0 16px 48px rgba(0,0,0,0.22);',
'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;',
'color:#1a1a2e;max-width:400px;min-width:260px;',
].join('');
var titleEl = document.createElement('div');
titleEl.textContent = title;
titleEl.style.cssText = 'font-weight:700;font-size:14px;margin-bottom:10px;';
card.appendChild(titleEl);
var msgEl = document.createElement('div');
msgEl.textContent = message;
msgEl.style.cssText = 'font-size:13px;color:#444;white-space:pre-wrap;margin-bottom:18px;line-height:1.5;max-height:60vh;overflow-y:auto;';
card.appendChild(msgEl);
var btnRow = document.createElement('div');
btnRow.style.cssText = 'display:flex;gap:8px;justify-content:flex-end;';
buttons.forEach(function (b) {
var btn = document.createElement('button');
btn.textContent = b.label;
btn.style.cssText = [
'padding:7px 18px;border:none;border-radius:8px;',
'font-size:12.5px;font-weight:600;cursor:pointer;transition:opacity .15s;',
'background:' + (b.primary ? '#4a90e2' : 'rgba(0,0,0,0.08)') + ';',
'color:' + (b.primary ? '#fff' : '#1a1a2e') + ';',
].join('');
btn.addEventListener('mouseenter', function () { btn.style.opacity = '0.8'; });
btn.addEventListener('mouseleave', function () { btn.style.opacity = '1'; });
btn.addEventListener('click', function () {
if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
if (b.action) b.action();
});
btnRow.appendChild(btn);
});
card.appendChild(btnRow);
overlay.appendChild(card);
document.body.appendChild(overlay);
}
function showAlert(title, message, onOk) {
showModal(title, message, [{ label: 'OK', primary: true, action: onOk || null }]);
}
function showConfirm(title, message, onConfirm) {
showModal(title, message, [
{ label: 'Abbrechen', primary: false },
{ label: 'Bestaetigen', primary: true, action: onConfirm },
]);
}
var lastUrl = '';
var panelBuilt = false;
var progressBar = null;
var activeInterval = null;
setInterval(function () {
var url = window.location.href;
if (url === lastUrl) return;
lastUrl = url;
if (activeInterval) { clearInterval(activeInterval); activeInterval = null; }
if (window.location.pathname.includes('/lessonDetails/')) {
onLessonDetailsPage();
} else {
onTimetablePage();
}
}, 300);
function onLessonDetailsPage() {
if (!GM_getValue('scrapingMode', false)) return;
var tries = 0;
activeInterval = setInterval(function () {
tries++;
if (document.querySelector('.empty-indicator.empty-indicator--without-card')) {
clearInterval(activeInterval); activeInterval = null;
saveAndGoBack('');
return;
}
var labels = document.querySelectorAll('.inline-text-input label');
for (var i = 0; i < labels.length; i++) {
if (labels[i].textContent.trim() === 'Lehrstoff') {
var container = labels[i].closest('.inline-text-input');
var ta = container && container.querySelector('textarea');
if (ta) {
clearInterval(activeInterval); activeInterval = null;
saveAndGoBack(ta.value || ta.textContent.trim());
return;
}
}
}
if (tries >= 30) { clearInterval(activeInterval); activeInterval = null; saveAndGoBack(''); }
}, 500);
}
function saveAndGoBack(lehrstoff) {
if (lehrstoff && lehrstoff.trim()) {
var subject = GM_getValue('currentSubject', '?');
var results = JSON.parse(GM_getValue('scrapingResults', '[]'));
var parts = window.location.pathname.split('/');
results.push({
subject: subject,
lehrstoff: lehrstoff.trim(),
startTime: decodeURIComponent(parts[7] || ''),
endTime: decodeURIComponent(parts[8] || '')
});
GM_setValue('scrapingResults', JSON.stringify(results));
}
history.back();
}
function onTimetablePage() {
if (GM_getValue('scrapingMode', false)) {
var idx = GM_getValue('scrapingIndex', 0);
var total = GM_getValue('scrapingTotal', 0);
if (idx < total) {
setProgressBar(idx, total);
clickCard(idx);
} else {
GM_setValue('scrapingMode', false);
removeProgressBar();
rebuildPanel();
var results = JSON.parse(GM_getValue('scrapingResults', '[]'));
if (results.length > 0) {
setTimeout(function () {
var text = buildText(results);
showModal('Scraping fertig', results.length + ' Lektionen:\n\n' + text, [
{
label: 'Alles kopieren',
primary: true,
action: function () {
navigator.clipboard.writeText(text);
}
},
{ label: 'Schließen', primary: false }
]);
}, 400);
}
}
} else {
if (!panelBuilt) { panelBuilt = true; buildTimetablePanel(); }
}
}
function clickCard(idx) {
var tries = 0;
activeInterval = setInterval(function () {
tries++;
var cards = document.querySelectorAll('.timetable-grid-card .lesson-card.clickable');
if (cards.length > idx) {
clearInterval(activeInterval); activeInterval = null;
var card = cards[idx];
var subEl = card.querySelector('[data-testid="lesson-card-resources-with-change-subject"] [data-testid="regular-resource"]');
GM_setValue('currentSubject', subEl ? subEl.textContent.trim() : ('Lektion ' + (idx + 1)));
GM_setValue('scrapingIndex', idx + 1);
card.click();
}
if (tries > 40) {
clearInterval(activeInterval); activeInterval = null;
GM_setValue('scrapingMode', false);
removeProgressBar();
showAlert('Scraping abgebrochen', 'Karte ' + (idx + 1) + ' nicht gefunden.');
rebuildPanel();
}
}, 500);
}
function setProgressBar(current, total) {
if (!progressBar) {
var overlay = document.createElement('div');
overlay.style.cssText = [
'position:fixed;inset:0;z-index:9999998;',
'background:rgba(0,0,0,0.45);',
'backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);',
].join('');
var card = document.createElement('div');
card.style.cssText = [
'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);',
'z-index:9999999;background:rgba(255,255,255,0.88);',
'backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);',
'border:1px solid rgba(255,255,255,0.6);border-radius:16px;padding:28px 32px;',
'box-shadow:0 16px 48px rgba(0,0,0,0.22);',
'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;',
'color:#1a1a2e;text-align:center;min-width:220px;',
].join('');
var spinWrap = document.createElement('div');
spinWrap.style.cssText = 'display:flex;justify-content:center;margin-bottom:16px;';
var spinSvg = icon(ICONS.loader, 36);
spinSvg.style.cssText += 'animation:__scraper_spin 1s linear infinite;color:#4a90e2;';
if (!document.getElementById('__scraper_keyframes')) {
var style = document.createElement('style');
style.id = '__scraper_keyframes';
style.textContent = '@keyframes __scraper_spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}';
document.head.appendChild(style);
}
spinWrap.appendChild(spinSvg);
card.appendChild(spinWrap);
var lbl = document.createElement('div');
lbl.style.cssText = 'font-size:14px;font-weight:600;margin-bottom:6px;';
card._label = lbl;
card.appendChild(lbl);
var sub = document.createElement('div');
sub.style.cssText = 'font-size:12px;color:#888;margin-bottom:6px;';
sub.textContent = 'Bitte verlassen Sie diesen Tab nicht…';
card.appendChild(sub);
var hint = document.createElement('div');
hint.style.cssText = 'font-size:11px;color:#bbb;margin-bottom:18px;';
hint.textContent = 'Sollten Sie nicht weiterkommen, drücken Sie bitte die ESC-Taste oder warten Sie ein bisschen.';
card.appendChild(hint);
var cancelBtn = document.createElement('button');
cancelBtn.style.cssText = [
'background:rgba(0,0,0,0.07);color:#1a1a2e;',
'border:1px solid rgba(0,0,0,0.14);border-radius:8px;',
'padding:6px 16px;font-size:12px;font-weight:600;cursor:pointer;',
'display:inline-flex;align-items:center;gap:6px;transition:background .15s;',
].join('');
cancelBtn.appendChild(icon(ICONS.xmark, 13));
var cspan = document.createElement('span');
cspan.textContent = 'Abbrechen';
cancelBtn.appendChild(cspan);
cancelBtn.addEventListener('mouseenter', function () { cancelBtn.style.background = 'rgba(0,0,0,0.13)'; });
cancelBtn.addEventListener('mouseleave', function () { cancelBtn.style.background = 'rgba(0,0,0,0.07)'; });
cancelBtn.addEventListener('click', function () {
if (activeInterval) { clearInterval(activeInterval); activeInterval = null; }
GM_setValue('scrapingMode', false);
GM_setValue('scrapingResults', '[]');
removeProgressBar();
rebuildPanel();
});
card.appendChild(cancelBtn);
overlay.appendChild(card);
document.body.appendChild(overlay);
progressBar = overlay;
progressBar._label = lbl;
}
progressBar._label.textContent = 'Scraping ' + (current + 1) + ' / ' + total;
}
function removeProgressBar() {
if (progressBar && progressBar.parentNode) {
progressBar.parentNode.removeChild(progressBar);
progressBar = null;
}
}
function rebuildPanel() {
['__scraperToggle', '__scraperPanel'].forEach(function (id) {
var el = document.getElementById(id);
if (el) el.parentNode.removeChild(el);
});
panelBuilt = true;
buildTimetablePanel();
}
function buildTimetablePanel() {
var overlay = document.createElement('div');
overlay.id = '__scraperPanel';
overlay.style.cssText = [
'position:fixed;inset:0;z-index:999999;',
'background:rgba(0,0,0,0.45);',
'backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);',
'display:none;align-items:center;justify-content:center;',
].join('');
overlay.addEventListener('click', function (e) {
if (e.target === overlay) overlay.style.display = 'none';
});
var card = document.createElement('div');
card.style.cssText = [
'background:rgba(255,255,255,0.92);',
'backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);',
'border:1px solid rgba(255,255,255,0.6);',
'border-radius:16px;padding:22px 24px 20px;',
'box-shadow:0 16px 48px rgba(0,0,0,0.22);',
'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;',
'font-size:13px;color:#1a1a2e;min-width:260px;max-width:320px;',
'position:relative;',
].join('');
var xBtn = document.createElement('button');
xBtn.title = 'Schließen';
xBtn.style.cssText = [
'position:absolute;top:12px;right:12px;',
'background:rgba(0,0,0,0.06);border:none;border-radius:50%;',
'width:26px;height:26px;cursor:pointer;padding:0;',
'display:flex;align-items:center;justify-content:center;',
'transition:background .15s;color:#555;',
].join('');
xBtn.appendChild(icon(ICONS.xmark, 13));
xBtn.addEventListener('mouseenter', function () { xBtn.style.background = 'rgba(0,0,0,0.13)'; });
xBtn.addEventListener('mouseleave', function () { xBtn.style.background = 'rgba(0,0,0,0.06)'; });
xBtn.addEventListener('click', function () { overlay.style.display = 'none'; });
card.appendChild(xBtn);
var helpBtn = document.createElement('button');
helpBtn.title = 'Info';
helpBtn.style.cssText = [
'position:absolute;top:12px;right:46px;',
'background:rgba(0,0,0,0.06);border:none;border-radius:50%;',
'width:26px;height:26px;cursor:pointer;padding:0;',
'display:flex;align-items:center;justify-content:center;',
'transition:background .15s;color:#555;',
'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;',
'font-size:13px;font-weight:700;',
].join('');
helpBtn.textContent = '?';
helpBtn.addEventListener('mouseenter', function () { helpBtn.style.background = 'rgba(0,0,0,0.13)'; });
helpBtn.addEventListener('mouseleave', function () { helpBtn.style.background = 'rgba(0,0,0,0.06)'; });
helpBtn.addEventListener('click', function () {
showAlert('WebUntis Topic Scraper',
'Eine inoffizielle Erweiterung für WebUntis, die die Lehrstoffe und Themen aus allen Unterrichtsstunden der jeweiligen Schulwoche automatisch herausliest.\n\n' +
'So funktioniert es:\n' +
'1. Zur gewünschten Schulwoche in WebUntis wechseln.\n' +
'2. Den WebUntis Topic Scraper öffnen und auf "Scrapen starten" klicken.\n' +
'3. Das Script klickt automatisch jede Unterrichtsstunde durch und liest den Lehrstoff aus.\n' +
'4. Die Ergebnisse können danach kopiert und ins Berichtsheft eingefügt werden.\n\n' +
'Projekt umgesetzt von Whiztech.'
);
});
card.appendChild(helpBtn);
//Title
var titleDiv = document.createElement('div');
titleDiv.textContent = 'WebUntis Topic Scraper';
titleDiv.style.cssText = 'font-weight:700;font-size:13px;margin-bottom:14px;color:#1a1a2e;letter-spacing:0.01em;padding-right:60px;';
card.appendChild(titleDiv);
//Scrape button
var scrapeBtn = makeBtn('Scrapen starten', 'play', '#4a90e2', '#357abd');
scrapeBtn.style.marginBottom = '0';
scrapeBtn.addEventListener('click', function () {
var cards = document.querySelectorAll('.timetable-grid-card .lesson-card.clickable');
if (cards.length === 0) { showAlert('Hinweis', 'Keine Lektionen gefunden.'); return; }
GM_setValue('scrapingMode', true);
GM_setValue('scrapingTotal', cards.length);
GM_setValue('scrapingIndex', 1);
GM_setValue('scrapingResults', '[]');
var firstSubEl = cards[0].querySelector('[data-testid="lesson-card-resources-with-change-subject"] [data-testid="regular-resource"]');
GM_setValue('currentSubject', firstSubEl ? firstSubEl.textContent.trim() : 'Lektion 1');
overlay.style.display = 'none';
setProgressBar(0, cards.length);
cards[0].click();
});
card.appendChild(scrapeBtn);
//Stored results section
var stored = JSON.parse(GM_getValue('scrapingResults', '[]'));
if (stored.length > 0) {
card.appendChild(sep());
var lbl = document.createElement('div');
lbl.textContent = stored.length + ' Ergebnisse gespeichert';
lbl.style.cssText = 'font-size:11.5px;color:#666;margin-bottom:8px;';
card.appendChild(lbl);
var clipBtn = makeBtn('Alles kopieren', 'copy', '#2ecc71', '#27ae60');
clipBtn.addEventListener('click', function () {
navigator.clipboard.writeText(buildText(stored)).then(function () {
clipBtn._span.textContent = 'Kopiert!';
clipBtn.replaceChild(icon(ICONS.check, 14), clipBtn.firstChild);
clipBtn.style.background = '#1a7a44';
setTimeout(function () {
clipBtn._span.textContent = 'Alles kopieren';
clipBtn.replaceChild(icon(ICONS.copy, 14), clipBtn.firstChild);
clipBtn.style.background = '#2ecc71';
}, 2000);
});
});
card.appendChild(clipBtn);
var showBtn = makeBtn('Ergebnisse anzeigen', 'eye', '#f39c12', '#d68910');
showBtn.addEventListener('click', function () {
showAlert('Gespeicherte Ergebnisse', stored.length + ' Lektionen:\n\n' + buildText(stored));
});
card.appendChild(showBtn);
var clearBtn = makeBtn('Speicher leeren', 'trash', '#e74c3c', '#c0392b');
clearBtn.style.marginBottom = '0';
clearBtn.addEventListener('click', function () {
showConfirm('Speicher leeren', 'Gespeicherte Ergebnisse wirklich löschen?', function () {
GM_setValue('scrapingResults', '[]');
rebuildPanel();
});
});
card.appendChild(clearBtn);
}
overlay.appendChild(card);
document.body.appendChild(overlay);
var headerPollInterval = setInterval(function () {
var controls = document.querySelector('.timetable-header-controls');
if (!controls) return;
if (document.getElementById('__scraperToggle')) return;
clearInterval(headerPollInterval);
var toggleBtn = document.createElement('button');
toggleBtn.id = '__scraperToggle';
toggleBtn.title = 'WebUntis Topic Scraper';
toggleBtn.style.cssText = [
'background:#4a90e2;color:#fff;border:none;border-radius:6px;',
'padding:0 10px;height:28px;cursor:pointer;margin-right:8px;',
'box-shadow:0 2px 8px rgba(0,0,0,0.12);transition:opacity .2s;',
'display:inline-flex;align-items:center;gap:6px;',
'font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Arial,sans-serif;',
'font-size:12px;font-weight:600;vertical-align:middle;',
].join('');
toggleBtn.appendChild(icon(ICONS.clipboard, 14));
var tlbl = document.createElement('span');
tlbl.textContent = 'Scraper';
toggleBtn.appendChild(tlbl);
toggleBtn.addEventListener('mouseenter', function () { toggleBtn.style.opacity = '0.82'; });
toggleBtn.addEventListener('mouseleave', function () { toggleBtn.style.opacity = '1'; });
controls.insertBefore(toggleBtn, controls.firstChild);
toggleBtn.addEventListener('click', function () {
overlay.style.display = overlay.style.display === 'flex' ? 'none' : 'flex';
});
}, 200);
}
function buildText(results) {
var grouped = {};
var order = [];
results.forEach(function (r) {
var key = r.subject || '?';
if (!grouped[key]) { grouped[key] = []; order.push(key); }
grouped[key].push(r.lehrstoff);
});
return order.map(function (key) {
return key + ': ' + grouped[key].join('; ');
}).join('\n');
}
})();