Redesigned uploaders a bit to support more stuff.

Added a functionality of uploading byte arrays and even files. Created RecordingFormat, which allows me to create states, I guess??, for RecordingContex's. Needed for, eg. gifs, which are horrible and I strongly suggest against, which will actually be stored as files per frame which are QImages encoded with QImage::Format_RGB888 (confirmation needed).
This commit is contained in:
ArsenArsen 2017-06-04 22:58:29 +02:00
parent 8f5197b826
commit 34624e5762
16 changed files with 168 additions and 63 deletions

View File

@ -50,7 +50,8 @@ SOURCES += main.cpp\
worker/worker.cpp \ worker/worker.cpp \
screenareaselector/screenareaselector.cpp \ screenareaselector/screenareaselector.cpp \
recording/recordingpreview.cpp \ recording/recordingpreview.cpp \
recording/recordingcontroller.cpp recording/recordingcontroller.cpp \
recording/recordingformats.cpp
HEADERS += mainwindow.hpp \ HEADERS += mainwindow.hpp \
cropeditor/cropeditor.hpp \ cropeditor/cropeditor.hpp \
@ -82,7 +83,8 @@ HEADERS += mainwindow.hpp \
worker/worker.hpp \ worker/worker.hpp \
screenareaselector/screenareaselector.hpp \ screenareaselector/screenareaselector.hpp \
recording/recordingpreview.hpp \ recording/recordingpreview.hpp \
recording/recordingcontroller.hpp recording/recordingcontroller.hpp \
recording/recordingformats.hpp
mac { mac {
SOURCES += $$PWD/platformspecifics/mac/macbackend.cpp SOURCES += $$PWD/platformspecifics/mac/macbackend.cpp

View File

@ -37,5 +37,7 @@ bool hotkeying::valid(QString seq) {
} }
QString hotkeying::sequence(QString seqName) { QString hotkeying::sequence(QString seqName) {
return hotkeys.contains(seqName) ? hotkeys.value(seqName)->shortcut().toString() : ""; return hotkeys.contains(seqName) ?
hotkeys.value(seqName)->isRegistered() ? hotkeys.value(seqName)->shortcut().toString() : "" :
"";
} }

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>512</width> <width>512</width>
<height>399</height> <height>410</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -25,6 +25,18 @@
</sizepolicy> </sizepolicy>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="9" column="1">
<widget class="QComboBox" name="comboBox">
<property name="currentIndex">
<number>0</number>
</property>
<item>
<property name="text">
<string>Recording disabled</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLineEdit" name="nameScheme"> <widget class="QLineEdit" name="nameScheme">
<property name="toolTip"> <property name="toolTip">
@ -63,7 +75,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="0" colspan="2"> <item row="11" column="0" colspan="2">
<widget class="QLabel" name="label_6"> <widget class="QLabel" name="label_6">
<property name="text"> <property name="text">
<string>&lt;a href=&quot;https://github.com/ArsenArsen/KShare&quot;&gt;Source code available free for everyone. Forever.&lt;/a&gt; <string>&lt;a href=&quot;https://github.com/ArsenArsen/KShare&quot;&gt;Source code available free for everyone. Forever.&lt;/a&gt;
@ -92,13 +104,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0" colspan="2">
<widget class="QCheckBox" name="hideToTray">
<property name="text">
<string>Pressing &lt;X&gt; hides to tray</string>
</property>
</widget>
</item>
<item row="1" column="1" rowspan="5"> <item row="1" column="1" rowspan="5">
<widget class="QListWidget" name="hotkeys"/> <widget class="QListWidget" name="hotkeys"/>
</item> </item>
@ -112,13 +117,27 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QListWidget" name="uploaderList"/> <widget class="QListWidget" name="uploaderList"/>
</item> </item>
<item row="8" column="0"> <item row="9" column="0">
<widget class="QCheckBox" name="captureCursor"> <widget class="QCheckBox" name="captureCursor">
<property name="text"> <property name="text">
<string>Capture cursor</string> <string>Capture cursor</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0">
<widget class="QCheckBox" name="hideToTray">
<property name="text">
<string>Pressing &lt;X&gt; hides to tray</string>
</property>
</widget>
</item>
<item row="7" column="1" rowspan="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Recording format</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QMenuBar" name="menuBar"> <widget class="QMenuBar" name="menuBar">
@ -127,7 +146,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>512</width> <width>512</width>
<height>24</height> <height>25</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">

View File

@ -8,6 +8,7 @@
#include <screenshotutil.hpp> #include <screenshotutil.hpp>
#include <settings.hpp> #include <settings.hpp>
#include <stdio.h> #include <stdio.h>
#include <uploaders/uploadersingleton.hpp>
#include <worker/worker.hpp> #include <worker/worker.hpp>
RecordingController::RecordingController() : timer(this) { RecordingController::RecordingController() : timer(this) {
@ -33,7 +34,7 @@ bool RecordingController::end() {
area = QRect(); area = QRect();
preview->close(); preview->close();
preview = 0; preview = 0;
_context->finalizer(); UploaderSingleton::inst().upload(_context->finalizer());
frame = 0; frame = 0;
time = 0; time = 0;
return true; return true;

View File

@ -3,6 +3,7 @@
#include "recordingpreview.hpp" #include "recordingpreview.hpp"
#include <QFile>
#include <QImage> #include <QImage>
#include <QRect> #include <QRect>
#include <QTimer> #include <QTimer>
@ -13,7 +14,7 @@ class RecordingContext {
public: public:
QImage::Format format; QImage::Format format;
std::function<void(QImage)> consumer; std::function<void(QImage)> consumer;
std::function<void()> finalizer; std::function<QFile()> finalizer;
}; };
class RecordingController : public QObject { class RecordingController : public QObject {

View File

@ -0,0 +1,35 @@
#include "recordingformats.hpp"
#include <QFile>
RecordingFormats::RecordingFormats(RecordingFormats::Format f) {
switch (f) {
case GIF:
// TODO
break;
default:
break;
}
}
std::function<void(QImage)> RecordingFormats::getConsumer() {
return consumer;
}
std::function<QFile()> RecordingFormats::getFinalizer() {
return finalizer;
}
QString RecordingFormats::getPrettyName(RecordingFormats::Format f) {
switch (f) {
case None:
return "None";
break;
case GIF:
return "gif";
break;
default:
return QString();
break;
}
}

View File

@ -0,0 +1,23 @@
#ifndef RECORDINGFORMATS_HPP
#define RECORDINGFORMATS_HPP
#include <QFile>
#include <QImage>
#include <QString>
#include <functional>
class RecordingFormats {
public:
enum Format { None, GIF };
RecordingFormats(Format f);
std::function<void(QImage)> getConsumer();
std::function<QByteArray()> getFinalizer();
static QString getPrettyName(Format f);
private:
std::function<void(QImage)> consumer;
std::function<QByteArray()> finalizer;
};
#endif // RECORDINGFORMATS_HPP

View File

@ -64,11 +64,11 @@ CustomUploader::CustomUploader(QString absFilePath) {
if (formatValue.isString()) { if (formatValue.isString()) {
QString formatString = formatValue.toString().toLower(); QString formatString = formatValue.toString().toLower();
if (formatString == "x-www-form-urlencoded") if (formatString == "x-www-form-urlencoded")
format = RequestFormat::X_WWW_FORM_URLENCODED; rFormat = RequestFormat::X_WWW_FORM_URLENCODED;
else if (formatString == "json") else if (formatString == "json")
format = RequestFormat::JSON; rFormat = RequestFormat::JSON;
else if (formatString == "plain") else if (formatString == "plain")
format = RequestFormat::PLAIN; rFormat = RequestFormat::PLAIN;
else else
error(absFilePath, "format invalid"); error(absFilePath, "format invalid");
} }
@ -85,7 +85,7 @@ CustomUploader::CustomUploader(QString absFilePath) {
} else } else
error(absFilePath, "imageformat invalid"); error(absFilePath, "imageformat invalid");
QJsonValue bodyValue = obj["body"]; QJsonValue bodyValue = obj["body"];
if (format != RequestFormat::PLAIN) { if (rFormat != RequestFormat::PLAIN) {
if (bodyValue.isUndefined()) error(absFilePath, "body not set"); if (bodyValue.isUndefined()) error(absFilePath, "body not set");
if (bodyValue.isObject()) if (bodyValue.isObject())
body = bodyValue; body = bodyValue;
@ -123,6 +123,10 @@ QString CustomUploader::description() {
return desc; return desc;
} }
std::tuple<QString, QString> CustomUploader::format() {
return std::tuple<QString, QString>(getFormatString(false), getFormatString(true));
}
QString getCType(RequestFormat format, QString plainType) { QString getCType(RequestFormat format, QString plainType) {
switch (format) { switch (format) {
case RequestFormat::X_WWW_FORM_URLENCODED: case RequestFormat::X_WWW_FORM_URLENCODED:
@ -149,14 +153,6 @@ QList<QPair<QString, QString>> getHeaders(QJsonObject h, QString imageFormat, QM
return headers; return headers;
} }
QByteArray imageBytes(QPixmap *pixmap, QString format) {
QByteArray returnVal;
QBuffer buff(&returnVal);
buff.open(QIODevice::WriteOnly);
pixmap->save(&buff, format.toUpper().toLocal8Bit().constData());
return returnVal;
}
QString CustomUploader::getFormatString(bool animated) { QString CustomUploader::getFormatString(bool animated) {
if (iFormat == "base64") if (iFormat == "base64")
return animated ? "GIF" : "PNG"; return animated ? "GIF" : "PNG";
@ -238,13 +234,12 @@ void parseResult(QJsonDocument result, QByteArray data, QString returnPathspec,
} }
} }
void CustomUploader::doUpload(QPixmap *pixmap) { void CustomUploader::doUpload(QByteArray imgData) {
auto h = getHeaders(headers, getFormatString(false), types, this->format); auto h = getHeaders(headers, getFormatString(false), types, this->rFormat);
QString format = getFormatString(false); // Soon:tm: QString format = getFormatString(false); // Soon:tm:
QByteArray data; QByteArray data;
QByteArray imgData = imageBytes(pixmap, format);
if (iFormat == "base64" || QRegExp("base64\\([^+]\\+[^+]\\)").exactMatch(iFormat)) imgData = imgData.toBase64(); if (iFormat == "base64" || QRegExp("base64\\([^+]\\+[^+]\\)").exactMatch(iFormat)) imgData = imgData.toBase64();
switch (this->format) { switch (this->rFormat) {
case RequestFormat::PLAIN: { case RequestFormat::PLAIN: {
data = imgData; data = imgData;
} break; } break;

View File

@ -15,7 +15,8 @@ class CustomUploader : public Uploader {
CustomUploader(QString absFilePath); CustomUploader(QString absFilePath);
QString name(); QString name();
QString description(); QString description();
void doUpload(QPixmap *pixmap); std::tuple<QString, QString> format();
void doUpload(QByteArray imgData);
QString getFormatString(bool animated); QString getFormatString(bool animated);
QMap<QString, QString> types; QMap<QString, QString> types;
@ -23,7 +24,7 @@ class CustomUploader : public Uploader {
double limit = -1; double limit = -1;
QString desc; QString desc;
QString uName; QString uName;
RequestFormat format = RequestFormat::JSON; RequestFormat rFormat = RequestFormat::JSON;
HttpMethod method = HttpMethod::POST; HttpMethod method = HttpMethod::POST;
QUrl target; QUrl target;
QJsonValue body; QJsonValue body;

View File

@ -4,7 +4,7 @@
#include <QClipboard> #include <QClipboard>
#include <notifications.hpp> #include <notifications.hpp>
void ClipboardUploader::doUpload(QPixmap *pixmap) { void ClipboardUploader::doUpload(QByteArray imgData) {
QApplication::clipboard()->setImage(pixmap->toImage()); QApplication::clipboard()->setImage(QImage::fromData(imgData, std::get<0>(format()).toLocal8Bit().constData()));
notifications::notify("KShare", "Copied to clipboard!"); notifications::notify("KShare", "Copied to clipboard!");
} }

View File

@ -12,7 +12,11 @@ class ClipboardUploader : public Uploader {
QString description() { QString description() {
return "Copies the image to clipboard"; return "Copies the image to clipboard";
} }
void doUpload(QPixmap *pixmap); std::tuple<QString, QString> format() {
return std::tuple<QString, QString>("PNG", "MP4");
}
void doUpload(QByteArray imgData);
}; };
#endif // CLIPBOARDUPLOADER_HPP #endif // CLIPBOARDUPLOADER_HPP

View File

@ -7,20 +7,19 @@
#include <notifications.hpp> #include <notifications.hpp>
#include <screenshotutil.hpp> #include <screenshotutil.hpp>
void ImgurUploader::doUpload(QPixmap *pixmap) { void ImgurUploader::doUpload(QByteArray byteArray) {
QByteArray byteArray; if (byteArray.size() > 1e+7) {
QBuffer buffer(&byteArray);
pixmap->save(&buffer, "PNG");
if (buffer.size() > 1e+7) {
notifications::notify("KShare imgur Uploader ", "Failed upload! Image too big"); notifications::notify("KShare imgur Uploader ", "Failed upload! Image too big");
return; return;
} }
ioutils::postJson(QUrl("https://api.imgur.com/3/image"), ioutils::postJson(QUrl("https://api.imgur.com/3/image"),
QList<QPair<QString, QString>>() << QPair<QString, QString>("Content-Type", "application/x-www-form-urlencoded") QList<QPair<QString, QString>>()
<< QPair<QString, QString>("Content-Type", "application/x-www-form-urlencoded")
<< QPair<QString, QString>("Authorization", "Client-ID 8a98f183fc895da"), << QPair<QString, QString>("Authorization", "Client-ID 8a98f183fc895da"),
byteArray, [](QJsonDocument res, QByteArray, QNetworkReply *) { byteArray, [](QJsonDocument res, QByteArray, QNetworkReply *) {
QString result = res.object()["data"].toObject()["link"].toString(); QString result = res.object()["data"].toObject()["link"].toString();
screenshotutil::toClipboard(result); screenshotutil::toClipboard(result);
notifications::notify("KShare imgur Uploader ", result.isEmpty() ? "Failed upload!" : "Uploaded to imgur!"); notifications::notify("KShare imgur Uploader ",
result.isEmpty() ? "Failed upload!" : "Uploaded to imgur!");
}); });
} }

View File

@ -11,7 +11,10 @@ class ImgurUploader : public Uploader {
QString description() { QString description() {
return "imgur.com uploader"; return "imgur.com uploader";
} }
void doUpload(QPixmap *pixmap); std::tuple<QString, QString> format() {
return std::tuple<QString, QString>("PNG", "MP4");
}
void doUpload(QByteArray byteArray);
}; };
#endif // IMGURUPLOADER_HPP #endif // IMGURUPLOADER_HPP

View File

@ -6,9 +6,10 @@
class Uploader { class Uploader {
public: public:
virtual void doUpload(QPixmap *pixmap) = 0; virtual void doUpload(QByteArray imgData) = 0;
virtual QString name() = 0; virtual QString name() = 0;
virtual QString description() = 0; virtual QString description() = 0;
virtual std::tuple<QString, QString> format() = 0;
}; };
#endif // UPLOADER_HPP #endif // UPLOADER_HPP

View File

@ -2,13 +2,15 @@
#include "customuploader.hpp" #include "customuploader.hpp"
#include "default/clipboarduploader.hpp" #include "default/clipboarduploader.hpp"
#include "default/imguruploader.hpp" #include "default/imguruploader.hpp"
#include <QBuffer>
#include <QDebug> #include <QDebug>
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include <formatter.hpp> #include <formatter.hpp>
#include <settings.hpp> #include <settings.hpp>
UploaderSingleton::UploaderSingleton() : QObject(), saveDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) { UploaderSingleton::UploaderSingleton()
: QObject(), saveDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)) {
if (QStandardPaths::writableLocation(QStandardPaths::PicturesLocation).isEmpty()) { if (QStandardPaths::writableLocation(QStandardPaths::PicturesLocation).isEmpty()) {
qFatal("Cannot determine location for pictures"); qFatal("Cannot determine location for pictures");
} }
@ -54,16 +56,30 @@ void UploaderSingleton::registerUploader(Uploader *uploader) {
} }
void UploaderSingleton::upload(QPixmap *pixmap) { void UploaderSingleton::upload(QPixmap *pixmap) {
if (settings::settings().contains("fileFormat")) { auto u = uploaders.value(uploader);
QString format = settings::settings().value("fileFormat").toString(); QByteArray arr;
if (!format.isEmpty()) { QBuffer data(&arr);
pixmap->save(saveDir.absoluteFilePath(formatter::format(format) + ".png"), "PNG"); pixmap->save(&data, std::get<0>(u->format()).toLocal8Bit().constData());
} u->doUpload(arr);
} data.close();
uploaders.value(uploader)->doUpload(pixmap);
delete pixmap; delete pixmap;
} }
void UploaderSingleton::upload(QByteArray img) {
uploaders.value(uploader)->doUpload(img);
}
void UploaderSingleton::upload(QFile img) {
if (img.open(QIODevice::ReadOnly)) {
uploaders.value(uploader)->doUpload(img.readAll());
img.close();
}
}
std::tuple<QString, QString> UploaderSingleton::format() {
return uploaders.value(uploader)->format();
}
QList<Uploader *> UploaderSingleton::uploaderList() { QList<Uploader *> UploaderSingleton::uploaderList() {
return uploaders.values(); return uploaders.values();
} }

View File

@ -14,6 +14,9 @@ class UploaderSingleton : public QObject {
} }
void registerUploader(Uploader *uploader); void registerUploader(Uploader *uploader);
void upload(QPixmap *pixmap); void upload(QPixmap *pixmap);
void upload(QByteArray img);
void upload(QFile img);
virtual std::tuple<QString, QString> format();
QList<Uploader *> uploaderList(); QList<Uploader *> uploaderList();
void set(QString uploader); void set(QString uploader);
QString selectedUploader(); QString selectedUploader();