]> git.sur5r.net Git - minitube/commitdiff
Support for 1080p videos
authorFlavio Tordini <flavio.tordini@gmail.com>
Tue, 20 Apr 2010 14:10:17 +0000 (16:10 +0200)
committerFlavio Tordini <flavio.tordini@gmail.com>
Tue, 20 Apr 2010 14:10:17 +0000 (16:10 +0200)
minitube.pro
src/MainWindow.cpp
src/MainWindow.h
src/video.cpp
src/video.h
src/videodefinition.cpp [new file with mode: 0644]
src/videodefinition.h [new file with mode: 0644]

index 1568135882f95b29e79fb7e1cbe18ef5a526b730..09f3649fcbd319e4158f2848e44084fd519de98f 100755 (executable)
@@ -41,7 +41,8 @@ HEADERS += src/MainWindow.h \
     src/videoareawidget.h \
     src/googlesuggest.h \
     src/videowidget.h \
-    src/flickcharm.h
+    src/flickcharm.h \
+    src/videodefinition.h
 SOURCES += src/main.cpp \
     src/MainWindow.cpp \
     src/SearchView.cpp \
@@ -67,7 +68,8 @@ SOURCES += src/main.cpp \
     src/videoareawidget.cpp \
     src/googlesuggest.cpp \
     src/videowidget.cpp \
-    src/flickcharm.cpp
+    src/flickcharm.cpp \
+    src/videodefinition.cpp
 RESOURCES += resources.qrc
 DESTDIR = build/target/
 OBJECTS_DIR = build/obj/
index 897f1da669ecb56d35486591c1085443316ddee2..31398c4abdbd379bd91faa0c6b8c93be94270390 100755 (executable)
@@ -3,13 +3,13 @@
 #include "Constants.h"
 #include "iconloader/qticonloader.h"
 #include "global.h"
+#include "videodefinition.h"
 
 MainWindow::MainWindow() :
         mediaObject(0),
         audioOutput(0),
-        aboutView(0) {
-
-    m_fullscreen = false;
+        aboutView(0),
+        m_fullscreen(false) {
 
     // views mechanism
     history = new QStack<QWidget*>();
@@ -178,7 +178,7 @@ void MainWindow::createActions() {
     actions->insert("site", siteAct);
     connect(siteAct, SIGNAL(triggered()), this, SLOT(visitSite()));
 
-    donateAct = new QAction(tr("&Donate"), this);
+    donateAct = new QAction(tr("Make a &donation"), this);
     donateAct->setStatusTip(tr("Please support the continued development of %1").arg(Constants::APP_NAME));
     actions->insert("donate", donateAct);
     connect(donateAct, SIGNAL(triggered()), this, SLOT(donate()));
@@ -217,13 +217,18 @@ void MainWindow::createActions() {
     connect(volumeMuteAct, SIGNAL(triggered()), this, SLOT(volumeMute()));
     addAction(volumeMuteAct);
 
-    QAction *hdAct = new QAction(this);
-    hdAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
-    hdAct->setIcon(createHDIcon());
-    hdAct->setCheckable(true);
-    actions->insert("hd", hdAct);
-    connect(hdAct, SIGNAL(toggled(bool)), this, SLOT(hdMode(bool)));
-    addAction(hdAct);
+    QAction *definitionAct = new QAction(this);
+    definitionAct->setShortcuts(QList<QKeySequence>() << QKeySequence(Qt::CTRL + Qt::Key_D));
+    /*
+    QMenu *definitionMenu = new QMenu(this);
+    foreach (QString definition, VideoDefinition::getDefinitionNames()) {
+        definitionMenu->addAction(definition);
+    }
+    definitionAct->setMenu(definitionMenu);
+    */
+    actions->insert("definition", definitionAct);
+    connect(definitionAct, SIGNAL(triggered()), SLOT(toggleDefinitionMode()));
+    addAction(definitionAct);
 
     // common action properties
     foreach (QAction *action, actions->values()) {
@@ -346,24 +351,20 @@ void MainWindow::createToolBars() {
 }
 
 void MainWindow::createStatusBar() {
+
+    // remove ugly borders on OSX
+    // also remove excessive spacing
+    statusBar()->setStyleSheet("::item{border:0 solid} QToolBar {padding:0;spacing:0;margin:0}");
+
     currentTime = new QLabel(this);
     statusBar()->addPermanentWidget(currentTime);
 
     totalTime = new QLabel(this);
     statusBar()->addPermanentWidget(totalTime);
 
-    // remove ugly borders on OSX
-    // and remove some excessive padding
-    statusBar()->setStyleSheet("::item{border:0 solid} "
-                               "QStatusBar, QToolBar, QToolButton {spacing:0;padding:0;margin:0} "
-                               );
-
     QToolBar *toolBar = new QToolBar(this);
-    int iconHeight = 24; // statusBar()->height();
-    int iconWidth = 36; // iconHeight * 3 / 2;
-    toolBar->setIconSize(QSize(iconWidth, iconHeight));
-    toolBar->setToolButtonStyle(Qt::ToolButtonIconOnly);
-    toolBar->addAction(The::globalActions()->value("hd"));
+    toolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
+    toolBar->addAction(The::globalActions()->value("definition"));
     statusBar()->addPermanentWidget(toolBar);
 
     statusBar()->show();
@@ -372,7 +373,7 @@ void MainWindow::createStatusBar() {
 void MainWindow::readSettings() {
     QSettings settings;
     restoreGeometry(settings.value("geometry").toByteArray());
-    hdMode(settings.value("hd").toBool());
+    setDefinitionMode(settings.value("definition", VideoDefinition::getDefinitionNames().first()).toString());
     audioOutput->setVolume(settings.value("volume", 1).toDouble());
     audioOutput->setMuted(settings.value("volumeMute").toBool());
 }
@@ -383,7 +384,6 @@ void MainWindow::writeSettings() {
         return;
     QSettings settings;
     settings.setValue("geometry", saveGeometry());
-    settings.setValue("hd", The::globalActions()->value("hd")->isChecked());
     settings.setValue("volume", audioOutput->volume());
     settings.setValue("volumeMute", audioOutput->isMuted());
     mediaView->saveSplitterState();
@@ -754,76 +754,27 @@ void MainWindow::volumeMutedChanged(bool muted) {
         statusBar()->showMessage(tr("Volume is unmuted"));
 }
 
-QPixmap MainWindow::createHDPixmap(bool enabled) {
-    QPixmap pixmap = QPixmap(24,24);
-    pixmap.fill(Qt::transparent);
-    QPainter painter(&pixmap);
-    painter.setRenderHints(QPainter::Antialiasing, true);
-
-    QRect rect(0, 3, 24, 18);
-
-    QPen pen;
-    pen.setColor(Qt::black);
-    pen.setWidth(1);
-    painter.setPen(pen);
-
-    if (enabled) {
-        painter.setBrush(palette().highlight());
-    } else {
-        QLinearGradient gradient(QPointF(0, 0), QPointF(0, rect.height() / 2));
-        gradient.setColorAt(0, QColor(0x6d, 0x6d, 0x6d));
-        gradient.setColorAt(1, QColor(0x25, 0x25, 0x25));
-        painter.setBrush(QBrush(gradient));
-    }
-    painter.drawRoundedRect(rect, 5, 5);
-
-    if (enabled) {
-        pen.setColor(palette().highlightedText().color());
-    } else {
-        pen.setColor(Qt::white);
-    }
-    painter.setPen(pen);
-
-    QFont font;
-    font.setPixelSize(12);
-    font.setBold(true);
-    painter.setFont(font);
-    painter.drawText(rect, Qt::AlignCenter, "HD");
-
-    return pixmap;
-}
-
-static QIcon hdOnIcon;
-static QIcon hdOffIcon;
-
-QIcon MainWindow::createHDIcon() {
-    hdOffIcon.addPixmap(createHDPixmap(false));
-    hdOnIcon.addPixmap(createHDPixmap(true));
-    return hdOffIcon;
-}
-
-void MainWindow::hdMode(bool enabled) {
-    QAction *hdAct = The::globalActions()->value("hd");
-    hdAct->setChecked(enabled);
-    if (enabled) {
-        hdAct->setStatusTip(tr("High Definition video is enabled") + " (" +  hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
-    } else {
-        hdAct->setStatusTip(tr("High Definition video is not enabled") + " (" +  hdAct->shortcut().toString(QKeySequence::NativeText) + ")");
-    }
-    statusBar()->showMessage(hdAct->statusTip());
+void MainWindow::setDefinitionMode(QString definitionName) {
+    QAction *definitionAct = The::globalActions()->value("definition");
+    definitionAct->setText(definitionName);
+    definitionAct->setStatusTip(tr("Maximum video definition set to %1").arg(definitionAct->text())
+                                + " (" +  definitionAct->shortcut().toString(QKeySequence::NativeText) + ")");
+    statusBar()->showMessage(definitionAct->statusTip());
     QSettings settings;
-    settings.setValue("hd", enabled);
+    settings.setValue("definition", definitionName);
 }
 
-void MainWindow::hdIndicator(bool isHd) {
-    QAction *hdAct = The::globalActions()->value("hd");
-    if (isHd) {
-        hdAct->setIcon(hdOnIcon);
-        hdAct->setToolTip(tr("The current video is in High Definition"));
-    } else {
-        hdAct->setIcon(hdOffIcon);
-        hdAct->setToolTip(tr("The current video is not in High Definition"));
+void MainWindow::toggleDefinitionMode() {
+    QSettings settings;
+    QString currentDefinition = settings.value("definition").toString();
+    QStringList definitionNames = VideoDefinition::getDefinitionNames();
+    int currentIndex = definitionNames.indexOf(currentDefinition);
+    int nextIndex = 0;
+    if (currentIndex != definitionNames.size() - 1) {
+        nextIndex = currentIndex + 1;
     }
+    QString nextDefinition = definitionNames.at(nextIndex);
+    setDefinitionMode(nextDefinition);
 }
 
 void MainWindow::showFullscreenToolbar(bool show) {
index bdb13967e3abaa63c698dab6b2875b79ad71423c..1eb025102b174e359ce5c560b1a3c50b5e2a1f21 100755 (executable)
@@ -21,9 +21,6 @@ public:
     MainWindow();
     ~MainWindow();
 
-public slots:
-    void hdIndicator(bool isHd);
-
 protected:
     void closeEvent(QCloseEvent *);
     bool eventFilter(QObject *obj, QEvent *event);
@@ -44,7 +41,8 @@ private slots:
     void searchFocus();
     void tick(qint64 time);
     void totalTimeChanged(qint64 time);
-    void hdMode(bool enabled);
+    void setDefinitionMode(QString definitionName);
+    void toggleDefinitionMode();
     void clearRecentKeywords();
 
     // volume shortcuts
@@ -67,8 +65,6 @@ private:
     void readSettings();
     void writeSettings();
     void showWidget(QWidget*);
-    QPixmap createHDPixmap(bool enabled);
-    QIcon createHDIcon();
     static QString formatTime(qint64 time);
 
     // view mechanism
index bb863749318ecd4eda41e0c959d5bdad52a21a62..635c95c07cb85d5119ba06047acf45b22f1b2303 100644 (file)
@@ -1,6 +1,7 @@
 #include "video.h"
 #include "networkaccess.h"
 #include <QtNetwork>
+#include "videodefinition.h"
 
 namespace The {
     NetworkAccess* http();
@@ -8,7 +9,7 @@ namespace The {
 
 Video::Video() : m_duration(0),
 m_viewCount(-1),
-m_hd(false),
+definitionCode(0),
 elIndex(0) { }
 
 void Video::preloadThumbnail() {
@@ -26,33 +27,22 @@ const QImage Video::thumbnail() const {
     return m_thumbnail;
 }
 
-void Video::loadStreamUrl() {
-    // if (m_streamUrl.isEmpty())
-        this->scrapeStreamUrl();
-    // else emit gotStreamUrl(m_streamUrl);
-}
-
 static const QStringList elTypes = QStringList() << "embedded" << "vevo" << "detailpage";
 
-void Video::scrapeStreamUrl() {
+void Video::loadStreamUrl() {
 
     // https://develop.participatoryculture.org/trac/democracy/browser/trunk/tv/portable/flashscraper.py
 
-    QUrl webpage = m_webpage;
-    // qDebug() << webpage.toString();
-
     // Get Video ID
     // youtube-dl line 428
     // QRegExp re("^((?:http://)?(?:\\w+\\.)?youtube\\.com/(?:(?:v/)|(?:(?:watch(?:\\.php)?)?\\?(?:.+&)?v=)))?([0-9A-Za-z_-]+)(?(1).+)?$");
     QRegExp re("^http://www\\.youtube\\.com/watch\\?v=([0-9A-Za-z_-]+).*");
-    bool match = re.exactMatch(webpage.toString());
+    bool match = re.exactMatch(m_webpage.toString());
     if (!match || re.numCaptures() < 1) {
-        emit errorStreamUrl(QString("Cannot get video id for %1").arg(webpage.toString()));
+        emit errorStreamUrl(QString("Cannot get video id for %1").arg(m_webpage.toString()));
         return;
     }
     videoId = re.cap(1);
-    // if (!videoId) return false;
-    // qDebug() << videoId;
 
     getVideoInfo();
 
@@ -64,7 +54,7 @@ void  Video::getVideoInfo() {
         // Don't panic! We have a plan B.
         // get the youtube video webpage
         QObject *reply = The::http()->get(webpage().toString());
-        connect(reply, SIGNAL(data(QByteArray)), SLOT(scrapWebPage(QByteArray)));
+        connect(reply, SIGNAL(data(QByteArray)), SLOT(scrapeWebPage(QByteArray)));
         connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(errorVideoInfo(QNetworkReply*)));
         // see you in scrapWebPage(QByteArray)
         return;
@@ -100,33 +90,30 @@ void  Video::gotVideoInfo(QByteArray data) {
     QString videoToken = re.cap(1);
     // FIXME proper decode
     videoToken = videoToken.replace("%3D", "=");
+    // we'll need this in gotHeadHeaders()
+    this->videoToken = videoToken;
+
     // qDebug() << "token" << videoToken;
 
     QSettings settings;
-    if (settings.value("hd").toBool())
-        findHdVideo(videoToken);
-    else
-        standardVideoUrl(videoToken);
+    QString definitionName = settings.value("definition").toString();
+    int definitionCode = VideoDefinition::getDefinitionCode(definitionName);
+    if (definitionCode == 18) {
+        // This is assumed always available
+        foundVideoUrl(videoToken, 18);
+    } else {
+        findVideoUrl(definitionCode);
+    }
 
 }
 
-void Video::standardVideoUrl(QString videoToken) {
-    QUrl videoUrl = QUrl(QString("http://www.youtube.com/get_video?video_id=")
-                         .append(videoId)
-                         .append("&t=").append(videoToken)
-                         .append("&eurl=&el=embedded&ps=default&fmt=18"));
-    m_streamUrl = videoUrl;
-    m_hd = false;
-    emit gotStreamUrl(videoUrl);
-}
+void Video::foundVideoUrl(QString videoToken, int definitionCode) {
+
+    QUrl videoUrl = QUrl(QString(
+            "http://www.youtube.com/get_video?video_id=%1&t=%2&eurl=&el=embedded&ps=default&fmt=%3"
+            ).arg(videoId, videoToken, QString::number(definitionCode)));
 
-void Video::hdVideoUrl(QString videoToken) {
-    QUrl videoUrl = QUrl(QString("http://www.youtube.com/get_video?video_id=")
-                         .append(videoId)
-                         .append("&t=").append(videoToken)
-                         .append("&eurl=&el=embedded&ps=default&fmt=22"));
     m_streamUrl = videoUrl;
-    m_hd = true;
     emit gotStreamUrl(videoUrl);
 }
 
@@ -134,7 +121,7 @@ void Video::errorVideoInfo(QNetworkReply *reply) {
     emit errorStreamUrl(tr("Network error: %1 for %2").arg(reply->errorString(), reply->url().toString()));
 }
 
-void Video::scrapWebPage(QByteArray data) {
+void Video::scrapeWebPage(QByteArray data) {
 
     QString videoHTML = QString::fromUtf8(data);
     QRegExp re(".*, \"t\": \"([^\"]+)\".*");
@@ -149,40 +136,78 @@ void Video::scrapWebPage(QByteArray data) {
     QString videoToken = re.cap(1);
     // FIXME proper decode
     videoToken = videoToken.replace("%3D", "=");
+
+    // we'll need this in gotHeadHeaders()
+    this->videoToken = videoToken;
+
     // qDebug() << "token" << videoToken;
 
     QSettings settings;
-    if (settings.value("hd").toBool())
-        findHdVideo(videoToken);
-    else
-        standardVideoUrl(videoToken);
+    QString definitionName = settings.value("definition").toString();
+    int definitionCode = VideoDefinition::getDefinitionCode(definitionName);
+    if (definitionCode == 18) {
+        // This is assumed always available
+        foundVideoUrl(videoToken, 18);
+    } else {
+        findVideoUrl(definitionCode);
+    }
 
 }
 
-void Video::findHdVideo(QString videoToken) {
+void Video::gotHeadHeaders(QNetworkReply* reply) {
+    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
+    // qDebug() << "gotHeaders" << statusCode;
+    if (statusCode == 200) {
+        foundVideoUrl(videoToken, definitionCode);
+    } else {
+
+        // try next (lower quality) definition
+        /*
+        QStringList definitionNames = VideoDefinition::getDefinitionNames();
+        int currentIndex = definitionNames.indexOf(currentDefinition);
+        int previousIndex = 0;
+        if (currentIndex > 0) {
+            previousIndex = currentIndex - 1;
+        }
+        if (previousIndex > 0) {
+            QString nextDefinitionName = definitionNames.at(previousIndex);
+            findVideoUrl(nextDefinitionName);
+        } else {
+            foundVideoUrl(videoToken, 18);
+        }*/
+
+
+        QList<int> definitionCodes = VideoDefinition::getDefinitionCodes();
+        int currentIndex = definitionCodes.indexOf(definitionCode);
+        int previousIndex = 0;
+        if (currentIndex > 0) {
+            previousIndex = currentIndex - 1;
+            int definitionCode = definitionCodes.at(previousIndex);
+            if (definitionCode == 18) {
+                // This is assumed always available
+                foundVideoUrl(videoToken, 18);
+            } else {
+                findVideoUrl(definitionCode);
+            }
+
+        } else {
+            foundVideoUrl(videoToken, 18);
+        }
 
-    // we'll need this in gotHeaders()
-    this->videoToken = videoToken;
+    }
+}
+
+void Video::findVideoUrl(int definitionCode) {
+    this->definitionCode = definitionCode;
 
-    // try HD: fmt=22
-    QUrl videoUrl = QUrl(QString("http://www.youtube.com/get_video?video_id=")
-                         .append(videoId)
-                         .append("&t=").append(videoToken)
-                         .append("&eurl=&el=embedded&ps=default&fmt=22"));
+    QUrl videoUrl = QUrl(QString(
+            "http://www.youtube.com/get_video?video_id=%1&t=%2&eurl=&el=embedded&ps=default&fmt=%3"
+            ).arg(videoId, videoToken, QString::number(definitionCode)));
 
     QObject *reply = The::http()->head(videoUrl);
-    connect(reply, SIGNAL(finished(QNetworkReply*)), SLOT(gotHdHeaders(QNetworkReply*)));
+    connect(reply, SIGNAL(finished(QNetworkReply*)), SLOT(gotHeadHeaders(QNetworkReply*)));
     // connect(reply, SIGNAL(error(QNetworkReply*)), SLOT(errorVideoInfo(QNetworkReply*)));
 
-    // see you in gotHeaders()
-}
+    // see you in gotHeadHeaders()
 
-void Video::gotHdHeaders(QNetworkReply* reply) {
-    int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
-    // qDebug() << "gotHeaders" << statusCode;
-    if (statusCode == 200) {
-        hdVideoUrl(videoToken);
-    } else {
-        standardVideoUrl(videoToken);
-    }
 }
index 5f3aa4696c74d763208464c2cb8699a5272b55b2..2702d7ae3f814e1e7635a4cdfbf1fbd3e2bf21be 100644 (file)
@@ -40,7 +40,7 @@ public:
     const QDateTime published() const { return m_published; }
     void setPublished( QDateTime published ) { m_published = published; }
 
-    bool isHd() const { return m_hd; }
+    bool getDefinitionCode() const { return definitionCode; }
 
     void loadStreamUrl();
     QUrl getStreamUrl() { return m_streamUrl; }
@@ -56,25 +56,21 @@ signals:
 private slots:
     void gotVideoInfo(QByteArray);
     void errorVideoInfo(QNetworkReply*);
-    void scrapWebPage(QByteArray);
-    void gotHdHeaders(QNetworkReply*);
+    void scrapeWebPage(QByteArray);
+    void gotHeadHeaders(QNetworkReply*);
 
 private:
-    void scrapeStreamUrl();
     void getVideoInfo();
-    void findHdVideo(QString videoToken);
-    void standardVideoUrl(QString videoToken);
-    void hdVideoUrl(QString videoToken);
+    void findVideoUrl(int definitionCode);
+    void foundVideoUrl(QString videoToken, int definitionCode);
 
     QString m_title;
     QString m_description;
     QString m_author;
-    // QUrl m_authorUrl;
     QUrl m_webpage;
     QUrl m_streamUrl;
     QImage m_thumbnail;
     QList<QUrl> m_thumbnailUrls;
-    // QList<QImage> m_thumbnails;
     int m_duration;
     QDateTime m_published;
     int m_viewCount;
@@ -84,7 +80,7 @@ private:
     QString videoId;
 
     QString videoToken;
-    int m_hd;
+    int definitionCode;
 
     // current index for the elTypes list
     // needed to iterate on elTypes
diff --git a/src/videodefinition.cpp b/src/videodefinition.cpp
new file mode 100644 (file)
index 0000000..c2180e2
--- /dev/null
@@ -0,0 +1,25 @@
+#include "videodefinition.h"
+
+QStringList VideoDefinition::getDefinitionNames() {
+    static QStringList definitionNames = QStringList() << "360p" << "720p" << "1080p";
+    return definitionNames;
+}
+
+QList<int> VideoDefinition::getDefinitionCodes() {
+    static QList<int> definitionCodes = QList<int>() << 18 << 22 << 37;
+    return definitionCodes;
+}
+
+QHash<QString, int> VideoDefinition::getDefinitions() {
+    static QHash<QString, int> definitions;
+    if (definitions.isEmpty()) {
+        definitions.insert("360p", 18);
+        definitions.insert("720p", 22);
+        definitions.insert("1080p", 37);
+    }
+    return definitions;
+}
+
+int VideoDefinition::getDefinitionCode(QString name) {
+    return VideoDefinition::getDefinitions().value(name);
+}
diff --git a/src/videodefinition.h b/src/videodefinition.h
new file mode 100644 (file)
index 0000000..8e2e4c0
--- /dev/null
@@ -0,0 +1,16 @@
+#ifndef VIDEODEFINITION_H
+#define VIDEODEFINITION_H
+
+#include <QtCore>
+
+class VideoDefinition {
+
+public:
+    static QStringList getDefinitionNames();
+    static QList<int> getDefinitionCodes();
+    static QHash<QString, int> getDefinitions();
+    static int getDefinitionCode(QString name);
+
+};
+
+#endif // VIDEODEFINITION_H