diff --git a/src/util/NuulsUploader.cpp b/src/util/NuulsUploader.cpp new file mode 100644 index 000000000..693ae3f58 --- /dev/null +++ b/src/util/NuulsUploader.cpp @@ -0,0 +1,205 @@ +#include "NuulsUploader.hpp" + +#include "common/Env.hpp" +#include "common/NetworkRequest.hpp" +#include "providers/twitch/TwitchMessageBuilder.hpp" + +#include + +namespace chatterino { +bool isUploading = false; + +std::queue uploadQueue; +void uploadImageToNuuls(QByteArray imageData, ChannelPtr channel, + ResizingTextEdit &textEdit) +{ + uploadImageToNuuls(imageData, channel, textEdit, "png"); +} +void uploadImageToNuuls(TypedBytes imageData, ChannelPtr channel, + ResizingTextEdit &textEdit) +{ + uploadImageToNuuls(imageData.data, channel, textEdit, imageData.type); +} +void uploadImageToNuuls(QByteArray imageData, ChannelPtr channel, + ResizingTextEdit &textEdit, std::string format) +{ + QByteArray dataToSend; + const char *boundary = "thisistheboudaryasd"; + static QUrl url(Env::get().imagePasteSiteUrl); + + dataToSend.insert(0, "--"); + dataToSend.append(boundary); + std::string temp = "\r\n" + "Content-Disposition: form-data; name=\"attachment\"; " + "filename=\"control_v.%\"\r\n" + "Content-Type: image/%\r\n" + "\r\n"; + boost::replace_all(temp, "%", format); + + dataToSend.append(temp.c_str()); + dataToSend.append(imageData); + dataToSend.append("\r\n--"); + dataToSend.append(boundary); + dataToSend.append("\r\n"); + + NetworkRequest(url, NetworkRequestType::Post) + .header("Content-Type", (std::string("multipart/form-data; boundary=") + + std::string(boundary)) + .c_str()) + + .payload(dataToSend) + .onSuccess([&textEdit, channel](NetworkResult result) -> Outcome { + textEdit.insertPlainText(result.getData() + QString(" ")); + // this->input_->ui_.textEdit->insertPlainText(result.getData()); + if (uploadQueue.size()) + { + channel->addMessage(makeSystemMessage( + QString("Your image has been uploaded. %1 left. Please " + "wait until all of them are uploaded. About %2 " + "seconds left.") + .arg(uploadQueue.size()) + .arg(uploadQueue.size() * 3))); + // Argument number 2 is the ETA. + // 2 seconds for the timer that's there not to spam Nuuls' server + // and 1 second of actual uploading. + } + else + { + channel->addMessage(makeSystemMessage( + QString("Your image has been uploaded."))); + } + isUploading = false; + QTimer::singleShot(2000, [channel, &textEdit]() { + if (uploadQueue.size()) + { + uploadImageToNuuls(uploadQueue.front(), channel, textEdit); + uploadQueue.pop(); + } + }); + return Success; + }) + .onError([channel](NetworkResult result) -> bool { + channel->addMessage(makeSystemMessage( + QString("An error happened while uploading your image: %1") + .arg(result.status()))); + isUploading = false; + return true; + }) + .execute(); +} +QString getImageFileFormat(QString path) +{ + static QStringList LIST_OF_IMAGE_FORMATS = {".png", ".jpg", ".jpeg"}; + for (QString i : LIST_OF_IMAGE_FORMATS) + { + if (path.endsWith(i)) + { + return i.replace('.', ""); + } + } + return QString(); +} + +void pasteFromClipboard(const QMimeData *source, ChannelPtr channel, + ResizingTextEdit &outputTextEdit) +{ + /* +static QUrl url("http://localhost:7494/upload?password=xd"); +// default port and password for nuuls' filehost. +*/ + if (isUploading) + { + channel->addMessage(makeSystemMessage( + QString("You are already uploading an image. " + "Please wait until the upload finishes."))); + return; + } + + isUploading = true; + channel->addMessage(makeSystemMessage(QString("Started upload..."))); + + if (source->hasFormat("image/png")) + { + uploadImageToNuuls(source->data("image/png"), channel, outputTextEdit); + } + else if (source->hasFormat("text/uri-list")) + { + QStringList potientialPathsToSend = + QString(source->data("text/uri-list").toStdString().c_str()) + .split("\r\n"); + + for (QString path : potientialPathsToSend) + { + if (path.isEmpty()) + { + break; + } + else + { + if (getImageFileFormat(path) != QString()) + { + channel->addMessage(makeSystemMessage( + QString("Uploading image: %1").arg(path))); + QImage img = QImage(QUrl(path).toLocalFile()); + if (img.isNull()) + { + channel->addMessage(makeSystemMessage( + QString("Couldn't load image :("))); + return; + } + QByteArray imageData; + QBuffer buf(&imageData); + buf.open(QIODevice::WriteOnly); + img.save(&buf, "png"); + + TypedBytes data = {imageData, "png"}; + uploadQueue.push(data); + } + else if (path.endsWith(".gif")) + { + channel->addMessage(makeSystemMessage( + QString("Uploading GIF: %1").arg(path))); + QFile file(QUrl(path).toLocalFile()); + bool isOkay = file.open(QIODevice::ReadOnly); + if (!isOkay) + { + channel->addMessage(makeSystemMessage( + QString("Failed to open file. :("))); + return; + } + TypedBytes data = {file.readAll(), "gif"}; + uploadQueue.push(data); + file.close(); + // file.readAll() => might be a bit big but it /should/ work + } + else + { + channel->addMessage(makeSystemMessage( + QString("Cannot upload file: %1, not an image") + .arg(path))); + } + } + } + if (uploadQueue.size()) + { + uploadImageToNuuls(uploadQueue.front(), channel, outputTextEdit); + uploadQueue.pop(); + } + } + else if (source->hasFormat("image/gif")) + { + TypedBytes data = {source->data("image/gif"), "gif"}; + uploadImageToNuuls(data, channel, outputTextEdit); + } + else + { // not PNG, try loading it into QImage and save it to a PNG. + QImage image = qvariant_cast(source->imageData()); + QByteArray imageData; + QBuffer buf(&imageData); + buf.open(QIODevice::WriteOnly); + image.save(&buf, "png"); + + uploadImageToNuuls(imageData, channel, outputTextEdit); + } +} +} // namespace chatterino diff --git a/src/util/NuulsUploader.hpp b/src/util/NuulsUploader.hpp new file mode 100644 index 000000000..938f94cb0 --- /dev/null +++ b/src/util/NuulsUploader.hpp @@ -0,0 +1,19 @@ +#include "common/Channel.hpp" +#include "widgets/helper/ResizingTextEdit.hpp" + +#include +#include + +namespace chatterino { +struct TypedBytes { + QByteArray data; + std::string type; +}; +void uploadImageToNuuls(QByteArray imageData, ChannelPtr channel, + ResizingTextEdit &textEdit, std::string format); +void uploadImageToNuuls(TypedBytes imageData, ChannelPtr channel, + ResizingTextEdit &textEdit); +QString getImageFileFormat(QString path); +void pasteFromClipboard(const QMimeData *source, ChannelPtr channel, + ResizingTextEdit &outputTextEdit); +} // namespace chatterino