mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
Use KDesktopFile/KConfigGroup to parse .desktop files reliably. This avoids Categories parsing pitfalls and improves detection of KDE stock games. Centralize game-category matching and use stable IDs based on the full desktop-file basename.
151 lines
4.4 KiB
C++
151 lines
4.4 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
|
|
|
|
#include "flatpakimporter.h"
|
|
|
|
#include <KConfigGroup>
|
|
#include <KDesktopFile>
|
|
#include <QDir>
|
|
#include <QFile>
|
|
#include <QProcess>
|
|
#include <QRegularExpression>
|
|
|
|
FlatpakImporter::FlatpakImporter(QObject *parent)
|
|
: PlatformImporter(parent)
|
|
{
|
|
}
|
|
|
|
QString FlatpakImporter::platformName() const
|
|
{
|
|
return QStringLiteral("Flatpak");
|
|
}
|
|
|
|
QString FlatpakImporter::platformId() const
|
|
{
|
|
return QStringLiteral("flatpak");
|
|
}
|
|
|
|
QStringList FlatpakImporter::getFlatpakPaths() const
|
|
{
|
|
QStringList paths;
|
|
|
|
// User Flatpak exports
|
|
paths << expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/applications"));
|
|
// System Flatpak exports
|
|
paths << QStringLiteral("/var/lib/flatpak/exports/share/applications");
|
|
|
|
return paths;
|
|
}
|
|
|
|
bool FlatpakImporter::isAvailable() const
|
|
{
|
|
return !findExecutable(QStringLiteral("flatpak")).isEmpty();
|
|
}
|
|
|
|
bool FlatpakImporter::isGameApp(const QString &desktopFilePath) const
|
|
{
|
|
KDesktopFile desktopFile(desktopFilePath);
|
|
KConfigGroup desktop = desktopFile.desktopGroup();
|
|
|
|
const QString type = desktop.readEntry(QStringLiteral("Type"));
|
|
if (type != QStringLiteral("Application")) {
|
|
return false;
|
|
}
|
|
|
|
if (desktop.readEntry(QStringLiteral("Hidden"), false)) {
|
|
return false;
|
|
}
|
|
if (desktop.readEntry(QStringLiteral("NoDisplay"), false)) {
|
|
return false;
|
|
}
|
|
|
|
const QStringList categories = desktop.readEntry(QStringLiteral("Categories")).split(QLatin1Char(';'), Qt::SkipEmptyParts);
|
|
|
|
return hasGameCategory(categories);
|
|
}
|
|
|
|
Game *FlatpakImporter::parseDesktopFile(const QString &filePath, const QString &appId) const
|
|
{
|
|
KDesktopFile desktopFile(filePath);
|
|
KConfigGroup desktop = desktopFile.desktopGroup();
|
|
|
|
const QString name = desktop.readEntry(QStringLiteral("Name"));
|
|
const QString icon = desktop.readEntry(QStringLiteral("Icon"));
|
|
const QString comment = desktop.readEntry(QStringLiteral("Comment"));
|
|
|
|
if (name.isEmpty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
QString gameId = QStringLiteral("flatpak_") + appId.toLower().replace(QStringLiteral("."), QStringLiteral("_"));
|
|
|
|
Game *game = new Game(gameId, name);
|
|
game->setPlatform(platformName());
|
|
game->setPlatformId(appId);
|
|
game->setLaunchCommand(QStringLiteral("flatpak run %1").arg(appId));
|
|
|
|
if (!comment.isEmpty()) {
|
|
game->setDescription(comment);
|
|
}
|
|
|
|
// Try to find icon
|
|
if (!icon.isEmpty()) {
|
|
QStringList iconPaths = {
|
|
expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/icons/hicolor/256x256/apps/") + icon + QStringLiteral(".png")),
|
|
QStringLiteral("/var/lib/flatpak/exports/share/icons/hicolor/256x256/apps/") + icon + QStringLiteral(".png"),
|
|
expandPath(QStringLiteral("~/.local/share/flatpak/exports/share/icons/hicolor/128x128/apps/") + icon + QStringLiteral(".png")),
|
|
QStringLiteral("/var/lib/flatpak/exports/share/icons/hicolor/128x128/apps/") + icon + QStringLiteral(".png"),
|
|
};
|
|
|
|
for (const QString &iconPath : iconPaths) {
|
|
if (QFile::exists(iconPath)) {
|
|
const QUrl url = QUrl::fromLocalFile(iconPath);
|
|
game->setIconUrl(url);
|
|
if (!game->coverUrl().isValid() || game->coverUrl().isEmpty()) {
|
|
game->setCoverUrl(url);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return game;
|
|
}
|
|
|
|
QList<Game *> FlatpakImporter::importGames()
|
|
{
|
|
QList<Game *> games;
|
|
|
|
for (const QString &path : getFlatpakPaths()) {
|
|
QDir dir(path);
|
|
if (!dir.exists()) {
|
|
continue;
|
|
}
|
|
|
|
QStringList desktopFiles = dir.entryList({QStringLiteral("*.desktop")}, QDir::Files);
|
|
int total = desktopFiles.count();
|
|
int current = 0;
|
|
|
|
for (const QString &fileName : desktopFiles) {
|
|
current++;
|
|
Q_EMIT importProgress(current, total);
|
|
|
|
QString filePath = dir.absoluteFilePath(fileName);
|
|
|
|
if (!isGameApp(filePath)) {
|
|
continue;
|
|
}
|
|
|
|
// Extract app ID from filename (e.g., "com.example.Game.desktop" -> "com.example.Game")
|
|
QString appId = fileName;
|
|
appId.chop(8); // Remove ".desktop"
|
|
|
|
Game *game = parseDesktopFile(filePath, appId);
|
|
if (game) {
|
|
games.append(game);
|
|
}
|
|
}
|
|
}
|
|
|
|
return games;
|
|
}
|