File indexing completed on 2024-11-17 04:43:14
0001 /* 0002 SPDX-FileCopyrightText: 2022 Kai Uwe Broulik <kde@broulik.de> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "itineraryextractor.h" 0008 0009 #include <KItinerary/ExtractorEngine> 0010 #include <KItinerary/ExtractorPostprocessor> 0011 #include <KItinerary/Datatypes> 0012 #include <KItinerary/JsonLdDocument> 0013 #include <KItinerary/LocationUtil> 0014 0015 #include <KItinerary/Event> 0016 #include <KItinerary/Flight> 0017 #include <KItinerary/Reservation> 0018 0019 #include <KPkPass/Pass> 0020 0021 #include <KLocalizedString> 0022 0023 #include <QFileInfo> 0024 #include <QJsonArray> 0025 0026 #include <optional> 0027 0028 using namespace KFileMetaData; 0029 using namespace KItinerary; 0030 0031 ItineraryExtractor::ItineraryExtractor(QObject* parent) 0032 : ExtractorPlugin(parent) 0033 { 0034 } 0035 0036 QStringList ItineraryExtractor::mimetypes() const 0037 { 0038 return QStringList{ 0039 QStringLiteral("application/vnd.apple.pkpass") 0040 }; 0041 } 0042 0043 void KFileMetaData::ItineraryExtractor::extract(ExtractionResult *result) 0044 { 0045 QFileInfo fi(result->inputUrl()); 0046 if (!fi.exists()) { 0047 return; 0048 } 0049 0050 auto contextDt = fi.birthTime(); 0051 if (!contextDt.isValid()) { 0052 contextDt = fi.lastModified(); 0053 } 0054 0055 const QScopedPointer<KPkPass::Pass> pass(KPkPass::Pass::fromFile(result->inputUrl(), nullptr)); 0056 if (pass.isNull()) { 0057 return; 0058 } 0059 0060 result->add(Property::Title, pass->description()); 0061 result->add(Property::Author, pass->organizationName()); 0062 0063 ExtractorEngine engine; 0064 engine.setContextDate(contextDt); 0065 0066 ExtractorPostprocessor postproc; 0067 postproc.setContextDate(contextDt); 0068 0069 engine.setContent(QVariant::fromValue(pass.data()), result->inputMimetype()); 0070 0071 const auto json = JsonLdDocument::fromJson(engine.extract()); 0072 postproc.process(json); 0073 0074 std::optional<Reservation> res; 0075 0076 for (const auto &jsonRes : json) { 0077 if (JsonLd::isA<Event>(jsonRes)) { // promote Event to EventReservation 0078 EventReservation ev; 0079 ev.setReservationFor(jsonRes); 0080 res = ev; 0081 break; 0082 } else if (JsonLd::canConvert<Reservation>(jsonRes)) { 0083 res = JsonLd::convert<Reservation>(jsonRes); 0084 break; 0085 } 0086 } 0087 0088 if (!res) { 0089 return; 0090 } 0091 0092 if (const QString reservationNumber = res->reservationNumber(); !reservationNumber.isEmpty()) { 0093 result->add(Property::Comment, reservationNumber); 0094 } 0095 0096 if (JsonLd::isA<Event>(res->reservationFor())) { 0097 const auto event = res->reservationFor().value<Event>(); 0098 // simplified() as some event names have line breaks and other rubbish in them 0099 if (const QString eventName = event.name().simplified(); !eventName.isEmpty()) { 0100 // only if it's not the same as the Title 0101 if (pass->description() != eventName) { 0102 result->add(Property::Subject, eventName); 0103 } 0104 } 0105 0106 const QString placeName = KItinerary::LocationUtil::name(event.location()); 0107 if (!placeName.isEmpty()) { 0108 result->add(Property::Location, placeName); 0109 } 0110 0111 const GeoCoordinates geo = KItinerary::LocationUtil::geo(event.location()); 0112 if (geo.isValid()) { 0113 result->add(Property::PhotoGpsLatitude, geo.latitude()); 0114 result->add(Property::PhotoGpsLongitude, geo.longitude()); 0115 } 0116 } else if (JsonLd::isA<Flight>(res->reservationFor())) { 0117 const auto flight = res->reservationFor().value<Flight>(); 0118 result->add(Property::Subject, i18nc("Airline Flightnumber from Airport to Airport on Date", 0119 "%1%2 from %3 to %4 on %5", 0120 flight.airline().iataCode(), 0121 flight.flightNumber(), 0122 flight.departureAirport().iataCode(), 0123 flight.arrivalAirport().iataCode(), 0124 QLocale().toString(flight.departureDay(), QLocale::ShortFormat))); 0125 } 0126 } 0127 0128 #include "moc_itineraryextractor.cpp"