QTfrontend/ui/page/pagevideos.cpp
changeset 7507 3032a5739fe1
parent 7447 01111960a48d
child 7531 0adcad8714c4
equal deleted inserted replaced
7503:deaeac102355 7507:3032a5739fe1
    40 #include <QDateTime>
    40 #include <QDateTime>
    41 #include <QRegExp>
    41 #include <QRegExp>
    42 #include <QNetworkAccessManager>
    42 #include <QNetworkAccessManager>
    43 #include <QNetworkRequest>
    43 #include <QNetworkRequest>
    44 #include <QNetworkReply>
    44 #include <QNetworkReply>
       
    45 #include <QXmlStreamReader>
    45 
    46 
    46 #include "hwconsts.h"
    47 #include "hwconsts.h"
    47 #include "pagevideos.h"
    48 #include "pagevideos.h"
    48 #include "igbox.h"
    49 #include "igbox.h"
    49 #include "libav_iteraction.h"
    50 #include "libav_iteraction.h"
    57 // columns in table with list of video files
    58 // columns in table with list of video files
    58 enum VideosColumns
    59 enum VideosColumns
    59 {
    60 {
    60     vcName,
    61     vcName,
    61     vcSize,
    62     vcSize,
    62     vcProgress,
    63     vcProgress, // either encoding or uploading
    63 
    64 
    64     vcNumColumns,
    65     vcNumColumns,
    65 };
    66 };
    66 
    67 
       
    68 // this class is used for items in first column in file-table
    67 class VideoItem : public QTableWidgetItem
    69 class VideoItem : public QTableWidgetItem
    68 {
    70 {
    69     // note: QTableWidgetItem is not Q_OBJECT
    71     // note: QTableWidgetItem is not Q_OBJECT
    70 
    72 
    71     public:
    73     public:
    72         VideoItem(const QString& name);
    74         VideoItem(const QString& name);
    73         ~VideoItem();
    75         ~VideoItem();
    74 
    76 
    75         QString name;
    77         QString name;
    76         QString desc; // description
    78         QString prefix; // original filename without extension
    77         QString uploadReply;
    79         QString desc;   // description (duration, resolution, etc...)
    78         HWRecorder * pRecorder; // non NULL if file is being encoded
    80         QString uploadUrl; // http://youtu.be/???????
       
    81         HWRecorder    * pRecorder; // non NULL if file is being encoded
    79         QNetworkReply * pUploading; // non NULL if file is being uploaded
    82         QNetworkReply * pUploading; // non NULL if file is being uploaded
    80         bool seen; // used when updating directory
    83         bool seen; // used when updating directory
    81         float lastSizeUpdate;
    84         float lastSizeUpdate;
    82         float progress;
    85         float progress;
    83 
    86 
   110     pPageLayout->setRowStretch(1, 1);
   113     pPageLayout->setRowStretch(1, 1);
   111 
   114 
   112     // options
   115     // options
   113     {
   116     {
   114         IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
   117         IconedGroupBox* pOptionsGroup = new IconedGroupBox(this);
   115         pOptionsGroup->setIcon(QIcon(":/res/Settings.png"));
   118         pOptionsGroup->setIcon(QIcon(":/res/Settings.png")); // FIXME
   116         pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   119         pOptionsGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   117         pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
   120         pOptionsGroup->setTitle(QGroupBox::tr("Video recording options"));
   118         QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
   121         QGridLayout * pOptLayout = new QGridLayout(pOptionsGroup);
   119 
   122 
   120         // label for format
   123         // label for format
   209     }
   212     }
   210 
   213 
   211     // list of videos
   214     // list of videos
   212     {
   215     {
   213         IconedGroupBox* pTableGroup = new IconedGroupBox(this);
   216         IconedGroupBox* pTableGroup = new IconedGroupBox(this);
   214         pTableGroup->setIcon(QIcon(":/res/graphicsicon.png"));
   217         pTableGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
   215         pTableGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   218         pTableGroup->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
   216         pTableGroup->setTitle(QGroupBox::tr("Videos"));
   219         pTableGroup->setTitle(QGroupBox::tr("Videos"));
   217 
   220 
   218         QStringList columns;
   221         QStringList columns;
   219         columns << tr("Name");
   222         columns << tr("Name");
   245     }
   248     }
   246 
   249 
   247     // description
   250     // description
   248     {
   251     {
   249         IconedGroupBox* pDescGroup = new IconedGroupBox(this);
   252         IconedGroupBox* pDescGroup = new IconedGroupBox(this);
   250         pDescGroup->setIcon(QIcon(":/res/graphicsicon.png"));
   253         pDescGroup->setIcon(QIcon(":/res/graphicsicon.png")); // FIXME
   251         pDescGroup->setTitle(QGroupBox::tr("Description"));
   254         pDescGroup->setTitle(QGroupBox::tr("Description"));
   252 
   255 
   253         QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
   256         QVBoxLayout* pDescLayout = new QVBoxLayout(pDescGroup);
   254         QHBoxLayout* pTopDescLayout = new QHBoxLayout(0);    // picture and text
   257         QHBoxLayout* pTopDescLayout = new QHBoxLayout(0);    // picture and text
   255         QHBoxLayout* pBottomDescLayout = new QHBoxLayout(0); // buttons
   258         QHBoxLayout* pBottomDescLayout = new QHBoxLayout(0); // buttons
   269         pTopDescLayout->addWidget(labelThumbnail, 2);
   272         pTopDescLayout->addWidget(labelThumbnail, 2);
   270 
   273 
   271         // label with file description
   274         // label with file description
   272         labelDesc = new QLabel(pDescGroup);
   275         labelDesc = new QLabel(pDescGroup);
   273         labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop);
   276         labelDesc->setAlignment(Qt::AlignLeft | Qt::AlignTop);
       
   277         labelDesc->setTextInteractionFlags(Qt::TextSelectableByMouse |
       
   278                                            Qt::TextSelectableByKeyboard	|
       
   279                                            Qt::LinksAccessibleByMouse |
       
   280                                            Qt::LinksAccessibleByKeyboard);
       
   281         labelDesc->setTextFormat(Qt::RichText);
   274         pTopDescLayout->addWidget(labelDesc, 1);
   282         pTopDescLayout->addWidget(labelDesc, 1);
   275 
   283 
   276         // buttons: play and delete
   284         // buttons: play and delete
   277         btnPlay = new QPushButton(QPushButton::tr("Play"), pDescGroup);
   285         btnPlay = new QPushButton(QPushButton::tr("Play"), pDescGroup);
   278         btnPlay->setEnabled(false);
   286         btnPlay->setEnabled(false);
   311     connect(filesTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(currentCellChanged(int,int,int,int)));
   319     connect(filesTable, SIGNAL(currentCellChanged(int,int,int,int)), this, SLOT(currentCellChanged(int,int,int,int)));
   312     connect(btnPlay,   SIGNAL(clicked()), this, SLOT(playSelectedFile()));
   320     connect(btnPlay,   SIGNAL(clicked()), this, SLOT(playSelectedFile()));
   313     connect(btnDelete, SIGNAL(clicked()), this, SLOT(deleteSelectedFiles()));
   321     connect(btnDelete, SIGNAL(clicked()), this, SLOT(deleteSelectedFiles()));
   314     connect(btnToYouTube, SIGNAL(clicked()), this, SLOT(uploadToYouTube()));
   322     connect(btnToYouTube, SIGNAL(clicked()), this, SLOT(uploadToYouTube()));
   315     connect(btnOpenDir, SIGNAL(clicked()), this, SLOT(openVideosDirectory()));
   323     connect(btnOpenDir, SIGNAL(clicked()), this, SLOT(openVideosDirectory()));
       
   324     connect(labelDesc, SIGNAL(linkActivated(const QString&)), this, SLOT(linkActivated(const QString&)));
   316  }
   325  }
   317 
   326 
   318 PageVideos::PageVideos(QWidget* parent) : AbstractPage(parent),
   327 PageVideos::PageVideos(QWidget* parent) : AbstractPage(parent),
   319     config(0), netManager(0)
   328     config(0), netManager(0)
   320 {
   329 {
   433     // first we should change format
   442     // first we should change format
   434     int iFormat = comboAVFormats->findData(format);
   443     int iFormat = comboAVFormats->findData(format);
   435     if (iFormat == -1)
   444     if (iFormat == -1)
   436         return false;
   445         return false;
   437     comboAVFormats->setCurrentIndex(iFormat);
   446     comboAVFormats->setCurrentIndex(iFormat);
       
   447     // format was changed, so lists of codecs were automatically updated to codecs supported by this format
   438 
   448 
   439     // try to find video codec
   449     // try to find video codec
   440     int iVCodec = comboVideoCodecs->findData(vcodec);
   450     int iVCodec = comboVideoCodecs->findData(vcodec);
   441     if (iVCodec == -1)
   451     if (iVCodec == -1)
   442         return false;
   452         return false;
   451 
   461 
   452     return true;
   462     return true;
   453 }
   463 }
   454 
   464 
   455 // get file size as string
   465 // get file size as string
   456 QString FileSizeStr(const QString & path)
   466 static QString FileSizeStr(const QString & path)
   457 {
   467 {
   458     quint64 size = QFileInfo(path).size();
   468     quint64 size = QFileInfo(path).size();
   459 
   469 
   460     quint64 KiB = 1024;
   470     quint64 KiB = 1024;
   461     quint64 MiB = 1024*KiB;
   471     quint64 MiB = 1024*KiB;
   476     VideoItem * item = nameItem(row);
   486     VideoItem * item = nameItem(row);
   477     QString path = item->ready()? item->path() : cfgdir->absoluteFilePath("VideoTemp/" + item->pRecorder->name);
   487     QString path = item->ready()? item->path() : cfgdir->absoluteFilePath("VideoTemp/" + item->pRecorder->name);
   478     filesTable->item(row, vcSize)->setText(FileSizeStr(path));
   488     filesTable->item(row, vcSize)->setText(FileSizeStr(path));
   479 }
   489 }
   480 
   490 
       
   491 // There is a button 'Open videos dir', so it is possible that user will open
       
   492 // this dir and rename/delete some files there, so we should handle this.
   481 void PageVideos::updateFileList(const QString & path)
   493 void PageVideos::updateFileList(const QString & path)
   482 {
   494 {
   483     // mark all files as non seen
   495     // mark all files as non seen
   484     int numRows = filesTable->rowCount();
   496     int numRows = filesTable->rowCount();
   485     for (int i = 0; i < numRows; i++)
   497     for (int i = 0; i < numRows; i++)
   543 }
   555 }
   544 
   556 
   545 void PageVideos::updateProgress(float value)
   557 void PageVideos::updateProgress(float value)
   546 {
   558 {
   547     HWRecorder * pRecorder = (HWRecorder*)sender();
   559     HWRecorder * pRecorder = (HWRecorder*)sender();
   548     VideoItem * item = (VideoItem*)pRecorder->item;
   560     VideoItem * item = pRecorder->item;
   549     int row = filesTable->row(item);
   561     int row = filesTable->row(item);
   550 
   562 
   551     // update file size every percent
   563     // update file size every percent
   552     if (value - item->lastSizeUpdate > 0.01)
   564     if (value - item->lastSizeUpdate > 0.01)
   553     {
   565     {
   607     VideoItem * item = nameItem(row);
   619     VideoItem * item = nameItem(row);
   608     QString oldName = item->name;
   620     QString oldName = item->name;
   609     QString newName = item->text();
   621     QString newName = item->text();
   610     if (!newName.contains('.')) // user forgot an extension
   622     if (!newName.contains('.')) // user forgot an extension
   611     {
   623     {
       
   624         // restore old extension
   612         int pt = oldName.lastIndexOf('.');
   625         int pt = oldName.lastIndexOf('.');
   613         if (pt != -1)
   626         if (pt != -1)
   614         {
   627         {
   615             newName += oldName.right(oldName.length() - pt);
   628             newName += oldName.right(oldName.length() - pt);
   616             setName(item, newName);
   629             setName(item, newName);
   674     return (VideoItem*)filesTable->item(row, vcName);
   687     return (VideoItem*)filesTable->item(row, vcName);
   675 }
   688 }
   676 
   689 
   677 void PageVideos::clearThumbnail()
   690 void PageVideos::clearThumbnail()
   678 {
   691 {
   679     // add empty image for proper sizing
   692     // add empty (transparent) image for proper sizing
   680     QPixmap pic(ThumbnailSize);
   693     QPixmap pic(ThumbnailSize);
   681     pic.fill(QColor(0,0,0,0));
   694     pic.fill(QColor(0,0,0,0));
   682     labelThumbnail->setPixmap(pic);
   695     labelThumbnail->setPixmap(pic);
   683 }
   696 }
   684 
   697 
   685 void PageVideos::updateDescription()
   698 void PageVideos::updateDescription()
   686 {
   699 {
   687     VideoItem * item = nameItem(filesTable->currentRow());
   700     VideoItem * item = nameItem(filesTable->currentRow());
   688     if (!item)
   701     if (!item)
   689     {
   702     {
       
   703         // nothing is selected => clear description and return
   690         labelDesc->clear();
   704         labelDesc->clear();
   691         clearThumbnail();
   705         clearThumbnail();
   692         btnPlay->setEnabled(false);
   706         btnPlay->setEnabled(false);
   693         btnDelete->setEnabled(false);
   707         btnDelete->setEnabled(false);
   694         btnToYouTube->setEnabled(false);
   708         btnToYouTube->setEnabled(false);
   695         return;
   709         return;
   696     }
   710     }
   697 
   711 
   698     btnPlay->setEnabled(item->ready());
   712     btnPlay->setEnabled(item->ready());
       
   713     btnToYouTube->setEnabled(item->ready());
   699     btnDelete->setEnabled(true);
   714     btnDelete->setEnabled(true);
   700     btnToYouTube->setEnabled(item->ready());
   715     btnDelete->setText(item->ready()? QPushButton::tr("Delete") :  QPushButton::tr("Cancel"));
   701 
   716     btnToYouTube->setText(item->pUploading? QPushButton::tr("Cancel uploading") :  QPushButton::tr("Upload to YouTube"));
       
   717 
       
   718     // construct string with desctiption of this file to display it
   702     QString desc = item->name + "\n\n";
   719     QString desc = item->name + "\n\n";
   703     QString thumbName = "";
   720 
   704 
   721     if (!item->ready())
   705     if (item->ready())
   722         desc += tr("(in progress...)");
       
   723     else
   706     {
   724     {
   707         QString path = item->path();
   725         QString path = item->path();
   708         desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + "\n";
   726         desc += tr("Date: ") + QFileInfo(path).created().toString(Qt::DefaultLocaleLongDate) + '\n';
   709         desc += tr("Size: ") + FileSizeStr(path) + "\n";
   727         desc += tr("Size: ") + FileSizeStr(path) + '\n';
   710         if (item->desc == "")
   728         if (item->desc.isEmpty())
       
   729         {
       
   730             // Extract description from file;
       
   731             // It will contain duration, resolution, etc and also comment added by hwengine.
   711             item->desc = LibavIteraction::instance().getFileInfo(path);
   732             item->desc = LibavIteraction::instance().getFileInfo(path);
   712         desc += item->desc;
   733 
   713 
   734             // extract prefix (original name) from description (it is enclosed in prefix[???]prefix)
   714         // extract thumbnail name fron description
   735             int prefixBegin = item->desc.indexOf("prefix[");
   715         int prefixBegin = desc.indexOf("prefix[");
   736             int prefixEnd   = item->desc.indexOf("]prefix");
   716         int prefixEnd = desc.indexOf("]prefix");
   737             if (prefixBegin != -1 && prefixEnd != -1)
   717         if (prefixBegin != -1 && prefixEnd != -1)
   738             {
       
   739                 item->prefix = desc.mid(prefixBegin + 7, prefixEnd - (prefixBegin + 7));
       
   740                 item->desc.remove(prefixBegin, prefixEnd + 7 - prefixBegin);
       
   741             }
       
   742         }
       
   743         desc += item->desc + '\n';
       
   744     }
       
   745 
       
   746     if (item->prefix.isEmpty())
       
   747     {
       
   748         // try to extract prefix from file name instead
       
   749         if (item->ready())
       
   750             item->prefix = item->name;
       
   751         else
       
   752             item->prefix = item->pRecorder->name;
       
   753 
       
   754         // remove extension
       
   755         int pt = item->prefix.lastIndexOf('.');
       
   756         if (pt != -1)
       
   757             item->prefix.truncate(pt);
       
   758     }
       
   759 
       
   760     if (item->ready() && item->uploadUrl.isEmpty())
       
   761     {
       
   762         // try to load url from file
       
   763         QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this);
       
   764         if (!file->open(QIODevice::ReadOnly))
       
   765             item->uploadUrl = "no";
       
   766         else
   718         {
   767         {
   719             QString prefix = desc.mid(prefixBegin + 7, prefixEnd - (prefixBegin + 7));
   768             QByteArray data = file->readAll();
   720             desc.remove(prefixBegin, prefixEnd + 7 - prefixBegin);
   769             file->close();
   721             thumbName = prefix;
   770             item->uploadUrl = QString::fromUtf8(data.data());
   722         }
   771         }
   723 
   772     }
   724         desc += item->uploadReply;
   773     if (item->uploadUrl != "no")
   725     }
   774         desc += QString("<a href=\"%1\">%1</a>").arg(item->uploadUrl);
   726     else
   775     desc.replace("\n", "<br/>");
   727         desc += tr("(in progress...)");
   776 
   728 
   777     labelDesc->setText(desc);
   729     if (thumbName.isEmpty())
   778 
   730     {
   779     if (!item->prefix.isEmpty())
   731         if (item->ready())
   780     {
   732             thumbName = item->name;
   781         QString thumbName = cfgdir->absoluteFilePath("VideoTemp/" + item->prefix);
   733         else
       
   734             thumbName = item->pRecorder->name;
       
   735         // remove extension
       
   736         int pt = thumbName.lastIndexOf('.');
       
   737         if (pt != -1)
       
   738             thumbName.truncate(pt);
       
   739     }
       
   740 
       
   741     if (!thumbName.isEmpty())
       
   742     {
       
   743         thumbName = cfgdir->absoluteFilePath("VideoTemp/" + thumbName);
       
   744         QPixmap pic;
   782         QPixmap pic;
   745         if (pic.load(thumbName + ".png") || pic.load(thumbName + ".bmp"))
   783         if (pic.load(thumbName + ".png") || pic.load(thumbName + ".bmp"))
   746         {
   784         {
   747             if (pic.height()*ThumbnailSize.width() > pic.width()*ThumbnailSize.height())
   785             if (pic.height()*ThumbnailSize.width() > pic.width()*ThumbnailSize.height())
   748                 pic = pic.scaledToWidth(ThumbnailSize.width());
   786                 pic = pic.scaledToWidth(ThumbnailSize.width());
   751             labelThumbnail->setPixmap(pic);
   789             labelThumbnail->setPixmap(pic);
   752         }
   790         }
   753         else
   791         else
   754             clearThumbnail();
   792             clearThumbnail();
   755     }
   793     }
   756     labelDesc->setText(desc);
       
   757 }
   794 }
   758 
   795 
   759 // user selected another cell, so we should change description
   796 // user selected another cell, so we should change description
   760 void PageVideos::currentCellChanged(int row, int column, int previousRow, int previousColumn)
   797 void PageVideos::currentCellChanged(int row, int column, int previousRow, int previousColumn)
   761 {
   798 {
   764 
   801 
   765 // open video file in external media player
   802 // open video file in external media player
   766 void PageVideos::play(int row)
   803 void PageVideos::play(int row)
   767 {
   804 {
   768     VideoItem * item = nameItem(row);
   805     VideoItem * item = nameItem(row);
   769     if (item->ready())
   806     if (item && item->ready())
   770         QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(item->path())));
   807         QDesktopServices::openUrl(QUrl("file:///" + QDir::toNativeSeparators(item->path())));
       
   808 }
       
   809 
       
   810 void PageVideos::linkActivated(const QString & link)
       
   811 {
       
   812     QDesktopServices::openUrl(QUrl(link));
   771 }
   813 }
   772 
   814 
   773 void PageVideos::playSelectedFile()
   815 void PageVideos::playSelectedFile()
   774 {
   816 {
   775     int index = filesTable->currentRow();
   817     int index = filesTable->currentRow();
   777         play(index);
   819         play(index);
   778 }
   820 }
   779 
   821 
   780 void PageVideos::deleteSelectedFiles()
   822 void PageVideos::deleteSelectedFiles()
   781 {
   823 {
       
   824     int index = filesTable->currentRow();
       
   825     if (index == -1)
       
   826         return;
       
   827 
       
   828     VideoItem * item = nameItem(index);
       
   829     if (!item)
       
   830         return;
       
   831 
       
   832     // ask user if (s)he is serious
       
   833     if (QMessageBox::question(this,
       
   834                               tr("Are you sure?"),
       
   835                               tr("Do you really want do remove %1?").arg(item->name),
       
   836                               QMessageBox::Yes | QMessageBox::No)
       
   837             != QMessageBox::Yes)
       
   838         return;
       
   839 
       
   840     // remove
       
   841     if (!item->ready())
       
   842         item->pRecorder->deleteLater();
       
   843     else
       
   844         cfgdir->remove("Videos/" + item->name);
       
   845 
       
   846 // this code is for removing several files when multiple selection is enabled
       
   847 #if 0
   782     QList<QTableWidgetItem*> items = filesTable->selectedItems();
   848     QList<QTableWidgetItem*> items = filesTable->selectedItems();
   783     int num = items.size() / vcNumColumns;
   849     int num = items.size() / vcNumColumns;
   784     if (num == 0)
   850     if (num == 0)
   785         return;
   851         return;
   786 
   852 
   801         if (!item->ready())
   867         if (!item->ready())
   802             item->pRecorder->deleteLater();
   868             item->pRecorder->deleteLater();
   803         else
   869         else
   804             cfgdir->remove("Videos/" + item->name);
   870             cfgdir->remove("Videos/" + item->name);
   805     }
   871     }
       
   872 #endif
   806 }
   873 }
   807 
   874 
   808 void PageVideos::keyPressEvent(QKeyEvent * pEvent)
   875 void PageVideos::keyPressEvent(QKeyEvent * pEvent)
   809 {
   876 {
   810     if (filesTable->hasFocus())
   877     if (filesTable->hasFocus())
   827 {
   894 {
   828     QString path = QDir::toNativeSeparators(cfgdir->absolutePath() + "/Videos");
   895     QString path = QDir::toNativeSeparators(cfgdir->absolutePath() + "/Videos");
   829     QDesktopServices::openUrl(QUrl("file:///" + path));
   896     QDesktopServices::openUrl(QUrl("file:///" + path));
   830 }
   897 }
   831 
   898 
   832 // clear VideoTemp directory (except for thumbnails)
   899 // clear VideoTemp directory (except for thumbnails and upload links)
   833 void PageVideos::clearTemp()
   900 void PageVideos::clearTemp()
   834 {
   901 {
   835     QDir temp(cfgdir->absolutePath() + "/VideoTemp");
   902     QDir temp(cfgdir->absolutePath() + "/VideoTemp");
   836     QStringList files = temp.entryList(QDir::Files);
   903     QStringList files = temp.entryList(QDir::Files);
   837     foreach (const QString& file, files)
   904     foreach (const QString& file, files)
   838     {
   905     {
   839         if (!file.endsWith(".bmp") && !file.endsWith(".png"))
   906         if (!file.endsWith(".bmp") && !file.endsWith(".png") && !file.endsWith("-url.txt"))
   840             temp.remove(file);
   907             temp.remove(file);
   841     }
   908     }
   842 }
   909 }
   843 
   910 
   844 bool PageVideos::tryQuit(HWForm * form)
   911 bool PageVideos::tryQuit(HWForm * form)
   910         }
   977         }
   911         addRecorder(pRecorder);
   978         addRecorder(pRecorder);
   912     }
   979     }
   913 }
   980 }
   914 
   981 
   915 void PageVideos::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
   982 VideoItem * PageVideos::itemFromReply(QNetworkReply* reply, int & row)
   916 {
   983 {
   917     QNetworkReply* reply = (QNetworkReply*)sender();
       
   918 
       
   919     VideoItem * item = NULL;
   984     VideoItem * item = NULL;
   920     int row;
       
   921     int count = filesTable->rowCount();
   985     int count = filesTable->rowCount();
   922     // find corresponding item (maybe there is a better wat to implement this?)
   986     // find corresponding item (maybe there is a better way to implement this?)
   923     for (int i = 0; i < count; i++)
   987     for (int i = 0; i < count; i++)
   924     {
   988     {
   925         item = nameItem(i);
   989         item = nameItem(i);
   926         if (item->pUploading == reply)
   990         if (item->pUploading == reply)
   927         {
   991         {
   928             row = i;
   992             row = i;
   929             break;
   993             break;
   930         }
   994         }
   931     }
   995     }
   932     Q_ASSERT(item);
   996     return item;
   933 
   997 }
       
   998 
       
   999 void PageVideos::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
       
  1000 {
       
  1001     QNetworkReply* reply = (QNetworkReply*)sender();
       
  1002     int row;
       
  1003     VideoItem * item = itemFromReply(reply, row);
   934     setProgress(row, item, bytesSent*1.0/bytesTotal);
  1004     setProgress(row, item, bytesSent*1.0/bytesTotal);
   935 }
  1005 }
   936 
  1006 
   937 void PageVideos::uploadFinished()
  1007 void PageVideos::uploadFinished()
   938 {
  1008 {
   939     QNetworkReply* reply = (QNetworkReply*)sender();
  1009     QNetworkReply* reply = (QNetworkReply*)sender();
   940 
  1010     reply->deleteLater();
   941     VideoItem * item = NULL;
  1011 
   942     int row;
  1012     int row;
   943     int count = filesTable->rowCount();
  1013     VideoItem * item = itemFromReply(reply, row);
   944     for (int i = 0; i < count; i++)
  1014     if (!item)
   945     {
  1015         return;
   946         item = nameItem(i);
  1016 
   947         if (item->pUploading == reply)
  1017     item->pUploading = NULL;
       
  1018 
       
  1019     // extract video id from reply
       
  1020     QString videoid;
       
  1021     QXmlStreamReader xml(reply);
       
  1022     while (!xml.atEnd())
       
  1023     {
       
  1024         xml.readNext();
       
  1025         if (xml.qualifiedName() == "yt:videoid")
   948         {
  1026         {
   949             row = i;
  1027             videoid = xml.readElementText();
   950             break;
  1028             break;
   951         }
  1029         }
   952     }
  1030     }
   953     Q_ASSERT(item);
  1031 
   954 
  1032     if (!videoid.isEmpty())
   955     item->pUploading = NULL;
  1033     {
   956     QByteArray answer = reply->readAll();
  1034         item->uploadUrl = "http://youtu.be/" + videoid;
   957     item->uploadReply = QString::fromUtf8(answer.data());
  1035         updateDescription();
   958    // QMessageBox::information(this,"",item->uploadReply,0);
  1036 
       
  1037         // save url in file
       
  1038         QFile * file = new QFile(cfgdir->absoluteFilePath("VideoTemp/" + item->prefix + "-url.txt"), this);
       
  1039         if (file->open(QIODevice::WriteOnly))
       
  1040         {
       
  1041             file->write(item->uploadUrl.toUtf8());
       
  1042             file->close();
       
  1043         }
       
  1044     }
       
  1045 
   959     filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
  1046     filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
   960     numUploads--;
  1047     numUploads--;
   961 }
  1048 }
   962 
  1049 
       
  1050 // this will protect saved youtube password from those who cannot read source code
       
  1051 static QString protectPass(QString str)
       
  1052 {
       
  1053     QByteArray array = str.toUtf8();
       
  1054     for (int i = 0; i < array.size(); i++)
       
  1055         array[i] = array[i] ^ 0xC4 ^ i;
       
  1056     array = array.toBase64();
       
  1057     return QString::fromAscii(array.data());
       
  1058 }
       
  1059 
       
  1060 static QString unprotectPass(QString str)
       
  1061 {
       
  1062     QByteArray array = QByteArray::fromBase64(str.toAscii());
       
  1063     for (int i = 0; i < array.size(); i++)
       
  1064         array[i] = array[i] ^ 0xC4 ^ i;
       
  1065     return QString::fromUtf8(array);
       
  1066 }
       
  1067 
   963 void PageVideos::uploadToYouTube()
  1068 void PageVideos::uploadToYouTube()
   964 {
  1069 {
   965     int row = filesTable->currentRow();
  1070     int row = filesTable->currentRow();
   966     VideoItem * item = nameItem(row);
  1071     VideoItem * item = nameItem(row);
   967 
  1072 
       
  1073     if (item->pUploading)
       
  1074     {
       
  1075         if (QMessageBox::question(this,
       
  1076                                   tr("Are you sure?"),
       
  1077                                   tr("Do you really want do cancel uploading %1?").arg(item->name),
       
  1078                                   QMessageBox::Yes | QMessageBox::No)
       
  1079                 != QMessageBox::Yes)
       
  1080             return;
       
  1081         item->pUploading->deleteLater();
       
  1082         filesTable->setCellWidget(row, vcProgress, NULL); // remove progress bar
       
  1083         numUploads--;
       
  1084         return;
       
  1085     }
       
  1086 
   968     if (!netManager)
  1087     if (!netManager)
   969         netManager = new QNetworkAccessManager(this);
  1088         netManager = new QNetworkAccessManager(this);
   970 
  1089 
   971     HWUploadVideoDialog* dlg = new HWUploadVideoDialog(this, item->name, netManager);
  1090     HWUploadVideoDialog* dlg = new HWUploadVideoDialog(this, item->name, netManager);
   972     dlg->deleteLater();
  1091     dlg->deleteLater();
   973     if (!dlg->exec())
  1092     if (config->value("youtube/save").toBool())
       
  1093     {
       
  1094         dlg->cbSave->setChecked(true);
       
  1095         dlg->leAccount->setText(config->value("youtube/name").toString());
       
  1096         dlg->lePassword->setText(unprotectPass(config->value("youtube/pswd").toString()));
       
  1097     }
       
  1098 
       
  1099     bool result = dlg->exec();
       
  1100 
       
  1101     if (dlg->cbSave->isChecked())
       
  1102     {
       
  1103         config->setValue("youtube/save", true);
       
  1104         config->setValue("youtube/name", dlg->leAccount->text());
       
  1105         config->setValue("youtube/pswd", protectPass(dlg->lePassword->text()));
       
  1106     }
       
  1107     else
       
  1108     {
       
  1109         config->setValue("youtube/save", false);
       
  1110         config->setValue("youtube/name", "");
       
  1111         config->setValue("youtube/pswd", "");
       
  1112     }
       
  1113 
       
  1114     if (!result)
   974         return;
  1115         return;
   975 
  1116 
   976     QNetworkRequest request(QUrl(dlg->location));
  1117     QNetworkRequest request(QUrl(dlg->location));
   977     request.setRawHeader("Content-Type", "application/octet-stream");
  1118     request.setRawHeader("Content-Type", "application/octet-stream");
   978 
  1119 
   983     // add progress bar
  1124     // add progress bar
   984     QProgressBar * progressBar = new QProgressBar(filesTable);
  1125     QProgressBar * progressBar = new QProgressBar(filesTable);
   985     progressBar->setMinimum(0);
  1126     progressBar->setMinimum(0);
   986     progressBar->setMaximum(10000);
  1127     progressBar->setMaximum(10000);
   987     progressBar->setValue(0);
  1128     progressBar->setValue(0);
   988     // make it different from encoding progress-bar
  1129     // make it different from progress-bar used during encoding (use blue color)
   989     progressBar->setStyleSheet("* {color: #00ccff; selection-background-color: #00ccff;}" );
  1130     progressBar->setStyleSheet("* {color: #00ccff; selection-background-color: #00ccff;}" );
   990     filesTable->setCellWidget(row, vcProgress, progressBar);
  1131     filesTable->setCellWidget(row, vcProgress, progressBar);
   991 
  1132 
   992     QNetworkReply* reply = netManager->put(request, file);
  1133     QNetworkReply* reply = netManager->put(request, file);
   993     item->pUploading = reply;
  1134     item->pUploading = reply;
   994     connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
  1135     connect(reply, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(uploadProgress(qint64, qint64)));
   995     connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished()));
  1136     connect(reply, SIGNAL(finished()), this, SLOT(uploadFinished()));
   996     numUploads++;
  1137     numUploads++;
   997 }
  1138 
       
  1139     updateDescription();
       
  1140 }