a-la-karte/src/flatpakimporter.cpp

171 lines
5.4 KiB
C++
Raw Normal View History

// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2026 A-La-Karte Contributors
#include "flatpakimporter.h"
#include <QDir>
#include <QFile>
#include <QProcess>
#include <QRegularExpression>
#include <QSettings>
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
{
QSettings desktop(desktopFilePath, QSettings::IniFormat);
desktop.beginGroup(QStringLiteral("Desktop Entry"));
QString type = desktop.value(QStringLiteral("Type")).toString();
if (type != QStringLiteral("Application")) {
return false;
}
if (desktop.value(QStringLiteral("Hidden"), false).toBool()) {
return false;
}
if (desktop.value(QStringLiteral("NoDisplay"), false).toBool()) {
return false;
}
QString categories = desktop.value(QStringLiteral("Categories")).toString();
QStringList gameCategories = {QStringLiteral("Game"),
QStringLiteral("ArcadeGame"),
QStringLiteral("ActionGame"),
QStringLiteral("AdventureGame"),
QStringLiteral("BlocksGame"),
QStringLiteral("BoardGame"),
QStringLiteral("CardGame"),
QStringLiteral("KidsGame"),
QStringLiteral("LogicGame"),
QStringLiteral("RolePlaying"),
QStringLiteral("Shooter"),
QStringLiteral("Simulation"),
QStringLiteral("SportsGame"),
QStringLiteral("StrategyGame")};
for (const QString &cat : gameCategories) {
if (categories.contains(cat, Qt::CaseInsensitive)) {
return true;
}
}
return false;
}
Game *FlatpakImporter::parseDesktopFile(const QString &filePath, const QString &appId) const
{
QSettings desktop(filePath, QSettings::IniFormat);
desktop.beginGroup(QStringLiteral("Desktop Entry"));
QString name = desktop.value(QStringLiteral("Name")).toString();
QString icon = desktop.value(QStringLiteral("Icon")).toString();
QString comment = desktop.value(QStringLiteral("Comment")).toString();
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(platformId());
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;
}