From 88d7bccd0206161f08cad7aead61aefa28f4993e Mon Sep 17 00:00:00 2001 From: Danhoby <37343749+Dan4oby@users.noreply.github.com> Date: Sun, 8 Feb 2026 22:03:53 +0300 Subject: [PATCH 1/4] Implement URL protocol import modpack functionality Signed-off-by: Danhoby <37343749+Dan4oby@users.noreply.github.com> --- launcher/ui/MainWindow.cpp | 78 +++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index d6c4ccbec..650395d78 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -940,6 +940,11 @@ void MainWindow::processURLs(QList urls) QMap extra_info; QUrl local_url; if (!url.isLocalFile()) { // download the remote resource and identify + + const bool isExternalURLImport = + (url.host().toLower() == "import") || + (url.path().startsWith("/import", Qt::CaseInsensitive)); + QUrl dl_url; if (url.scheme() == "curseforge") { // need to find the download link for the modpack / resource @@ -993,7 +998,7 @@ void MainWindow::processURLs(QList urls) dlUrlDialod.execWithTask(job.get()); } - } else if (url.scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME) { + } else if (url.scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME && !isExternalURLImport) { QVariantMap receivedData; const QUrlQuery query(url.query()); const auto items = query.queryItems(); @@ -1001,6 +1006,77 @@ void MainWindow::processURLs(QList urls) receivedData.insert(it->first, it->second); emit APPLICATION->oauthReplyRecieved(receivedData); continue; + } else if (url.scheme() == "prismlauncher" && isExternalURLImport) { + // PrismLauncher URL protocol modpack import + // works for any prism fork + // preferred import format: ://import?url=ENCODED + + const auto host = url.host().toLower(); + const auto path = url.path(); + + QString encodedTarget; + + { + QUrlQuery query(url); + const auto values = query.allQueryItemValues("url"); + if (!values.isEmpty()) { + encodedTarget = values.first(); + } + } + + // alternative import format: ://import/ENCODED + if (encodedTarget.isEmpty()) { + + QString p = path; + + if (p.startsWith("/import/", Qt::CaseInsensitive)) { + p = p.mid(QString("/import/").size()); + } else if (host == "import" && p.startsWith("/")) { + p = p.mid(1); + } + + if (!p.isEmpty() && p != "/import") { + encodedTarget = p; + } + } + + if (encodedTarget.isEmpty()) { + CustomMessageBox::selectable( + this, + tr("Error"), + tr("Invalid import link: missing 'url' parameter."), + QMessageBox::Critical + )->show(); + continue; + } + + const QString decodedStr = QUrl::fromPercentEncoding(encodedTarget.toUtf8()).trimmed(); + + QUrl target = QUrl::fromUserInput(decodedStr); + + // Validate: only allow http(s) + if (!target.isValid() || (target.scheme() != "https" && target.scheme() != "http")) { + CustomMessageBox::selectable( + this, + tr("Error"), + tr("Invalid import link: URL must be http(s)."), + QMessageBox::Critical + )->show(); + continue; + } + + const auto res = QMessageBox::question( + this, + tr("Install modpack"), + tr("Do you want to download and import a modpack from:\n%1\n\nURL:\n%2") + .arg(target.host(), target.toString()), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::Yes + ); + if (res != QMessageBox::Yes) { + continue; + } + } else { dl_url = url; } From 9d534d5a8f8cb542c9a21e3a6d54c7a428dbad6b Mon Sep 17 00:00:00 2001 From: Danhoby <37343749+Dan4oby@users.noreply.github.com> Date: Sun, 8 Feb 2026 22:38:08 +0300 Subject: [PATCH 2/4] Fix import Signed-off-by: Danhoby <37343749+Dan4oby@users.noreply.github.com> --- launcher/ui/MainWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 650395d78..73c5ad962 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include From 6e09f0171458ffd60b570e36688eb9b083bb4729 Mon Sep 17 00:00:00 2001 From: Danhoby <37343749+Dan4oby@users.noreply.github.com> Date: Mon, 9 Feb 2026 20:03:03 +0300 Subject: [PATCH 3/4] Fix issues Signed-off-by: Danhoby <37343749+Dan4oby@users.noreply.github.com> --- launcher/ui/MainWindow.cpp | 8 +++++--- program_info/win_install.nsi.in | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 73c5ad962..5033498d0 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1007,10 +1007,11 @@ void MainWindow::processURLs(QList urls) receivedData.insert(it->first, it->second); emit APPLICATION->oauthReplyRecieved(receivedData); continue; - } else if (url.scheme() == "prismlauncher" && isExternalURLImport) { + } else if ((url.scheme() == "prismlauncher" || url.scheme() == BuildConfig.LAUNCHER_APP_BINARY_NAME) + && isExternalURLImport) { // PrismLauncher URL protocol modpack import // works for any prism fork - // preferred import format: ://import?url=ENCODED + // preferred import format: prismlauncher://import?url=ENCODED const auto host = url.host().toLower(); const auto path = url.path(); @@ -1025,7 +1026,7 @@ void MainWindow::processURLs(QList urls) } } - // alternative import format: ://import/ENCODED + // alternative import format: prismlauncher://import/ENCODED if (encodedTarget.isEmpty()) { QString p = path; @@ -1078,6 +1079,7 @@ void MainWindow::processURLs(QList urls) continue; } + dl_url = target; } else { dl_url = url; } diff --git a/program_info/win_install.nsi.in b/program_info/win_install.nsi.in index e957f4d36..ba6b7e061 100644 --- a/program_info/win_install.nsi.in +++ b/program_info/win_install.nsi.in @@ -397,6 +397,10 @@ Section "@Launcher_DisplayName@" WriteRegStr HKCU Software\Classes\@Launcher_APP_BINARY_NAME@ "URL Protocol" "" WriteRegStr HKCU Software\Classes\@Launcher_APP_BINARY_NAME@\shell\open\command "" '"$INSTDIR\@Launcher_APP_BINARY_NAME@.exe" "%1"' + ; Write the URL Handler into registry for prismlauncher import + WriteRegStr HKCU Software\Classes\prismlauncher "URL Protocol" "" + WriteRegStr HKCU Software\Classes\prismlauncher\shell\open\command "" '"$INSTDIR\@Launcher_APP_BINARY_NAME@.exe" "%1"' + ; Write the uninstall keys for Windows ; https://learn.microsoft.com/en-us/windows/win32/msi/uninstall-registry-key ${GetParameters} $R0 From 92e92642300d11790efeb9c291fd275962eb5899 Mon Sep 17 00:00:00 2001 From: Danhoby <37343749+Dan4oby@users.noreply.github.com> Date: Mon, 9 Feb 2026 21:53:43 +0300 Subject: [PATCH 4/4] Danhoby <37343749+Dan4oby@users.noreply.github.com> DCO Remediation Commit for Danhoby <37343749+Dan4oby@users.noreply.github.com> I, Danhoby <37343749+Dan4oby@users.noreply.github.com>, hereby add my Signed-off-by to this commit: 1bd07392e07417956f45ed56bede6f31f1dc8d2d I, Danhoby <37343749+Dan4oby@users.noreply.github.com>, hereby add my Signed-off-by to this commit: c1003dec2f3b6925453680b90a168300b0cba42a I, Danhoby <37343749+Dan4oby@users.noreply.github.com>, hereby add my Signed-off-by to this commit: 9d5d7742a5e1f583578685087f8785909d386997 Signed-off-by: Danhoby <37343749+Dan4oby@users.noreply.github.com> --- launcher/ui/MainWindow.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 5033498d0..1afc248b7 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1012,7 +1012,6 @@ void MainWindow::processURLs(QList urls) // PrismLauncher URL protocol modpack import // works for any prism fork // preferred import format: prismlauncher://import?url=ENCODED - const auto host = url.host().toLower(); const auto path = url.path();