mirror of
https://invent.kde.org/marcoa/a-la-karte.git
synced 2026-02-09 21:13:08 +00:00
171 lines
5.4 KiB
C++
171 lines
5.4 KiB
C++
|
|
// 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;
|
||
|
|
}
|