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"