--- a/QTfrontend/net/recorder.cpp Mon Aug 06 00:40:26 2012 +0400
+++ b/QTfrontend/net/recorder.cpp Mon Aug 06 00:44:32 2012 +0400
@@ -26,6 +26,13 @@
#include "game.h"
#include "libav_iteraction.h"
+// Encoding is memory expensive process, so we need to limit maximum number
+// of simultaneous encoders.
+static const int maxRecorders = 3;
+static int numRecorders = 0;
+
+static QList<HWRecorder*> queue;
+
HWRecorder::HWRecorder(GameUIConfig * config, const QString &prefix) :
TCPBase(false)
{
@@ -38,6 +45,10 @@
HWRecorder::~HWRecorder()
{
emit encodingFinished(finished);
+ if (queue.empty())
+ numRecorders--;
+ else
+ queue.takeFirst()->Start();
}
void HWRecorder::onClientDisconnect()
@@ -76,8 +87,13 @@
toSendBuf.replace(QByteArray("\x02TN"), QByteArray("\x02TV"));
toSendBuf.replace(QByteArray("\x02TS"), QByteArray("\x02TV"));
- // run engine
- Start();
+ if (numRecorders < maxRecorders)
+ {
+ numRecorders++;
+ Start(); // run engine
+ }
+ else
+ queue.push_back(this);
}
QStringList HWRecorder::getArguments()
--- a/QTfrontend/ui/dialog/upload_video.cpp Mon Aug 06 00:40:26 2012 +0400
+++ b/QTfrontend/ui/dialog/upload_video.cpp Mon Aug 06 00:44:32 2012 +0400
@@ -29,6 +29,10 @@
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
+#include <QMessageBox>
+#include <QRegExp>
+#include <QRegExpValidator>
+#include <QMessageBox>
#include "upload_video.h"
#include "hwconsts.h"
@@ -50,86 +54,107 @@
// Google requires us to display this, see https://developers.google.com/youtube/terms
QString GoogleNotice =
- "By clicking 'upload,' you certify that you own all rights to the content or that\n"
- "you are authorized by the owner to make the content publicly available on YouTube,\n"
- "and that it otherwise complies with the YouTube Terms of Service located at\n"
+ "By clicking 'upload,' you certify that you own all rights to the content or that "
+ "you are authorized by the owner to make the content publicly available on YouTube, "
+ "and that it otherwise complies with the YouTube Terms of Service located at "
"http://www.youtube.com/t/terms.";
+ // youtube doesn't understand this characters, even when they are properly escaped
+ // (either with CDATA or with < or >)
+ QRegExp rx("[^<>]*");
+
+ int row = 0;
+
QGridLayout * layout = new QGridLayout(this);
QLabel * lbLabel = new QLabel(this);
+ lbLabel->setWordWrap(true);
lbLabel->setText(QLabel::tr(
- "Please provide either the YouTube account name\n"
+ "Please provide either the YouTube account name "
"or the email address associated with the Google Account."));
- layout->addWidget(lbLabel, 0, 0, 1, 2);
+ layout->addWidget(lbLabel, row++, 0, 1, 2);
lbLabel = new QLabel(this);
lbLabel->setText(QLabel::tr("Account name (or email): "));
- layout->addWidget(lbLabel, 1, 0);
+ layout->addWidget(lbLabel, row, 0);
leAccount = new QLineEdit(this);
- layout->addWidget(leAccount, 1, 1);
+ layout->addWidget(leAccount, row++, 1);
lbLabel = new QLabel(this);
lbLabel->setText(QLabel::tr("Password: "));
- layout->addWidget(lbLabel, 2, 0);
+ layout->addWidget(lbLabel, row, 0);
lePassword = new QLineEdit(this);
lePassword->setEchoMode(QLineEdit::Password);
- layout->addWidget(lePassword, 2, 1);
+ layout->addWidget(lePassword, row++, 1);
cbSave = new QCheckBox(this);
cbSave->setText(QCheckBox::tr("Save account name and password"));
- layout->addWidget(cbSave, 3, 0, 1, 2);
+ layout->addWidget(cbSave, row++, 0, 1, 2);
QFrame * hr = new QFrame(this);
hr->setFrameStyle(QFrame::HLine);
hr->setLineWidth(3);
hr->setFixedHeight(10);
- layout->addWidget(hr, 4, 0, 1, 2);
+ layout->addWidget(hr, row++, 0, 1, 2);
lbLabel = new QLabel(this);
lbLabel->setText(QLabel::tr("Video title: "));
- layout->addWidget(lbLabel, 5, 0);
+ layout->addWidget(lbLabel, row, 0);
leTitle = new QLineEdit(this);
leTitle->setText(filename);
- layout->addWidget(leTitle, 5, 1);
+ leTitle->setValidator(new QRegExpValidator(rx));
+ layout->addWidget(leTitle, row++, 1);
lbLabel = new QLabel(this);
lbLabel->setText(QLabel::tr("Video description: "));
- layout->addWidget(lbLabel, 6, 0, 1, 2);
+ layout->addWidget(lbLabel, row++, 0, 1, 2);
teDescription = new QPlainTextEdit(this);
- layout->addWidget(teDescription, 7, 0, 1, 2);
+ layout->addWidget(teDescription, row++, 0, 1, 2);
+
+ lbLabel = new QLabel(this);
+ lbLabel->setText(QLabel::tr("Tags (comma separated): "));
+ layout->addWidget(lbLabel, row, 0);
+
+ leTags = new QLineEdit(this);
+ leTags->setText("hedgewars");
+ leTags->setMaxLength(500);
+ leTags->setValidator(new QRegExpValidator(rx));
+ layout->addWidget(leTags, row++, 1);
+
+ cbPrivate = new QCheckBox(this);
+ cbPrivate->setText(QCheckBox::tr("Video is private"));
+ layout->addWidget(cbPrivate, row++, 0, 1, 2);
hr = new QFrame(this);
hr->setFrameStyle(QFrame::HLine);
hr->setLineWidth(3);
hr->setFixedHeight(10);
- layout->addWidget(hr, 8, 0, 1, 2);
+ layout->addWidget(hr, row++, 0, 1, 2);
lbLabel = new QLabel(this);
+ lbLabel->setWordWrap(true);
lbLabel->setText(GoogleNotice);
- layout->addWidget(lbLabel, 9, 0, 1, 2);
-
- labelLog = new QLabel(this);
- layout->addWidget(labelLog, 10, 0, 1, 2);
+ layout->addWidget(lbLabel, row++, 0, 1, 2);
QDialogButtonBox* dbbButtons = new QDialogButtonBox(this);
btnUpload = dbbButtons->addButton(tr("Upload"), QDialogButtonBox::ActionRole);
QPushButton * pbCancel = dbbButtons->addButton(QDialogButtonBox::Cancel);
- layout->addWidget(dbbButtons, 11, 0, 1, 2);
+ layout->addWidget(dbbButtons, row++, 0, 1, 2);
+
+ /* hr = new QFrame(this);
+ hr->setFrameStyle(QFrame::HLine);
+ hr->setLineWidth(3);
+ hr->setFixedHeight(10);
+ layout->addWidget(hr, row++, 0, 1, 2);*/
connect(btnUpload, SIGNAL(clicked()), this, SLOT(upload()));
connect(pbCancel, SIGNAL(clicked()), this, SLOT(reject()));
}
-void HWUploadVideoDialog::log(const QString& text)
-{
- labelLog->setText(labelLog->text() + text);
-}
-
void HWUploadVideoDialog::setEditable(bool editable)
{
leTitle->setEnabled(editable);
@@ -142,9 +167,6 @@
{
setEditable(false);
- labelLog->clear();
- log(tr("Authenticating at www.google.com... "));
-
// Documentation is at https://developers.google.com/youtube/2.0/developers_guide_protocol_clientlogin#ClientLogin_Authentication
QNetworkRequest request;
request.setUrl(QUrl("https://www.google.com/accounts/ClientLogin"));
@@ -159,9 +181,12 @@
connect(reply, SIGNAL(finished()), this, SLOT(authFinished()));
}
-QString XmlEscape(const QString& str)
+static QString XmlEscape(const QString& str)
{
QString str2 = str;
+ // youtube doesn't understand this characters, even when they are properly escaped
+ // (either with CDATA or with < >)
+ str2.replace('<', ' ').replace('>', ' ');
return "<![CDATA[" + str2.replace("]]>", "]]]]><![CDATA[>") + "]]>";
}
@@ -170,6 +195,8 @@
QNetworkReply *reply = (QNetworkReply*)sender();
reply->deleteLater();
+ int HttpCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+
QByteArray answer = reply->readAll();
QString authToken = "";
QList<QByteArray> lines = answer.split('\n');
@@ -184,14 +211,15 @@
}
if (authToken.isEmpty())
{
- log(tr("failed\n"));
- log(reply->errorString() + "\n");
+ QString errorStr = QMessageBox::tr("Error while authenticating at google.com:\n");
+ if (HttpCode == 403)
+ errorStr += QMessageBox::tr("Login or password is incorrect");
+ else
+ errorStr += reply->errorString();
+ QMessageBox::warning(this, QMessageBox::tr("Error"), errorStr);
setEditable(true);
return;
}
- log(tr("Ok\n"));
-
- log(tr("Sending metadata... "));
QByteArray auth = ("GoogleLogin auth=" + authToken).toAscii();
@@ -203,13 +231,20 @@
"xmlns:media=\"http://search.yahoo.com/mrss/\" "
"xmlns:yt=\"http://gdata.youtube.com/schemas/2007\">"
"<media:group>"
- "<yt:incomplete/>"
+ // "<yt:incomplete/>"
"<media:category "
"scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games"
"</media:category>"
"<media:title type=\"plain\">"
+ XmlEscape(leTitle->text()).toUtf8() +
"</media:title>"
+ "<media:description type=\"plain\">"
+ + XmlEscape(teDescription->toPlainText()).toUtf8() +
+ "</media:description>"
+ "<media:keywords type=\"plain\">"
+ + XmlEscape(leTags->text()).toUtf8() +
+ "</media:keywords>"
+ + (cbPrivate->isChecked()? "<yt:private/>" : "") +
"</media:group>"
"</entry>";
@@ -234,12 +269,12 @@
location = QString::fromAscii(reply->rawHeader("Location"));
if (location.isEmpty())
{
- log(tr("failed\n"));
- log(reply->errorString() + "\n");
+ QString errorStr = QMessageBox::tr("Error while sending metadata to youtube.com:\n");
+ errorStr += reply->errorString();
+ QMessageBox::warning(this, QMessageBox::tr("Error"), errorStr);
setEditable(true);
return;
}
- log(tr("Ok\n"));
accept();
}
--- a/QTfrontend/ui/dialog/upload_video.h Mon Aug 06 00:40:26 2012 +0400
+++ b/QTfrontend/ui/dialog/upload_video.h Mon Aug 06 00:44:32 2012 +0400
@@ -39,18 +39,17 @@
QLineEdit* leTitle;
QPlainTextEdit* teDescription;
+ QLineEdit* leTags;
+ QCheckBox* cbPrivate;
QPushButton* btnUpload;
- QLabel* labelLog;
-
QString location;
private:
QNetworkAccessManager* netManager;
QString filename;
- void log(const QString& text);
void setEditable(bool editable);
private slots:
--- a/QTfrontend/ui/page/pagevideos.cpp Mon Aug 06 00:40:26 2012 +0400
+++ b/QTfrontend/ui/page/pagevideos.cpp Mon Aug 06 00:44:32 2012 +0400
@@ -42,6 +42,7 @@
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
+#include <QXmlStreamReader>
#include "hwconsts.h"
#include "pagevideos.h"
@@ -59,11 +60,12 @@
{
vcName,
vcSize,
- vcProgress,
+ vcProgress, // either encoding or uploading
vcNumColumns,
};
+// this class is used for items in first column in file-table
class VideoItem : public QTableWidgetItem
{
// note: QTableWidgetItem is not Q_OBJECT
@@ -73,9 +75,10 @@
~VideoItem();
QString name;
- QString desc; // description
- QString uploadReply;
- HWRecorder * pRecorder; // non NULL if file is being encoded
+ QString prefix; // original filename without extension
+ QString desc; // description (duration, resolution, etc...)
+ QString uploadUrl; // http://youtu.be/???????
+ HWRecorder * pRecorder; // non NULL if file is being encoded
QNetworkReply * pUploading; // non NULL if file is being uploaded
bool seen; // used when updating directory
float lastSizeUpdate;
@@ -112,7 +115,7 @@
// options
{
IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
- pOptionsGroup->setIcon(QIcon(":/res/Settings.png"));
+ pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME
pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
@@ -211,7 +214,7 @@
// list of videos
{
IconedGroupBox* pTableGroup = new IconedGroupBox(this);
- pTableGroup->setIcon(QIcon(":/res/graphicsicon.png"));
+ pTableGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
pTableGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pTableGroup->setTitle(QGroupBox::tr("Videos"));
@@ -247,7 +250,7 @@
// description
{
IconedGroupBox* pDescGroup = new IconedGroupBox(this);
- pDescGroup->setIcon(QIcon(":/res/graphicsicon.png"));
+ pDescGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
pDescGroup->setTitle(QGroupBox::tr("Description"));
QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
@@ -271,6 +274,11 @@
// label with file description
labelDesc = new QLabel(pDescGroup);
labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop);
+ labelDesc->setTextInteractionFlags(Qt::TextSelectableByMouse |
+ Qt::TextSelectableByKeyboard |
+ Qt::LinksAccessibleByMouse |
+ Qt::LinksAccessibleByKeyboard);
+ labelDesc->setTextFormat(Qt::RichText);
pTopDescLayout->addWidget(labelDesc, 1);
// buttons: play and delete
@@ -313,6 +321,7 @@
connect(btnDelete, SIGNAL(clicked()), this, SLOT(deleteSelectedFiles()));
connect(btnToYouTube, SIGNAL(clicked()), this, SLOT(uploadToYouTube()));
connect(btnOpenDir, SIGNAL(clicked()), this, SLOT(openVideosDirectory()));
+ connect(labelDesc, SIGNAL(linkActivated(const QString&)), this, SLOT(linkActivated(const QString&)));
}
PageVideos::PageVideos(QWidget* parent) : AbstractPage(parent),
@@ -435,6 +444,7 @@
if (iFormat == -1)
return false;
comboAVFormats->setCurrentIndex(iFormat);
+ // format was changed, so lists of codecs were automatically updated to codecs supported by this format
// try to find video codec
int iVCodec = comboVideoCodecs->findData(vcodec);
@@ -453,7 +463,7 @@
}
// get file size as string
-QString FileSizeStr(const QString & path)
+static QString FileSizeStr(const QString & path)
{
quint64 size = QFileInfo(path).size();
@@ -478,6 +488,8 @@
filesTable->item(row, vcSize)->setText(FileSizeStr(path));
}
+// There is a button 'Open videos dir', so it is possible that user will open
+// this dir and rename/delete some files there, so we should handle this.
void PageVideos::updateFileList(const QString & path)
{
// mark all files as non seen
@@ -545,7 +557,7 @@
void PageVideos::updateProgress(float value)
{
HWRecorder * pRecorder = (HWRecorder*)sender();
- VideoItem * item = (VideoItem*)pRecorder->item;
+ VideoItem * item = pRecorder->item;
int row = filesTable->row(item);
// update file size every percent
@@ -609,6 +621,7 @@
QString newName = item->text();
if (!newName.contains('.')) // user forgot an extension
{
+ // restore old extension
int pt = oldName.lastIndexOf('.');
if (pt != -1)
{
@@ -676,7 +689,7 @@
void PageVideos::clearThumbnail()
{
- // add empty image for proper sizing
+ // add empty (transparent) image for proper sizing
QPixmap pic(ThumbnailSize);
pic.fill(QColor(0,0,0,0));
labelThumbnail->setPixmap(pic);
@@ -687,6 +700,7 @@
VideoItem * item = nameItem(filesTable->currentRow());
if (!item)
{
+ // nothing is selected => clear description and return
labelDesc->clear();
clearThumbnail();
btnPlay->setEnabled(false);
@@ -696,51 +710,75 @@
}
btnPlay->setEnabled(item->ready());
+ btnToYouTube->setEnabled(item->ready());
btnDelete->setEnabled(true);
- btnToYouTube->setEnabled(item->ready());
+ btnDelete->setText(item->ready()? QPushButton::tr("Delete") : QPushButton::tr("Cancel"));
+ btnToYouTube->setText(item->pUploading? QPushButton::tr("Cancel uploading") : QPushButton::tr("Upload to YouTube"));
+ // construct string with desctiption of this file to display it
QString desc = item->name + "\n\n";
- QString thumbName = "";
- if (item->ready())
+ if (!item->ready())
+ desc += tr("(in progress...)");
+ else
{
QString path = item->path();
- desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + "\n";
- desc += tr("Size: ") + FileSizeStr(path) + "\n";
- if (item->desc == "")
+ desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + '\n';
+ desc += tr("Size: ") + FileSizeStr(path) + '\n';
+ if (item->desc.isEmpty())
+ {
+ // Extract description from file;
+ // It will contain duration, resolution, etc and also comment added by hwengine.
item->desc = LibavIteraction::instance().getFileInfo(path);
- desc += item->desc;
-
- // extract thumbnail name fron description
- int prefixBegin = desc.indexOf("prefix[");
- int prefixEnd = desc.indexOf("]prefix");
- if (prefixBegin != -1 && prefixEnd != -1)
- {
- QString prefix = desc.mid(prefixBegin + 7, prefixEnd - (prefixBegin + 7));
- desc.remove(prefixBegin, prefixEnd + 7 - prefixBegin);
- thumbName = prefix;
- }
- desc += item->uploadReply;
- }
- else
- desc += tr("(in progress...)");
-
- if (thumbName.isEmpty())
- {
- if (item->ready())
- thumbName = item->name;
- else
- thumbName = item->pRecorder->name;
- // remove extension
- int pt = thumbName.lastIndexOf('.');
- if (pt != -1)
- thumbName.truncate(pt);
+ // extract prefix (original name) from description (it is enclosed in prefix[???]prefix)
+ int prefixBegin = item->desc.indexOf("prefix[");
+ int prefixEnd = item->desc.indexOf("]prefix");
+ if (prefixBegin != -1 && prefixEnd != -1)
+ {
+ item->prefix = desc.mid(prefixBegin + 7, prefixEnd - (prefixBegin + 7));
+ item->desc.remove(prefixBegin, prefixEnd + 7 - prefixBegin);
+ }
+ }
+ desc += item->desc + '\n';
}
- if (!thumbName.isEmpty())
+ if (item->prefix.isEmpty())
+ {
+ // try to extract prefix from file name instead
+ if (item->ready())
+ item->prefix = item->name;
+ else
+ item->prefix = item->pRecorder->name;
+
+ // remove extension
+ int pt = item->prefix.lastIndexOf('.');
+ if (pt != -1)
+ item->prefix.truncate(pt);
+ }
+
+ if (item->ready() && item->uploadUrl.isEmpty())
{
- thumbName = cfgdir->absoluteFilePath("VideoTemp/" + thumbName);
+ // try to load url from file
+ QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this);
+ if (!file->open(QIODevice::ReadOnly))
+ item->uploadUrl = "no";
+ else
+ {
+ QByteArray data = file->readAll();
+ file->close();
+ item->uploadUrl = QString::fromUtf8(data.data());
+ }
+ }
+ if (item->uploadUrl != "no")
+ desc += QString("<a href=\"%1\">%1</a>").arg(item->uploadUrl);
+ desc.replace("\n", "<br/>");
+
+ labelDesc->setText(desc);
+
+ if (!item->prefix.isEmpty())
+ {
+ QString thumbName = cfgdir->absoluteFilePath("VideoTemp/" + item->prefix);
QPixmap pic;
if (pic.load(thumbName + ".png") || pic.load(thumbName + ".bmp"))
{
@@ -753,7 +791,6 @@
else
clearThumbnail();
}
- labelDesc->setText(desc);
}
// user selected another cell, so we should change description
@@ -766,10 +803,15 @@
void PageVideos::play(int row)
{
VideoItem * item = nameItem(row);
- if (item->ready())
+ if (item && item->ready())
QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(item->path())));
}
+void PageVideos::linkActivated(const QString & link)
+{
+ QDesktopServices::openUrl(QUrl(link));
+}
+
void PageVideos::playSelectedFile()
{
int index = filesTable->currentRow();
@@ -779,6 +821,30 @@
void PageVideos::deleteSelectedFiles()
{
+ int index = filesTable->currentRow();
+ if (index == -1)
+ return;
+
+ VideoItem * item = nameItem(index);
+ if (!item)
+ return;
+
+ // ask user if (s)he is serious
+ if (QMessageBox::question(this,
+ tr("Are you sure?"),
+ tr("Do you really want do remove %1?").arg(item->name),
+ QMessageBox::Yes | QMessageBox::No)
+ != QMessageBox::Yes)
+ return;
+
+ // remove
+ if (!item->ready())
+ item->pRecorder->deleteLater();
+ else
+ cfgdir->remove("Videos/" + item->name);
+
+// this code is for removing several files when multiple selection is enabled
+#if 0
QList<QTableWidgetItem*> items = filesTable->selectedItems();
int num = items.size() / vcNumColumns;
if (num == 0)
@@ -803,6 +869,7 @@
else
cfgdir->remove("Videos/" + item->name);
}
+#endif
}
void PageVideos::keyPressEvent(QKeyEvent * pEvent)
@@ -829,14 +896,14 @@
QDesktopServices::openUrl(QUrl("file:///" + path));
}
-// clear VideoTemp directory (except for thumbnails)
+// clear VideoTemp directory (except for thumbnails and upload links)
void PageVideos::clearTemp()
{
QDir temp(cfgdir->absolutePath() + "/VideoTemp");
QStringList files = temp.entryList(QDir::Files);
foreach (const QString& file, files)
{
- if (!file.endsWith(".bmp") && !file.endsWith(".png"))
+ if (!file.endsWith(".bmp") && !file.endsWith(".png") && !file.endsWith("-url.txt"))
temp.remove(file);
}
}
@@ -912,14 +979,11 @@
}
}
-void PageVideos::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
+VideoItem * PageVideos::itemFromReply(QNetworkReply* reply, int & row)
{
- QNetworkReply* reply = (QNetworkReply*)sender();
-
VideoItem * item = NULL;
- int row;
int count = filesTable->rowCount();
- // find corresponding item (maybe there is a better wat to implement this?)
+ // find corresponding item (maybe there is a better way to implement this?)
for (int i = 0; i < count; i++)
{
item = nameItem(i);
@@ -929,48 +993,125 @@
break;
}
}
- Q_ASSERT(item);
+ return item;
+}
+void PageVideos::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
+{
+ QNetworkReply* reply = (QNetworkReply*)sender();
+ int row;
+ VideoItem * item = itemFromReply(reply, row);
setProgress(row, item, bytesSent*1.0/bytesTotal);
}
void PageVideos::uploadFinished()
{
QNetworkReply* reply = (QNetworkReply*)sender();
+ reply->deleteLater();
- VideoItem * item = NULL;
int row;
- int count = filesTable->rowCount();
- for (int i = 0; i < count; i++)
+ VideoItem * item = itemFromReply(reply, row);
+ if (!item)
+ return;
+
+ item->pUploading = NULL;
+
+ // extract video id from reply
+ QString videoid;
+ QXmlStreamReader xml(reply);
+ while (!xml.atEnd())
{
- item = nameItem(i);
- if (item->pUploading == reply)
+ xml.readNext();
+ if (xml.qualifiedName() == "yt:videoid")
{
- row = i;
+ videoid = xml.readElementText();
break;
}
}
- Q_ASSERT(item);
+
+ if (!videoid.isEmpty())
+ {
+ item->uploadUrl = "http://youtu.be/" + videoid;
+ updateDescription();
- item->pUploading = NULL;
- QByteArray answer = reply->readAll();
- item->uploadReply = QString::fromUtf8(answer.data());
- // QMessageBox::information(this,"",item->uploadReply,0);
+ // save url in file
+ QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this);
+ if (file->open(QIODevice::WriteOnly))
+ {
+ file->write(item->uploadUrl.toUtf8());
+ file->close();
+ }
+ }
+
filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
numUploads--;
}
+// this will protect saved youtube password from those who cannot read source code
+static QString protectPass(QString str)
+{
+ QByteArray array = str.toUtf8();
+ for (int i = 0; i < array.size(); i++)
+ array[i] = array[i] ^ 0xC4 ^ i;
+ array = array.toBase64();
+ return QString::fromAscii(array.data());
+}
+
+static QString unprotectPass(QString str)
+{
+ QByteArray array = QByteArray::fromBase64(str.toAscii());
+ for (int i = 0; i < array.size(); i++)
+ array[i] = array[i] ^ 0xC4 ^ i;
+ return QString::fromUtf8(array);
+}
+
void PageVideos::uploadToYouTube()
{
int row = filesTable->currentRow();
VideoItem * item = nameItem(row);
+ if (item->pUploading)
+ {
+ if (QMessageBox::question(this,
+ tr("Are you sure?"),
+ tr("Do you really want do cancel uploading %1?").arg(item->name),
+ QMessageBox::Yes | QMessageBox::No)
+ != QMessageBox::Yes)
+ return;
+ item->pUploading->deleteLater();
+ filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
+ numUploads--;
+ return;
+ }
+
if (!netManager)
netManager = new QNetworkAccessManager(this);
HWUploadVideoDialog* dlg = new HWUploadVideoDialog(this, item->name, netManager);
dlg->deleteLater();
- if (!dlg->exec())
+ if (config->value("youtube/save").toBool())
+ {
+ dlg->cbSave->setChecked(true);
+ dlg->leAccount->setText(config->value("youtube/name").toString());
+ dlg->lePassword->setText(unprotectPass(config->value("youtube/pswd").toString()));
+ }
+
+ bool result = dlg->exec();
+
+ if (dlg->cbSave->isChecked())
+ {
+ config->setValue("youtube/save", true);
+ config->setValue("youtube/name", dlg->leAccount->text());
+ config->setValue("youtube/pswd", protectPass(dlg->lePassword->text()));
+ }
+ else
+ {
+ config->setValue("youtube/save", false);
+ config->setValue("youtube/name", "");
+ config->setValue("youtube/pswd", "");
+ }
+
+ if (!result)
return;
QNetworkRequest request(QUrl(dlg->location));
@@ -985,7 +1126,7 @@
progressBar->setMinimum(0);
progressBar->setMaximum(10000);
progressBar->setValue(0);
- // make it different from encoding progress-bar
+ // make it different from progress-bar used during encoding (use blue color)
progressBar->setStyleSheet("* {color: #00ccff; selection-background-color: #00ccff;}" );
filesTable->setCellWidget(row, vcProgress, progressBar);
@@ -994,4 +1135,6 @@
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished()));
numUploads++;
+
+ updateDescription();
}
--- a/QTfrontend/ui/page/pagevideos.h Mon Aug 06 00:40:26 2012 +0400
+++ b/QTfrontend/ui/page/pagevideos.h Mon Aug 06 00:44:32 2012 +0400
@@ -23,6 +23,7 @@
#include "AbstractPage.h"
class QNetworkAccessManager;
+class QNetworkReply;
class GameUIConfig;
class HWRecorder;
class VideoItem;
@@ -76,6 +77,7 @@
void clearTemp();
void clearThumbnail();
void setProgress(int row, VideoItem* item, float value);
+ VideoItem * itemFromReply(QNetworkReply* reply, int & row);
GameUIConfig * config;
QNetworkAccessManager* netManager;
@@ -118,6 +120,7 @@
void uploadToYouTube();
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
void uploadFinished();
+ void linkActivated(const QString & link);
};
#endif // PAGE_VIDEOS_H