aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/main.cpp7
-rw-r--r--src/src/nxmhandler_linux.cpp51
-rw-r--r--src/src/nxmhandler_linux.h1
-rw-r--r--src/src/shared/util.cpp3
4 files changed, 44 insertions, 18 deletions
diff --git a/src/src/main.cpp b/src/src/main.cpp
index b12ac7e..eed977e 100644
--- a/src/src/main.cpp
+++ b/src/src/main.cpp
@@ -205,6 +205,13 @@ int run(int argc, char* argv[])
.arg(link.expires)
.arg(link.user_id));
});
+
+ QObject::connect(&nxmHandler, &NxmHandlerLinux::directDownloadReceived,
+ &app.core(), [&](const QString& url, const QString&) {
+ QMetaObject::invokeMethod(&app.core(), [&app, url] {
+ app.core().downloadManager()->startDownloadURLs(QStringList{url});
+ }, Qt::QueuedConnection);
+ });
}
#endif
diff --git a/src/src/nxmhandler_linux.cpp b/src/src/nxmhandler_linux.cpp
index fbf94d7..9441375 100644
--- a/src/src/nxmhandler_linux.cpp
+++ b/src/src/nxmhandler_linux.cpp
@@ -102,12 +102,15 @@ void updateMimeAppsList(const QString& path, const QString& mimeType,
std::optional<NxmLink> NxmLink::parse(const QString& url)
{
const QUrl parsed(url);
- if (!parsed.isValid() || parsed.scheme().compare("nxm", Qt::CaseInsensitive) != 0) {
+ const QString scheme = parsed.scheme().toLower();
+ if (!parsed.isValid() || (scheme != "nxm" && scheme != "modl")) {
+ log::debug("NxmLink::parse rejected scheme: '{}'", url);
return {};
}
const QString gameDomain = parsed.host().trimmed();
if (gameDomain.isEmpty()) {
+ log::debug("NxmLink::parse rejected empty host: '{}'", url);
return {};
}
@@ -115,6 +118,7 @@ std::optional<NxmLink> NxmLink::parse(const QString& url)
parsed.path().split('/', Qt::SkipEmptyParts);
if (parts.size() != 4 || parts[0] != "mods" || parts[2] != "files") {
+ log::debug("NxmLink::parse rejected path (expected /mods/ID/files/ID): '{}'", url);
return {};
}
@@ -123,22 +127,15 @@ std::optional<NxmLink> NxmLink::parse(const QString& url)
const uint64_t modId = parts[1].toULongLong(&modOk);
const uint64_t fileId = parts[3].toULongLong(&fileOk);
if (!modOk || !fileOk) {
+ log::debug("NxmLink::parse rejected non-numeric IDs: '{}'", url);
return {};
}
+ // key/expires are required for NXM but optional for modl:// (mod.pub).
const QUrlQuery query(parsed);
- const QString key = query.queryItemValue("key");
- if (key.isEmpty()) {
- return {};
- }
-
- bool expiresOk = false;
- const uint64_t expires = query.queryItemValue("expires").toULongLong(&expiresOk);
- if (!expiresOk) {
- return {};
- }
-
- const int userId = query.queryItemValue("user_id").toInt();
+ const QString key = query.queryItemValue("key");
+ const uint64_t expires = query.queryItemValue("expires").toULongLong();
+ const int userId = query.queryItemValue("user_id").toInt();
return NxmLink{gameDomain, modId, fileId, key, expires, userId};
}
@@ -229,7 +226,7 @@ void NxmHandlerLinux::registerHandler() const
"Type=Application\n"
"Name=Mod Organizer 2 NXM Handler\n"
"Exec=%1\n"
- "MimeType=x-scheme-handler/nxm;\n"
+ "MimeType=x-scheme-handler/nxm;x-scheme-handler/modl;\n"
"NoDisplay=true\n").arg(execLine);
if (!writeTextFile(desktopPath, desktop)) {
@@ -241,6 +238,10 @@ void NxmHandlerLinux::registerHandler() const
"mo2-nxm-handler.desktop");
updateMimeAppsList(appsDir + "/mimeapps.list", "x-scheme-handler/nxm",
"mo2-nxm-handler.desktop");
+ updateMimeAppsList(configDir + "/mimeapps.list", "x-scheme-handler/modl",
+ "mo2-nxm-handler.desktop");
+ updateMimeAppsList(appsDir + "/mimeapps.list", "x-scheme-handler/modl",
+ "mo2-nxm-handler.desktop");
const auto result =
QProcess::execute("update-desktop-database", QStringList() << appsDir);
@@ -302,13 +303,29 @@ void NxmHandlerLinux::processSocketData(QLocalSocket* socket)
continue;
}
+ log::info("received link on socket: {}", line);
+
+ // Try NXM-style parse first (nxm:// or modl:// with /mods/ID/files/ID path).
const auto link = NxmLink::parse(line);
- if (!link) {
- log::warn("received invalid nxm url on socket: {}", line);
+ if (link) {
+ emit nxmReceived(*link);
continue;
}
- emit nxmReceived(*link);
+ // modl:// direct download: modl://GAME/?url=<encoded-download-url>
+ const QUrl parsed(line);
+ if (parsed.isValid() && parsed.scheme().compare("modl", Qt::CaseInsensitive) == 0) {
+ const QUrlQuery query(parsed);
+ const QString downloadUrl = query.queryItemValue("url", QUrl::FullyDecoded);
+ if (!downloadUrl.isEmpty()) {
+ const QString gameDomain = parsed.host().trimmed();
+ log::info("modl direct download for '{}': {}", gameDomain, downloadUrl);
+ emit directDownloadReceived(downloadUrl, gameDomain);
+ continue;
+ }
+ }
+
+ log::warn("received unrecognized url on socket: {}", line);
}
}
diff --git a/src/src/nxmhandler_linux.h b/src/src/nxmhandler_linux.h
index b6bd675..c4631aa 100644
--- a/src/src/nxmhandler_linux.h
+++ b/src/src/nxmhandler_linux.h
@@ -41,6 +41,7 @@ public:
signals:
void nxmReceived(NxmLink link);
+ void directDownloadReceived(QString url, QString gameDomain);
private:
void onNewConnection();
diff --git a/src/src/shared/util.cpp b/src/src/shared/util.cpp
index 2c982dc..70c0aeb 100644
--- a/src/src/shared/util.cpp
+++ b/src/src/shared/util.cpp
@@ -510,5 +510,6 @@ void ResetExitFlag()
bool isNxmLink(const QString& link)
{
- return link.startsWith("nxm://", Qt::CaseInsensitive);
+ return link.startsWith("nxm://", Qt::CaseInsensitive) ||
+ link.startsWith("modl://", Qt::CaseInsensitive);
}