Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package kitinerary for openSUSE:Factory checked in at 2026-07-02 22:05:03 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitinerary (Old) and /work/SRC/openSUSE:Factory/.kitinerary.new.1982 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitinerary" Thu Jul 2 22:05:03 2026 rev:99 rq:1363268 version:26.04.3 Changes: -------- --- /work/SRC/openSUSE:Factory/kitinerary/kitinerary.changes 2026-06-08 14:08:36.347476541 +0200 +++ /work/SRC/openSUSE:Factory/.kitinerary.new.1982/kitinerary.changes 2026-07-02 22:06:30.414777143 +0200 @@ -1,0 +2,20 @@ +Tue Jun 30 18:19:37 UTC 2026 - Christophe Marin <[email protected]> + +- Update to 26.04.3 + * New bugfix release + * For more details please see: + * https://kde.org/announcements/gear/26.04.3/ +- Changes since 26.04.2: + * Fix extracting multi-column VR tickets + * 12go: Add support for extracting receipt + * Manually extract BDZ ticket prices + * Add polferries extractor + * Add missing poppler include + * Extract checkin times and prices from Accor hotel bookings + * Fix arrival stop extraction on French-operated Flixbus tickets + * Don't choke on missing currency symbol on IRCTC tickets + * Attempt to support both less and more than 1000 in `irctc` PDF + * Add price extraction for SRT (thai-railway) + * Add price extraction for IRCTC QR ticket + +------------------------------------------------------------------- Old: ---- kitinerary-26.04.2.tar.xz kitinerary-26.04.2.tar.xz.sig New: ---- kitinerary-26.04.3.tar.xz kitinerary-26.04.3.tar.xz.sig ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitinerary.spec ++++++ --- /var/tmp/diff_new_pack.sy9cjo/_old 2026-07-02 22:06:31.498814294 +0200 +++ /var/tmp/diff_new_pack.sy9cjo/_new 2026-07-02 22:06:31.502814431 +0200 @@ -18,11 +18,11 @@ %define kf6_version 6.19.0 %define qt6_version 6.9.0 -%define kpim6_version 6.7.2 +%define kpim6_version 6.7.3 %bcond_without released Name: kitinerary -Version: 26.04.2 +Version: 26.04.3 Release: 0 Summary: Data model and extraction system for travel reservations License: LGPL-2.1-or-later ++++++ kitinerary-26.04.2.tar.xz -> kitinerary-26.04.3.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/CMakeLists.txt new/kitinerary-26.04.3/CMakeLists.txt --- old/kitinerary-26.04.2/CMakeLists.txt 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/CMakeLists.txt 2026-06-29 18:39:40.000000000 +0200 @@ -7,10 +7,10 @@ # KDE Application Version, managed by release script set (RELEASE_SERVICE_VERSION_MAJOR "26") set (RELEASE_SERVICE_VERSION_MINOR "04") -set (RELEASE_SERVICE_VERSION_MICRO "2") +set (RELEASE_SERVICE_VERSION_MICRO "3") set (RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}") -set(PIM_VERSION "6.7.2") +set(PIM_VERSION "6.7.3") project(KItinerary VERSION ${PIM_VERSION}) set(QT_REQUIRED_VERSION "6.7.0") @@ -49,8 +49,8 @@ find_package(SharedMimeInfo 1.3 REQUIRED) endif() -set(KMIME_VERSION "6.7.2") -set(PIM_PKPASS "6.7.2") +set(KMIME_VERSION "6.7.3") +set(PIM_PKPASS "6.7.3") find_package(KPim6Mime ${KMIME_VERSION} CONFIG REQUIRED) find_package(KPim6PkPass ${PIM_PKPASS} CONFIG REQUIRED) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/autotests/extractordata/irctc/qr-ticket.txt.json new/kitinerary-26.04.3/autotests/extractordata/irctc/qr-ticket.txt.json --- old/kitinerary-26.04.2/autotests/extractordata/irctc/qr-ticket.txt.json 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/autotests/extractordata/irctc/qr-ticket.txt.json 2026-06-29 18:39:40.000000000 +0200 @@ -3,6 +3,7 @@ "@context": "http://schema.org", "@type": "TrainReservation", "modifiedTime": "2018-01-01T00:00:00", + "priceCurrency": "INR", "reservationFor": { "@type": "TrainTrip", "arrivalStation": { @@ -54,6 +55,7 @@ "seatingType": "THIRD AC (3A)" } }, + "totalPrice": 1257.4, "underName": { "@type": "Person", "name": "Katie Dragon" @@ -63,6 +65,7 @@ "@context": "http://schema.org", "@type": "TrainReservation", "modifiedTime": "2018-01-01T00:00:00", + "priceCurrency": "INR", "reservationFor": { "@type": "TrainTrip", "arrivalStation": { @@ -114,6 +117,7 @@ "seatingType": "THIRD AC (3A)" } }, + "totalPrice": 1257.4, "underName": { "@type": "Person", "name": "Konqi Dragon" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/po/nn/kitinerary6.po new/kitinerary-26.04.3/po/nn/kitinerary6.po --- old/kitinerary-26.04.2/po/nn/kitinerary6.po 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/po/nn/kitinerary6.po 2026-06-29 18:39:40.000000000 +0200 @@ -8,7 +8,7 @@ "POT-Creation-Date: 2025-11-17 11:52+0000\n" "PO-Revision-Date: 2022-07-26 20:58+0200\n" "Last-Translator: Karl Ove Hufthammer <[email protected]>\n" -"Language-Team: Norwegian Nynorsk <[email protected]>\n" +"Language-Team: Norwegian Nynorsk <[email protected]>\n" "Language: nn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/cli/org.kde.kitinerary-extractor.appdata.xml new/kitinerary-26.04.3/src/cli/org.kde.kitinerary-extractor.appdata.xml --- old/kitinerary-26.04.2/src/cli/org.kde.kitinerary-extractor.appdata.xml 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/cli/org.kde.kitinerary-extractor.appdata.xml 2026-06-29 18:39:40.000000000 +0200 @@ -133,6 +133,7 @@ </categories> <launchable type="desktop-id">org.kde.kitinerary-extractor.desktop</launchable> <releases> + <release version="6.7.3" date="2026-07-02"/> <release version="6.7.2" date="2026-06-04"/> <release version="6.7.1" date="2026-05-07"/> <release version="6.7.0" date="2026-04-16"/> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/pdf/pdfextractoroutputdevice.cpp new/kitinerary-26.04.3/src/lib/pdf/pdfextractoroutputdevice.cpp --- old/kitinerary-26.04.2/src/lib/pdf/pdfextractoroutputdevice.cpp 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/pdf/pdfextractoroutputdevice.cpp 2026-06-29 18:39:40.000000000 +0200 @@ -13,6 +13,7 @@ #include <Annot.h> #include <Link.h> #include <Page.h> +#include <Stream.h> #include <QDebug> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/12go.js new/kitinerary-26.04.3/src/lib/scripts/12go.js --- old/kitinerary-26.04.2/src/lib/scripts/12go.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/12go.js 2026-06-29 18:39:40.000000000 +0200 @@ -1,5 +1,6 @@ /* SPDX-FileCopyrightText: 2023 Volker Krause <[email protected]> + SPDX-FileCopyrightText: 2026 Carl Schwan <[email protected]> SPDX-License-Identifier: LGPL-2.0-or-later */ @@ -33,6 +34,8 @@ function fixSchemaOrg(html, node) { let results = node.result; for (res of results) { + if (!res["potentialAction"]) + continue; // not a schema.org result // doesn't match what's in the PDF res.reservationNumber = undefined; if (res.reservationFor.departureTime == res.reservationFor.arrivalTime) @@ -42,3 +45,40 @@ } return results; } + +function extractReceipt(content) { + let res = JsonLd.newBusReservation(); + + + const lines = content.split('\n'); + + for (let i = 0, count = lines.length; i < count; i++) { + const line = lines[i]; + + if (line.startsWith('Name:')) { + res.underName.name = line.split(': ')[1]; + } + + if (line.startsWith('Booking number:')) { + res.reservationNumber = lines[i + 1]; + } + + if (line.startsWith('Route:')) { + const match = line.match("Route: (.*)-(.*)"); + res.reservationFor.departureBusStop.name = match[1]; + res.reservationFor.arrivalBusStop.name = match[2]; + } + + if (line.startsWith('Departure:')) { + const match = line.match("Departure: (.*), (.*)"); + res.reservationFor.departureTime = JsonLd.toDateTime(match[2] + ' ' + match[1], 'dd MMM yyyy hh:mm AP', 'en'); + } + + if (line.startsWith('Total amount:')) { + const match = line.match("Total amount: (.*) (.*)"); + res.totalPrice = parseFloat(match[1]); + res.priceCurrency = match[2]; + } + } + return res; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/12go.json new/kitinerary-26.04.3/src/lib/scripts/12go.json --- old/kitinerary-26.04.2/src/lib/scripts/12go.json 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/12go.json 2026-06-29 18:39:40.000000000 +0200 @@ -22,5 +22,18 @@ "function": "fixSchemaOrg", "mimeType": "text/html", "script": "12go.js" +}, +{ + "filter": [ + { + "match": "12go.asia", + "field": "From", + "mimeType": "message/rfc822", + "scope": "Ancestors" + } + ], + "function": "extractReceipt", + "mimeType": "text/plain", + "script": "12go.js" } ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/accor.js new/kitinerary-26.04.3/src/lib/scripts/accor.js --- old/kitinerary-26.04.2/src/lib/scripts/accor.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/accor.js 2026-06-29 18:39:40.000000000 +0200 @@ -4,20 +4,26 @@ SPDX-License-Identifier: LGPL-2.0-or-later */ -function parseConfirmation(html) { - var res = JsonLd.newLodgingReservation(); +function parseConfirmation(html, node) { + let res = node.result.length === 1 ? node.result[0] : JsonLd.newLodgingReservation(); const content = html.root.recursiveContent; - res.reservationNumber = content.match(/(?:Reservation number|Buchungsnummer):?\s*([0-9A-Z]+)/)[1]; + res.reservationNumber = content.match(/(?:Reservation number|Reservation n°|Reservierung Nr.|Buchungsnummer):?\s*([0-9A-Z]+)/)[1]; let dt = content.match(/(\d{2}[|/.]\d{2}[|/.]\d{4}).*(\d{2}[|/.]\d{2}[|/.]\d{4})/); if (!dt) // US format dt = content.match(/([A-Z][a-z]{2}\. \d{2}, \d{4}).*([A-Z][a-z]{2}\. \d{2}, \d{4})/); if (!dt) dt = content.match(/(\d{2} [A-Z][a-z]{2} \d{4}).*(\d{2} [A-Z][a-z]{2} \d{4})/); - const formats = [ "dd.MM.yyyy", "dd/MM/yyyy", "MMM. dd, yyyy", "dd MMM yyyy"]; - res.checkinTime = JsonLd.toDateTime(dt[1], formats, "en"); - res.checkoutTime = JsonLd.toDateTime(dt[2], formats, "en"); + const times = content.match(/(?:Check in Policy|Anreisezeit):?\n.*(\d\d:\d\d).*\n(?:Check out Policy|Abreisezeit):?\n.*(\d\d:\d\d)/); + const formats = [ + "dd.MM.yyyyHH:mm", "dd.MM.yyyy", + "dd/MM/yyyyHH:mm", "dd/MM/yyyy", + "MMM. dd, yyyyHH:mm", "MMM. dd, yyyy", + "dd MMM yyyyHH:mm", "dd MMM yyyy" + ]; + res.checkinTime = JsonLd.toDateTime(dt[1] + (times ? times[1] : ""), formats, "en"); + res.checkoutTime = JsonLd.toDateTime(dt[2] + (times ? times[2] : ""), formats, "en"); let hotelNode = html.eval('//table//table//table[@class="table-full"]'); if (!hotelNode || hotelNode.length === 0) @@ -33,18 +39,24 @@ // no contact information present hotel = hotelContent.match(/^(.*)\n+(.*\n.*)\n(?:.|\n)*/); } - res.reservationFor.name = hotel[1]; + if (hotel) { + res.reservationFor.name = hotel[1]; - var addr = hotel[2].match(/(.*)(?: - |\n)(.*) - (.*)/); - res.reservationFor.address.streetAddress = addr[1]; - res.reservationFor.address.addressLocality = addr[2]; - res.reservationFor.address.addressCountry = addr[3]; + const addr = hotel[2].match(/(.*)(?: - |\n)(.*) - (.*)/); + res.reservationFor.address.streetAddress = addr[1]; + res.reservationFor.address.addressLocality = addr[2]; + res.reservationFor.address.addressCountry = addr[3]; + } // this is in an HTML comment... if (html.rawData.match(/TARS - AH - Client - Cancellation - Email/)) { res.reservationStatus = "ReservationCancelled" } + ExtractorEngine.extractPrice(content, res); + const price = content.match(/(?:Total|Gesamt).*\n(\s*\n)?.*\d.*\n/); + if (price && !res.totalPrice) + ExtractorEngine.extractPrice(price[0], res); return res; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/bdz.js new/kitinerary-26.04.3/src/lib/scripts/bdz.js --- old/kitinerary-26.04.2/src/lib/scripts/bdz.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/bdz.js 2026-06-29 18:39:40.000000000 +0200 @@ -23,6 +23,11 @@ res.reservedTicket.ticketedSeat.seatNumber = leg[10]; const barcode = node.findChildNodes({ scope: "Descendants", mimeType: "application/octet-stream" })[0]; res.reservedTicket.ticketToken = 'qrcodebin:' + ByteArray.toBase64(barcode.content); + + const price = text.match(/(\d+\.\d\d) (?:euro|евро)/); + res.priceCurrency = "EUR"; + res.totalPrice = price[1]; + reservations.push(res); } return reservations; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/extractors.qrc new/kitinerary-26.04.3/src/lib/scripts/extractors.qrc --- old/kitinerary-26.04.2/src/lib/scripts/extractors.qrc 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/extractors.qrc 2026-06-29 18:39:40.000000000 +0200 @@ -303,6 +303,10 @@ <file>pkp-app.js</file> <file>planway.json</file> <file>planway.js</file> + <file>polferries.json</file> + <file>polferries.js</file> + <file>polregio.json</file> + <file>polregio.js</file> <file>predpredaj.json</file> <file>predpredaj.js</file> <file>premier-inn.json</file> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/flixbus.js new/kitinerary-26.04.3/src/lib/scripts/flixbus.js --- old/kitinerary-26.04.2/src/lib/scripts/flixbus.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/flixbus.js 2026-06-29 18:39:40.000000000 +0200 @@ -63,7 +63,7 @@ let reservations = []; while (true) { const times = timeColumn.substr(idxTime).match(/(\d\d:\d\d)\n+([^:]*?\n)?([^:]*?\n)?(\d\d:\d\d)/); - const stations = stationColumn.substr(idxStations).match(/(?:\n|^)([^].*)\n[ ]+(.*)(?:\n+|(,?\n+ +.*)\n+)(?:.*(?:NOTE:|Wagennummerierung|platform|The regional part|Die Bussteignummer|Operated|Platform).(?:.*\n+)+?)?.*(?:Bus|Autobus|Zug|Strecke|Route|Tratta)\s+(\S.+)\n+.*(?:Direction|à destination de|Kierunek|richting|Richtung|Direzione) (.*)\n+(?:.*(?:Operated|Betrieben|Uitgevoerd|Effettuata).*\n+(?:.*Lda\.\n+)?)?(.*)\n+(?:[ ]+(.*?)(?:\n+|(,\n +.*)\n+))?/); + const stations = stationColumn.substr(idxStations).match(/(?:\n|^)([^].*)\n[ ]+(.*)(?:\n+|(,?\n+ +.*)\n+)(?:.*(?:NOTE:|Wagennummerierung|platform|The regional part|Die Bussteignummer|Operated|Platform).(?:.*\n+)+?)?.*(?:Bus|Autobus|Zug|Strecke|Route|Tratta)\s+(\S.+)\n+.*(?:Direction|à destination de|Kierunek|richting|Richtung|Direzione) (.*)\n+(?:.*(?:Operated|Betrieben|Uitgevoerd|Effettuata).*\n+(?:.*Lda\.\n+|S\.A\.R\.L\.\n+)?)?(.*)\n+(?:[ ]+(.*?)(?:\n+|(,\n +.*)\n+))?/); if (!times || !stations) { break; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/irctc.js new/kitinerary-26.04.3/src/lib/scripts/irctc.js --- old/kitinerary-26.04.2/src/lib/scripts/irctc.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/irctc.js 2026-06-29 18:39:40.000000000 +0200 @@ -43,6 +43,11 @@ res.reservationFor.departureDay = JsonLd.toDateTime(text.match(/Date Of Journey:(.*),/)[1], "dd-MMM-yyyy", "en"); } res.reservedTicket.ticketedSeat.seatingType = text.match(/Class:(.*),/)[1]; + // There may be missing charges but this is the best extractable from QR. + let fare = parseFloat(text.match(/Ticket Fare: Rs(.*),/)[1]); + let fees = parseFloat(text.match(/IRCTC C Fee: Rs(.*)\+/)[1]); + res.totalPrice = fare + fees; + res.priceCurrency = 'INR'; let idx = 0; let reservations = []; @@ -64,7 +69,13 @@ const text = pdf.pages[triggerNode.location].text; const arr = JsonLd.toDateTime(text.match(/Arrival\* (.*)\n/)[1], "hh:mm dd-MMM-yyyy", "en"); let res = triggerNode.result; - for (let r of res) + // Manually redo price since having a value prevents the data from being extracted + // again automatically, and PDF gives a better estimate than QR. + const priceAsString = text.match(/Total Fare \(all inclusive\) *(?:₹ )?([0-9\,]+\.\d{2})/)[1]; + let totalPrice = parseFloat(priceAsString.replace(/,/g,'')); + for (let r of res) { r.reservationFor.arrivalTime = arr; + r.totalPrice = totalPrice; + } return res; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/polferries.js new/kitinerary-26.04.3/src/lib/scripts/polferries.js --- old/kitinerary-26.04.2/src/lib/scripts/polferries.js 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-26.04.3/src/lib/scripts/polferries.js 2026-06-29 18:39:40.000000000 +0200 @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: 2026 Volker Krause <[email protected]> +// SPDX-License-Identifier: LGPL-2.0-or-later + +function extractTicket(pdf) { + let reservations = []; + for (const page of pdf.pages) { + const text = page.text; + let baseRes = JsonLd.newBoatReservation(); + baseRes.reservationNumber = text.match(/Ticket(?: number:)? *(IT\d+)\n/)[1]; + const trip = text.match(/Route:? (\S.*\S)-(\S.*\S) +Date: (\d\d-\d\d-\d{4}) .* +Time: *(\d\d:\d\d) /); + baseRes.reservationFor.departureBoatTerminal.name = trip[1]; + baseRes.reservationFor.arrivalBoatTerminal.name = trip[2]; + baseRes.reservationFor.departureTime = JsonLd.toDateTime(trip[3] + trip[4], "dd-MM-yyyyHH:mm", "en"); + + let idx = 0; + while (true) { + const pas = text.substr(idx).match(/\d\. (\S.*\S) .*\n/); + if (!pas) + break; + idx += pas.index + pas[0].length; + let res = JsonLd.clone(baseRes); + res.underName.name = pas[1]; + reservations.push(res); + } + } + return reservations; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/polferries.json new/kitinerary-26.04.3/src/lib/scripts/polferries.json --- old/kitinerary-26.04.2/src/lib/scripts/polferries.json 1970-01-01 01:00:00.000000000 +0100 +++ new/kitinerary-26.04.3/src/lib/scripts/polferries.json 2026-06-29 18:39:40.000000000 +0200 @@ -0,0 +1,13 @@ +{ + "filter": [ + { + "field": "creator", + "match": "PaxSold\\)$", + "mimeType": "application/pdf", + "scope": "Current" + } + ], + "function": "extractTicket", + "mimeType": "application/pdf", + "script": "polferries.js" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/thailand-railway.js new/kitinerary-26.04.3/src/lib/scripts/thailand-railway.js --- old/kitinerary-26.04.2/src/lib/scripts/thailand-railway.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/thailand-railway.js 2026-06-29 18:39:40.000000000 +0200 @@ -19,5 +19,7 @@ res.reservedTicket.ticketedSeat.seatingType = times[4]; res.reservedTicket.ticketedSeat.seatSection = times[5]; res.reservedTicket.ticketedSeat.seatNumber = times[6]; + res.totalPrice = parseFloat(text.match(/Price : (\d*\.*\d*)/)[1]); + res.priceCurrency = 'THB'; return res; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitinerary-26.04.2/src/lib/scripts/vr.fi.js new/kitinerary-26.04.3/src/lib/scripts/vr.fi.js --- old/kitinerary-26.04.2/src/lib/scripts/vr.fi.js 2026-05-31 16:44:52.000000000 +0200 +++ new/kitinerary-26.04.3/src/lib/scripts/vr.fi.js 2026-06-29 18:39:40.000000000 +0200 @@ -61,18 +61,25 @@ } function parseMobilePdf(pdf, node, ssb) { + const ssbCodes = node.findChildNodes({ scope: "Descendants", mimeType: "internal/era-ssb" }) + .filter((ssbNode) => ssbNode.location == ssb.location); + let res = ssb.result[0]; - const text = pdf.pages[ssb.location].textInRect(0.0, 0.0, 0.5, 0.5); - const trip = text.match(/(\d{1,2}\.\d{1,2}\.\d{4})\n+ *(\S.*\S) +(\S.*)\n+ *(\d\d:\d\d) +(\d\d:\d\d)\n/); - res.reservationFor.departureTime = JsonLd.toDateTime(trip[4], "hh:mm", "en"); - res.reservationFor.arrivalTime = JsonLd.toDateTime(trip[5], "hh:mm", "en"); - res.reservationFor.departureStation.name = trip[2]; - res.reservationFor.arrivalStation.name = trip[3]; - const seat = text.substr(trip.index + trip[0].length).match(/.*\n *([A-Z]+ \d+) +(\d+).* (\d+)/); - if (seat) { - res.reservationFor.trainNumber = seat[1]; - res.reservedTicket.ticketedSeat.seatSection = seat[2]; - res.reservedTicket.ticketedSeat.seatNumber = seat[3]; + for (const column in [0, 1]) { + const text = pdf.pages[ssb.location].textInRect(0.0 + column * 0.5, 0.0, 0.5 + column * 0.5, 0.5); + const trip = text.match(/(\d{1,2}\.\d{1,2}\.\d{4})\n+ *(\S.*\S) +(\S.*)\n+ *(\d\d:\d\d) +(\d\d:\d\d)\n/); + if (ssbCodes.length > 1 && trip[4].substr(0, 4) != res.reservationFor.departureTime.substr(11, 4)) + continue; + res.reservationFor.departureTime = JsonLd.toDateTime(trip[4], "hh:mm", "en"); + res.reservationFor.arrivalTime = JsonLd.toDateTime(trip[5], "hh:mm", "en"); + res.reservationFor.departureStation.name = trip[2]; + res.reservationFor.arrivalStation.name = trip[3]; + const seat = text.substr(trip.index + trip[0].length).match(/.*\n *([A-Z]+ \d+) +(?:(\d+).* (\d+)|Any)/); + if (seat) { + res.reservationFor.trainNumber = seat[1]; + res.reservedTicket.ticketedSeat.seatSection = seat[2]; + res.reservedTicket.ticketedSeat.seatNumber = seat[3]; + } + return res; } - return res; }
