1
0

Compare commits

..

38 Commits

Author SHA1 Message Date
0ec0d9164e Version 0.7 2020-09-21 16:22:40 +02:00
678d00a57b Ignore rows not containing any collectable data 2020-09-20 19:55:03 +02:00
7b3e750513 Change product naming scheme to match marudor 2020-09-20 15:51:31 +02:00
a216984bb4 Comment station links 2020-09-20 13:07:49 +02:00
7df84bca5c Link to self-signed downloads 2020-09-20 13:03:00 +02:00
60ae28c9d3 Train link to dbf 2020-09-19 23:35:59 +02:00
c0f50dfe3e Move timestamp to date object 2020-09-19 23:35:35 +02:00
5c89d26691 Add train id to data 2020-09-19 23:06:19 +02:00
efec9271c3 Linking to trains with timestamp 2020-09-19 23:02:42 +02:00
68301c44d4 Add Firefox install url 2020-09-19 22:26:01 +02:00
6e3e3eb8e8 Prevent multiple injections 2020-09-19 22:12:02 +02:00
b5b6431662 Fix name in license *ooops* 2020-09-19 21:52:48 +02:00
fbaec27ed7 Version 0.6 2020-09-19 21:48:12 +02:00
76febca006 Add dbf.finalrewind.org to linked pages 2020-09-19 21:43:42 +02:00
48056a0380 Match icon sizes to values already used by bahn.de 2020-09-19 21:43:14 +02:00
33cd61e116 Rewrite injection process and pack all added elements into containers 2020-09-19 21:42:11 +02:00
d9fa338813 Log current stage to console 2020-09-19 21:38:23 +02:00
650bed8348 Fix detection if current time is shown 2020-09-19 20:59:27 +02:00
b6f6f65c63 Comment data collection section 2020-09-19 20:22:08 +02:00
60c24d8a5e Comment functions 2020-09-19 20:17:36 +02:00
4efc000794 Comment structure 2020-09-19 20:11:06 +02:00
357fff97f2 Create object containing all data for connection 2020-09-19 20:09:43 +02:00
0d16660d97 Version 0.5 2020-09-16 15:05:31 +02:00
6789e044ed Fix linebreaks in train names 2020-09-16 15:05:04 +02:00
8cd52728c8 Button with target _blank again 2020-09-16 14:55:46 +02:00
6c9bd60235 Version 0.4 2020-09-16 14:53:39 +02:00
bf884ac39c Replace innerHTML hack with proper DOM manipulation 2020-09-16 14:53:04 +02:00
d3d1aeecd8 Refactor code and renaming vars 2020-09-16 14:22:10 +02:00
83feb9af10 Rename to connection_result_observer 2020-09-16 14:19:31 +02:00
d4d97d899d Mind multiple train names for one train 2020-09-16 14:18:20 +02:00
0c17dfc94f Clean train name string before parsing 2020-09-16 14:16:47 +02:00
a4c68ec801 Version 0.3 2020-09-16 13:48:12 +02:00
2ecf1b59af Exclude specific products from parsing as train name 2020-09-16 13:45:43 +02:00
c2d96c6a98 Fixed readme 2020-09-16 13:25:10 +02:00
b426fb304e Version 0.2 2020-09-16 13:18:17 +02:00
69da0d3652 Cleanup trains names before generating links 2020-09-16 13:17:49 +02:00
373e56eb68 Observe only if there are any results 2020-09-16 13:03:05 +02:00
a9d7a3bcc0 Cleaning up code 2020-09-16 12:47:22 +02:00
5 changed files with 312 additions and 34 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017 marudor
Copyright (c) 2020 clerie
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -4,14 +4,19 @@ Extends the booking portal of bahn.de with linking to useful information.
## Installation
### Aus Firefox Add-ons (Empfohlen)
Einfach zu Firefox hinzufügen:
TBD
https://addons.mozilla.org/firefox/addon/bahn-insight/
### Self-signed binarys
Because Mozilla isn't as fast anymore at reviewing addons you can download the self-signed Versions here:
https://clerie.de/bahn-insight/
### Als Entwicklerversion
1. Herunterladen
2. Entpacken
3. In Firefox nach `about:debugging` navigieren
4. Add-on temporär laden
5. YouTube aufrufen
Die Installation besteht nur während der aktuellen Session.

View File

@@ -7,40 +7,313 @@ function getMediaURL(path) {
return chrome.runtime.getURL(path) || browser.runtime.getURL(path);
}
/**
* Return train name in format "PRODUCT TRAIN_NUMER"
* i.e. "ICE 112", "RE 12734"
* Sometimes train name is in format "PRODUCT LINE_NUMER (TRAIN_NUMER)"
* i.e. "STB 12 (62371)"
* Sometimes 'trains' are not trains or we can't find an unique id for them
* i.e. busses, ferrys, trams
* they will also be cleaned up and returned as undefined, because we can't link to them correctly
*/
function bahnParseTrainName(dirty_train_name) {
var name_list = dirty_train_name.trim().replace(/ +/g, ' ').split(" ");
// Train name in format "STB 12 (23561)"
if(name_list.length == 3 && name_list[2].charAt(0) == '(' && name_list[2].charAt(name_list[2].length-1) == ')') {
return name_list[0] + " " + name_list[2].substring(1, name_list[2].length-1);
}
// Exclude linking to specific products
if(["bus", "fäh", "str"].indexOf(name_list[0].toLowerCase()) !== -1) {
return undefined;
}
return dirty_train_name;
}
/**
* Returns date string in format YYYYMMDDHHMM
*
* @param datetime Date object
*/
function datetimeToYYYYMMDDHHMM(datetime) {
return datetime.getFullYear().toString().padStart(4, '0') + "" + (datetime.getMonth()+1).toString().padStart(2, '0') + "" + datetime.getDate().toString().padStart(2, '0') + "" + datetime.getHours().toString().padStart(2, '0') + "" + datetime.getMinutes().toString().padStart(2, '0')
}
/**
* Returns HTML a as DOM object
*
* @param href URI as string
*/
function domCreateLink(href) {
var link = document.createElement("a");
link.setAttribute("href", href);
return link;
}
/**
* Returns HTML img as DOM object
*
* @param src Image URI as string
*/
function domCreateImage(src) {
var image = document.createElement("img");
image.setAttribute("src", src);
return image;
}
/**
* Returns HTML br as DOM object
*/
function domCreateLinebreak() {
var linebreak = document.createElement("br");
return linebreak;
}
/**
* Returns HTML span as DOM object
*/
function domCreateSpan() {
var span = document.createElement("span");
return span;
}
/**
* Returns an 'image button' like construct as DOM object
*
* @param href URI as string
* @param image_src Image URI as string
*/
function domCreateButton(href, image_src) {
var link = domCreateLink(href);
link.setAttribute("target", "_blank");
var image = domCreateImage(image_src);
image.setAttribute("style", "height: 16px; vertical-align:middle;");
link.append(image);
return link;
}
/**
* Returns an 'image buttom' to specifically link to marudor.de
*
* @param path URL path part after https://marudor.de
*/
function domCreateButtonMarudor(path) {
var button = domCreateButton("https://marudor.de" + path, getMediaURL("marudor.svg"));
button.setAttribute("title", "marudor.de");
return button;
}
/**
* Returns an 'image buttom' to specifically link to dbf.finalrewind.org
*
* @param path URL path part after https://dbf.finalrewind.org
*/
function domCreateButtonDbf(path) {
var button = domCreateButton("https://dbf.finalrewind.org" + path, getMediaURL("dbf.png"));
button.setAttribute("title", "dbf.finalrewind.org");
return button;
}
/**
* Returns a 'bahn-insight' element as DOM object
*
* Used to determine if this is an object set by this extension itself
*/
function domCreateBahnInsightField() {
var span = domCreateSpan();
span.setAttribute("class", "bahn-insight");
return span;
}
var connection_result_observer = new MutationObserver((mutations) => {
log("change detected")
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
var target = mutation.target;
if (target.tagName === 'TD') {
log("change is interesting");
var timetable = target.querySelector("td div.detailContainer table.result tbody");
// Just break if there are elements injected by us
if(timetable.querySelectorAll(".bahn-insight").length != 0) {
log("links already injected")
return;
}
/*
* COLLECT DATA
*/
var data = [];
var relations = timetable.querySelectorAll("tr.first");
relations.forEach((relation, i) => {
var relationend = relation.nextElementSibling;
while(relationend.querySelector("td.station") == null) {
relationend = relationend.nextElementSibling;
}
data[i] = {};
data[i]["from"] = {}
data[i]["to"] = {}
// Depature station name
var relation_from = relation.querySelector("td.station");
data[i]["from"]["station"] = relation_from.innerText;
// Arrival station name
var relation_to = relationend.querySelector("td.station");
data[i]["to"]["station"] = relation_to.innerText;
// Departure time & current estimation
var relation_departure = relation.querySelector("td.time");
var relation_departure_list = relation_departure.firstChild.textContent.trim().split(" ");
data[i]["from"]["time"] = relation_departure_list[1];
data[i]["from"]["time_current"] = null;
var relation_departure_current = relation_departure.querySelector("span.delay, span.delayOnTime");
if(relation_departure_current != null) {
data[i]["from"]["time_current"] = relation_departure_current.innerText.trim();
}
// Arrival time & current estimation
var relation_arrival = relationend.querySelector("td.time");
var relation_arrival_list = relation_arrival.firstChild.textContent.trim().split(" ");
data[i]["to"]["time"] = relation_arrival_list[1];
data[i]["to"]["time_current"] = null;
var relation_arrival_current = relation_arrival.querySelector("span.delay, span.delayOnTime");
if(relation_arrival_current != null) {
data[i]["to"]["time_current"] = relation_arrival_current.innerText.trim();
}
// Departure platform
var relation_platform = relation.querySelector("td.platform");
data[i]["from"]["platform"] = relation_platform.innerText;
// Arrival platform
var relation_to_platform = relationend.querySelector("td.platform");
data[i]["to"]["platform"] = relation_to_platform.innerText;
// Travel products
var relation_products = relation.querySelector("td.products");
data[i]["products"] = [];
// Fetch all products for this travel
var relation_trains = relation_products.querySelectorAll("span a");
relation_trains.forEach((train, j) => {
data[i]["products"][j] = {};
// Prodcut details
data[i]["products"][j]["type"] = null;
data[i]["products"][j]["train_number"] = null;
data[i]["products"][j]["train_name"] = null;
data[i]["products"][j]["line_name"] = null;
var name_list = train.innerText.trim().replace(/ +/g, ' ').split(" ");
// Product name in format "STB 12 (23561)"
if(name_list.length == 3 && name_list[2].charAt(0) == '(' && name_list[2].charAt(name_list[2].length-1) == ')') {
data[i]["products"][j]["type"] = name_list[0];
data[i]["products"][j]["train_number"] = name_list[2].substring(1, name_list[2].length-1)
data[i]["products"][j]["line_name"] = name_list[0] + " " + name_list[1];
}
// Product name in format "ICE 234"
else {
data[i]["products"][j]["type"] = name_list[0];
data[i]["products"][j]["train_number"] = name_list[1];
}
data[i]["products"][j]["train_name"] = data[i]["products"][j]["type"] + " " + data[i]["products"][j]["train_number"];
});
// Travel information
var relation_items = relation.querySelectorAll("td");
var relation_info = relation_items[relation_items.length-1];
data[i]["info"] = relation_info.innerText;
});
log("data collected");
console.log(data);
/*
* INJECT CUSTOM UI
*/
var relations = timetable.querySelectorAll("tr.first");
relations.forEach((relation, i) => {
var relationend = relation.nextElementSibling;
while(relationend.querySelector("td.station") == null) {
relationend = relationend.nextElementSibling;
}
var products = relation.querySelectorAll("td.products span a");
products.forEach((product, j) => {
// Field for 'bahn-insight' stuff
var bahn_insight_field = domCreateBahnInsightField();
product.after(bahn_insight_field);
var departure_time = new Date(Date.parse(connection_result_date + " " + data[i]["from"]["time"]));
// Button linking to marudor.de
var marudor_button = domCreateButtonMarudor("/details/" + data[i]["products"][j]["train_name"] + "/" + departure_time.getTime());
bahn_insight_field.appendChild(marudor_button);
var dbf_button = domCreateButtonDbf("/_wr/" + data[i]["products"][j]["train_number"] + "/" + datetimeToYYYYMMDDHHMM(departure_time));
bahn_insight_field.appendChild(dbf_button);
// Move linebreaks from link inner, after our 'bahn-insight' field
var linebreaks = product.querySelectorAll("br");
if(linebreaks.length != 0) {
linebreaks.forEach((linebreak) => {
product.removeChild(linebreak);
});
bahn_insight_field.after(domCreateLinebreak());
}
});
// Linking to station
var from = relation.querySelector("td.station");
var bahn_insight_field = domCreateBahnInsightField();
from.appendChild(bahn_insight_field);
var marudor_button = domCreateButtonMarudor("/" + data[i]["from"]["station"]);
bahn_insight_field.appendChild(marudor_button);
var dbf_button = domCreateButtonDbf("/" + data[i]["from"]["station"]);
bahn_insight_field.appendChild(dbf_button);
// Linking to station
var to = relationend.querySelector("td.station");
var bahn_insight_field = domCreateBahnInsightField();
to.appendChild(bahn_insight_field);
var marudor_button = domCreateButtonMarudor("/" + data[i]["to"]["station"]);
bahn_insight_field.appendChild(marudor_button);
var dbf_button = domCreateButtonDbf("/" + data[i]["to"]["station"]);
bahn_insight_field.appendChild(dbf_button);
});
log("ui injected");
}
}
});
});
log("Bahn Insight loaded");
var target = document.getElementById('resultsOverview');
log("target");
console.log(target);
if(typeof target !== 'undefined') {
var observer = new MutationObserver((mutations, observer) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList') {
// Changed object
var target = mutation.target;
if (target.tagName === 'TD') {
var timetable = target.querySelector("td div.detailContainer table.result tbody");
var products = timetable.querySelectorAll("tr.first td.products");
products.forEach((product) => {
var train_name = product.querySelector("span a").innerText;
product.innerHTML = product.innerHTML + ' <a href="https://marudor.de/details/' + train_name + '" target="_blank"><img src="' + getMediaURL("marudor.svg") + '" style="height: 2em; vertical-align:middle;"></a>';
log("added to");
console.log(product);
});
var stations = timetable.querySelectorAll("tr td.station");
stations.forEach((station) => {
var station_name = station.innerText;
station.innerHTML = station.innerHTML + ' <a href="https://marudor.de/' + station_name + '" target="_blank"><img src="' + getMediaURL("marudor.svg") + '" style="height: 2em; vertical-align:middle;"></a>';
});
var connection_result_date = document.querySelector("html body div div div.resultContentHolder form div h2 span").innerText.replace(/(\d{2})\.(\d{2})\.(\d{2})/,'20$3-$2-$1');
}
}
});
});
connection_result_observer.observe(target, {
subtree: true,
childList: true
});
observer.observe(target, {
subtree: true,
childList: true
});
log("observation started")
}

View File

@@ -2,7 +2,7 @@
"manifest_version": 2,
"name": "Bahn Insight",
"version": "0.1",
"version": "0.7",
"description": "Extends the booking portal of bahn.de with linking to useful information.",
"homepage_url": "https://git.clerie.de/clerie/bahn-insight/",

BIN
media/dbf.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B