From 688d0ae5d89b8ecef31a197ef4bbdcdf9dfaa3ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20R=C3=BCmpelein?= Date: Fri, 2 Dec 2016 12:46:39 +0100 Subject: [PATCH] Initial getting from fsinfoscreen. --- .gitignore | 1 + dub.json | 14 +++++++ source/app.d | 90 +++++++++++++++++++++++++++++++++++++++++++ source/substitution.d | 35 +++++++++++++++++ 4 files changed, 140 insertions(+) create mode 100644 .gitignore create mode 100644 dub.json create mode 100644 source/app.d create mode 100644 source/substitution.d diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96fa1c5 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bayernfahrplan diff --git a/dub.json b/dub.json new file mode 100644 index 0000000..d5076dd --- /dev/null +++ b/dub.json @@ -0,0 +1,14 @@ +{ + "name": "bayernfahrplan", + "authors": [ + "Johannes Loher", + "Oliver Rümpelein" + ], + "dependencies": { + "requests": "~>0.3.1", + "kxml": "~>1.0.1" + }, + "description": "A minimal D application.", + "copyright": "Copyright © 2016, Johannes Loher", + "license": "proprietary" +} diff --git a/source/app.d b/source/app.d new file mode 100644 index 0000000..e3b76eb --- /dev/null +++ b/source/app.d @@ -0,0 +1,90 @@ +import std.algorithm : filter, map, startsWith; +import std.array : array, empty, front, replace; +import std.conv : to; +import std.datetime : dur, TimeOfDay, Clock; +import std.getopt : defaultGetoptPrinter, getopt; +import std.json : JSONValue; +import std.regex : ctRegex, matchAll; +import std.stdio : File, stdout, writeln; +import std.string : strip; +import std.typecons : tuple; +import std.format : format; + +import kxml.xml : readDocument, XmlNode; + +import requests : postContent; + +import substitution; + +auto parseTime(in string input) +{ + auto matches = matchAll(input, ctRegex!(`(?P\d+):(?P\d+)`)); + auto actualTime = TimeOfDay(matches.front["hours"].to!int, matches.front["minutes"].to!int); + matches.popFront; + if (!matches.empty) + { + auto expectedTime = TimeOfDay(matches.front["hours"].to!int, + matches.front["minutes"].to!int); + return tuple(expectedTime, actualTime - expectedTime); + + } + return tuple(actualTime, dur!"minutes"(0)); +} + +auto getRowContents(XmlNode[] rows) +{ + return rows.map!(row => row.parseXPath("//td")[1 .. $ - 1].map!((column) { + auto link = column.parseXPath("//a"); + if (!link.empty) + return link.front.getCData.replace("...", ""); + return column.getCData;})); +} + +void main(string[] args) +{ + string fileName; + string busStop = "Universität Regensburg"; + string substitutionFileName = "replacement.txt"; + auto helpInformation = getopt(args, + "file|f", "The file that the data is written to.", &fileName, + "stop|s", "The bus stop for which to fetch data.", &busStop, + "replacement-file|r", "The file that contais the direction name replacement info.", &substitutionFileName); + if (helpInformation.helpWanted) + { + defaultGetoptPrinter("Some information about the program.", helpInformation.options); + return; + } + + auto content = postContent("http://txt.bayern-fahrplan.de/textversion/bcl_abfahrtstafel", + ["limit" : "20", + "useRealtime" : "1", + "name_dm" : busStop, + "mode" : "direct", + "type_dm" : "any", + "itdLPxx_bcl" : "true"]); + + auto currentTime = Clock.currTime; + loadSubstitutionFile(substitutionFileName); + JSONValue j = ["time" : "%02s:%02s".format(currentTime.hour, currentTime.minute)]; + j.object["departures"] = readDocument(cast(string) content.data) + .parseXPath(`//table[@id="departureMonitor"]/tbody/tr`)[1 .. $] + .getRowContents + .filter!(row => !row.empty) + .map!(a => ["departure" : a[0].parseTime[0].to!string[0 .. $ - 3], + "delay" : a[0].parseTime[1].total!"minutes".to!string, + "line" : a[1], + "direction" : a[2].substitute]) + .array.JSONValue; + + if (fileName !is null) + { + auto output = File(fileName, "w"); + scope(exit) output.close; + output.writeln(j.toPrettyString.replace("\\/", "/")); + } + else + { + j.toPrettyString.replace("\\/", "/").writeln; + } + +} diff --git a/source/substitution.d b/source/substitution.d new file mode 100644 index 0000000..0937dc2 --- /dev/null +++ b/source/substitution.d @@ -0,0 +1,35 @@ +module substitution; + +public: + +void loadSubstitutionFile(string fileName) +{ + import std.file : slurp, exists, isFile; + import std.array : assocArray; + import std.algorithm.iteration : each; + + if (fileName.exists && fileName.isFile) + { + auto data = slurp!(string, string)(fileName, `"%s" = "%s"`); + map = (string[string]).init; + data.each!(pair => map[pair[0]] = pair[1]); + foreach (pair; data) + { + map[pair[0]] = pair[1]; + } + map.rehash; + } + else + { + map = (string[string]).init; + } +} + +auto substitute(string s) +{ + return s in map ? map[s] : s; +} + +private: + +string[string] map;