1 #include "ytjssinglevideosource.h"
8 QDateTime parsePublishedText(const QString &s) {
10 const auto parts = s.splitRef(' ');
11 for (const auto &part : parts) {
15 if (num == 0) return QDateTime();
17 auto now = QDateTime::currentDateTimeUtc();
18 if (s.contains("hour")) {
19 return now.addSecs(-num * 3600);
20 } else if (s.contains("day")) {
21 return now.addDays(-num);
22 } else if (s.contains("week")) {
23 return now.addDays(-num * 7);
24 } else if (s.contains("month")) {
25 return now.addMonths(-num);
26 } else if (s.contains("year")) {
27 return now.addDays(-num * 365);
34 YTJSSingleVideoSource::YTJSSingleVideoSource(QObject *parent)
35 : VideoSource(parent), video(nullptr) {}
37 void YTJSSingleVideoSource::loadVideos(int max, int startIndex) {
40 if (startIndex == 1) {
43 name = video->getTitle();
44 qDebug() << "Emitting name changed" << name;
45 emit nameChanged(name);
47 emit gotVideos({video->clone()});
52 .callFunction(new JSResult(this), "videoInfo", {videoId})
53 .onJson([this](auto &doc) {
56 auto obj = doc.object();
58 auto parseVideoObject = [](QJsonObject i) {
59 Video *video = new Video();
61 QString id = i["id"].toString();
62 if (id.isEmpty()) id = i["videoId"].toString();
65 QString title = i["title"].toString();
66 video->setTitle(title);
68 QString desc = i["description"].toString();
69 if (desc.isEmpty()) desc = i["desc"].toString();
70 if (desc.isEmpty()) desc = i["shortDescription"].toString();
72 video->setDescription(desc);
74 const auto thumbs = i["thumbnails"].toArray();
75 for (const auto &t : thumbs) {
76 video->addThumb(t["width"].toInt(), t["height"].toInt(),
80 qDebug() << i["view_count"] << i["viewCount"];
81 int views = i["view_count"].toString().toInt();
82 if (views == 0) views = i["viewCount"].toString().toInt();
83 video->setViewCount(views);
85 int duration = i["length_seconds"].toInt();
86 video->setDuration(duration);
88 auto author = i["author"];
89 if (author.isObject()) {
90 auto authorObject = author.toObject();
91 video->setChannelId(authorObject["id"].toString());
92 video->setChannelTitle(authorObject["name"].toString());
93 } else if (author.isString()) {
94 video->setChannelId(i["ucid"].toString());
95 video->setChannelTitle(author.toString());
98 auto published = parsePublishedText(i["published"].toString());
99 if (published.isValid()) video->setPublished(published);
104 QVector<Video *> videos;
108 auto video = parseVideoObject(obj["videoDetails"].toObject());
110 name = video->getTitle();
111 qDebug() << "Emitting name changed" << name;
112 emit nameChanged(name);
115 const auto items = obj["related_videos"].toArray();
116 videos.reserve(items.size());
118 for (const auto &i : items) {
119 videos << parseVideoObject(i.toObject());
122 if (videos.isEmpty()) {
123 emit error("No results");
125 emit gotVideos(videos);
126 emit finished(videos.size());
129 // fake more videos by loading videos related to the last one
131 if (!videos.isEmpty()) videoId = videos.last()->getId();
133 .onError([this](auto &msg) { emit error(msg); });
136 void YTJSSingleVideoSource::setVideo(Video *video) {
138 videoId = video->getId();
141 void YTJSSingleVideoSource::abort() {
145 QString YTJSSingleVideoSource::getName() {