File indexing completed on 2024-04-21 04:59:27

0001 // SPDX-FileCopyrightText: 2022 Bharadwaj Raju <bharadwaj.raju777@protonmail.com>
0002 // SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-or-later OR LicenseRef-KDE-Accepted-GPL
0003 
0004 #include "linkpreviewer.h"
0005 
0006 #include <Quotient/connection.h>
0007 #include <Quotient/csapi/content-repo.h>
0008 #include <Quotient/events/roommessageevent.h>
0009 
0010 #include "neochatconfig.h"
0011 #include "neochatroom.h"
0012 #include "utils.h"
0013 
0014 using namespace Quotient;
0015 
0016 LinkPreviewer::LinkPreviewer(const NeoChatRoom *room, const Quotient::RoomMessageEvent *event)
0017     : QObject(nullptr)
0018     , m_currentRoom(room)
0019     , m_event(event)
0020     , m_loaded(false)
0021     , m_url(linkPreview(event))
0022 {
0023     connect(this, &LinkPreviewer::urlChanged, this, &LinkPreviewer::emptyChanged);
0024 
0025     if (m_event != nullptr && m_currentRoom != nullptr) {
0026         loadUrlPreview();
0027         connect(m_currentRoom, &NeoChatRoom::urlPreviewEnabledChanged, this, &LinkPreviewer::loadUrlPreview);
0028         // Make sure that we react to edits
0029         connect(m_currentRoom, &NeoChatRoom::replacedEvent, this, [this](const Quotient::RoomEvent *newEvent) {
0030             if (m_event->id() == newEvent->id()) {
0031                 m_event = eventCast<const Quotient::RoomMessageEvent>(newEvent);
0032                 m_url = linkPreview(m_event);
0033                 Q_EMIT urlChanged();
0034                 loadUrlPreview();
0035             }
0036         });
0037     }
0038     connect(NeoChatConfig::self(), &NeoChatConfig::ShowLinkPreviewChanged, this, &LinkPreviewer::loadUrlPreview);
0039 }
0040 
0041 bool LinkPreviewer::loaded() const
0042 {
0043     return m_loaded;
0044 }
0045 
0046 QString LinkPreviewer::title() const
0047 {
0048     return m_title;
0049 }
0050 
0051 QString LinkPreviewer::description() const
0052 {
0053     return m_description;
0054 }
0055 
0056 QUrl LinkPreviewer::imageSource() const
0057 {
0058     return m_imageSource;
0059 }
0060 
0061 QUrl LinkPreviewer::url() const
0062 {
0063     return m_url;
0064 }
0065 
0066 void LinkPreviewer::loadUrlPreview()
0067 {
0068     if (!m_currentRoom || !NeoChatConfig::showLinkPreview() || !m_currentRoom->urlPreviewEnabled()) {
0069         return;
0070     }
0071     if (m_url.scheme() == QStringLiteral("https")) {
0072         m_loaded = false;
0073         Q_EMIT loadedChanged();
0074 
0075         auto conn = m_currentRoom->connection();
0076         GetUrlPreviewJob *job = conn->callApi<GetUrlPreviewJob>(m_url);
0077 
0078         connect(job, &BaseJob::success, this, [this, job, conn]() {
0079             const auto json = job->jsonData();
0080             m_title = json["og:title"_ls].toString().trimmed();
0081             m_description = json["og:description"_ls].toString().trimmed().replace("\n"_ls, " "_ls);
0082 
0083             auto imageUrl = QUrl(json["og:image"_ls].toString());
0084             if (imageUrl.isValid() && imageUrl.scheme() == QStringLiteral("mxc")) {
0085                 m_imageSource = conn->makeMediaUrl(imageUrl);
0086             } else {
0087                 m_imageSource = QUrl();
0088             }
0089 
0090             m_loaded = true;
0091             Q_EMIT titleChanged();
0092             Q_EMIT descriptionChanged();
0093             Q_EMIT imageSourceChanged();
0094             Q_EMIT loadedChanged();
0095         });
0096     }
0097 }
0098 
0099 bool LinkPreviewer::empty() const
0100 {
0101     return m_url.isEmpty();
0102 }
0103 
0104 QUrl LinkPreviewer::linkPreview(const Quotient::RoomMessageEvent *event)
0105 {
0106     if (event == nullptr) {
0107         return {};
0108     }
0109 
0110     QString text;
0111     if (event->hasTextContent()) {
0112         auto textContent = static_cast<const Quotient::EventContent::TextContent *>(event->content());
0113         if (textContent) {
0114             text = textContent->body;
0115         } else {
0116             text = event->plainBody();
0117         }
0118     } else {
0119         text = event->plainBody();
0120     }
0121 
0122     auto data = text.remove(TextRegex::removeRichReply);
0123     auto linksMatch = TextRegex::url.globalMatch(data);
0124     while (linksMatch.hasNext()) {
0125         auto link = linksMatch.next().captured();
0126         if (!link.contains(QStringLiteral("matrix.to"))) {
0127             return QUrl(link);
0128         }
0129     }
0130     return {};
0131 }
0132 
0133 bool LinkPreviewer::hasPreviewableLinks(const Quotient::RoomMessageEvent *event)
0134 {
0135     return !linkPreview(event).isEmpty();
0136 }
0137 
0138 #include "moc_linkpreviewer.cpp"