]> git.sur5r.net Git - minitube/commitdiff
Channels!
authorFlavio <flavio@odisseo.local>
Wed, 26 Jan 2011 00:09:30 +0000 (01:09 +0100)
committerFlavio <flavio@odisseo.local>
Wed, 26 Jan 2011 00:09:30 +0000 (01:09 +0100)
minitube.pro
src/ListModel.cpp
src/MainWindow.cpp
src/MainWindow.h
src/SearchView.cpp
src/SearchView.h
src/autocomplete.cpp
src/autocomplete.h
src/searchlineedit.cpp
src/searchlineedit.h

index 94ac55ed328ed6fa11a182e08b3983eb3abe5242..f78cd09ae56f7d236d67a63dedb7e091e389b4bd 100644 (file)
@@ -1,6 +1,6 @@
 CONFIG += release
 TEMPLATE = app
-VERSION = 1.3
+VERSION = 1.4
 DEFINES += APP_VERSION="$$VERSION"
 INCLUDEPATH += /usr/include/phonon
 
@@ -36,7 +36,7 @@ HEADERS += src/MainWindow.h \
     src/minisplitter.h \
     src/loadingwidget.h \
     src/videoareawidget.h \
-    src/googlesuggest.h \
+    src/autocomplete.h \
     src/videowidget.h \
     src/videodefinition.h \
     src/fontutils.h \
@@ -48,7 +48,10 @@ HEADERS += src/MainWindow.h \
     src/downloadview.h \
     src/downloadmodel.h \
     src/downloadlistview.h \
-    src/downloadsettings.h
+    src/downloadsettings.h \
+    src/youtubesuggest.h \
+    src/suggester.h \
+    src/channelsuggest.h
 SOURCES += src/main.cpp \
     src/MainWindow.cpp \
     src/SearchView.cpp \
@@ -72,7 +75,7 @@ SOURCES += src/main.cpp \
     src/minisplitter.cpp \
     src/loadingwidget.cpp \
     src/videoareawidget.cpp \
-    src/googlesuggest.cpp \
+    src/autocomplete.cpp \
     src/videowidget.cpp \
     src/videodefinition.cpp \
     src/constants.cpp \
@@ -85,7 +88,9 @@ SOURCES += src/main.cpp \
     src/downloadview.cpp \
     src/downloadmodel.cpp \
     src/downloadlistview.cpp \
-    src/downloadsettings.cpp
+    src/downloadsettings.cpp \
+    src/youtubesuggest.cpp \
+    src/channelsuggest.cpp
 RESOURCES += resources.qrc
 DESTDIR = build/target/
 OBJECTS_DIR = build/obj/
index 1c146eec728e1fbf0eedf47397f0c167c3586b78..8fff12afe82c583028a0b61cd0c1663a6d4c9861 100644 (file)
@@ -3,6 +3,7 @@
 
 #define MAX_ITEMS 10
 static const QString recentKeywordsKey = "recentKeywords";
+static const QString recentChannelsKey = "recentChannels";
 
 ListModel::ListModel(QWidget *parent) : QAbstractListModel(parent) {
     youtubeSearch = 0;
@@ -202,17 +203,32 @@ void ListModel::addVideo(Video* video) {
 
         // save keyword
         QString query = searchParams->keywords();
-        if (query.startsWith("http://")) {
-            // Save the video title
-            query += "|" + videos.first()->title();
+        if (!query.isEmpty()) {
+            if (query.startsWith("http://")) {
+                // Save the video title
+                query += "|" + videos.first()->title();
+            }
+            QSettings settings;
+            QStringList keywords = settings.value(recentKeywordsKey).toStringList();
+            keywords.removeAll(query);
+            keywords.prepend(query);
+            while (keywords.size() > 10)
+                keywords.removeLast();
+            settings.setValue(recentKeywordsKey, keywords);
         }
-        QSettings settings;
-        QStringList keywords = settings.value(recentKeywordsKey).toStringList();
-        keywords.removeAll(query);
-        keywords.prepend(query);
-        while (keywords.size() > 10)
-            keywords.removeLast();
-        settings.setValue(recentKeywordsKey, keywords);
+
+        // save channel
+        QString channel = searchParams->author();
+        if (!channel.isEmpty()) {
+            QSettings settings;
+            QStringList channels = settings.value(recentChannelsKey).toStringList();
+            channels.removeAll(channel);
+            channels.prepend(channel);
+            while (channels.size() > 10)
+                channels.removeLast();
+            settings.setValue(recentChannelsKey, channels);
+        }
+
     }
 
 }
index d52cbfddf1e192f4c5bce616c6b0b177f624c7c5..b405a82b90cdd0fc8511e8652f2849eda303135d 100644 (file)
@@ -13,6 +13,7 @@
 // #include "local/mac/mac_startup.h"
 #endif
 #include "downloadmanager.h"
+#include "youtubesuggest.h"
 
 MainWindow::MainWindow() :
         aboutView(0),
@@ -28,7 +29,7 @@ MainWindow::MainWindow() :
 
     // views
     searchView = new SearchView(this);
-    connect(searchView, SIGNAL(search(QString)), this, SLOT(showMedia(QString)));
+    connect(searchView, SIGNAL(search(SearchParams*)), this, SLOT(showMedia(SearchParams*)));
     views->addWidget(searchView);
 
     mediaView = new MediaView(this);
@@ -36,7 +37,8 @@ MainWindow::MainWindow() :
 
     toolbarSearch = new SearchLineEdit(this);
     toolbarSearch->setMinimumWidth(toolbarSearch->fontInfo().pixelSize()*15);
-    connect(toolbarSearch, SIGNAL(search(const QString&)), searchView, SLOT(watch(const QString&)));
+    toolbarSearch->setSuggester(new YouTubeSuggest(this));
+    connect(toolbarSearch, SIGNAL(search(const QString&)), this, SLOT(startToolbarSearch(const QString&)));
 
     // build ui
     createActions();
@@ -620,9 +622,7 @@ void MainWindow::showSearch() {
     totalTime->clear();
 }
 
-void MainWindow::showMedia(QString query) {
-    SearchParams *searchParams = new SearchParams();
-    searchParams->setKeywords(query);
+void MainWindow::showMedia(SearchParams *searchParams) {
     mediaView->search(searchParams);
     showWidget(mediaView);
 }
@@ -981,3 +981,19 @@ void MainWindow::toggleDownloads(bool show) {
     if (show) showWidget(downloadView);
     else goBack();
 }
+
+void MainWindow::startToolbarSearch(QString query) {
+
+    query = query.trimmed();
+
+    // check for empty query
+    if (query.length() == 0) {
+        return;
+    }
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setKeywords(query);
+
+    // go!
+    showMedia(searchParams);
+}
index 203a2144523248eaa45ddeee8410db72db3baf6c..5034df8afb8dc1c18e249ddece89e6b26f054ccd 100644 (file)
@@ -31,7 +31,7 @@ private slots:
     void fadeInWidget(QWidget *oldWidget, QWidget *newWidget);
     void goBack();
     void showSearch();
-    void showMedia(QString query);
+    void showMedia(SearchParams *params);
     void visitSite();
     void donate();
     void about();
@@ -63,6 +63,8 @@ private slots:
     void downloadsFinished();
     void toggleDownloads(bool show);
 
+    void startToolbarSearch(QString query);
+
 private:
     void initPhonon();
     void createActions();
index 0e6deb3aed0c4643741e1b6c8e75129cda240e03..ce1cd8582a9523e8e9407fb8defdc46d63732bd1 100644 (file)
@@ -1,12 +1,16 @@
 #include "SearchView.h"
 #include "constants.h"
 #include "fontutils.h"
+#include "searchparams.h"
+#include "youtubesuggest.h"
+#include "channelsuggest.h"
 
 namespace The {
     QMap<QString, QAction*>* globalActions();
 }
 
 static const QString recentKeywordsKey = "recentKeywords";
+static const QString recentChannelsKey = "recentChannels";
 static const int PADDING = 30;
 
 SearchView::SearchView(QWidget *parent) : QWidget(parent) {
@@ -77,9 +81,24 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
 
     layout->addSpacing(PADDING / 2);
 
-    QLabel *tipLabel = new QLabel(tr("Enter a keyword to start watching videos."), this);
+    QBoxLayout *tipLayout = new QHBoxLayout();
+    tipLayout->setSpacing(10);
+
+    QLabel *tipLabel = new QLabel(tr("Enter"), this);
+    tipLabel->setFont(biggerFont);
+    tipLayout->addWidget(tipLabel);
+
+    typeCombo = new QComboBox(this);
+    typeCombo->addItem(tr("a keyword"));
+    typeCombo->addItem(tr("a channel"));
+    typeCombo->setFont(biggerFont);
+    connect(typeCombo, SIGNAL(currentIndexChanged(int)), SLOT(searchTypeChanged(int)));
+    tipLayout->addWidget(typeCombo);
+
+    tipLabel = new QLabel(tr("to start watching videos."), this);
     tipLabel->setFont(biggerFont);
-    layout->addWidget(tipLabel);
+    tipLayout->addWidget(tipLabel);
+    layout->addLayout(tipLayout);
 
     layout->addSpacing(PADDING / 2);
 
@@ -93,8 +112,12 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
     queryEdit->setFocus(Qt::OtherFocusReason);
     connect(queryEdit, SIGNAL(search(const QString&)), this, SLOT(watch(const QString&)));
     connect(queryEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));
-    searchLayout->addWidget(queryEdit);
 
+    youtubeSuggest = new YouTubeSuggest(this);
+    channelSuggest = new ChannelSuggest(this);
+    searchTypeChanged(0);
+
+    searchLayout->addWidget(queryEdit);
     searchLayout->addSpacing(10);
 
     watchButton = new QPushButton(tr("Watch"), this);
@@ -113,7 +136,7 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
 
     recentKeywordsLayout = new QVBoxLayout();
     recentKeywordsLayout->setSpacing(5);
-    recentKeywordsLayout->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
+    recentKeywordsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
     recentKeywordsLabel = new QLabel(tr("Recent keywords").toUpper(), this);
 #if defined(APP_MAC) | defined(APP_WIN)
     QPalette palette = recentKeywordsLabel->palette();
@@ -128,6 +151,24 @@ SearchView::SearchView(QWidget *parent) : QWidget(parent) {
 
     otherLayout->addLayout(recentKeywordsLayout);
 
+    // recent channels
+    recentChannelsLayout = new QVBoxLayout();
+    recentChannelsLayout->setSpacing(5);
+    recentChannelsLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
+    recentChannelsLabel = new QLabel(tr("Recent channels").toUpper(), this);
+#if defined(APP_MAC) | defined(APP_WIN)
+    palette = recentChannelsLabel->palette();
+    palette.setColor(QPalette::WindowText, QColor(0x65, 0x71, 0x80));
+    recentChannelsLabel->setPalette(palette);
+#else
+    recentChannelsLabel->setForegroundRole(QPalette::Dark);
+#endif
+    recentChannelsLabel->hide();
+    recentChannelsLabel->setFont(smallerFont);
+    recentChannelsLayout->addWidget(recentChannelsLabel);
+
+    otherLayout->addLayout(recentChannelsLayout);
+
     layout->addLayout(otherLayout);
 
     mainLayout->addSpacing(PADDING);
@@ -179,10 +220,48 @@ void SearchView::updateRecentKeywords() {
 
 }
 
+void SearchView::updateRecentChannels() {
+
+    // cleanup
+    QLayoutItem *item;
+    while ((item = recentChannelsLayout->takeAt(1)) != 0) {
+        item->widget()->close();
+        delete item;
+    }
 
+    // load
+    QSettings settings;
+    QStringList keywords = settings.value(recentChannelsKey).toStringList();
+    recentChannelsLabel->setVisible(!keywords.isEmpty());
+    // TODO The::globalActions()->value("clearRecentKeywords")->setEnabled(!keywords.isEmpty());
+
+    foreach (QString keyword, keywords) {
+        QString link = keyword;
+        QString display = keyword;
+        if (keyword.startsWith("http://")) {
+            int separator = keyword.indexOf("|");
+            if (separator > 0 && separator + 1 < keyword.length()) {
+                link = keyword.left(separator);
+                display = keyword.mid(separator+1);
+            }
+        }
+        QLabel *itemLabel = new QLabel("<a href=\"" + link
+                                       + "\" style=\"color:palette(text); text-decoration:none\">"
+                                       + display + "</a>", this);
+
+        itemLabel->setMaximumWidth(queryEdit->width() + watchButton->width());
+        // itemLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+        // Make links navigable with the keyboard too
+        itemLabel->setTextInteractionFlags(Qt::LinksAccessibleByKeyboard | Qt::LinksAccessibleByMouse);
+
+        connect(itemLabel, SIGNAL(linkActivated(QString)), this, SLOT(watchChannel(QString)));
+        recentChannelsLayout->addWidget(itemLabel);
+    }
+
+}
 
 void SearchView::watch() {
-    QString query = queryEdit->text().simplified();
+    QString query = queryEdit->text();
     watch(query);
 }
 
@@ -192,14 +271,47 @@ void SearchView::textChanged(const QString &text) {
 
 void SearchView::watch(QString query) {
 
+    query = query.simplified();
+
     // check for empty query
     if (query.length() == 0) {
         queryEdit->setFocus(Qt::OtherFocusReason);
         return;
     }
 
+    SearchParams *searchParams = new SearchParams();
+    if (typeCombo->currentIndex() == 0)
+        searchParams->setKeywords(query);
+    else {
+        // remove spaces from channel name
+        query = query.replace(" ", "");
+        searchParams->setAuthor(query);
+        searchParams->setSortBy(SearchParams::SortByNewest);
+    }
+
     // go!
-    emit search(query);
+    emit search(searchParams);
+}
+
+void SearchView::watchChannel(QString channel) {
+
+    channel = channel.simplified();
+
+    // check for empty query
+    if (channel.length() == 0) {
+        queryEdit->setFocus(Qt::OtherFocusReason);
+        return;
+    }
+
+    // remove spaces from channel name
+    channel = channel.replace(" ", "");
+
+    SearchParams *searchParams = new SearchParams();
+    searchParams->setAuthor(channel);
+    searchParams->setSortBy(SearchParams::SortByNewest);
+
+    // go!
+    emit search(searchParams);
 }
 
 void SearchView::checkForUpdate() {
@@ -255,3 +367,11 @@ void SearchView::paintEvent(QPaintEvent * /*event*/) {
     painter.fillRect(0, 0, width(), height(), brush);
 #endif
 }
+
+void SearchView::searchTypeChanged(int index) {
+    if (index == 0) {
+        queryEdit->setSuggester(youtubeSuggest);
+    } else {
+        queryEdit->setSuggester(channelSuggest);
+    }
+}
index c32db4b5bb2adbb662785750110febab0b51327b..dfdfee9d72e50f8082891218b6c9f1820996eae1 100644 (file)
@@ -6,6 +6,10 @@
 #include "searchlineedit.h"
 #include "updatechecker.h"
 
+class SearchParams;
+class YouTubeSuggest;
+class ChannelSuggest;
+
 class SearchView : public QWidget, public View {
 
     Q_OBJECT
@@ -13,9 +17,11 @@ class SearchView : public QWidget, public View {
 public:
     SearchView(QWidget *parent);
     void updateRecentKeywords();
+    void updateRecentChannels();
 
     void appear() {
         updateRecentKeywords();
+        updateRecentChannels();
         queryEdit->clear();
         queryEdit->setFocus(Qt::OtherFocusReason);
         queryEdit->enableSuggest();
@@ -32,10 +38,11 @@ public:
 
 public slots:
     void watch(QString query);
+    void watchChannel(QString channel);
     void gotNewVersion(QString version);
 
 signals:
-    void search(QString query);
+    void search(SearchParams*);
 
 protected:
     void paintEvent(QPaintEvent *);
@@ -43,13 +50,20 @@ protected:
 private slots:
     void watch();
     void textChanged(const QString &text);
+    void searchTypeChanged(int index);
 
 private:
     void checkForUpdate();
 
+    YouTubeSuggest *youtubeSuggest;
+    ChannelSuggest *channelSuggest;
+
+    QComboBox *typeCombo;
     SearchLineEdit *queryEdit;
     QLabel *recentKeywordsLabel;
-    QVBoxLayout *recentKeywordsLayout;
+    QBoxLayout *recentKeywordsLayout;
+    QLabel *recentChannelsLabel;
+    QBoxLayout *recentChannelsLayout;
     QLabel *message;
     QPushButton *watchButton;
 
index 656c6512876a84e808b9ddd4e4eda09d9b85023b..1db03ee648084d95578ee4f65fb64730bb8e597f 100644 (file)
@@ -1,14 +1,8 @@
-#include "googlesuggest.h"
-#include "networkaccess.h"
+#include "autocomplete.h"
+#include "suggester.h"
 
-#define GSUGGEST_URL "http://suggestqueries.google.com/complete/search?ds=yt&output=toolbar&hl=%1&q=%2"
-
-namespace The {
-    NetworkAccess* http();
-}
-
-GSuggestCompletion::GSuggestCompletion(QWidget *parent, QLineEdit *editor):
-        QObject(parent), buddy(parent), editor(editor) {
+AutoComplete::AutoComplete(QWidget *parent, QLineEdit *editor):
+        QObject(parent), buddy(parent), editor(editor), suggester(0) {
 
     enabled = true;
 
@@ -40,11 +34,11 @@ GSuggestCompletion::GSuggestCompletion(QWidget *parent, QLineEdit *editor):
 
 }
 
-GSuggestCompletion::~GSuggestCompletion() {
+AutoComplete::~AutoComplete() {
     delete popup;
 }
 
-bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) {
+bool AutoComplete::eventFilter(QObject *obj, QEvent *ev) {
     if (obj != popup)
         return false;
 
@@ -104,7 +98,7 @@ bool GSuggestCompletion::eventFilter(QObject *obj, QEvent *ev) {
     return false;
 }
 
-void GSuggestCompletion::showCompletion(const QStringList &choices) {
+void AutoComplete::showCompletion(const QStringList &choices) {
 
     if (choices.isEmpty())
         return;
@@ -129,7 +123,7 @@ void GSuggestCompletion::showCompletion(const QStringList &choices) {
     popup->show();
 }
 
-void GSuggestCompletion::doneCompletion() {
+void AutoComplete::doneCompletion() {
     timer->stop();
     popup->hide();
     editor->setFocus();
@@ -144,19 +138,25 @@ void GSuggestCompletion::doneCompletion() {
     }
 }
 
-void GSuggestCompletion::preventSuggest() {
+void AutoComplete::preventSuggest() {
     // qDebug() << "preventSuggest";
     timer->stop();
     enabled = false;
     popup->hide();
 }
 
-void GSuggestCompletion::enableSuggest() {
+void AutoComplete::enableSuggest() {
     // qDebug() << "enableSuggest";
     enabled = true;
 }
 
-void GSuggestCompletion::autoSuggest() {
+void AutoComplete::setSuggester(Suggester* suggester) {
+    if (this->suggester) this->suggester->disconnect();
+    this->suggester = suggester;
+    connect(suggester, SIGNAL(ready(QStringList)), SLOT(suggestionsReady(QStringList)));
+}
+
+void AutoComplete::autoSuggest() {
     if (!enabled) return;
 
     QString query = editor->text();
@@ -164,38 +164,16 @@ void GSuggestCompletion::autoSuggest() {
     // qDebug() << "originalText" << originalText;
     if (query.isEmpty()) return;
 
-    QString locale = QLocale::system().name().replace("_", "-");
-    // case for system locales such as "C"
-    if (locale.length() < 2) {
-        locale = "en-US";
-    }
-
-    QString url = QString(GSUGGEST_URL).arg(locale, query);
-
-    QObject *reply = The::http()->get(url);
-    connect(reply, SIGNAL(data(QByteArray)), SLOT(handleNetworkData(QByteArray)));
+    if (suggester)
+        suggester->suggest(query);
 }
 
-void GSuggestCompletion::handleNetworkData(QByteArray response) {
+void AutoComplete::suggestionsReady(QStringList suggestions) {
     if (!enabled) return;
-
-    QStringList choices;
-
-    QXmlStreamReader xml(response);
-    while (!xml.atEnd()) {
-        xml.readNext();
-        if (xml.tokenType() == QXmlStreamReader::StartElement)
-            if (xml.name() == "suggestion") {
-            QStringRef str = xml.attributes().value("data");
-            choices << str.toString();
-        }
-    }
-
-    showCompletion(choices);
-
+    showCompletion(suggestions);
 }
 
-void GSuggestCompletion::currentItemChanged(QListWidgetItem *current) {
+void AutoComplete::currentItemChanged(QListWidgetItem *current) {
     if (current) {
         // qDebug() << "current" << current->text();
         current->setSelected(true);
index 9773380db7514520f5435c1933aea72f9045e5a9..9a6e8b31c5b2a871d5cb6e05e2cfc23ef7c0d5de 100644 (file)
@@ -1,24 +1,27 @@
-#ifndef GOOGLESUGGEST_H
-#define GOOGLESUGGEST_H
+#ifndef SUGGESTCOMPLETION_H
+#define SUGGESTCOMPLETION_H
 
 #include <QtGui>
 
-class GSuggestCompletion : public QObject {
+class Suggester;
+
+class AutoComplete : public QObject {
     Q_OBJECT
 
 public:
-    GSuggestCompletion(QWidget *parent, QLineEdit *editor);
-    ~GSuggestCompletion();
+    AutoComplete(QWidget *parent, QLineEdit *editor);
+    ~AutoComplete();
     bool eventFilter(QObject *obj, QEvent *ev);
     void showCompletion(const QStringList &choices);
+    void setSuggester(Suggester* suggester);
 
 public slots:
     void doneCompletion();
     void preventSuggest();
     void enableSuggest();
     void autoSuggest();
-    void handleNetworkData(QByteArray response);
     void currentItemChanged(QListWidgetItem *current);
+    void suggestionsReady(QStringList suggestions);
 
 private:
     QWidget *buddy;
@@ -27,7 +30,8 @@ private:
     QListWidget *popup;
     QTimer *timer;
     bool enabled;
+    Suggester* suggester;
 
 };
 
-#endif // GOOGLESUGGEST_H
+#endif // SUGGESTCOMPLETION_H
index 42c2aeee3726e07708d31500b805ec02a631790a..e63fbd951f9682359056ea799e6c03f24fcfef79 100644 (file)
@@ -47,7 +47,7 @@
 #include <QtGui/QStyle>
 #include <QtGui/QStyleOptionFrameV2>
 
-#include "googlesuggest.h"
+#include "autocomplete.h"
 
 ClearButton::ClearButton(QWidget *parent)
     : QAbstractButton(parent)
@@ -180,7 +180,7 @@ m_searchButton(new SearchButton(this))
     setSizePolicy(QSizePolicy::Preferred, policy.verticalPolicy());
 
     // completion
-    completion = new GSuggestCompletion(this, m_lineEdit);
+    completion = new AutoComplete(this, m_lineEdit);
 
 }
 
index a1d71c44f64193aea715b7f4d0085dabaaf5bcf7..f56ca8061b9b91ce0d9e96afd31c6b8c9b1b62d2 100644 (file)
@@ -43,6 +43,7 @@
 #define SEARCHLINEEDIT_H
 
 #include "urllineedit.h"
+#include "autocomplete.h"
 
 #include <QtGui/QLineEdit>
 #include <QtGui/QAbstractButton>
@@ -52,7 +53,7 @@ class QMenu;
 QT_END_NAMESPACE
 
 class SearchButton;
-class GSuggestCompletion;
+class Suggester;
 
 /*
     Clear button on the right hand side of the search widget.
@@ -93,6 +94,7 @@ public:
     void enableSuggest();
     void preventSuggest();
     void selectAll() { lineEdit()->selectAll(); };
+    void setSuggester(Suggester *suggester) { completion->setSuggester(suggester); }
 
 protected:
     void resizeEvent(QResizeEvent *event);
@@ -107,7 +109,7 @@ private:
     SearchButton *m_searchButton;
     QString m_inactiveText;
 
-    GSuggestCompletion *completion;
+    AutoComplete *completion;
 };
 
 #endif // SEARCHLINEEDIT_H