1 /*
2  *   SPDX-FileCopyrightText: 2017 Aleix Pol Gonzalez <aleixpol@kde.org>
3  *
4  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5  */
6 
7 #include "AppStreamUtils.h"
8 
9 #include "utils.h"
10 #include <AppStreamQt/release.h>
11 #include <AppStreamQt/screenshot.h>
12 #include <KLocalizedString>
13 #include <QDebug>
14 #include <QJsonArray>
15 #include <QJsonObject>
16 #include <QUrlQuery>
17 #include <AppStreamQt/spdx.h>
18 
19 using namespace AppStreamUtils;
20 
imageOfKind(const QList<AppStream::Image> & images,AppStream::Image::Kind kind)21 QUrl AppStreamUtils::imageOfKind(const QList<AppStream::Image> &images, AppStream::Image::Kind kind)
22 {
23     QUrl ret;
24     for (const AppStream::Image &i : images) {
25         if (i.kind() == kind) {
26             ret = i.url();
27             break;
28         }
29     }
30     return ret;
31 }
32 
changelogToHtml(const AppStream::Component & appdata)33 QString AppStreamUtils::changelogToHtml(const AppStream::Component &appdata)
34 {
35     if (appdata.releases().isEmpty())
36         return {};
37 
38     const auto release = appdata.releases().constFirst();
39     if (release.description().isEmpty())
40         return {};
41 
42     QString changelog =
43         QLatin1String("<h3>") + release.version() + QLatin1String("</h3>") + QStringLiteral("<p>") + release.description() + QStringLiteral("</p>");
44     return changelog;
45 }
46 
fetchScreenshots(const AppStream::Component & appdata)47 QPair<QList<QUrl>, QList<QUrl>> AppStreamUtils::fetchScreenshots(const AppStream::Component &appdata)
48 {
49     QList<QUrl> screenshots, thumbnails;
50     const auto appdataScreenshots = appdata.screenshots();
51     for (const AppStream::Screenshot &s : appdataScreenshots) {
52         const auto images = s.images();
53         const QUrl thumbnail = AppStreamUtils::imageOfKind(images, AppStream::Image::KindThumbnail);
54         const QUrl plain = AppStreamUtils::imageOfKind(images, AppStream::Image::KindSource);
55         if (plain.isEmpty())
56             qWarning() << "invalid screenshot for" << appdata.name();
57 
58         screenshots << plain;
59         thumbnails << (thumbnail.isEmpty() ? plain : thumbnail);
60     }
61     return {thumbnails, screenshots};
62 }
63 
licenses(const AppStream::Component & appdata)64 QJsonArray AppStreamUtils::licenses(const AppStream::Component &appdata)
65 {
66     QJsonArray ret;
67     const auto licenses = AppStream::SPDX::tokenizeLicense(appdata.projectLicense());
68     for (const auto &token : licenses) {
69         QString license = token;
70         license.remove(0, 1); // tokenize prefixes with an @ for some reason
71         if (!AppStream::SPDX::isLicenseId(license))
72             continue;
73         ret.append(QJsonObject{{QStringLiteral("name"), license}, {QStringLiteral("url"), {AppStream::SPDX::licenseUrl(license)}}});
74     }
75     return ret;
76 }
77 
appstreamIds(const QUrl & appstreamUrl)78 QStringList AppStreamUtils::appstreamIds(const QUrl &appstreamUrl)
79 {
80     QStringList ret;
81     ret += appstreamUrl.host().isEmpty() ? appstreamUrl.path() : appstreamUrl.host();
82     if (appstreamUrl.hasQuery()) {
83         QUrlQuery query(appstreamUrl);
84         ret << query.queryItemValue(QStringLiteral("alt")).split(QLatin1Char(','), Qt::SkipEmptyParts);
85     }
86     return ret;
87 }
88 
versionString(const QString & version,const AppStream::Component & appdata)89 QString AppStreamUtils::versionString(const QString &version, const AppStream::Component &appdata)
90 {
91     if (version.isEmpty()) {
92         return {};
93     } else {
94         if (appdata.releases().isEmpty())
95             return version;
96 
97         auto release = appdata.releases().constFirst();
98         if (release.timestamp().isValid() && version.startsWith(release.version())) {
99             QLocale l;
100             qDebug() << "versionversion" << version << release.version();
101             return i18n("%1, released on %2", version, l.toString(release.timestamp().date(), QLocale::ShortFormat));
102         } else {
103             return version;
104         }
105     }
106 }
107