// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2026 A-La-Karte Contributors #include "bottlesimporter.h" #include #include #include #include #include BottlesImporter::BottlesImporter(QObject *parent) : PlatformImporter(parent) { } QString BottlesImporter::platformName() const { return QStringLiteral("Bottles"); } QString BottlesImporter::platformId() const { return QStringLiteral("bottles"); } QStringList BottlesImporter::getBottlesPaths() const { QStringList paths; // Standard Bottles locations paths << expandPath(QStringLiteral("~/.local/share/bottles")); // Flatpak Bottles paths << expandPath(QStringLiteral("~/.var/app/com.usebottles.bottles/data/bottles")); return paths; } bool BottlesImporter::isAvailable() const { for (const QString &path : getBottlesPaths()) { if (directoryExists(path)) { return true; } } return false; } QList BottlesImporter::parseBottle(const QString &bottlePath, const QString &bottleName) const { QList games; // Look for programs in the bottle QString programsPath = bottlePath + QStringLiteral("/programs.json"); QFile programsFile(programsPath); if (!programsFile.open(QIODevice::ReadOnly)) { return games; } QJsonDocument doc = QJsonDocument::fromJson(programsFile.readAll()); if (!doc.isObject()) { return games; } QJsonObject programs = doc.object(); for (auto it = programs.begin(); it != programs.end(); ++it) { QString programName = it.key(); QJsonObject programData = it.value().toObject(); QString executable = programData[QStringLiteral("executable")].toString(); QString path = programData[QStringLiteral("path")].toString(); if (programName.isEmpty() || executable.isEmpty()) { continue; } QString gameId = QStringLiteral("bottles_%1_%2").arg(bottleName, programName).replace(QStringLiteral(" "), QStringLiteral("_")).toLower(); Game *game = new Game(gameId, programName); game->setPlatform(platformName()); game->setPlatformId(platformId()); // Build launch command using bottles CLI QString launchCmd = QStringLiteral("flatpak run com.usebottles.bottles -e \"%1\" -b \"%2\"").arg(executable, bottleName); // Check if native bottles is available if (!findExecutable(QStringLiteral("bottles-cli")).isEmpty()) { launchCmd = QStringLiteral("bottles-cli run -e \"%1\" -b \"%2\"").arg(executable, bottleName); } game->setLaunchCommand(launchCmd); game->setDescription(QStringLiteral("Wine application from %1 bottle").arg(bottleName)); games.append(game); } return games; } QList BottlesImporter::importGames() { QList games; for (const QString &basePath : getBottlesPaths()) { QString bottlesDir = basePath + QStringLiteral("/bottles"); QDir dir(bottlesDir); if (!dir.exists()) { continue; } QStringList bottles = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); int total = bottles.count(); int current = 0; for (const QString &bottleName : bottles) { current++; Q_EMIT importProgress(current, total); QString bottlePath = dir.absoluteFilePath(bottleName); QList bottleGames = parseBottle(bottlePath, bottleName); games.append(bottleGames); } } return games; }