// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2026 A-La-Karte Contributors #include "itchimporter.h" #include #include #include #include #include #include #include #include ItchImporter::ItchImporter(QObject *parent) : PlatformImporter(parent) { } QString ItchImporter::platformName() const { return QStringLiteral("itch.io"); } QString ItchImporter::platformId() const { return QStringLiteral("itch"); } QString ItchImporter::getItchDatabasePath() const { QStringList paths = { expandPath(QStringLiteral("~/.config/itch/db/butler.db")), expandPath(QStringLiteral("~/.var/app/io.itch.itch/config/itch/db/butler.db")), }; for (const QString &path : paths) { if (QFile::exists(path)) { return path; } } return QString(); } bool ItchImporter::isAvailable() const { return !getItchDatabasePath().isEmpty(); } QList ItchImporter::parseItchDatabase(const QString &dbPath) const { QList games; // Use a unique connection name QString connectionName = QStringLiteral("itch_import_%1").arg(reinterpret_cast(this)); { QSqlDatabase db = QSqlDatabase::addDatabase(QStringLiteral("QSQLITE"), connectionName); db.setDatabaseName(dbPath); if (!db.open()) { return games; } // Query caves table for installed games QSqlQuery query(db); query.prepare( QStringLiteral("SELECT c.id, c.game_id, g.title, g.short_text, g.cover_url, c.install_folder_name " "FROM caves c " "LEFT JOIN games g ON c.game_id = g.id " "WHERE c.install_folder_name IS NOT NULL")); if (!query.exec()) { db.close(); return games; } while (query.next()) { QString caveId = query.value(0).toString(); QString gameId = query.value(1).toString(); QString title = query.value(2).toString(); QString shortText = query.value(3).toString(); QString coverUrl = query.value(4).toString(); QString installFolder = query.value(5).toString(); if (title.isEmpty()) { continue; } QString id = QStringLiteral("itch_%1").arg(gameId); Game *game = new Game(id, title); game->setPlatform(platformName()); game->setPlatformId(platformId()); if (!shortText.isEmpty()) { game->setDescription(shortText); } if (!coverUrl.isEmpty()) { game->setCoverUrl(QUrl(coverUrl)); } // Build launch command using itch app QString launchCmd = QStringLiteral("itch://caves/%1/launch").arg(caveId); game->setLaunchCommand(QStringLiteral("xdg-open \"%1\"").arg(launchCmd)); games.append(game); } db.close(); } QSqlDatabase::removeDatabase(connectionName); return games; } QList ItchImporter::importGames() { QString dbPath = getItchDatabasePath(); if (dbPath.isEmpty()) { return {}; } return parseItchDatabase(dbPath); }