File indexing completed on 2024-12-29 04:51:03
0001 /* 0002 SPDX-FileCopyrightText: 2017 Volker Krause <vkrause@kde.org> 0003 SPDX-FileCopyrightText: 2018 Daniel Vrátil <dvratil@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 function isHeaderOrFooter(line) { 0009 return line.search(/(Jízdní řád( a rezervace)?|Jízdenku lze použít po stejné trase|Jízdní doklad zakoupený u obchodníka)/) >= 0; 0010 } 0011 0012 function createSeat(res) 0013 { 0014 if (!res.reservedTicket) 0015 res.reservedTicket = JsonLd.newObject("Ticket"); 0016 if (!res.reservedTicket.ticketedSeat) 0017 res.reservedTicket.ticketedSeat = JsonLd.newObject("Seat"); 0018 } 0019 0020 function parseSeat(res, text) { 0021 var coach = text.match(/(\s+)(\d+)/); 0022 var idx = 0; 0023 if (coach) { 0024 createSeat(res); 0025 res.reservedTicket.ticketedSeat.seatSection = coach[2]; 0026 idx = coach.index + coach[1].length + coach[2].length; 0027 } 0028 var seat = text.substr(idx).match(/\s+([\d,\- ]+)/) 0029 if (seat && seat[1].trim()) { 0030 seatNumber = seat[1].trim(); 0031 if (seatNumber) { 0032 createSeat(res); 0033 res.reservedTicket.ticketedSeat.seatNumber = seatNumber; 0034 } 0035 } 0036 } 0037 0038 // There's no validity year anywhere in the ticket, so we take the purchase date and 0039 // if the trip month and day are after the purchase month and day we assume the 0040 // the ticket will become valid the same year it was purchased, otherwise we assume 0041 // the ticket is for next year. 0042 // This fails when you buy the ticket more than a year ahead of the trip, but I doubt 0043 // you can even do that with Czech Railways... 0044 function detectYear(tripDate, purchaseDate) 0045 { 0046 var tripDay = parseInt(tripDate[1]); 0047 var tripMonth = parseInt(tripDate[2]); 0048 var purchaseDay = parseInt(purchaseDate[2]); 0049 var purchaseMonth = parseInt(purchaseDate[3]); 0050 var purchaseYear = parseInt(purchaseDate[4]); 0051 0052 if ((purchaseMonth < tripMonth) || 0053 (purchaseMonth === tripMonth) && (purchaseDay <= tripDay)) { 0054 return purchaseYear; 0055 } else { 0056 return purchaseYear + 1; 0057 } 0058 } 0059 0060 function parseDeparture(res, line, purchaseDate) { 0061 res.reservationFor.departureStation = JsonLd.newObject("TrainStation"); 0062 var station = line.match(/^(.+?) /); 0063 if (!station) 0064 return; 0065 var idx = station.index + station[0].length; 0066 res.reservationFor.departureStation.name = station[1]; 0067 var dt = line.substr(idx).match(/([0-9]{2})\.([0-9]{2})\. ([0-9]{2}:[0-9]{2})/); 0068 if (dt) { 0069 idx += dt.index + dt[0].length; 0070 res.reservationFor.departureTime = JsonLd.toDateTime(dt[1] + ' ' + dt[2] + ' ' + detectYear(dt, purchaseDate) + ' ' + dt[3], "dd MM yyyy hh:mm", "cs"); 0071 } 0072 var trainId = line.substr(idx).match(/([a-zA-Z]+ [0-9a-zA-Z]+)/); 0073 if (trainId) { 0074 idx += trainId.index + trainId[0].length 0075 res.reservationFor.trainNumber = trainId[1]; 0076 } 0077 parseSeat(res, line.substr(idx)); 0078 } 0079 0080 function parseArrival(res, line, purchaseDate) { 0081 res.reservationFor.arrivalStation = JsonLd.newObject("TrainStation"); 0082 var station = line.match(/^(.+?) /); 0083 if (!station) 0084 return; 0085 var idx = station.index + station[0].length; 0086 res.reservationFor.arrivalStation.name = station[1]; 0087 var dt = line.substr(idx).match(/([0-9]{2})\.([0-9]{2})\. ([0-9]{2}:[0-9]{2})/); 0088 if (dt) { 0089 idx += dt.index + dt[0].length; 0090 res.reservationFor.arrivalTime = JsonLd.toDateTime(dt[1] + ' ' + dt[2] + ' ' + detectYear(dt, purchaseDate) + ' ' + dt[3], "dd MM yyyy hh:mm", "cs"); 0091 } 0092 } 0093 0094 function findNextStationLineIndex(lines, start) { 0095 var pos = start; 0096 while (pos < lines.length && (lines[pos].startsWith(" ") || lines[pos].startsWith("Ref:"))) { 0097 pos += 1; 0098 } 0099 return pos; 0100 } 0101 0102 function parseLegs(text, purchaseDate) { 0103 var reservations = new Array(); 0104 var lines = text.split('\n'); 0105 var depIdx = 1, arrIdx = 2; 0106 while (depIdx < lines.length) { 0107 // stop when reaching the footer or the next itinerary header 0108 if (isHeaderOrFooter(lines[depIdx])) 0109 return reservations; 0110 0111 var res = JsonLd.newObject("TrainReservation"); 0112 res.reservationFor = JsonLd.newObject("TrainTrip"); 0113 0114 arrIdx = findNextStationLineIndex(lines, depIdx + 1) 0115 parseDeparture(res, lines[depIdx], purchaseDate); 0116 parseArrival(res, lines[arrIdx], purchaseDate); 0117 0118 // Find the next leg 0119 depIdx = findNextStationLineIndex(lines, arrIdx + 1); 0120 0121 reservations.push(res); 0122 } 0123 0124 return reservations; 0125 } 0126 0127 function main(text) { 0128 var reservations = new Array(); 0129 var pos = 0; 0130 0131 var purchaseDate = text.match(/([d|D]atum platby|UZP): ([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{4})/) 0132 0133 while (true) { 0134 // find itinerary headers 0135 var header = text.substr(pos).match(/Timetable( and Reservations)?/); 0136 if (!header) 0137 break; 0138 var idx = header.index + header[0].length; 0139 var timetableHeader = text.substr(pos + idx).match(/(Místo \/ Seat \/ Sitzplatz)/) 0140 idx = idx + timetableHeader.index + timetableHeader[0].length; 0141 reservations = reservations.concat(parseLegs(text.substr(pos + idx), purchaseDate)); 0142 if (idx == 0) 0143 break; 0144 pos += idx + 1; 0145 } 0146 0147 var bookingRef = text.match(/Kód transakce:\s*([A-Z0-9]{6})\n/); 0148 for (var i = 0; bookingRef && i < reservations.length; ++i) 0149 reservations[i].reservationNumber = bookingRef[1]; 0150 return reservations; 0151 } 0152 0153 // ### this is based on an international ticket, do domestic ones look the same? 0154 function parsePdfTicket(content, node, triggerNode) { 0155 const page = content.pages[triggerNode.location]; 0156 const text = page.textInRect(0.0, 0.0, 0.675, 1.0); 0157 let idx = 0; 0158 let reservations = []; 0159 while (true) { 0160 let leg = text.substr(idx).match(/\n(.*?) +(\d\d\.\d\d\.) +(\d\d:\d\d) +(.*?)(?: +(\d+) +(\d+))?\n(.*?) +(\d\d.\d\d.) +(\d\d:\d\d)/); 0161 if (!leg) { 0162 break; 0163 } 0164 let res = JsonLd.newTrainReservation(); 0165 res.reservationFor.departureStation.name = leg[1]; 0166 res.reservationFor.departureTime = JsonLd.toDateTime(leg[2] + leg[3], 'dd.MM.hh:mm', 'cz'); 0167 res.reservationFor.arrivalStation.name = leg[7]; 0168 res.reservationFor.arrivalTime = JsonLd.toDateTime(leg[8] + leg[9], 'dd.MM.hh:mm', 'cz'); 0169 res.reservationFor.trainNumber = leg[4]; 0170 if (leg[5] && leg[6]) { 0171 res.reservedTicket.ticketedSeat.seatSection = leg[5]; 0172 res.reservedTicket.ticketedSeat.seatNumber = leg[6]; 0173 } 0174 0175 if (triggerNode.result[0]['@type'] == 'TrainReservation') { 0176 res = JsonLd.apply(triggerNode.result[0], res); 0177 res.reservationNumber = triggerNode.content.block('1154UT').findSubBlock('KK').content; 0178 } 0179 res.reservedTicket = JsonLd.apply(triggerNode.result[0].reservedTicket, res.reservedTicket); 0180 0181 reservations.push(res); 0182 idx += leg.index + leg[0].length; 0183 } 0184 0185 return reservations; 0186 } 0187 0188 function parseUicTicket(uic, node) 0189 { 0190 if (node.result[0]['@type'] == 'TrainReservation') { 0191 let res = node.result[0]; 0192 res.reservationNumber = uic.block('1154UT').findSubBlock('KK').content; 0193 res.reservedTicket.ticketNumber = uic.pnr; 0194 return res; 0195 } else { 0196 let ticket = node.result[0]; 0197 ticket.ticketNumber = uic.pnr; 0198 return ticket; 0199 } 0200 } 0201 0202 function parseEvent(event) { 0203 let reservations = []; 0204 let idx = 0; 0205 while (true) { 0206 const leg = event.description.substr(idx).match(/(.*)\n(.*) (\d\d):(\d\d)\n(.*) (\d\d):(\d\d)\n.* (\d+),.* (\d+)/); 0207 if (!leg) 0208 break; 0209 idx += leg.index + leg[0].length; 0210 0211 let res = JsonLd.newTrainReservation(); 0212 res.reservationFor.trainNumber = leg[1]; 0213 res.reservationFor.departureStation.name = leg[2]; 0214 res.reservationFor.departureTime = new Date(event.dtStart); 0215 res.reservationFor.departureTime.setHours(leg[3], leg[4]); 0216 res.reservationFor.arrivalStation.name = leg[5]; 0217 res.reservationFor.arrivalTime = new Date(event.dtStart); 0218 res.reservationFor.arrivalTime.setHours(leg[6], leg[7]); 0219 res.reservedTicket.ticketedSeat.seatSection = leg[8]; 0220 res.reservedTicket.ticketedSeat.seatNumber = leg[9]; 0221 reservations.push(res); 0222 } 0223 return reservations; 0224 }