bahn.de+

Zeigt durchschnittliche Verspätung (by zugfinder.de) und den vorrausichtlich eingesetzten Zugtyp für durch die DB betriebene Fernverkehrszüge an

  1. // ==UserScript==
  2. // @name bahn.de+
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0.0
  5. // @description Zeigt durchschnittliche Verspätung (by zugfinder.de) und den vorrausichtlich eingesetzten Zugtyp für durch die DB betriebene Fernverkehrszüge an
  6. // @author kingjan1999
  7. // @match *://reiseauskunft.bahn.de/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_addStyle
  10. // @connect zugfinder.de
  11. // @connect grahnert.de
  12. // @require https://code.jquery.com/jquery-3.3.1.min.js
  13. // @require https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js
  14. // ==/UserScript==
  15. (function () {
  16. /******/ (function(modules) { // webpackBootstrap
  17. /******/ // The module cache
  18. /******/ var installedModules = {};
  19. /******/
  20. /******/ // The require function
  21. /******/ function __webpack_require__(moduleId) {
  22. /******/
  23. /******/ // Check if module is in cache
  24. /******/ if(installedModules[moduleId]) {
  25. /******/ return installedModules[moduleId].exports;
  26. /******/ }
  27. /******/ // Create a new module (and put it into the cache)
  28. /******/ var module = installedModules[moduleId] = {
  29. /******/ i: moduleId,
  30. /******/ l: false,
  31. /******/ exports: {}
  32. /******/ };
  33. /******/
  34. /******/ // Execute the module function
  35. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  36. /******/
  37. /******/ // Flag the module as loaded
  38. /******/ module.l = true;
  39. /******/
  40. /******/ // Return the exports of the module
  41. /******/ return module.exports;
  42. /******/ }
  43. /******/
  44. /******/
  45. /******/ // expose the modules object (__webpack_modules__)
  46. /******/ __webpack_require__.m = modules;
  47. /******/
  48. /******/ // expose the module cache
  49. /******/ __webpack_require__.c = installedModules;
  50. /******/
  51. /******/ // define getter function for harmony exports
  52. /******/ __webpack_require__.d = function(exports, name, getter) {
  53. /******/ if(!__webpack_require__.o(exports, name)) {
  54. /******/ Object.defineProperty(exports, name, {
  55. /******/ configurable: false,
  56. /******/ enumerable: true,
  57. /******/ get: getter
  58. /******/ });
  59. /******/ }
  60. /******/ };
  61. /******/
  62. /******/ // getDefaultExport function for compatibility with non-harmony modules
  63. /******/ __webpack_require__.n = function(module) {
  64. /******/ var getter = module && module.__esModule ?
  65. /******/ function getDefault() { return module['default']; } :
  66. /******/ function getModuleExports() { return module; };
  67. /******/ __webpack_require__.d(getter, 'a', getter);
  68. /******/ return getter;
  69. /******/ };
  70. /******/
  71. /******/ // Object.prototype.hasOwnProperty.call
  72. /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  73. /******/
  74. /******/ // __webpack_public_path__
  75. /******/ __webpack_require__.p = "";
  76. /******/
  77. /******/ // Load entry module and return exports
  78. /******/ return __webpack_require__(__webpack_require__.s = 0);
  79. /******/ })
  80. /************************************************************************/
  81. /******/ ([
  82. /* 0 */
  83. /***/ (function(module, exports, __webpack_require__) {
  84.  
  85. module.exports = __webpack_require__(1);
  86.  
  87.  
  88. /***/ }),
  89. /* 1 */
  90. /***/ (function(module, exports, __webpack_require__) {
  91.  
  92. "use strict";
  93.  
  94.  
  95. var _Zugfinder = __webpack_require__(2);
  96.  
  97. var _States = _interopRequireDefault(__webpack_require__(3));
  98.  
  99. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  100.  
  101. GM_addStyle(_States.default.toString());
  102. $(function () {
  103. $("tr.details ").bind("DOMSubtreeModified", function () {
  104. $(this).find(".products").each(function () {
  105. var item = $(this);
  106.  
  107. if (item.hasClass("erledigt")) {
  108. return;
  109. }
  110.  
  111. item.addClass("erledigt");
  112. var product = item.text().replace(/ +(?= )/g, '');
  113. product = product.replace(/^\s+|\s+$/g, '');
  114.  
  115. if (product !== 'Produkte' && product.trim().length > 1) {
  116. console.log("Produkt: " + product); // Hier haben wir die Zugnummer
  117.  
  118. var fernverkehr_regex = /(IC|ICE|EC|EN|RJ)\s[0-9]+/g;
  119.  
  120. if (product.match(fernverkehr_regex) !== null) {
  121. if (product.match(fernverkehr_regex).length > 1) {
  122. // mehrere Zugnummer (z.B. ICE 633 ICE 683)
  123. product = product.match(fernverkehr_regex)[0];
  124. }
  125.  
  126. var zugnummer = product.split(" ")[1];
  127. console.log(zugnummer);
  128. console.log("Fernverkehr!");
  129. (0, _Zugfinder.resolveZugTyp)(product).then(function (typ) {
  130. if (typ) {
  131. item.append("<br /> Zugtyp (vorraus.): " + typ);
  132. }
  133. });
  134. (0, _Zugfinder.resolveDelay)(product).then(function (_ref) {
  135. var average = _ref.average,
  136. quote = _ref.quote;
  137. var quote_zahl = parseInt(quote);
  138.  
  139. if (quote_zahl > 95) {
  140. item.addClass("immer_puenktlich");
  141. } else if (quote_zahl >= 90) {
  142. item.addClass("fast_puenktlich");
  143. } else if (quote_zahl >= 80) {
  144. item.addClass("puenktlich");
  145. } else if (quote_zahl >= 70) {
  146. item.addClass("leicht_unpuenktlich");
  147. } else if (quote_zahl < 70) {
  148. item.addClass("unpuenktlich");
  149. }
  150.  
  151. if (average.length > 0) {
  152. item.append("<br /> &empty; Verspätung: " + average);
  153. }
  154.  
  155. if (quote.length > 0) {
  156. item.append("<br /> Quote: " + quote + "%");
  157. }
  158. });
  159. }
  160. }
  161. });
  162. });
  163. });
  164.  
  165. /***/ }),
  166. /* 2 */
  167. /***/ (function(module, exports, __webpack_require__) {
  168.  
  169. "use strict";
  170.  
  171.  
  172. Object.defineProperty(exports, "__esModule", {
  173. value: true
  174. });
  175. exports.resolveDelay = exports.resolveZugTyp = void 0;
  176.  
  177. function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _next(value) { step("next", value); } function _throw(err) { step("throw", err); } _next(); }); }; }
  178.  
  179. var zugtyp =
  180. /*#__PURE__*/
  181. function () {
  182. var _ref = _asyncToGenerator(
  183. /*#__PURE__*/
  184. regeneratorRuntime.mark(function _callee(product) {
  185. var regex, zugnummer, year, pad, zugid, data, typ;
  186. return regeneratorRuntime.wrap(function _callee$(_context) {
  187. while (1) {
  188. switch (_context.prev = _context.next) {
  189. case 0:
  190. regex = /^(ICE|IC)\s([0-9]+)$/g;
  191.  
  192. if (!(product.match(regex) === null)) {
  193. _context.next = 3;
  194. break;
  195. }
  196.  
  197. return _context.abrupt("return", null);
  198.  
  199. case 3:
  200. zugnummer = regex.exec(product)[2];
  201. year = new Date().getFullYear();
  202. pad = '00000';
  203. zugid = year + "01" + pad.substring(0, pad.length - zugnummer.length) + zugnummer; // 01 = erstes Ergebnis
  204.  
  205. _context.next = 9;
  206. return makeGMRequest("http://grahnert.de/fernbahn/datenbank/suche/index.php?zug_id=".concat(zugid));
  207.  
  208. case 9:
  209. data = _context.sent;
  210. typ = jQuery(data).find("#stammdaten p strong:contains('IC/ICE-Typ')").next().text();
  211. console.log("Typ: " + typ);
  212. return _context.abrupt("return", typ);
  213.  
  214. case 13:
  215. case "end":
  216. return _context.stop();
  217. }
  218. }
  219. }, _callee, this);
  220. }));
  221.  
  222. return function zugtyp(_x) {
  223. return _ref.apply(this, arguments);
  224. };
  225. }();
  226.  
  227. exports.resolveZugTyp = zugtyp;
  228.  
  229. var delay =
  230. /*#__PURE__*/
  231. function () {
  232. var _ref2 = _asyncToGenerator(
  233. /*#__PURE__*/
  234. regeneratorRuntime.mark(function _callee2(product) {
  235. var data, average, quote;
  236. return regeneratorRuntime.wrap(function _callee2$(_context2) {
  237. while (1) {
  238. switch (_context2.prev = _context2.next) {
  239. case 0:
  240. _context2.next = 2;
  241. return makeGMRequest("https://www.zugfinder.de/zuginfo.php?zugnr=".concat(product));
  242.  
  243. case 2:
  244. data = _context2.sent;
  245. average = $(data).find('.uhrbig').first().text().trim();
  246. quote = $(data).find('[itemprop="ratingValue"]').text().trim();
  247. quote = quote.substring(0, quote.length - 1); // remove % sign
  248.  
  249. return _context2.abrupt("return", {
  250. average: average,
  251. quote: quote
  252. });
  253.  
  254. case 7:
  255. case "end":
  256. return _context2.stop();
  257. }
  258. }
  259. }, _callee2, this);
  260. }));
  261.  
  262. return function delay(_x2) {
  263. return _ref2.apply(this, arguments);
  264. };
  265. }();
  266.  
  267. exports.resolveDelay = delay;
  268.  
  269. function makeGMRequest(url) {
  270. return new Promise(function (resolve, reject) {
  271. GM_xmlhttpRequest({
  272. method: 'GET',
  273. url: url,
  274. onload: function onload(res) {
  275. return resolve(res.responseText);
  276. },
  277. onerror: function onerror(res) {
  278. return reject(res);
  279. }
  280. });
  281. });
  282. }
  283.  
  284. /***/ }),
  285. /* 3 */
  286. /***/ (function(module, exports, __webpack_require__) {
  287.  
  288. exports = module.exports = __webpack_require__(4)(false);
  289. // imports
  290.  
  291.  
  292. // module
  293. exports.push([module.i, "#content div.detailContainer table.result tr td.immer_puenktlich {\n background-color: #3b5323; }\n\n#content div.detailContainer table.result tr td.fast_puenktlich {\n background-color: #6e9b41; }\n\n#content div.detailContainer table.result tr td.puenktlich {\n background-color: #a1c77a; }\n\n#content div.detailContainer table.result tr td.leicht_unpuenktlich {\n background-color: #d04343; }\n\n#content div.detailContainer table.result tr td.unpuenktlich {\n background-color: #8b2323;\n color: white; }\n #content div.detailContainer table.result tr td.unpuenktlich a {\n color: white; }\n", ""]);
  294.  
  295. // exports
  296.  
  297.  
  298. /***/ }),
  299. /* 4 */
  300. /***/ (function(module, exports) {
  301.  
  302. /*
  303. MIT License http://www.opensource.org/licenses/mit-license.php
  304. Author Tobias Koppers @sokra
  305. */
  306. // css base code, injected by the css-loader
  307. module.exports = function(useSourceMap) {
  308. var list = [];
  309.  
  310. // return the list of modules as css string
  311. list.toString = function toString() {
  312. return this.map(function (item) {
  313. var content = cssWithMappingToString(item, useSourceMap);
  314. if(item[2]) {
  315. return "@media " + item[2] + "{" + content + "}";
  316. } else {
  317. return content;
  318. }
  319. }).join("");
  320. };
  321.  
  322. // import a list of modules into the list
  323. list.i = function(modules, mediaQuery) {
  324. if(typeof modules === "string")
  325. modules = [[null, modules, ""]];
  326. var alreadyImportedModules = {};
  327. for(var i = 0; i < this.length; i++) {
  328. var id = this[i][0];
  329. if(typeof id === "number")
  330. alreadyImportedModules[id] = true;
  331. }
  332. for(i = 0; i < modules.length; i++) {
  333. var item = modules[i];
  334. // skip already imported module
  335. // this implementation is not 100% perfect for weird media query combinations
  336. // when a module is imported multiple times with different media queries.
  337. // I hope this will never occur (Hey this way we have smaller bundles)
  338. if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) {
  339. if(mediaQuery && !item[2]) {
  340. item[2] = mediaQuery;
  341. } else if(mediaQuery) {
  342. item[2] = "(" + item[2] + ") and (" + mediaQuery + ")";
  343. }
  344. list.push(item);
  345. }
  346. }
  347. };
  348. return list;
  349. };
  350.  
  351. function cssWithMappingToString(item, useSourceMap) {
  352. var content = item[1] || '';
  353. var cssMapping = item[3];
  354. if (!cssMapping) {
  355. return content;
  356. }
  357.  
  358. if (useSourceMap && typeof btoa === 'function') {
  359. var sourceMapping = toComment(cssMapping);
  360. var sourceURLs = cssMapping.sources.map(function (source) {
  361. return '/*# sourceURL=' + cssMapping.sourceRoot + source + ' */'
  362. });
  363.  
  364. return [content].concat(sourceURLs).concat([sourceMapping]).join('\n');
  365. }
  366.  
  367. return [content].join('\n');
  368. }
  369.  
  370. // Adapted from convert-source-map (MIT)
  371. function toComment(sourceMap) {
  372. // eslint-disable-next-line no-undef
  373. var base64 = btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap))));
  374. var data = 'sourceMappingURL=data:application/json;charset=utf-8;base64,' + base64;
  375.  
  376. return '/*# ' + data + ' */';
  377. }
  378.  
  379.  
  380. /***/ })
  381. /******/ ]);
  382. })();