From 59b700299f860f0854c37906eaa5a5850cc45f59 Mon Sep 17 00:00:00 2001 From: davidpkj Date: Sat, 13 Apr 2024 12:28:41 +0200 Subject: univis stuff & docs --- .vscode/settings.json | 1 + README.adoc | 58 +++++++++++++++++++- future_format.yaml | 16 ------ package-lock.json | 22 ++++++-- package.json | 6 ++- public/config.yaml | 55 +++++++++++++++++++ public/style.css | 66 +++++++++++++++++++++++ src/files.js | 20 +++++++ src/main.js | 49 +++++++++-------- src/univis.js | 41 +++++++++++++++ src/variables.js | 143 -------------------------------------------------- 11 files changed, 289 insertions(+), 188 deletions(-) create mode 100644 .vscode/settings.json delete mode 100644 future_format.yaml create mode 100644 public/config.yaml create mode 100644 public/style.css create mode 100644 src/files.js create mode 100644 src/univis.js delete mode 100644 src/variables.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/README.adoc b/README.adoc index 58a57a2..86ff908 100644 --- a/README.adoc +++ b/README.adoc @@ -1,6 +1,6 @@ = Stundenplan -A small JavaScript project to generate beautiful PDF schedules. Takes information from `src/variables.js`. Planning to use direct UnivIS-XML export. +A small JavaScript project to generate beautiful PDF schedules. Takes information from `src/variables.js`. == Usage @@ -10,3 +10,59 @@ Requires the `npm` tool. npm i # installes packages npm run main # runs the software ``` + +=== Optional: Parse UnivIS XML + +You have the option to parse a full `public/data.xml` UnivIS export to get 80% of the way to a working configuration. You still have to manually clean up and refactor the information to yaml. But you dont have to write all those characters out. + +If you use vim, it then should be only a matter of seconds until you have your `.pdf`. + +```bash +npm run parse +``` + +== Configuration Structure + +Generally, you may edit anything in the `public` directory. The default are how I like it. + +To configure the actual displayed information you shoudl edit the `.yaml` file. It should look something like the following, where things like `` should be replaced by your text. + +Comments (things that are ignored by the software) is everything after a `#` sign. More information on the file format and syntax can be found https://yaml.org/[here]. + +```yaml +# General Information +student: +semester: +filename: # i.e. Stundenplan_SS24.pdf + +# Each of these lines will be listed at the bottom of the PDF +hinweise: + - # i.e. "Mensabetrieb: 11:15 - 14:15 Uhr + 00:15 min" + +# Time definitions +eintraege: + - : + : + - [, , , ] +``` + +Please note that times should be given in the format `HHhMM` so to say 9:19 AM, you would actually write 09h19. Also the Module and Lecture `BLOCKED` is reserved for a cross hatched block. + +So writing +```yaml +... + - BLOCKED: + BLOCKED: +... +``` + +would put a blocked area in the pdf, instead of putting an actual block with the text "BLOCKED / BLOCKED". + +== Known issues + +- Doesnt work if not all days are set (null checks in general) +- Have to use the exact yaml structure +- Margin on the left not easily configurable +- Mensa times are not actually displayed +- All config.yaml items are required +- Code is german spaghetti \ No newline at end of file diff --git a/future_format.yaml b/future_format.yaml deleted file mode 100644 index bbb9590..0000000 --- a/future_format.yaml +++ /dev/null @@ -1,16 +0,0 @@ -student: David Penkowoj -semester: Sommersemester 2024 -hinweise: - - "Mensabetrieb: 11:15 - 14:15 Uhr + 00:15 min" - - "GET 2 / V am 23.05. & 04.07. im V1" - - "GET 2 / Ü am 24.05. im T S2" - - "FuQ / V am 24.05. im T S1" - -eintraege: - - GET 2: - U: - - [Mo, 12h00, 13h00, AM S4] - - [Fr, 11h30, 13h00, AM S4] - V: - - [Di, 08h30, 10h00, H 1] - - [Do, 08h30, 10h00, Z 1/2] diff --git a/package-lock.json b/package-lock.json index fc58f20..d3e4a15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,9 @@ "html-pdf-node": "^1.0.8", "js-yaml": "^4.1.0", "jsdom": "^24.0.0", - "jspdf": "^2.5.1" - }, - "devDependencies": {} + "jspdf": "^2.5.1", + "xml-js": "^1.6.11" + } }, "node_modules/@babel/runtime": { "version": "7.24.4", @@ -1309,6 +1309,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" + }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", @@ -1588,6 +1593,17 @@ } } }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, "node_modules/xml-name-validator": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", diff --git a/package.json b/package.json index 7eca5a1..7bbb1a8 100644 --- a/package.json +++ b/package.json @@ -7,10 +7,12 @@ "html-pdf-node": "^1.0.8", "js-yaml": "^4.1.0", "jsdom": "^24.0.0", - "jspdf": "^2.5.1" + "jspdf": "^2.5.1", + "xml-js": "^1.6.11" }, "scripts": { - "main": "node src/main.js" + "main": "node src/main.js", + "parse": "node src/univis.js" }, "author": "David Penkowoj", "license": "GPL-3.0-or-later", diff --git a/public/config.yaml b/public/config.yaml new file mode 100644 index 0000000..c9bece2 --- /dev/null +++ b/public/config.yaml @@ -0,0 +1,55 @@ +# Allgemeine Informationen +student: David Penkowoj +semester: Sommersemester 2024 +filename: Stundenplan_SS24.pdf + +# Jeder hinweis wird unter dem Stundenplan aufgelistet +hinweise: + - "Mensabetrieb: 11:15 - 14:15 Uhr + 00:15 min" + - "GET 2 / V am 23.05. & 04.07. im V1" + - "GET 2 / Ü am 24.05. im T S2" + - "FuQ / V am 24.05. im T S1" + +# Modul- und Veranstaltungsdefinitionen +eintraege: + - GET 2: + U: + - [Mo, 12h00, 13h00, AM S4] + - [Fr, 11h30, 13h00, AM S4] + V: + - [Di, 08h30, 10h00, H 1] + - [Do, 08h30, 10h00, Z 1/2] + - TGI 1: + V: + - [Mi, 08h15, 09h45, AM 1] + U: + - [Do, 15h00, 16h00, AM 1] + Prak. Gr. 2: + - [Di, 14h30, 16h30, ITI 131] + - Pho: + V: + - [Fr, 08h30, 10h00, T 1] + U: + - [Mi, 12h00, 13h00, AM 1] + - Ana 2: + V: + - [Di, 12h30, 14h00, AM 1] + U: + - [Do, 16h15, 17h15, H 1] + Helpdesk: + - [Di, 18h00, 19h00, O-Sync] + - [Mi, 18h00, 19h00, O-Sync] + - EiBMO: + V: + - [Mi, 14h00, 16h00, H 1] + U: + - [Mi, 16h00, 17h00, H 1] + - FuQ: + V: + - [Fr, 10h00, 11h30, AM 4] + U: + - [Di, 11h00, 12h00, SI 4 (Minsky)] + - BLOCKED: + BLOCKED: + - [Mo, 13h00, 19h00, BLOCKED] + - [Do, 10h00, 15h00, BLOCKED] \ No newline at end of file diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..acc57b4 --- /dev/null +++ b/public/style.css @@ -0,0 +1,66 @@ +* { + font-weight: 300; + font-family: "Abel", sans-serif; + + print-color-adjust: exact; + -webkit-print-color-adjust: exact; + + --entries-b: #ccc; + --entries-f: #111; + --headers-b: #333; + --headers-f: #fff; + + --block: #ccc; +} + +em { + font-style: normal; + text-decoration: underline; +} + +table { + width: 100%; +} + +table td, +table tr { + background: var(--headers-f); + height: 4px; +} + +table th, +table td:not(:empty) { + background-color: var(--entries-b); + color: var(--entries-f); + padding: 0.5em 1em; + position: relative +} + +table th { + background-color: var(--headers-b); + color: var(--headers-f); +} + +table th.tag { + width: 20%; +} + +table td { + font-size: 12px; +} + +table td.block { + background-image: repeating-linear-gradient(314deg, var(--block), var(--block) 10px, transparent 10px, transparent 20px); + background-size: 99.9999999% 99.9999999%; /* because 100% gives wrong scaling for some reason */ + border: 2px solid var(--block); +} + +div { + position: absolute; + display: flex; + + top: 0.4em; + left: 0.4em; + width: calc(100% - 0.8em); + justify-content: space-between; +} \ No newline at end of file diff --git a/src/files.js b/src/files.js new file mode 100644 index 0000000..970d28d --- /dev/null +++ b/src/files.js @@ -0,0 +1,20 @@ +import * as yml from "js-yaml" +import * as fs from "fs" + +const dir = "./public"; + +function readConfig() { + return yml.load(fs.readFileSync(`${dir}/config.yaml`, 'utf8')); +} + +function readStyle() { + return fs.readFileSync(`${dir}/style.css`, 'utf8'); +} + +export function readXML() { + return fs.readFileSync(`${dir}/data.xml`, 'utf8'); +} + +export const c = readConfig(); + +c.style = ``; \ No newline at end of file diff --git a/src/main.js b/src/main.js index 5b326d7..c3cbec9 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,10 @@ import * as fs from "fs" import * as html_to_pdf from "html-pdf-node" -import * as v from './variables.js' +import { c } from './files.js' let hinweise = "
    "; -for (let hinweis of v.hinweise) { +for (let hinweis of c.hinweise) { hinweise += `
  • ${hinweis}
  • `; } hinweise += `
`; @@ -133,14 +133,19 @@ function main() { let tage = structuredClone(ctage); let tage_runtimes = structuredClone(ctage); - for (let eintrag of v.eintraege) { - for (let termin of eintrag.termine) { - tage[termin.wochentag].push({ - "name": eintrag.name, - "raum": termin.raum, - "von": termin.von, - "bis": termin.bis, - }) + for (let eintrag of c.eintraege) { + let eintragName = Object.keys(eintrag)[0]; + eintrag = eintrag[eintragName] + + for (let veranstaltung in eintrag) { + for (let termin of eintrag[veranstaltung]) { + tage[termin[0]].push({ + "name": `${eintragName.toString()} / ${veranstaltung.toString()}`, + "raum": termin[3], + "von": termin[1].replace("h", ":"), + "bis": termin[2].replace("h", ":"), + }) + } } } @@ -167,7 +172,7 @@ function main() { let el = tage_runtimes[day][0]; - if (el.name == "BLOCKED" && el.raum == "BLOCKED") { + if (el.name.includes("BLOCKED") && el.raum == "BLOCKED") { res += ``; } else { let name = el.name == "BUFFER" ? "" : `
${el.name}`; @@ -183,31 +188,29 @@ function main() { res += "" } - // console.log(res) - return res } let html = ` -${v.style} -

Persönlicher Stundenplan von ${v.student} für das ${v.semester}. Stand: ${date}.

+${c.style} +

Persönlicher Stundenplan von ${c.student} für das ${c.semester}. Stand: ${date}.

- - - - - - + + + + + + ${main()}
Uhrzeit Montag Dienstag Mittwoch Donnerstag Freitag UhrzeitMontagDienstagMittwochDonnerstagFreitag

- Hinweise: +Hinweise: ${hinweise} `; html_to_pdf.generatePdf({content: html}, options).then(pdfBuffer => { // fs.writeFileSync("test.html", html) - fs.writeFileSync(v.filename, pdfBuffer); + fs.writeFileSync(c.filename, pdfBuffer); }); diff --git a/src/univis.js b/src/univis.js new file mode 100644 index 0000000..f770bd7 --- /dev/null +++ b/src/univis.js @@ -0,0 +1,41 @@ +import * as xml from "xml-js" + +import { readXML } from "./files.js" + +function getRoomName(key) { + for (let room of res.Room) { + if (room._attributes.key == key) { + return room.short._text; + } + } + + return "?"; +} + +function serializeLecture(lecture) { + let name = lecture.short?._text ?? lecture.name._text + + for (let term in lecture.terms) { + let t = lecture.terms[term]; + + if (!t.starttime) continue; + + let von = t.starttime._text.replace(":", "h"); + let bis = t.endtime._text.replace(":", "h"); + + let raum = getRoomName(t.room.UnivISRef._attributes.key); + + console.log(`${name}, ${von}, ${bis}, ${raum}`); + } +} + +let data = readXML(); +let res = (xml.xml2js(data, {compact: true})).UnivIS; + +let semester = res._attributes.semester; + +console.log("semester: " + semester) + +for (let lecture of res.Lecture) { + serializeLecture(lecture) +} \ No newline at end of file diff --git a/src/variables.js b/src/variables.js deleted file mode 100644 index bf98ca1..0000000 --- a/src/variables.js +++ /dev/null @@ -1,143 +0,0 @@ -// Dont touch this -class Eintrag { - constructor(name, termine) { - this.name = name; - this.termine = termine; - } -} - -class Termin { - constructor(wochentag, raum, von, bis) { - this.wochentag = wochentag; - this.raum = raum; - this.von = von; - this.bis = bis; - } -} - -// You may touch this -export const student = "David Penkowoj"; -export const semester = "Sommersemester 2024"; -export const filename = `Stundenplan-${semester.replace(" ", "-")}.pdf`; - -export const hinweise = [ - "Mensabetrieb: 11:15 - 14:15 Uhr + 00:15 min", - "GET 2 / V am 23.05. & 04.07. im V1", - "GET 2 / Ü am 24.05. im T S2", - "FuQ / V am 24.05. im T S1", -]; - -export const eintraege = [ - new Eintrag("GET 2 / Ü", [ - new Termin("Mo", "AM S4", "12:00", "13:00"), - new Termin("Fr", "AM S4", "11:30", "13:00") - ]), - new Eintrag("GET 2 / V", [ - new Termin("Di", "H1", "08:30", "10:00"), - new Termin("Do", "Z 1/2", "08:30", "10:00") - ]), - new Eintrag("TGI 1 / V", [ - new Termin("Mi", "AM 1", "08:15", "09:45"), - ]), - new Eintrag("TGI 1 / Ü", [ - new Termin("Do", "AM 1", "15:00", "16:00"), - ]), - new Eintrag("TGI 1 / Prak. Gr. 2", [ - new Termin("Di", "ITI 131", "14:30", "17:30"), - ]), - new Eintrag("Pho / V", [ - new Termin("Fr", "T 1", "08:30", "10:00"), - ]), - new Eintrag("Pho / Ü", [ - new Termin("Mi", "AM 1", "12:00", "13:00"), - ]), - new Eintrag("Ana 2 / V", [ - new Termin("Di", "AM 1", "12:30", "14:00"), - ]), - new Eintrag("Ana 2 / Ü", [ - new Termin("Do", "H 1", "16:15", "17:15"), - ]), - new Eintrag("Ana 2 / Helpdesk", [ - new Termin("Di", "O-Sync", "18:00", "19:00"), - new Termin("Mi", "O-Sync", "18:00", "19:00") - ]), - new Eintrag("EiBMO / V", [ - new Termin("Mi", "H 1", "14:00", "16:00"), - ]), - new Eintrag("EiBMO / Ü", [ - new Termin("Mi", "H 1", "16:00", "17:00"), - ]), - new Eintrag("FuQ / V", [ - new Termin("Fr", "AM 4", "10:00", "11:30"), - ]), - new Eintrag("FuQ / Ü", [ - new Termin("Di", "SI 4 (Minsky)", "11:00", "12:00"), - ]), - new Eintrag("BLOCKED", [ - new Termin("Mo", "BLOCKED", "13:00", "19:00"), - new Termin("Do", "BLOCKED", "10:00", "15:00") - ]) -]; - -// You may touch this, if you know what you are doing -export const style = ` - -`; -- cgit v1.2.3