All Downloads are FREE. Search and download functionalities are using the official Maven repository.

me.vertretungsplan.parser.DSBLightParser Maven / Gradle / Ivy

/*
 * substitution-schedule-parser - Java library for parsing schools' substitution schedules
 * Copyright (c) 2016 Johan v. Forstner
 *
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

package me.vertretungsplan.parser;

import me.vertretungsplan.exception.CredentialInvalidException;
import me.vertretungsplan.objects.SubstitutionSchedule;
import me.vertretungsplan.objects.SubstitutionScheduleData;
import me.vertretungsplan.objects.credential.UserPasswordCredential;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpResponseException;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Connection;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.FormElement;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Parser for Untis substitution schedules served by
 * DSBlight. Supports both password-protected and public
 * schedules.
 * 

* It seems that the "light" version of DSB is discontinued, many schools are currently switching to the newer * DSBmobile (which can be parsed with {@link DSBMobileParser}. *

* This parser can be accessed using "dsblight" for {@link SubstitutionScheduleData#setApi(String)}. * *

Configuration parameters

* These parameters can be supplied in {@link SubstitutionScheduleData#setData(JSONObject)} to configure the parser: * *
*
id (String, required)
*
The ID of the DSBlight instance. This is a * UUID and can be found in the URL * (Player.aspx?ID=...)
* *
classes (Array of Strings, required)
*
The list of all classes, as they can appear in the schedule
* *
encoding (String, required)
*
The charset of the Untis schedule. DSBlight itself always uses UTF-8, but the hosted HTML schedule can * also be ISO-8859-1.
* *
login (Boolean, optional, Default: false)
*
Whether this DSBlight instance requires login using a username and a password.
* *
baseurl (String, optional, Default: https://light.dsbcontrol * .de/DSBlightWebsite/Homepage/)
*
URL where this DSBlight instance is located
* *
iframeIndex (Integer, optional)
*
If this is set, the content of only one of the displayed iframes is used
*
* * Additionally, this parser supports the parameters specified in {@link UntisCommonParser} and {@link LoginHandler} * (the latter as an alternative to the Boolean login parameter defined here). * * For password protected schedules, you have to use a * {@link me.vertretungsplan.objects.authentication.UserPasswordAuthenticationData}. */ public class DSBLightParser extends UntisCommonParser { private static final String BASE_URL = "https://light.dsbcontrol.de/DSBlightWebsite/Homepage/"; private static final String ENCODING = "UTF-8"; private static final String PARAM_ID = "id"; private static final String PARAM_LOGIN = "login"; private static final String PARAM_CLASSES = "classes"; private static final String PARAM_ENCODING = "encoding"; private static final String PARAM_BASEURL = "baseurl"; private static final String PARAM_IFRAME_INDEX = "iframeIndex"; private JSONObject data; public DSBLightParser(SubstitutionScheduleData scheduleData, CookieProvider cookieProvider) { super(scheduleData, cookieProvider); data = scheduleData.getData(); } @Override public SubstitutionSchedule getSubstitutionSchedule() throws IOException, JSONException, CredentialInvalidException { String id = data.getString(PARAM_ID); SubstitutionSchedule v = SubstitutionSchedule.fromData(scheduleData); Map referer = new HashMap<>(); String baseUrl = data.optString(PARAM_BASEURL, BASE_URL); referer.put("Referer", baseUrl + "/Player.aspx?ID=" + id); String response = httpGet(baseUrl + "/Player.aspx?ID=" + id, ENCODING, referer); Document doc = Jsoup.parse(response); // IFrame.aspx String iframeUrl = doc.select("iframe").first().attr("src"); response = httpGet(iframeUrl, ENCODING, referer); doc = Jsoup.parse(response); if (data.has(PARAM_LOGIN) && data.get(PARAM_LOGIN) instanceof Boolean && data.getBoolean(PARAM_LOGIN)) { if (!(credential instanceof UserPasswordCredential)) { throw new IllegalArgumentException("no login"); } String username = ((UserPasswordCredential) credential).getUsername(); String password = ((UserPasswordCredential) credential).getPassword(); List params = new ArrayList<>(); params.add(new BasicNameValuePair("__VIEWSTATE", doc.select( "#__VIEWSTATE").attr("value"))); params.add(new BasicNameValuePair("__VIEWSTATEGENERATOR", doc.select( "#__VIEWSTATEGENERATOR").attr("value"))); params.add(new BasicNameValuePair("__EVENTVALIDATION", doc.select( "#__EVENTVALIDATION").attr("value"))); params.add(new BasicNameValuePair("ctl02$txtBenutzername", username)); params.add(new BasicNameValuePair("ctl02$txtPasswort", password)); params.add(new BasicNameValuePair("ctl02$btnLogin", "weiter")); response = httpPost(iframeUrl, ENCODING, params, referer); doc = Jsoup.parse(response); if (doc.select("#ctl02_lblLoginFehlgeschlagen").size() > 0) throw new CredentialInvalidException(); } else if (data.has(PARAM_LOGIN) && data.get(PARAM_LOGIN) instanceof JSONObject) { new LoginHandler(scheduleData, credential, cookieProvider).handleLogin(executor, cookieStore); } Elements iframes = doc.select("iframe"); if (data.has(PARAM_IFRAME_INDEX)) { parsePreProgram(v, referer, iframes.get(data.getInt(PARAM_IFRAME_INDEX))); } else { for (Element iframe : iframes) { parsePreProgram(v, referer, iframe); } } v.setClasses(getAllClasses()); v.setTeachers(getAllTeachers()); v.setWebsite(baseUrl + "/Player.aspx?ID=" + id); return v; } private void parsePreProgram(SubstitutionSchedule v, Map referer, Element iframe) throws IOException, CredentialInvalidException, JSONException { Pattern regex = Pattern.compile("location\\.href=\"([^\"]*)\""); // PreProgram.aspx String response2 = httpGet(iframe.attr("src"), ENCODING, referer); Matcher matcher = regex.matcher(response2); if (matcher.find()) { // Program.aspx String url = matcher.group(1); parseProgram(url, v, referer); } else { throw new IOException("URL nicht gefunden"); } } private void parseProgram(String url, SubstitutionSchedule schedule, Map referer) throws IOException, JSONException, CredentialInvalidException { String response = httpGet(url, ENCODING, referer); parseProgram(url, response, schedule, referer, null); } private void parseProgram(String url, String html, SubstitutionSchedule schedule, Map referer, String firstUrl) throws IOException, JSONException, CredentialInvalidException { Document doc = Jsoup.parse(html, url); if (doc.select("iframe").attr("src").equals(firstUrl) || doc.select("iframe").size() == 0) { return; } for (Element iframe : doc.select("iframe")) { // Data parseDay(iframe.attr("src"), referer, schedule, iframe.attr("src")); } if (firstUrl == null) { firstUrl = doc.select("iframe").attr("src"); } if (doc.select("#hlNext").size() > 0) { String nextUrl = doc.select("#hlNext").first().attr("abs:href"); try { String response = httpGet(nextUrl, ENCODING, referer); parseProgram(response, nextUrl, schedule, referer, firstUrl); } catch (HttpResponseException ignored) { } } if (html.contains("Timer1")) { List formData = ((FormElement) doc.select("form").first()).formData(); List formParams = new ArrayList<>(); for (Connection.KeyVal kv:formData) { formParams.add(new BasicNameValuePair(kv.key(), kv.value())); } formParams.add(new BasicNameValuePair("__EVENTTARGET", "Timer1")); formParams.add(new BasicNameValuePair("__EVENTARGUMENT", "")); String response = httpPost(url, ENCODING, formParams, referer); parseProgram(url, response, schedule, referer, firstUrl); } } private void parseDay(String url, Map referer, SubstitutionSchedule schedule, String startUrl) throws IOException, JSONException, CredentialInvalidException { String html = httpGet(url, data.optString(PARAM_ENCODING, null), referer); Document doc = Jsoup.parse(html); if (doc.title().toLowerCase().contains("untis") || doc.html().toLowerCase().contains("untis") || doc.select(".mon_list").size() > 0) { parseMultipleMonitorDays(schedule, doc, data); if (doc.select("meta[http-equiv=refresh]").size() > 0) { Element meta = doc.select("meta[http-equiv=refresh]").first(); String attr = meta.attr("content").toLowerCase(); String redirectUrl = url.substring(0, url.lastIndexOf("/") + 1) + attr.substring(attr.indexOf("url=") + 4); if (!redirectUrl.equals(startUrl)) { parseDay(redirectUrl, referer, schedule, startUrl); } } } } @Override public List getAllClasses() throws IOException, JSONException { return getClassesFromJson(); } @Override public List getAllTeachers() { return null; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy