File indexing completed on 2024-04-28 04:55:54

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     Based on the imagepreview extension
0005     SPDX-FileCopyrightText: 2010-2012 Emanuele Bigiarini <pulmro@gmail.com>
0006     SPDX-FileCopyrightText: 2008-2012 Mehrdad Momeny <mehrdad.momeny@gmail.com>
0007 
0008     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0009 */
0010 
0011 #include "videopreview.h"
0012 
0013 #include <QDebug>
0014 #include <QDomDocument>
0015 #include <QDomElement>
0016 #include <QEventLoop>
0017 #include <QTimer>
0018 
0019 #include <KIO/StoredTransferJob>
0020 #include <KJobWidgets>
0021 #include <KPluginFactory>
0022 
0023 #include "choqokuiglobal.h"
0024 #include "postwidget.h"
0025 #include "notifymanager.h"
0026 #include "mediamanager.h"
0027 #include "textbrowser.h"
0028 #include "shortenmanager.h"
0029 
0030 K_PLUGIN_CLASS_WITH_JSON(VideoPreview, "choqok_videopreview.json")
0031 
0032 const QRegExp VideoPreview::mYouTuRegExp(QLatin1String("(https?://youtu.[^\\s<>\"]+[^!,\\.\\s<>'\\\"\\]])"));
0033 const QRegExp VideoPreview::mYouTubeRegExp(QLatin1String("(https?://www.youtube.[^\\s<>\"]+[^!,\\.\\s<>'\\\"\\]])"));
0034 const QRegExp VideoPreview::mVimeoRegExp(QLatin1String("(https?://(.+)?vimeo.com/(.+)[&]?)"));
0035 
0036 const QRegExp VideoPreview::mYouTuCode(QLatin1String("youtu.(.+)/(.+)[?&]?"));
0037 
0038 VideoPreview::VideoPreview(QObject *parent, const QList< QVariant > &)
0039     : Choqok::Plugin(QLatin1String("choqok_videopreview"), parent)
0040     , state(Stopped)
0041 {
0042     connect(Choqok::UI::Global::SessionManager::self(), &Choqok::UI::Global::SessionManager::newPostWidgetAdded,
0043             this, &VideoPreview::slotAddNewPostWidget);
0044     connect(Choqok::ShortenManager::self(), &Choqok::ShortenManager::newUnshortenedUrl,
0045             this, &VideoPreview::slotNewUnshortenedUrl);
0046 }
0047 
0048 VideoPreview::~VideoPreview()
0049 {
0050 
0051 }
0052 
0053 void VideoPreview::slotAddNewPostWidget(Choqok::UI::PostWidget *newWidget)
0054 {
0055     postsQueue.enqueue(newWidget);
0056     if (state == Stopped) {
0057         state = Running;
0058         QTimer::singleShot(1000, this, SLOT(startParsing()));
0059     }
0060 }
0061 
0062 void VideoPreview::slotNewUnshortenedUrl(Choqok::UI::PostWidget *widget, const QUrl &fromUrl, const QUrl &toUrl)
0063 {
0064     Q_UNUSED(fromUrl)
0065     if (mYouTubeRegExp.indexIn(toUrl.toDisplayString()) != -1) {
0066         QUrl thisurl(mYouTubeRegExp.cap(0));
0067         QUrlQuery thisurlQuery(thisurl);
0068         QUrl thumbUrl = parseYoutube(thisurlQuery.queryItemValue(QLatin1String("v")), widget);
0069         connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched,
0070                 this, &VideoPreview::slotImageFetched);
0071         Choqok::MediaManager::self()->fetchImage(thumbUrl, Choqok::MediaManager::Async);
0072     } else if (mVimeoRegExp.indexIn(toUrl.toDisplayString()) != -1) {
0073         QUrl thumbUrl = parseVimeo(mVimeoRegExp.cap(3), widget);
0074         connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched,
0075                 this, &VideoPreview::slotImageFetched);
0076         Choqok::MediaManager::self()->fetchImage(thumbUrl, Choqok::MediaManager::Async);
0077     }
0078 
0079 }
0080 
0081 void VideoPreview::startParsing()
0082 {
0083     int i = 8;
0084     while (!postsQueue.isEmpty() && i > 0) {
0085         parse(postsQueue.dequeue());
0086         --i;
0087     }
0088 
0089     if (postsQueue.isEmpty()) {
0090         state = Stopped;
0091     } else {
0092         QTimer::singleShot(500, this, SLOT(startParsing()));
0093     }
0094 }
0095 
0096 void VideoPreview::parse(QPointer<Choqok::UI::PostWidget> postToParse)
0097 {
0098     if (!postToParse) {
0099         return;
0100     }
0101     int pos = 0;
0102     int pos1 = 0;
0103     int pos2 = 0;
0104     int pos3 = 0;
0105     QList<QUrl> thumbList;
0106 
0107     QString content = postToParse->currentPost()->content;
0108 
0109     while (((pos1 = mYouTuRegExp.indexIn(content, pos)) != -1) |
0110             ((pos2 = mYouTubeRegExp.indexIn(content, pos)) != -1) |
0111             ((pos3 = mVimeoRegExp.indexIn(content, pos)) != -1)) {
0112 
0113         if (pos1 >= 0) {
0114             pos = pos1 + mYouTuRegExp.matchedLength();
0115             if (mYouTuCode.indexIn(mYouTuRegExp.cap(0)) != -1) {
0116                 thumbList << parseYoutube(mYouTuCode.cap(2), postToParse);
0117             }
0118         } else if (pos2 >= 0) {
0119             pos = pos2 + mYouTubeRegExp.matchedLength();
0120             QUrl thisurl(mYouTubeRegExp.cap(0));
0121             QUrlQuery thisurlQuery(thisurl);
0122             thumbList << parseYoutube(thisurlQuery.queryItemValue(QLatin1String("v")), postToParse);
0123         } else if (pos3 >= 0) {
0124             pos = pos3 + mVimeoRegExp.matchedLength();
0125             thumbList << parseVimeo(mVimeoRegExp.cap(3), postToParse);
0126         }
0127     }
0128 
0129     for (const QUrl &thumb_url: thumbList) {
0130         connect(Choqok::MediaManager::self(), &Choqok::MediaManager::imageFetched,
0131                 this, &VideoPreview::slotImageFetched);
0132 
0133         Choqok::MediaManager::self()->fetchImage(thumb_url, Choqok::MediaManager::Async);
0134     }
0135 
0136 }
0137 
0138 QUrl VideoPreview::parseYoutube(QString videoid, QPointer< Choqok::UI::PostWidget > postToParse)
0139 {
0140     QString youtubeUrl = QStringLiteral("https://gdata.youtube.com/feeds/api/videos/%1").arg(videoid);
0141     QUrl th_url(youtubeUrl);
0142     KIO::StoredTransferJob *job = KIO::storedGet(th_url, KIO::NoReload, KIO::HideProgressInfo);
0143     KJobWidgets::setWindow(job, Choqok::UI::Global::mainWindow());
0144     QString title, description;
0145     QUrl thumb_url;
0146 
0147     job->exec();
0148     if (!job->error()) {
0149         QDomDocument document;
0150         document.setContent(job->data());
0151         QDomElement root = document.documentElement();
0152         if (!root.isNull()) {
0153             QDomElement node;
0154             node = root.firstChildElement(QLatin1String("title"));
0155             if (!node.isNull()) {
0156                 title = QString(node.text());
0157             }
0158             node = root.firstChildElement(QLatin1String("media:group"));
0159             node = node.firstChildElement(QLatin1String("media:description"));
0160             if (!node.isNull()) {
0161                 description = QString(node.text());
0162             }
0163 
0164             node = node.nextSiblingElement(QLatin1String("media:thumbnail"));
0165             if (!node.isNull()) {
0166                 thumb_url = QUrl::fromUserInput(node.attributeNode(QLatin1String("url")).value());
0167             }
0168         }
0169 
0170         description = description.left(70);
0171 
0172         mParsingList.insert(thumb_url, postToParse);
0173         mBaseUrlMap.insert(thumb_url, QLatin1String("https://www.youtube.com/watch?v=") + videoid);
0174         mTitleVideoMap.insert(thumb_url, title);
0175         mDescriptionVideoMap.insert(thumb_url, description);
0176     } else {
0177         qCritical() << "Youtube XML response is NULL!";
0178     }
0179 
0180     return thumb_url;
0181 }
0182 
0183 QUrl VideoPreview::parseVimeo(QString videoid, QPointer< Choqok::UI::PostWidget > postToParse)
0184 {
0185     QString vimeoUrl = QStringLiteral("https://vimeo.com/api/v2/video/%1.xml").arg(videoid);
0186     QUrl th_url(vimeoUrl);
0187     QEventLoop loop;
0188     KIO::StoredTransferJob *job = KIO::storedGet(th_url, KIO::NoReload, KIO::HideProgressInfo);
0189     KJobWidgets::setWindow(job, Choqok::UI::Global::mainWindow());
0190     QString title, description;
0191     QUrl thumb_url;
0192 
0193     job->exec();
0194     if (!job->error()) {
0195         QDomDocument document;
0196         document.setContent(job->data());
0197         QDomElement root = document.documentElement();
0198         if (!root.isNull()) {
0199             QDomElement videotag;
0200             videotag = root.firstChildElement(QLatin1String("video"));
0201             if (!videotag.isNull()) {
0202                 QDomElement node;
0203                 node = videotag.firstChildElement(QLatin1String("title"));
0204                 if (!node.isNull()) {
0205                     title = QString(node.text());
0206                 }
0207                 node = videotag.firstChildElement(QLatin1String("description"));
0208                 if (!node.isNull()) {
0209                     description = QString(node.text());
0210                 }
0211                 node = videotag.firstChildElement(QLatin1String("thumbnail_small"));
0212                 if (!node.isNull()) {
0213                     thumb_url = QUrl::fromUserInput(node.text());
0214                 }
0215             }
0216         }
0217         description = description.left(70);
0218 
0219         mParsingList.insert(thumb_url, postToParse);
0220         mBaseUrlMap.insert(thumb_url, QLatin1String("https://vimeo.com/") + videoid);
0221         mTitleVideoMap.insert(thumb_url, title);
0222         mDescriptionVideoMap.insert(thumb_url, description);
0223     } else {
0224         qCritical() << "Vimeo XML response is NULL!";
0225     }
0226 
0227     return thumb_url;
0228 }
0229 
0230 void VideoPreview::slotImageFetched(const QUrl &remoteUrl, const QPixmap &pixmap)
0231 {
0232     Choqok::UI::PostWidget *postToParse = mParsingList.take(remoteUrl);
0233     QString baseUrl = mBaseUrlMap.take(remoteUrl);
0234     QString title = mTitleVideoMap.take(remoteUrl);
0235     QString description = mDescriptionVideoMap.take(remoteUrl);
0236 
0237     if (!postToParse) {
0238         return;
0239     }
0240     QString content = postToParse->content();
0241     QUrl imgU(remoteUrl);
0242     imgU.setScheme(QLatin1String("img"));
0243     postToParse->mainWidget()->document()->addResource(QTextDocument::ImageResource, imgU, pixmap);
0244 
0245     QString temp(QLatin1String("<br/><table><tr><td rowspan=2><img align='left' height=64 src='")
0246                  + imgU.toDisplayString() + QLatin1String("' /></td>"));
0247     temp.append(QLatin1String("<td><a href='") + baseUrl + QLatin1String("' title='") + baseUrl + QLatin1String("'><b>") + title + QLatin1String("</b></a></td></tr>"));
0248     temp.append(QLatin1String("<tr><font size=\"-1\">") + description + QLatin1String("</font></tr></table>"));
0249 
0250     content.append(temp);
0251     postToParse->setContent(content);
0252 }
0253 
0254 #include "moc_videopreview.cpp"
0255 #include "videopreview.moc"