✨ Add support for BOLLE
This commit is contained in:
85
server/parser/bolle.js
Normal file
85
server/parser/bolle.js
Normal file
@ -0,0 +1,85 @@
|
||||
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",
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user