X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2FMediaView.cpp;h=a77fba219122456205572e7d42eb4b3f5746ccec;hb=3c8c537559e6bef5f019196b0989e95863ddd3ee;hp=d41c69eae29e8970cd34ec805be6f986b639d5cc;hpb=63b7586c1282acfb82a9b1971320052d6ee0a707;p=minitube diff --git a/src/MediaView.cpp b/src/MediaView.cpp index d41c69e..a77fba2 100644 --- a/src/MediaView.cpp +++ b/src/MediaView.cpp @@ -1,4 +1,5 @@ #include "MediaView.h" +#include "playlistview.h" #include "playlist/PrettyItemDelegate.h" #include "networkaccess.h" #include "videowidget.h" @@ -7,15 +8,16 @@ #include "downloadmanager.h" #include "downloaditem.h" #include "MainWindow.h" +#include "temporary.h" namespace The { - NetworkAccess* http(); +NetworkAccess* http(); } namespace The { - QMap* globalActions(); - QMap* globalMenus(); - QNetworkAccessManager* networkAccessManager(); +QMap* globalActions(); +QMap* globalMenus(); +QNetworkAccessManager* networkAccessManager(); } MediaView::MediaView(QWidget *parent) : QWidget(parent) { @@ -23,13 +25,13 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { reallyStopped = false; downloadItem = 0; - QBoxLayout *layout = new QHBoxLayout(); + QBoxLayout *layout = new QVBoxLayout(); layout->setMargin(0); splitter = new MiniSplitter(this); splitter->setChildrenCollapsible(false); - sortBar = new THBlackBar(this); + sortBar = new SegmentedControl(this); mostRelevantAction = new QAction(tr("Most relevant"), this); QKeySequence keySequence(Qt::CTRL + Qt::Key_1); mostRelevantAction->setShortcut(keySequence); @@ -52,7 +54,7 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { connect(mostViewedAction, SIGNAL(triggered()), this, SLOT(searchMostViewed()), Qt::QueuedConnection); sortBar->addAction(mostViewedAction); - listView = new QListView(this); + listView = new PlaylistView(this); listView->setItemDelegate(new PrettyItemDelegate(this)); listView->setSelectionMode(QAbstractItemView::ExtendedSelection); @@ -82,6 +84,8 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { SIGNAL(selectionChanged ( const QItemSelection & , const QItemSelection & )), this, SLOT(selectionChanged ( const QItemSelection & , const QItemSelection & ))); + connect(listView, SIGNAL(authorPushed(QModelIndex)), SLOT(authorPushed(QModelIndex))); + playlistWidget = new PlaylistWidget(this, sortBar, listView); splitter->addWidget(playlistWidget); @@ -89,7 +93,7 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { videoAreaWidget = new VideoAreaWidget(this); videoAreaWidget->setMinimumSize(320,240); -#ifdef APP_MAC +#ifdef APP_MAC_NO // mouse autohide does not work on the Mac (no mouseMoveEvent) videoWidget = new Phonon::VideoWidget(this); #else @@ -107,6 +111,9 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { layout->addWidget(splitter); setLayout(layout); + splitter->setStretchFactor(0, 1); + splitter->setStretchFactor(1, 6); + // restore splitter state QSettings settings; splitter->restoreState(settings.value("splitter").toByteArray()); @@ -131,9 +138,12 @@ MediaView::MediaView(QWidget *parent) : QWidget(parent) { void MediaView::initialize() { connect(videoAreaWidget, SIGNAL(doubleClicked()), The::globalActions()->value("fullscreen"), SLOT(trigger())); + + /* videoAreaWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(videoAreaWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showVideoContextMenu(QPoint))); + */ } void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) { @@ -153,17 +163,9 @@ void MediaView::search(SearchParams *searchParams) { #ifdef APP_DEMO demoTimer->stop(); #endif - - videoAreaWidget->clear(); workaroundTimer->stop(); errorTimer->stop(); - mediaObject->pause(); - if (downloadItem) { - delete downloadItem; - downloadItem = 0; - } - this->searchParams = searchParams; // start serching for videos @@ -174,7 +176,6 @@ void MediaView::search(SearchParams *searchParams) { listView->setFocus(); - QString keyword = searchParams->keywords(); QString display = keyword; if (keyword.startsWith("http://") || keyword.startsWith("https://")) { @@ -182,23 +183,21 @@ void MediaView::search(SearchParams *searchParams) { if (separator > 0 && separator + 1 < keyword.length()) { display = keyword.mid(separator+1); } + } - // also hide sidebar - playlistWidget->hide(); - } else playlistWidget->show(); - // tr("You're watching \"%1\"").arg(searchParams->keywords()) +} +void MediaView::appear() { + listView->setFocus(); } void MediaView::disappear() { timerPlayFlag = true; } -void MediaView::handleError(QString message) { - // if (message.indexOf("movie atom") != -1 || message.indexOf("Could not open") != -1) { - QTimer::singleShot(1000, this, SLOT(startPlaying())); - return; - // } +void MediaView::handleError(QString /* message */) { + + QTimer::singleShot(100, this, SLOT(startPlaying())); /* videoAreaWidget->showError(message); @@ -242,25 +241,24 @@ void MediaView::stateChanged(Phonon::State newState, Phonon::State /*oldState*/) break; - case Phonon::PausedState: + case Phonon::PausedState: qDebug("paused"); break; - case Phonon::BufferingState: + case Phonon::BufferingState: qDebug("buffering"); break; - case Phonon::LoadingState: + case Phonon::LoadingState: qDebug("loading"); break; - default: - ; } } void MediaView::pause() { // qDebug() << "pause() called" << mediaObject->state(); + switch( mediaObject->state() ) { case Phonon::PlayingState: mediaObject->pause(); @@ -269,6 +267,11 @@ void MediaView::pause() { mediaObject->play(); break; } + +} + +QRegExp MediaView::wordRE(QString s) { + return QRegExp("\\W" + s + "\\W?", Qt::CaseInsensitive); } void MediaView::stop() { @@ -308,9 +311,9 @@ void MediaView::activeRowChanged(int row) { // immediately show the loading widget videoAreaWidget->showLoading(video); - connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl))); + connect(video, SIGNAL(gotStreamUrl(QUrl)), SLOT(gotStreamUrl(QUrl)), Qt::UniqueConnection); // TODO handle signal in a proper slot and impl item error status - connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString))); + connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection); video->loadStreamUrl(); @@ -321,7 +324,6 @@ void MediaView::activeRowChanged(int row) { QMainWindow* mainWindow = dynamic_cast(window()); if (mainWindow) mainWindow->statusBar()->showMessage(video->title()); - The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0); // ensure active item is visible // int row = listModel->activeRow(); @@ -330,6 +332,12 @@ void MediaView::activeRowChanged(int row) { listView->scrollTo(index, QAbstractItemView::EnsureVisible); } + // enable/disable actions + The::globalActions()->value("download")->setEnabled(DownloadManager::instance()->itemForVideo(video) == 0); + The::globalActions()->value("skip")->setEnabled(true); + The::globalActions()->value("previous")->setEnabled(row > 0); + The::globalActions()->value("stopafterthis")->setEnabled(true); + // see you in gotStreamUrl... } @@ -344,16 +352,7 @@ void MediaView::gotStreamUrl(QUrl streamUrl) { } video->disconnect(this); - - QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation); -#ifdef Q_WS_X11 - QString tempFile = tempDir + "/minitube-" + getenv("USERNAME") + ".mp4"; -#else - QString tempFile = tempDir + "/minitube.mp4"; -#endif - if (QFile::exists(tempFile) && !QFile::remove(tempFile)) { - qDebug() << "Cannot remove temp file"; - } + QString tempFile = Temporary::filename(); Video *videoCopy = video->clone(); if (downloadItem) { @@ -361,12 +360,12 @@ void MediaView::gotStreamUrl(QUrl streamUrl) { delete downloadItem; } downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this); - connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged())); + connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()), Qt::UniqueConnection); // connect(downloadItem, SIGNAL(progress(int)), SLOT(downloadProgress(int))); - connect(downloadItem, SIGNAL(bufferProgress(int)), loadingWidget, SLOT(bufferStatus(int))); + connect(downloadItem, SIGNAL(bufferProgress(int)), loadingWidget, SLOT(bufferStatus(int)), Qt::UniqueConnection); // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished())); - connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString))); - connect(downloadItem, SIGNAL(error(QString)), SLOT(handleError(QString))); + connect(video, SIGNAL(errorStreamUrl(QString)), SLOT(handleError(QString)), Qt::UniqueConnection); + connect(downloadItem, SIGNAL(error(QString)), SLOT(handleError(QString)), Qt::UniqueConnection); downloadItem->start(); } @@ -427,8 +426,9 @@ void MediaView::startPlaying() { } // go! - qDebug() << "Playing" << downloadItem->currentFilename(); - mediaObject->setCurrentSource(downloadItem->currentFilename()); + QString source = downloadItem->currentFilename(); + qDebug() << "Playing" << source; + mediaObject->setCurrentSource(source); mediaObject->play(); // ensure we always have 10 videos ahead @@ -442,16 +442,27 @@ void MediaView::startPlaying() { } #ifdef APP_DEMO - demoTimer->start(30000); + demoTimer->start(60000); #endif } void MediaView::itemActivated(const QModelIndex &index) { - if (listModel->rowExists(index.row())) - listModel->setActiveRow(index.row()); + if (listModel->rowExists(index.row())) { + + // if it's the current video, just rewind and play + Video *activeVideo = listModel->activeVideo(); + Video *video = listModel->videoAt(index.row()); + if (activeVideo && video && activeVideo == video) { + mediaObject->seek(0); + mediaObject->play(); + } else listModel->setActiveRow(index.row()); + // the user doubleclicked on the "Search More" item - else listModel->searchMore(); + } else { + listModel->searchMore(); + listView->selectionModel()->clearSelection(); + } } void MediaView::currentSourceChanged(const Phonon::MediaSource /* source */ ) { @@ -480,13 +491,24 @@ void MediaView::skip() { listModel->setActiveRow(nextRow); } +void MediaView::skipBackward() { + int prevRow = listModel->previousRow(); + if (prevRow == -1) return; + listModel->setActiveRow(prevRow); +} + void MediaView::playbackFinished() { // qDebug() << "finished" << mediaObject->currentTime() << mediaObject->totalTime(); // add 10 secs for imprecise Phonon backends (VLC, Xine) if (mediaObject->currentTime() + 10000 < mediaObject->totalTime()) { // mediaObject->seek(mediaObject->currentTime()); - QTimer::singleShot(3000, this, SLOT(playbackResume())); - } else skip(); + QTimer::singleShot(500, this, SLOT(playbackResume())); + } else { + QAction* stopAfterThisAction = The::globalActions()->value("stopafterthis"); + if (stopAfterThisAction->isChecked()) { + stopAfterThisAction->setChecked(false); + } else skip(); + } } void MediaView::playbackResume() { @@ -505,7 +527,6 @@ void MediaView::copyWebPage() { Video* video = listModel->activeVideo(); if (!video) return; QString address = video->webpage().toString(); - address.remove("&feature=youtube_gdata"); QApplication::clipboard()->setText(address); QMainWindow* mainWindow = dynamic_cast(window()); QString message = tr("You can now paste the YouTube link into another application"); @@ -517,7 +538,7 @@ void MediaView::copyVideoLink() { if (!video) return; QApplication::clipboard()->setText(video->getStreamUrl().toEncoded()); QString message = tr("You can now paste the video stream URL into another application") - + ". " + tr("The link will be valid only for a limited time."); + + ". " + tr("The link will be valid only for a limited time."); QMainWindow* mainWindow = dynamic_cast(window()); if (mainWindow) mainWindow->statusBar()->showMessage(message); } @@ -607,30 +628,53 @@ void MediaView::saveSplitterState() { } #ifdef APP_DEMO + +static QPushButton *continueButton; + void MediaView::demoMessage() { if (mediaObject->state() != Phonon::PlayingState) return; mediaObject->pause(); QMessageBox msgBox(this); msgBox.setIconPixmap(QPixmap(":/images/app.png").scaled(64, 64, Qt::KeepAspectRatio, Qt::SmoothTransformation)); - msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::APP_NAME)); + msgBox.setText(tr("This is just the demo version of %1.").arg(Constants::NAME)); msgBox.setInformativeText(tr("It allows you to test the application and see if it works for you.")); msgBox.setModal(true); // make it a "sheet" on the Mac msgBox.setWindowModality(Qt::WindowModal); - QPushButton *quitButton = msgBox.addButton(tr("Continue"), QMessageBox::RejectRole); + continueButton = msgBox.addButton("5", QMessageBox::RejectRole); + continueButton->setEnabled(false); QPushButton *buyButton = msgBox.addButton(tr("Get the full version"), QMessageBox::ActionRole); + QTimeLine *timeLine = new QTimeLine(6000, this); + timeLine->setCurveShape(QTimeLine::LinearCurve); + timeLine->setFrameRange(5, 0); + connect(timeLine, SIGNAL(frameChanged(int)), SLOT(updateContinueButton(int))); + timeLine->start(); + msgBox.exec(); if (msgBox.clickedButton() == buyButton) { - QDesktopServices::openUrl(QString(Constants::WEBSITE) + "#download"); + QDesktopServices::openUrl(QUrl(QString(Constants::WEBSITE) + "#download")); } else { mediaObject->play(); - demoTimer->start(300000); + demoTimer->start(600000); + } + + delete timeLine; + +} + +void MediaView::updateContinueButton(int value) { + if (value == 0) { + continueButton->setText(tr("Continue")); + continueButton->setEnabled(true); + } else { + continueButton->setText(QString::number(value)); } } + #endif void MediaView::downloadVideo() { @@ -701,3 +745,107 @@ void MediaView::seekTo(int value) { } */ + +void MediaView::findVideoParts() { + + // parts + Video* video = listModel->activeVideo(); + if (!video) return; + + QString query = video->title(); + + static QString optionalSpace = "\\s*"; + static QString staticCounterSeparators = "[\\/\\-]"; + QString counterSeparators = "( of | " + + tr("of", "Used in video parts, as in '2 of 3'") + + " |" + staticCounterSeparators + ")"; + + // numbers from 1 to 15 + static QString counterNumber = "([1-9]|1[0-5])"; + + // query.remove(QRegExp(counterSeparators + optionalSpace + counterNumber)); + query.remove(QRegExp(counterNumber + optionalSpace + counterSeparators + optionalSpace + counterNumber)); + query.remove(wordRE("pr?t\\.?" + optionalSpace + counterNumber)); + query.remove(wordRE("ep\\.?" + optionalSpace + counterNumber)); + query.remove(wordRE("part" + optionalSpace + counterNumber)); + query.remove(wordRE("episode" + optionalSpace + counterNumber)); + query.remove(wordRE(tr("part", "This is for video parts, as in 'Cool video - part 1'") + + optionalSpace + counterNumber)); + query.remove(wordRE(tr("episode", "This is for video parts, as in 'Cool series - episode 1'") + + optionalSpace + counterNumber)); + query.remove(QRegExp("[\\(\\)\\[\\]]")); + +#define NUMBERS "one|two|three|four|five|six|seven|eight|nine|ten" + + QRegExp englishNumberRE = QRegExp(QLatin1String(".*(") + NUMBERS + ").*", Qt::CaseInsensitive); + // bool numberAsWords = englishNumberRE.exactMatch(query); + query.remove(englishNumberRE); + + QRegExp localizedNumberRE = QRegExp(QLatin1String(".*(") + tr(NUMBERS) + ").*", Qt::CaseInsensitive); + // if (!numberAsWords) numberAsWords = localizedNumberRE.exactMatch(query); + query.remove(localizedNumberRE); + + SearchParams *searchParams = new SearchParams(); + searchParams->setTransient(true); + searchParams->setKeywords(query); + searchParams->setAuthor(video->author()); + + /* + if (!numberAsWords) { + qDebug() << "We don't have number as words"; + // searchParams->setSortBy(SearchParams::SortByNewest); + // TODO searchParams->setReverseOrder(true); + // TODO searchParams->setMax(50); + } + */ + + search(searchParams); + +} + +void MediaView::shareViaTwitter() { + Video* video = listModel->activeVideo(); + if (!video) return; + QUrl url("https://twitter.com/intent/tweet"); + url.addQueryItem("via", "minitubeapp"); + url.addQueryItem("text", video->title()); + url.addQueryItem("url", video->webpage().toString()); + QDesktopServices::openUrl(url); +} + +void MediaView::shareViaFacebook() { + Video* video = listModel->activeVideo(); + if (!video) return; + QUrl url("https://www.facebook.com/sharer.php"); + url.addQueryItem("t", video->title()); + url.addQueryItem("u", video->webpage().toString()); + QDesktopServices::openUrl(url); +} + +void MediaView::shareViaEmail() { + Video* video = listModel->activeVideo(); + if (!video) return; + QUrl url("mailto:"); + url.addQueryItem("subject", video->title()); + QString body = video->title() + "\n" + + video->webpage().toString() + "\n\n" + + tr("Sent from %1").arg(Constants::NAME) + "\n" + + Constants::WEBSITE; + url.addQueryItem("body", body); + QDesktopServices::openUrl(url); +} + +void MediaView::authorPushed(QModelIndex index) { + Video* video = listModel->videoAt(index.row()); + if (!video) return; + + QString channel = video->author(); + if (channel.isEmpty()) return; + + SearchParams *searchParams = new SearchParams(); + searchParams->setAuthor(channel); + searchParams->setSortBy(SearchParams::SortByNewest); + + // go! + search(searchParams); +}