commit 99e3349bf64e2c651e5e3c4c78b3858632c71fea
Author: Luke Granger-Brown <git@lukegb.com>
Date:   Sun Aug 4 00:56:02 2024 +0100

    Add fup upload support

diff --git a/src/config/generalconf.cpp b/src/config/generalconf.cpp
index 8c8024de..9e1883b8 100644
--- a/src/config/generalconf.cpp
+++ b/src/config/generalconf.cpp
@@ -57,6 +57,11 @@ GeneralConf::GeneralConf(QWidget* parent)
     initUploadHistoryMax();
     initUndoLimit();
     initUploadClientSecret();
+    initFupUploadClientSecret();
+    initAllowMultipleGuiInstances();
+#if !defined(Q_OS_WIN)
+    initAutoCloseIdleDaemon();
+#endif
     initPredefinedColorPaletteLarge();
     initShowSelectionGeometry();
 
@@ -573,6 +578,31 @@ void GeneralConf::uploadClientKeyEdited()
     ConfigHandler().setUploadClientSecret(m_uploadClientKey->text());
 }
 
+void GeneralConf::initFupUploadClientSecret()
+{
+    auto* box = new QGroupBox(tr("Fup Secret"));
+    box->setFlat(true);
+    m_layout->addWidget(box);
+
+    auto* vboxLayout = new QVBoxLayout();
+    box->setLayout(vboxLayout);
+
+    m_fupUploadClientKey = new QLineEdit(this);
+    QString foreground = this->palette().windowText().color().name();
+    m_fupUploadClientKey->setStyleSheet(
+      QStringLiteral("color: %1").arg(foreground));
+    m_fupUploadClientKey->setText(ConfigHandler().fupUploadClientSecret());
+    connect(m_fupUploadClientKey,
+            SIGNAL(editingFinished()),
+            this,
+            SLOT(fupUploadClientKeyEdited()));
+    vboxLayout->addWidget(m_fupUploadClientKey);
+}
+
+void GeneralConf::fupUploadClientKeyEdited()
+{
+    ConfigHandler().setFupUploadClientSecret(m_fupUploadClientKey->text());
+}
 void GeneralConf::uploadHistoryMaxChanged(int max)
 {
     ConfigHandler().setUploadHistoryMax(max);
diff --git a/src/config/generalconf.h b/src/config/generalconf.h
index e1f49791..b49a876a 100644
--- a/src/config/generalconf.h
+++ b/src/config/generalconf.h
@@ -53,6 +53,7 @@ private slots:
     void resetConfiguration();
     void togglePathFixed();
     void uploadClientKeyEdited();
+    void fupUploadClientKeyEdited();
     void useJpgForClipboardChanged(bool checked);
     void setSaveAsFileExtension(const QString& extension);
     void setGeometryLocation(int index);
@@ -89,6 +90,7 @@ private:
     void initUseJpgForClipboard();
     void initUploadHistoryMax();
     void initUploadClientSecret();
+    void initFupUploadClientSecret();
     void initSaveLastRegion();
     void initShowSelectionGeometry();
     void initJpegQuality();
@@ -121,6 +123,7 @@ private:
     QCheckBox* m_saveAfterCopy;
     QLineEdit* m_savePath;
     QLineEdit* m_uploadClientKey;
+    QLineEdit* m_fupUploadClientKey;
     QPushButton* m_changeSaveButton;
     QCheckBox* m_screenshotPathFixedCheck;
     QCheckBox* m_historyConfirmationToDelete;
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index d2a62924..eea75beb 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -10,6 +10,8 @@ target_sources(
   flameshot
         PRIVATE imgupload/storages/imgur/imguruploader.h
         imgupload/storages/imgur/imguruploader.cpp
+        imgupload/storages/fup/fupuploader.h
+        imgupload/storages/fup/fupuploader.cpp
         imgupload/storages/imguploaderbase.h
         imgupload/storages/imguploaderbase.cpp
         imgupload/imguploadertool.h
diff --git a/src/tools/imgupload/imguploadermanager.cpp b/src/tools/imgupload/imguploadermanager.cpp
index 37df80c0..8a7e2125 100644
--- a/src/tools/imgupload/imguploadermanager.cpp
+++ b/src/tools/imgupload/imguploadermanager.cpp
@@ -8,7 +8,7 @@
 
 // TODO - remove this hard-code and create plugin manager in the future, you may
 // include other storage headers here
-#include "storages/imgur/imguruploader.h"
+#include "storages/fup/fupuploader.h"
 
 ImgUploaderManager::ImgUploaderManager(QObject* parent)
   : QObject(parent)
@@ -29,8 +29,8 @@ void ImgUploaderManager::init()
     //    m_qstrUrl = "https://imgur.com/";
     //    m_imgUploaderPlugin = "imgur";
     //}
-    m_urlString = "https://imgur.com/";
-    m_imgUploaderPlugin = "imgur";
+    m_urlString = "https://p.lukegb.com/";
+    m_imgUploaderPlugin = "fup";
 }
 
 ImgUploaderBase* ImgUploaderManager::uploader(const QPixmap& capture,
@@ -45,7 +45,7 @@ ImgUploaderBase* ImgUploaderManager::uploader(const QPixmap& capture,
     //    m_imgUploaderBase =
     //      (ImgUploaderBase*)(new ImgurUploader(capture, parent));
     //}
-    m_imgUploaderBase = (ImgUploaderBase*)(new ImgurUploader(capture, parent));
+    m_imgUploaderBase = (ImgUploaderBase*)(new FupUploader(capture, parent));
     if (m_imgUploaderBase && !capture.isNull()) {
         m_imgUploaderBase->upload();
     }
diff --git a/src/tools/imgupload/storages/fup/fupuploader.cpp b/src/tools/imgupload/storages/fup/fupuploader.cpp
new file mode 100644
index 00000000..e2e7d94b
--- /dev/null
+++ b/src/tools/imgupload/storages/fup/fupuploader.cpp
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// SPDX-FileCopyrightText: 2017-2019 Alejandro Sirgo Rica & Contributors
+
+#include "fupuploader.h"
+#include "src/utils/confighandler.h"
+#include "src/utils/filenamehandler.h"
+#include "src/utils/history.h"
+#include "src/widgets/loadspinner.h"
+#include "src/widgets/notificationwidget.h"
+#include <QBuffer>
+#include <QDesktopServices>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QShortcut>
+#include <QUrlQuery>
+
+FupUploader::FupUploader(const QPixmap& capture, QWidget* parent)
+  : ImgUploaderBase(capture, parent)
+{
+    m_NetworkAM = new QNetworkAccessManager(this);
+    connect(m_NetworkAM,
+            &QNetworkAccessManager::finished,
+            this,
+            &FupUploader::handleReply);
+}
+
+void FupUploader::handleReply(QNetworkReply* reply)
+{
+    spinner()->deleteLater();
+    m_currentImageName.clear();
+    if (reply->error() == QNetworkReply::NoError) {
+        QJsonDocument response = QJsonDocument::fromJson(reply->readAll());
+        QJsonObject json = response.object();
+        setImageURL(json[QStringLiteral("display_url")].toString());
+
+        // save history
+        m_currentImageName = imageURL().toString();
+        int lastSlash = m_currentImageName.lastIndexOf("/");
+        if (lastSlash >= 0) {
+            m_currentImageName = m_currentImageName.mid(lastSlash + 1);
+        }
+
+        // save image to history
+        History history;
+        m_currentImageName =
+          history.packFileName("fup", "", m_currentImageName);
+        history.save(pixmap(), m_currentImageName);
+
+        emit uploadOk(imageURL());
+    } else {
+        setInfoLabelText(reply->errorString());
+    }
+    new QShortcut(Qt::Key_Escape, this, SLOT(close()));
+}
+
+void FupUploader::upload()
+{
+    QByteArray byteArray;
+    QBuffer buffer(&byteArray);
+    pixmap().save(&buffer, "PNG");
+
+    QString basicAuthValue = QStringLiteral(":%1")
+        .arg(ConfigHandler().fupUploadClientSecret())
+        .toUtf8().toBase64();
+
+    QUrl url(QStringLiteral("https://p.lukegb.com/upload/image.png").toUtf8());
+    QNetworkRequest request(url);
+    request.setHeader(QNetworkRequest::ContentTypeHeader,
+                      "image/png");
+    request.setRawHeader("Accept", "application/json");
+    request.setRawHeader("Authorization", QStringLiteral("Basic %1").arg(basicAuthValue).toUtf8());
+
+    m_NetworkAM->put(request, byteArray);
+}
+
+void FupUploader::deleteImage(const QString& fileName,
+                              const QString& deleteToken)
+{
+    Q_UNUSED(fileName)
+    Q_UNUSED(deleteToken)
+
+    emit deleteOk();
+}
diff --git a/src/tools/imgupload/storages/fup/fupuploader.h b/src/tools/imgupload/storages/fup/fupuploader.h
new file mode 100644
index 00000000..4748ada9
--- /dev/null
+++ b/src/tools/imgupload/storages/fup/fupuploader.h
@@ -0,0 +1,29 @@
+// SPDX-License-Identifier: GPL-3.0-or-later
+// SPDX-FileCopyrightText: 2017-2022 Alejandro Sirgo Rica & Contributors
+
+#pragma once
+
+#include "src/tools/imgupload/storages/imguploaderbase.h"
+#include <QUrl>
+#include <QWidget>
+
+class QNetworkReply;
+class QNetworkAccessManager;
+class QUrl;
+
+class FupUploader : public ImgUploaderBase
+{
+    Q_OBJECT
+public:
+    explicit FupUploader(const QPixmap& capture, QWidget* parent = nullptr);
+    void deleteImage(const QString& fileName, const QString& deleteToken);
+
+private slots:
+    void handleReply(QNetworkReply* reply);
+
+private:
+    void upload();
+
+private:
+    QNetworkAccessManager* m_NetworkAM;
+};
diff --git a/src/utils/confighandler.cpp b/src/utils/confighandler.cpp
index 485fb265..ba6e44eb 100644
--- a/src/utils/confighandler.cpp
+++ b/src/utils/confighandler.cpp
@@ -124,6 +124,7 @@ static QMap<class QString, QSharedPointer<ValueHandler>>
     // drawFontSize, remember to update ConfigHandler::toolSize
     OPTION("copyOnDoubleClick"           ,Bool               ( false         )),
     OPTION("uploadClientSecret"          ,String             ( "313baf0c7b4d3ff"            )),
+    OPTION("fupUploadClientSecret"       ,String             ( ""            )),
     OPTION("showSelectionGeometry"  , BoundedInt               (0,5,4)),
     OPTION("showSelectionGeometryHideTime", LowerBoundedInt       (0, 3000)),
     OPTION("jpegQuality", BoundedInt     (0,100,75))
diff --git a/src/utils/confighandler.h b/src/utils/confighandler.h
index f2eb4ad9..16b7126f 100644
--- a/src/utils/confighandler.h
+++ b/src/utils/confighandler.h
@@ -125,6 +125,7 @@ public:
     CONFIG_GETTER_SETTER(squareMagnifier, setSquareMagnifier, bool)
     CONFIG_GETTER_SETTER(copyOnDoubleClick, setCopyOnDoubleClick, bool)
     CONFIG_GETTER_SETTER(uploadClientSecret, setUploadClientSecret, QString)
+    CONFIG_GETTER_SETTER(fupUploadClientSecret, setFupUploadClientSecret, QString)
     CONFIG_GETTER_SETTER(saveLastRegion, setSaveLastRegion, bool)
     CONFIG_GETTER_SETTER(showSelectionGeometry, setShowSelectionGeometry, int)
     CONFIG_GETTER_SETTER(jpegQuality, setJpegQuality, int)