]> git.sur5r.net Git - minitube/commitdiff
Seeking 2.1.3
authorFlavio <flavio@odisseo.local>
Fri, 6 Sep 2013 14:22:58 +0000 (16:22 +0200)
committerFlavio <flavio@odisseo.local>
Fri, 6 Sep 2013 14:22:58 +0000 (16:22 +0200)
minitube.pro
src/downloaditem.cpp
src/downloaditem.h
src/mainwindow.cpp
src/mainwindow.h
src/mediaview.cpp
src/mediaview.h
src/networkaccess.cpp
src/networkaccess.h
src/seekslider.cpp [new file with mode: 0644]
src/seekslider.h [new file with mode: 0644]

index 532c28a5cbb02b93697b5a2b398f069802b8960d..40fb16d4fbbf54ecd6ccf610b505806fa91068fb 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG += release
 TEMPLATE = app
-VERSION = 2.1.2
+VERSION = 2.1.3
 DEFINES += APP_VERSION="$$VERSION"
 
 APP_NAME = Minitube
@@ -80,7 +80,8 @@ HEADERS += \
     src/aggregatevideosource.h \
     src/channelview.h \
     src/channelitemdelegate.h \
-    src/jsfunctions.h
+    src/jsfunctions.h \
+    src/seekslider.h
 SOURCES += src/main.cpp \
     src/searchlineedit.cpp \
     src/urllineedit.cpp \
@@ -142,7 +143,8 @@ SOURCES += src/main.cpp \
     src/aggregatevideosource.cpp \
     src/channelview.cpp \
     src/channelitemdelegate.cpp \
-    src/jsfunctions.cpp
+    src/jsfunctions.cpp \
+    src/seekslider.cpp
 RESOURCES += resources.qrc
 DESTDIR = build/target/
 OBJECTS_DIR = build/obj/
index 12bb7c2c9f7c27bb3739cc3fd053f72f63cde3a2..9b7982163cf5ed2c3d85f31bbc675fff1bc779ee 100644 (file)
@@ -39,6 +39,8 @@ DownloadItem::DownloadItem(Video *video, QUrl url, QString filename, QObject *pa
     , m_startedSaving(false)
     , m_finishedDownloading(false)
     , m_url(url)
+    , m_offset(0)
+    , sendStatusChanges(true)
     , m_file(filename)
     , m_reply(0)
     , video(video)
@@ -48,6 +50,9 @@ DownloadItem::DownloadItem(Video *video, QUrl url, QString filename, QObject *pa
     speedCheckTimer->setInterval(2000);
     speedCheckTimer->setSingleShot(true);
     connect(speedCheckTimer, SIGNAL(timeout()), SLOT(speedCheck()));
+
+    if (m_file.exists())
+        m_file.remove();
 }
 
 DownloadItem::~DownloadItem() {
@@ -61,8 +66,70 @@ DownloadItem::~DownloadItem() {
     }
 }
 
+bool DownloadItem::needsDownload(qint64 offset) {
+    return offset < m_offset || offset > m_offset + m_bytesReceived;
+}
+
+bool DownloadItem::isBuffered(qint64 offset) {
+    QMap<qint64, qint64>::iterator i;
+    for (i = buffers.begin(); i != buffers.end(); ++i) {
+        if (offset >= i.key() && offset <= i.value()) {
+            // qDebug() << "Buffered! " << i.key() << ":" << i.value();
+            return true;
+        }
+    }
+    // qDebug() << offset << "is not buffered";
+    return false;
+}
+
+qint64 DownloadItem::blankAtOffset(qint64 offset) {
+    // qDebug() << buffers;
+    QMap<qint64, qint64>::iterator i;
+    for (i = buffers.begin(); i != buffers.end(); ++i) {
+        if (offset >= i.key() && offset <= i.value()) {
+            // qDebug() << "Offset was" << offset << "now" << i.value();
+            return i.value() + 1;
+        }
+    }
+    return offset;
+}
+
+void DownloadItem::seekTo(qint64 offset, bool sendStatusChanges) {
+    // qDebug() << __PRETTY_FUNCTION__ << offset << sendStatusChanges;
+    stop();
+    if (m_bytesReceived > 0) {
+        bool bufferModified = false;
+        QMap<qint64, qint64>::iterator i;
+        for (i = buffers.begin(); i != buffers.end(); ++i) {
+            if (m_offset - 1 <= i.value()) {
+                /*
+                qDebug() << "Extending existing buffer "
+                         << i.key() << i.value() << "now" << m_offset + m_bytesReceived;
+                */
+                bufferModified = true;
+                i.value() = m_offset + m_bytesReceived;
+                break;
+            }
+        }
+        if (!bufferModified)
+            buffers.insert(m_offset, m_offset + m_bytesReceived);
+    }
+    m_offset = offset;
+    this->sendStatusChanges = sendStatusChanges;
+    bool seekSuccess = m_file.seek(offset);
+    if (!seekSuccess) {
+        qWarning() << "Cannot seek to offset" << offset << "in file" << m_file.fileName();
+        return;
+    }
+    start();
+}
+
 void DownloadItem::start() {
-    m_reply = The::http()->request(m_url);
+    // qDebug() << "Starting download at" << m_offset;
+    if (m_offset > 0)
+        m_reply = The::http()->request(m_url, QNetworkAccessManager::GetOperation, QByteArray(), m_offset);
+    else
+        m_reply = The::http()->request(m_url);
     init();
 }
 
@@ -70,11 +137,8 @@ void DownloadItem::init() {
     if (!m_reply)
         return;
 
-    if (m_file.exists())
-        m_file.remove();
-
     m_status = Starting;
-
+    m_bytesReceived = 0;
     m_startedSaving = false;
     m_finishedDownloading = false;
 
@@ -147,6 +211,7 @@ void DownloadItem::downloadReadyRead() {
         emit statusChanged();
     }
 
+    // qWarning() << __PRETTY_FUNCTION__ << m_file.pos();
     if (-1 == m_file.write(m_reply->readAll())) {
         qWarning() << "Error saving." << m_file.errorString();
     } else {
@@ -183,10 +248,7 @@ void DownloadItem::metaDataChanged() {
         tryAgain();
         return;
     }
-
-#ifdef DOWNLOADMANAGER_DEBUG
-    qDebug() << "DownloadItem::" << __FUNCTION__ << "not handled.";
-#endif
+    // qDebug() << m_reply->rawHeaderList();
 }
 
 int DownloadItem::initialBufferSize() {
@@ -204,13 +266,15 @@ int DownloadItem::initialBufferSize() {
 
 void DownloadItem::downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
 
-    // qDebug() << bytesReceived << bytesTotal << m_downloadTime.elapsed();
+    // qDebug() << __PRETTY_FUNCTION__ << bytesReceived << bytesTotal << m_downloadTime.elapsed();
+
+    m_bytesReceived = bytesReceived;
+
+    if (!sendStatusChanges) return;
 
     if (m_lastProgressTime.elapsed() < 150) return;
     m_lastProgressTime.start();
 
-    m_bytesReceived = bytesReceived;
-
     if (m_status != Downloading) {
 
         int neededBytes = (int) (bytesTotal * .005);
@@ -327,7 +391,7 @@ void DownloadItem::requestFinished() {
         m_status = Downloading;
         emit statusChanged();
     }
-    m_file.close();
+    if (m_offset == 0) m_file.close();
     m_status = Finished;
     m_totalTime = m_downloadTime.elapsed() / 1000.0;
     emit statusChanged();
index 7a100e0b136af68e13d2f07c278656b4097a1f0c..2c074f0c1d7a4076dd26df647ee40e6e114f2b65 100644 (file)
@@ -61,6 +61,11 @@ public:
     static QString formattedSpeed(double speed);
     static QString formattedTime(double time, bool remaining = true);
     QString errorMessage() const;
+    qint64 offset() const { return m_offset; }
+    bool needsDownload(qint64 offset);
+    bool isBuffered(qint64 offset);
+    qint64 blankAtOffset(qint64 offset);
+    void seekTo(qint64 offset, bool sendStatusChanges = true);
 
 public slots:
     void start();
@@ -92,6 +97,9 @@ private:
 
     QUrl m_url;
 
+    qint64 m_offset;
+    bool sendStatusChanges;
+
     QFile m_file;
     QNetworkReply *m_reply;
     Video *video;
@@ -101,6 +109,7 @@ private:
 
     QTimer *speedCheckTimer;
 
+    QMap<qint64, qint64> buffers;
 };
 
 // This is required in order to use QPointer<DownloadItem> as a QVariant
index 3ae36bd8c7e3236922837aa7e967506806c72daa..3392ff2cf04c6fcebc5308444283c4c0cd04a79b 100644 (file)
@@ -69,6 +69,7 @@ $END_LICENSE */
 #include "database.h"
 #include "videoareawidget.h"
 #include "jsfunctions.h"
+#include "seekslider.h"
 
 static MainWindow *singleton = 0;
 
@@ -565,6 +566,11 @@ void MainWindow::createActions() {
     connect(action, SIGNAL(triggered()), mediaView, SLOT(relatedVideos()));
     actions->insert("related-videos", action);
 
+    action = new QAction(tr("Open in &Browser..."), this);
+    action->setEnabled(false);
+    actions->insert("open-in-browser", action);
+    connect(action, SIGNAL(triggered()), mediaView, SLOT(openInBrowser()));
+
 #ifdef APP_ACTIVATION
     Extra::createActivationAction(tr("Buy %1...").arg(Constants::NAME));
 #endif
@@ -630,6 +636,7 @@ void MainWindow::createMenus() {
     videoMenu->addSeparator();
     videoMenu->addAction(The::globalActions()->value("download"));
     videoMenu->addAction(copyLinkAct);
+    videoMenu->addAction(The::globalActions()->value("open-in-browser"));
     // videoMenu->addAction(The::globalActions()->value("snapshot"));
 
     QMenu* viewMenu = menuBar()->addMenu(tr("&View"));
@@ -695,20 +702,23 @@ void MainWindow::createToolBars() {
     currentTime->setFont(smallerFont);
     mainToolBar->addWidget(currentTime);
 
+#ifdef APP_PHONON_SEEK
     mainToolBar->addWidget(new Spacer());
-
     seekSlider = new Phonon::SeekSlider(this);
+    seekSlider->setVisible(false);
     seekSlider->setIconVisible(false);
     seekSlider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
     mainToolBar->addWidget(seekSlider);
+#endif
 
-    /*
     mainToolBar->addWidget(new Spacer());
-    slider = new QSlider(this);
+    slider = new SeekSlider(this);
+    slider->setEnabled(false);
+    slider->setTracking(false);
+    slider->setMaximum(1000);
     slider->setOrientation(Qt::Horizontal);
     slider->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
     mainToolBar->addWidget(slider);
-*/
 
     mainToolBar->addWidget(new Spacer());
 
@@ -1266,7 +1276,9 @@ void MainWindow::initPhonon() {
             this, SLOT(stateChanged(Phonon::State, Phonon::State)));
     connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(tick(qint64)));
     connect(mediaObject, SIGNAL(totalTimeChanged(qint64)), this, SLOT(totalTimeChanged(qint64)));
+#ifdef APP_PHONON_SEEK
     seekSlider->setMediaObject(mediaObject);
+#endif
     audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory, this);
     connect(audioOutput, SIGNAL(volumeChanged(qreal)), this, SLOT(volumeChanged(qreal)));
     connect(audioOutput, SIGNAL(mutedChanged(bool)), this, SLOT(volumeMutedChanged(bool)));
@@ -1291,11 +1303,12 @@ void MainWindow::tick(qint64 time) {
     const qint64 remainingTime = mediaObject->remainingTime();
     currentTime->setStatusTip(tr("Remaining time: %1").arg(formatTime(remainingTime)));
 
-    /*
     slider->blockSignals(true);
-    slider->setValue(time/1000);
+    const qint64 totalTime = mediaObject->totalTime();
+    // qWarning() << totalTime << time << time * 100 / totalTime;
+    if (totalTime > 0 && time > 0 && !slider->isSliderDown() && mediaObject->state() == Phonon::PlayingState)
+        slider->setValue(time * slider->maximum() / totalTime);
     slider->blockSignals(false);
-    */
 }
 
 void MainWindow::totalTimeChanged(qint64 time) {
index 73f09b578c29ea6273976a1a867ceec211fd25a0..404fa137e13b2a5464f7076033345e0c89e96b85 100644 (file)
@@ -44,7 +44,10 @@ public:
     static MainWindow* instance();
     MainWindow();
     ~MainWindow();
+#ifdef APP_PHONON_SEEK
     Phonon::SeekSlider* getSeekSlider() { return seekSlider; }
+#endif
+    QSlider* getSlider() { return slider; }
     void readSettings();
     void writeSettings();
     static void printHelp();
@@ -192,7 +195,10 @@ private:
     QAction *regionAction;
 
     // phonon
+    QSlider *slider;
+#ifdef APP_PHONON_SEEK
     Phonon::SeekSlider *seekSlider;
+#endif
     Phonon::VolumeSlider *volumeSlider;
     Phonon::MediaObject *mediaObject;
     Phonon::AudioOutput *audioOutput;
index 9f5aafa03c1184aeedfd6bc30b0a68fb961e6ade..c1a08468c065ec7f909372f319eb6259df7615d0 100644 (file)
@@ -142,10 +142,10 @@ void MediaView::initialize() {
             << The::globalActions()->value("webpage")
             << The::globalActions()->value("pagelink")
             << The::globalActions()->value("videolink")
+            << The::globalActions()->value("open-in-browser")
             << The::globalActions()->value("findVideoParts")
             << The::globalActions()->value("skip")
             << The::globalActions()->value("previous")
-            // << The::globalActions()->value("download")
             << The::globalActions()->value("stopafterthis")
             << The::globalActions()->value("related-videos")
             << The::globalActions()->value("refine-search")
@@ -153,6 +153,9 @@ void MediaView::initialize() {
             << The::globalActions()->value("facebook")
             << The::globalActions()->value("buffer")
             << The::globalActions()->value("email");
+
+    QSlider *slider = MainWindow::instance()->getSlider();
+    connect(slider, SIGNAL(valueChanged(int)), SLOT(sliderMoved(int)));
 }
 
 void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
@@ -161,17 +164,6 @@ void MediaView::setMediaObject(Phonon::MediaObject *mediaObject) {
     connect(mediaObject, SIGNAL(finished()), SLOT(playbackFinished()));
     connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)),
             SLOT(stateChanged(Phonon::State, Phonon::State)));
-    /*
-    const char* s = Constants::NAME;
-    const int l = strlen(s);
-    int t = The::globalActions()->count();
-    for (int i = 0; i < l; i++) {
-        t += s[i];
-        qDebug() << t << The::globalActions()->count();
-    }
-    qDebug() << t << The::globalActions()->count();
-    if (t != s[0]) return;
-    */
     connect(mediaObject, SIGNAL(aboutToFinish()), SLOT(aboutToFinish()));
 }
 
@@ -332,6 +324,7 @@ void MediaView::stop() {
         downloadItem->stop();
         delete downloadItem;
         downloadItem = 0;
+        currentVideoSize = 0;
     }
     The::globalActions()->value("refine-search")->setChecked(false);
     updateSubscriptionAction(0, false);
@@ -348,6 +341,10 @@ void MediaView::stop() {
 
     mediaObject->stop();
     currentVideoId.clear();
+
+    QSlider *slider = MainWindow::instance()->getSlider();
+    slider->setEnabled(false);
+    slider->setValue(0);
 }
 
 const QString & MediaView::getCurrentVideoId() {
@@ -364,6 +361,7 @@ void MediaView::activeRowChanged(int row) {
         downloadItem->stop();
         delete downloadItem;
         downloadItem = 0;
+        currentVideoSize = 0;
     }
 
     Video *video = playlistModel->videoAt(row);
@@ -390,7 +388,6 @@ void MediaView::activeRowChanged(int row) {
     // 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);
     The::globalActions()->value("related-videos")->setEnabled(true);
@@ -413,6 +410,10 @@ void MediaView::activeRowChanged(int row) {
     foreach (QAction *action, currentVideoActions)
         action->setEnabled(true);
 
+    QSlider *slider = MainWindow::instance()->getSlider();
+    slider->setEnabled(false);
+    slider->setValue(0);
+
     // see you in gotStreamUrl...
 }
 
@@ -436,24 +437,7 @@ void MediaView::gotStreamUrl(QUrl streamUrl) {
     mediaObject->setCurrentSource(streamUrl);
     mediaObject->play();
 #else
-    QString tempFile = Temporary::filename();
-    Video *videoCopy = video->clone();
-    if (downloadItem) {
-        downloadItem->stop();
-        delete downloadItem;
-    }
-    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
-    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)), Qt::UniqueConnection);
-    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
-    connect(video, SIGNAL(errorStreamUrl(QString)),
-            SLOT(handleError(QString)), Qt::UniqueConnection);
-    connect(downloadItem, SIGNAL(error(QString)),
-            SLOT(handleError(QString)), Qt::UniqueConnection);
-    downloadItem->start();
+    startDownloading();
 #endif
 
     // ensure we always have 10 videos ahead
@@ -478,50 +462,31 @@ void MediaView::gotStreamUrl(QUrl streamUrl) {
     ChannelAggregator::instance()->videoWatched(video);
 }
 
-/*
-void MediaView::downloadProgress(int percent) {
-    MainWindow* mainWindow = dynamic_cast<MainWindow*>(window());
-
-    mainWindow->getSeekSlider()->setStyleSheet(" QSlider::groove:horizontal {"
-        "border: 1px solid #999999;"
-        // "border-left: 50px solid rgba(255, 0, 0, 128);"
-        "height: 8px;"
-        "background: qlineargradient(x1:0, y1:0, x2:.5, y2:0, stop:0 rgba(255, 0, 0, 92), stop:"
-        + QString::number(percent/100.0) +
-
-        " rgba(255, 0, 0, 92), stop:" + QString::number((percent+1)/100.0) + " transparent, stop:1 transparent);"
-        "margin: 2px 0;"
-    "}"
-    "QSlider::handle:horizontal {"
-        "background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);"
-        "border: 1px solid #5c5c5c;"
-        "width: 16px;"
-        "height: 16px;"
-        "margin: -2px 0;"
-        "border-radius: 8px;"
-    "}"
-
-    );
-}
-*/
-
 void MediaView::downloadStatusChanged() {
+    // qDebug() << __PRETTY_FUNCTION__;
     switch(downloadItem->status()) {
     case Downloading:
-        startPlaying();
+        // qDebug() << "Downloading";
+        if (downloadItem->offset() == 0) startPlaying();
+        else {
+            // qDebug() << "Seeking to" << downloadItem->offset();
+            mediaObject->seek(offsetToTime(downloadItem->offset()));
+            mediaObject->play();
+        }
         break;
     case Starting:
         // qDebug() << "Starting";
         break;
     case Finished:
         // qDebug() << "Finished" << mediaObject->state();
-        // if (mediaObject->state() == Phonon::StoppedState) startPlaying();
 #ifdef Q_WS_X11
-        MainWindow::instance()->getSeekSlider()->setEnabled(mediaObject->isSeekable());
+        // MainWindow::instance()->getSeekSlider()->setEnabled(mediaObject->isSeekable());
 #endif
         break;
     case Failed:
         // qDebug() << "Failed";
+        skip();
+        break;
     case Idle:
         // qDebug() << "Idle";
         break;
@@ -529,21 +494,29 @@ void MediaView::downloadStatusChanged() {
 }
 
 void MediaView::startPlaying() {
+    // qDebug() << __PRETTY_FUNCTION__;
     if (stopped) return;
     if (!downloadItem) {
         skip();
         return;
     }
 
+    if (downloadItem->offset() == 0) {
+        currentVideoSize = downloadItem->bytesTotal();
+        // qDebug() << "currentVideoSize" << currentVideoSize;
+    }
+
     // go!
     QString source = downloadItem->currentFilename();
-    // qDebug() << "Playing" << source;
+    qDebug() << "Playing" << source << QFile::exists(source);
     mediaObject->setCurrentSource(source);
     mediaObject->play();
 #ifdef Q_WS_X11
-    MainWindow::instance()->getSeekSlider()->setEnabled(false);
+    // MainWindow::instance()->getSeekSlider()->setEnabled(false);
 #endif
 
+    QSlider *slider = MainWindow::instance()->getSlider();
+    slider->setEnabled(true);
 }
 
 void MediaView::itemActivated(const QModelIndex &index) {
@@ -553,7 +526,8 @@ void MediaView::itemActivated(const QModelIndex &index) {
         Video *activeVideo = playlistModel->activeVideo();
         Video *video = playlistModel->videoAt(index.row());
         if (activeVideo && video && activeVideo == video) {
-            mediaObject->seek(0);
+            // mediaObject->seek(0);
+            sliderMoved(0);
             mediaObject->play();
         } else playlistModel->setActiveRow(index.row());
 
@@ -597,7 +571,6 @@ void MediaView::aboutToFinish() {
     qint64 totalTime = mediaObject->totalTime();
     qDebug() << __PRETTY_FUNCTION__ << currentTime << totalTime;
     if (totalTime < 1 || currentTime + 10000 < totalTime) {
-        // mediaObject->seek(mediaObject->currentTime());
         // QTimer::singleShot(500, this, SLOT(playbackResume()));
         mediaObject->seek(currentTime);
         mediaObject->play();
@@ -606,8 +579,8 @@ void MediaView::aboutToFinish() {
 
 void MediaView::playbackFinished() {
     if (stopped) return;
-    const int totalTime = mediaObject->totalTime();
-    const int currentTime = mediaObject->currentTime();
+    const qint64 totalTime = mediaObject->totalTime();
+    const qint64 currentTime = mediaObject->currentTime();
     qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime() << totalTime;
     // add 10 secs for imprecise Phonon backends (VLC, Xine)
     if (totalTime < 1 || (currentTime > 0 && currentTime + 10000 < totalTime)) {
@@ -623,8 +596,10 @@ void MediaView::playbackFinished() {
 
 void MediaView::playbackResume() {
     if (stopped) return;
-    qDebug() << __PRETTY_FUNCTION__ << mediaObject->currentTime();
-    mediaObject->seek(mediaObject->currentTime());
+    const qint64 currentTime = mediaObject->currentTime();
+    qDebug() << __PRETTY_FUNCTION__ << currentTime;
+    if (currentTime > 0)
+        mediaObject->seek(currentTime);
     mediaObject->play();
 }
 
@@ -653,6 +628,13 @@ void MediaView::copyVideoLink() {
     MainWindow::instance()->showMessage(message);
 }
 
+void MediaView::openInBrowser() {
+    Video* video = playlistModel->activeVideo();
+    if (!video) return;
+    mediaObject->pause();
+    QDesktopServices::openUrl(video->getStreamUrl());
+}
+
 void MediaView::removeSelected() {
     if (!playlistView->selectionModel()->hasSelection()) return;
     QModelIndexList indexes = playlistView->selectionModel()->selectedIndexes();
@@ -792,52 +774,59 @@ void MediaView::fullscreen() {
     videoAreaWidget->showFullScreen();
 }
 
-/*
-void MediaView::setSlider(QSlider *slider) {
-    this->slider = slider;
-    // slider->setEnabled(false);
-    slider->setTracking(false);
-    // connect(slider, SIGNAL(valueChanged(int)), SLOT(sliderMoved(int)));
+void MediaView::startDownloading() {
+    Video *video = playlistModel->activeVideo();
+    if (!video) return;
+    Video *videoCopy = video->clone();
+    if (downloadItem) {
+        downloadItem->stop();
+        delete downloadItem;
+    }
+    QString tempFile = Temporary::filename();
+    downloadItem = new DownloadItem(videoCopy, video->getStreamUrl(), tempFile, this);
+    connect(downloadItem, SIGNAL(statusChanged()),
+            SLOT(downloadStatusChanged()), Qt::UniqueConnection);
+    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)), Qt::UniqueConnection);
+    connect(downloadItem, SIGNAL(error(QString)),
+            SLOT(handleError(QString)), Qt::UniqueConnection);
+    downloadItem->start();
 }
 
 void MediaView::sliderMoved(int value) {
-    qDebug() << __func__;
-    int sliderPercent = (value * 100) / (slider->maximum() - slider->minimum());
-    qDebug() << slider->minimum() << value << slider->maximum();
-    if (sliderPercent <= downloadItem->currentPercent()) {
-        qDebug() << sliderPercent << downloadItem->currentPercent();
-        mediaObject->seek(value);
+    if (currentVideoSize <= 0 || !downloadItem || !mediaObject->isSeekable())
+        return;
+
+    QSlider *slider = MainWindow::instance()->getSlider();
+    if (slider->isSliderDown()) return;
+
+    qint64 offset = (currentVideoSize * value) / slider->maximum();
+
+    bool needsDownload = downloadItem->needsDownload(offset);
+    if (needsDownload) {
+        if (downloadItem->isBuffered(offset)) {
+            qint64 realOffset = downloadItem->blankAtOffset(offset);
+            if (offset < currentVideoSize)
+                downloadItem->seekTo(realOffset, false);
+            mediaObject->seek(offsetToTime(offset));
+        } else {
+            mediaObject->pause();
+            downloadItem->seekTo(offset);
+        }
     } else {
-        seekTo(value);
+        // qDebug() << "simple seek";
+        mediaObject->seek(offsetToTime(offset));
     }
 }
 
-void MediaView::seekTo(int value) {
-    qDebug() << __func__;
-    mediaObject->pause();
-    errorTimer->stop();
-    // mediaObject->clear();
-
-    QString tempDir = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
-    QString tempFile = tempDir + "/minitube" + QString::number(value) + ".mp4";
-    if (!QFile::remove(tempFile)) {
-        qDebug() << "Cannot remove temp file";
-    }
-    Video *videoCopy = downloadItem->getVideo()->clone();
-    QUrl streamUrl = videoCopy->getStreamUrl();
-    streamUrl.addQueryItem("begin", QString::number(value));
-    if (downloadItem) delete downloadItem;
-    downloadItem = new DownloadItem(videoCopy, streamUrl, tempFile, this);
-    connect(downloadItem, SIGNAL(statusChanged()), SLOT(downloadStatusChanged()));
-    // connect(downloadItem, SIGNAL(finished()), SLOT(itemFinished()));
-    downloadItem->start();
-
-    // slider->setMinimum(value);
-
+qint64 MediaView::offsetToTime(qint64 offset) {
+    const qint64 totalTime = mediaObject->totalTime();
+    return ((offset * totalTime) / currentVideoSize);
 }
 
-*/
-
 void MediaView::findVideoParts() {
 
     // parts
index 6259e1337552db6778eaa232de9ca725bf69949f..2bc3f29e3a3e380822ff59abe6320f93df84d46d 100644 (file)
@@ -72,6 +72,7 @@ public slots:
     void openWebPage();
     void copyWebPage();
     void copyVideoLink();
+    void openInBrowser();
     void shareViaTwitter();
     void shareViaFacebook();
     void shareViaBuffer();
@@ -114,12 +115,9 @@ private slots:
     void playbackResume();
     void authorPushed(QModelIndex);
     void searchAgain();
-
-    /*
-    void downloadProgress(int percent);
     void sliderMoved(int value);
-    void seekTo(int value);
-    */
+    qint64 offsetToTime(qint64 offset);
+    void startDownloading();
 
 private:
     MediaView(QWidget *parent = 0);
@@ -150,6 +148,8 @@ private:
     DownloadItem *downloadItem;
     QList<VideoSource*> history;
     QList<QAction*> currentVideoActions;
+
+    qint64 currentVideoSize;
 };
 
 #endif // __MEDIAVIEW_H__
index 96132c997b47c054b84297e03988cbe205cdf66c..ea8b557b9d339a82d7582d6bd43bb72f419b1066 100644 (file)
@@ -32,7 +32,7 @@ const QString USER_AGENT = QString(Constants::NAME)
                            + " (" + Constants::WEBSITE + ")";
 */
 
-const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36";
+const QString USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.65 Safari/537.36";
 
 NetworkReply::NetworkReply(QNetworkReply *networkReply) :
     QObject(networkReply),
@@ -141,11 +141,14 @@ QNetworkRequest NetworkAccess::buildRequest(QUrl url) {
     return request;
 }
 
-QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body) {
+QNetworkReply* NetworkAccess::request(QUrl url, int operation, const QByteArray& body, uint offset) {
     QNetworkAccessManager *manager = The::networkAccessManager();
 
     QNetworkRequest request = buildRequest(url);
 
+    if (offset > 0)
+        request.setRawHeader("Range", QString("bytes=%1-").arg(offset).toUtf8());
+
     QNetworkReply *networkReply;
     switch (operation) {
 
index d01f491ae30392178c824396085f79b4f2c77dc0..770818651bf4295e8de1dbfd45bc53e0391e2f76 100644 (file)
@@ -63,7 +63,7 @@ public:
     NetworkAccess(QObject* parent = 0);
     QNetworkReply* request(QUrl url,
                              int operation = QNetworkAccessManager::GetOperation,
-                             const QByteArray &body = QByteArray());
+                             const QByteArray &body = QByteArray(), uint offset = 0);
     NetworkReply* get(QUrl url);
     NetworkReply* head(QUrl url);
     NetworkReply* post(QUrl url, const QMap<QString, QString>& params);
diff --git a/src/seekslider.cpp b/src/seekslider.cpp
new file mode 100644 (file)
index 0000000..281673f
--- /dev/null
@@ -0,0 +1,15 @@
+#include "seekslider.h"
+
+class MyProxyStyle : public QProxyStyle {
+public:
+    int styleHint(StyleHint hint, const QStyleOption *option = 0,
+                  const QWidget *widget = 0, QStyleHintReturn *returnData = 0) const {
+        if (hint == SH_Slider_AbsoluteSetButtons)
+                return Qt::LeftButton;
+        return QProxyStyle::styleHint(hint, option, widget, returnData);
+    }
+};
+
+SeekSlider::SeekSlider(QWidget *parent) : QSlider(parent) {
+    setStyle(new MyProxyStyle());
+}
diff --git a/src/seekslider.h b/src/seekslider.h
new file mode 100644 (file)
index 0000000..87e6cb9
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef SEEKSLIDER_H
+#define SEEKSLIDER_H
+
+#include <QtGui>
+
+class SeekSlider : public QSlider {
+
+    Q_OBJECT
+
+public:
+    SeekSlider(QWidget *parent = 0);
+    
+};
+
+#endif // SEEKSLIDER_H