+++ /dev/null
-#include "ytjssearch.h"
-
-#include "mainwindow.h"
-#include "searchparams.h"
-#include "video.h"
-#include "ytjs.h"
-#include "ytsearch.h"
-
-namespace {
-
-int parseDuration(const QString &s) {
- const auto parts = s.splitRef(':');
- int secs = 0;
- int p = 0;
- for (auto i = parts.crbegin(); i != parts.crend(); ++i) {
- if (p == 0) {
- secs = i->toInt();
- } else if (p == 1) {
- secs += i->toInt() * 60;
- } else if (p == 2) {
- secs += i->toInt() * 60 * 60;
- }
- p++;
- }
- return secs;
-}
-
-QString parseChannelId(const QString &channelUrl) {
- int pos = channelUrl.lastIndexOf('/');
- if (pos >= 0) return channelUrl.mid(pos + 1);
- return QString();
-}
-
-QDateTime parsePublishedText(const QString &s) {
- int num = 0;
- const auto parts = s.splitRef(' ');
- for (const auto &part : parts) {
- num = part.toInt();
- if (num > 0) break;
- }
- if (num == 0) return QDateTime();
-
- auto now = QDateTime::currentDateTimeUtc();
- if (s.contains("day")) {
- return now.addDays(-num);
- } else if (s.contains("week")) {
- return now.addDays(-num * 7);
- } else if (s.contains("month")) {
- return now.addMonths(-num);
- } else if (s.contains("year")) {
- return now.addDays(-num * 365);
- }
- return QDateTime();
-}
-
-} // namespace
-
-YTJSSearch::YTJSSearch(SearchParams *searchParams, QObject *parent)
- : VideoSource(parent), searchParams(searchParams) {}
-
-void YTJSSearch::loadVideos(int max, int startIndex) {
- auto &ytjs = YTJS::instance();
- if (!ytjs.isInitialized()) {
- QTimer::singleShot(500, this, [this, max, startIndex] { loadVideos(max, startIndex); });
- return;
- }
- auto &engine = ytjs.getEngine();
-
- aborted = false;
-
- auto function = engine.evaluate("search");
- if (!function.isCallable()) {
- qWarning() << function.toString() << " is not callable";
- emit error(function.toString());
- return;
- }
-
- QString q;
- if (!searchParams->keywords().isEmpty()) {
- if (searchParams->keywords().startsWith("http://") ||
- searchParams->keywords().startsWith("https://")) {
- q = YTSearch::videoIdFromUrl(searchParams->keywords());
- } else
- q = searchParams->keywords();
- }
-
- // Options
-
- QJSValue options = engine.newObject();
-
- if (startIndex > 1 && !nextpageRef.isEmpty()) options.setProperty("nextpageRef", nextpageRef);
- options.setProperty("limit", max);
-
- switch (searchParams->safeSearch()) {
- case SearchParams::None:
- options.setProperty("safeSearch", false);
- break;
- case SearchParams::Strict:
- options.setProperty("safeSearch", true);
- break;
- }
-
- // Filters
-
- auto filterMap = engine.evaluate("new Map()");
- auto jsMapSet = filterMap.property("set");
- auto addFilter = [&filterMap, &jsMapSet](QString name, QString value) {
- jsMapSet.callWithInstance(filterMap, {name, value});
- };
-
- addFilter("Type", "Video");
-
- switch (searchParams->sortBy()) {
- case SearchParams::SortByNewest:
- addFilter("Sort by", "Upload date");
- break;
- case SearchParams::SortByViewCount:
- addFilter("Sort by", "View count");
- break;
- case SearchParams::SortByRating:
- addFilter("Sort by", "Rating");
- break;
- }
-
- switch (searchParams->duration()) {
- case SearchParams::DurationShort:
- addFilter("Duration", "Short");
- break;
- case SearchParams::DurationMedium:
- case SearchParams::DurationLong:
- addFilter("Duration", "Long");
- break;
- }
-
- switch (searchParams->time()) {
- case SearchParams::TimeToday:
- addFilter("Upload date", "Today");
- break;
- case SearchParams::TimeWeek:
- addFilter("Upload date", "This week");
- break;
- case SearchParams::TimeMonth:
- addFilter("Upload date", "This month");
- break;
- }
-
- switch (searchParams->quality()) {
- case SearchParams::QualityHD:
- addFilter("Features", "HD");
- break;
- case SearchParams::Quality4K:
- addFilter("Features", "4K");
- break;
- case SearchParams::QualityHDR:
- addFilter("Features", "HDR");
- break;
- }
-
- auto handler = new ResultHandler;
- connect(handler, &ResultHandler::error, this, &VideoSource::error);
- connect(handler, &ResultHandler::data, this, [this](const QJsonDocument &doc) {
- if (aborted) return;
-
- auto obj = doc.object();
-
- /*
- QFile jsonFile("/Users/flavio/test.json");
- jsonFile.open(QFile::WriteOnly);
- jsonFile.write(doc.toJson());
- */
-
- nextpageRef = obj["nextpageRef"].toString();
-
- const auto items = obj["items"].toArray();
- QVector<Video *> videos;
- videos.reserve(items.size());
-
- for (const auto &i : items) {
- QString type = i["type"].toString();
- if (type != "video") continue;
-
- Video *video = new Video();
-
- QString id = YTSearch::videoIdFromUrl(i["link"].toString());
- video->setId(id);
-
- QString title = i["title"].toString();
- video->setTitle(title);
-
- QString desc = i["description"].toString();
- video->setDescription(desc);
-
- QString thumb = i["thumbnail"].toString();
- video->setThumbnailUrl(thumb);
-
- int views = i["views"].toInt();
- video->setViewCount(views);
-
- int duration = parseDuration(i["duration"].toString());
- video->setDuration(duration);
-
- auto published = parsePublishedText(i["uploaded_at"].toString());
- if (published.isValid()) video->setPublished(published);
-
- auto authorObj = i["author"];
- QString channelName = authorObj["name"].toString();
- video->setChannelTitle(channelName);
- QString channelId = parseChannelId(authorObj["ref"].toString());
- video->setChannelId(channelId);
-
- videos << video;
- }
-
- emit gotVideos(videos);
- emit finished(videos.size());
- });
- QJSValue h = engine.newQObject(handler);
- auto value = function.call({h, q, options, filterMap});
- if (ytjs.checkError(value)) emit error(value.toString());
-}
-
-QString YTJSSearch::getName() {
- if (!name.isEmpty()) return name;
- if (!searchParams->keywords().isEmpty()) return searchParams->keywords();
- return QString();
-}
-
-const QList<QAction *> &YTJSSearch::getActions() {
- static const QList<QAction *> channelActions = {
- MainWindow::instance()->getAction("subscribeChannel")};
- if (searchParams->channelId().isEmpty()) {
- static const QList<QAction *> noActions;
- return noActions;
- }
- return channelActions;
-}