Files
Timetable-V2/server/parser/bolle.js
2023-06-02 21:14:33 +02:00

86 lines
2.6 KiB
JavaScript

import axios from "axios";
import crypto from "node:crypto";
import { log } from "../logs.js";
/*
This BOLLE (https://bolle-software.de/) parser tries to download
the latest substitution plan HTML files from the "Pinnwand".
It uses the same API that the mobile app (v0.3.6) uses.
To get your login credentials you need to log into your BOLLE account
and register a new device in the settings (/einstellungen/geraete_personal).
Click on "Manuelle Logindaten Einblenden" and use "ID" as apiUser
and "Token" as apiKey. You need to make at least one request with
this API token before closing the registration window or else the
token will be invalidated immediately.
*/
// Files to download from the "Pinnwand"
const filenames = ["vp_heute", "vp_morgen"];
export class BolleClient {
constructor(bolleInstance, apiUser, apiKey) {
this.bolleInstance = bolleInstance;
this.apiUser = apiUser;
this.apiKey = apiKey;
}
async getFiles() {
try {
let contents = [];
for (let file of filenames) {
contents.push(await this.getFile(file));
}
return contents;
} catch (error) {
log("Parser / Bolle", "Error getting data: " + error);
return [];
}
}
async getFile(filename) {
// Generate the BOLLE api payload
let payload = {
api_payload: JSON.stringify({
method: "vertretungsplan_html",
payload: { content: filename },
}),
};
// Generate request headers
let headers = this.buildRequestHeaders(payload.api_payload);
// Send the POST request
let response = await axios.post(this.getRequestUrl(), payload, {
headers,
});
// The server responds with a json object
// containing the base64 encoded html data
let base64 = response.data["html_base64"];
// Decode the base64 data using the latin1 (ISO 8859-1) character set
return Buffer.from(base64, "base64").toString("latin1");
}
getRequestUrl() {
// The API that the bolle mobile app uses is available at /app/basic
return `https://${this.bolleInstance}/app/basic`;
}
buildRequestHeaders(payload) {
// Bolle needs the sha1 hash of the payload
// to be set as the "b-hash" header
let hash = crypto.createHash("sha1");
hash.update(payload);
return {
Accept: "application/json",
// Set the auth headers
"X-Auth-User": this.apiUser,
"X-Auth-Token": this.apiKey,
"App-Version": "4",
// Set the hash
"B-Hash": hash.digest("hex"),
"Content-Type": "application/json",
Connection: "Keep-Alive",
"Accept-Encoding": "gzip",
"User-Agent": "okhttp/4.9.2",
};
}
}