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"