discord-awesomeaudio/src/discordpage.cpp

278 lines
11 KiB
C++
Raw Normal View History

2022-07-09 22:07:14 +02:00
#include "discordpage.h"
2022-08-02 12:41:32 +02:00
#include "log.h"
2022-10-10 19:50:26 +00:00
#include "mainwindow.h"
2022-07-09 22:07:14 +02:00
#include "virtmic.h"
#include <QApplication>
#include <QDesktopServices>
#include <QFile>
2023-02-15 01:59:22 +01:00
#include <QFileInfo>
2022-10-10 19:50:26 +00:00
#include <QMessageBox>
2022-10-11 19:48:57 +02:00
#include <QNetworkReply>
2022-07-09 22:07:14 +02:00
#include <QTimer>
#include <QWebChannel>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
setBackgroundColor(QColor("#202225"));
connect(this, &QWebEnginePage::featurePermissionRequested, this,
&DiscordPage::featurePermissionRequested);
2023-02-15 01:59:22 +01:00
setupPermissions();
2022-07-28 17:34:54 +02:00
2023-02-15 01:59:22 +01:00
injectFile(&DiscordPage::injectScript, "qwebchannel.js",
":/qtwebchannel/qwebchannel.js");
setUrl(QUrl("https://discord.com/app"));
setWebChannel(new QWebChannel(this));
webChannel()->registerObject("userscript", &m_userScript);
injectFile(&DiscordPage::injectScript, "userscript.js",
":/assets/userscript.js");
setupUserStyles();
}
void DiscordPage::setupPermissions() {
2022-07-09 22:07:14 +02:00
settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true);
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true);
settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent,
true);
settings()->setAttribute(
QWebEngineSettings::AllowWindowActivationFromJavaScript, true);
settings()->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true);
settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture,
false);
2022-07-27 14:53:16 +02:00
settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, false);
2022-10-10 21:54:26 +02:00
settings()->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, true);
2023-02-15 01:59:22 +01:00
}
2022-07-09 22:07:14 +02:00
2023-02-15 01:59:22 +01:00
void DiscordPage::setupUserStyles() {
auto file = new QFile(
2023-02-15 01:59:22 +01:00
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) +
"/userstyles.css");
if (file->exists()) {
qDebug(userstylesLog) << "Found userstyles:" << file->fileName();
fetchUserStyles(file);
2023-02-15 01:59:22 +01:00
}
2022-07-09 22:07:14 +02:00
}
void DiscordPage::fetchUserStyles(QFile *file) {
file->open(QIODevice::ReadOnly);
auto fileContent = file->readAll();
file->close();
QRegularExpression importRegex(
R"r(@import url\(['"]{0,1}([^'"]+?)['"]{0,1}\);)r");
QRegularExpression urlRegex(
R"r(url\(['"]{0,1}((?!data:)[^'"]+?)['"]{0,1}\))r");
bool foundImport = true;
auto match = importRegex.match(fileContent);
if (!match.hasMatch()) {
foundImport = false;
match = urlRegex.match(fileContent);
}
if (match.hasMatch()) {
auto url = match.captured(1);
if (url.toLower().contains("usrbg.css") ||
url.toLower().contains("usrbgs.css")) {
qDebug(userstylesLog)
<< "Skipping" << url << "because it we can't prefetch it";
} else {
qDebug(userstylesLog) << "Fetching" << url;
QNetworkRequest request(url);
auto reply = m_networkAccessManager.get(request);
connect(reply, &QNetworkReply::finished, [=]() {
QByteArray content = "";
if (reply->error() == QNetworkReply::NoError) {
if (!reply->attribute(QNetworkRequest::RedirectionTargetAttribute)
.isNull())
content =
reply->attribute(QNetworkRequest::RedirectionTargetAttribute)
.toByteArray();
else
content = reply->readAll();
} else
qDebug(userstylesLog) << reply->errorString().toUtf8().constData();
file->open(QIODevice::WriteOnly);
file->write(
QString(fileContent)
.replace(match.captured(0),
foundImport
? content
: "url(data:application/octet-stream;base64," +
content.toBase64() + ")")
.toUtf8()
.constData());
file->close();
fetchUserStyles(file);
});
return;
}
}
injectFile(&DiscordPage::injectStylesheet, "userstyles.js", file->fileName());
file->close();
file->deleteLater();
}
2023-02-15 01:59:22 +01:00
void DiscordPage::injectScript(
QString name, QString content,
QWebEngineScript::InjectionPoint injectionPoint) {
2022-10-10 19:50:26 +00:00
qDebug(mainLog) << "Injecting " << name;
QWebEngineScript script;
2022-07-09 22:07:14 +02:00
2022-10-10 19:50:26 +00:00
script.setSourceCode(content);
script.setName(name);
script.setWorldId(QWebEngineScript::MainWorld);
2023-02-15 01:59:22 +01:00
script.setInjectionPoint(injectionPoint);
2022-10-10 19:50:26 +00:00
script.setRunsOnSubFrames(false);
scripts().insert(script);
}
2023-02-15 01:59:22 +01:00
void DiscordPage::injectScript(QString name, QString content) {
injectScript(name, content, QWebEngineScript::DocumentCreation);
}
void DiscordPage::injectStylesheet(QString name, QString content) {
auto script = QString(R"(const stylesheet = document.createElement("style");
stylesheet.type = "text/css";
stylesheet.id = "%1";
stylesheet.innerText = `%2`;
document.head.appendChild(stylesheet);
)")
.arg(name)
.arg(content);
injectScript(name, script, QWebEngineScript::DocumentReady);
}
void DiscordPage::injectFile(void (DiscordPage::*inject)(QString, QString),
QString name, QString source) {
2022-10-11 19:48:57 +02:00
QFile file(source);
2022-07-09 22:07:14 +02:00
2022-10-11 19:48:57 +02:00
if (!file.open(QIODevice::ReadOnly)) {
2022-07-09 22:07:14 +02:00
qFatal("Failed to load %s with error: %s", source.toLatin1().constData(),
2022-10-11 19:48:57 +02:00
file.errorString().toLatin1().constData());
2022-07-09 22:07:14 +02:00
} else {
2023-02-15 01:59:22 +01:00
(this->*inject)(name, file.readAll());
2022-07-09 22:07:14 +02:00
}
}
void DiscordPage::featurePermissionRequested(const QUrl &securityOrigin,
QWebEnginePage::Feature feature) {
// Allow every permission asked
setFeaturePermission(securityOrigin, feature,
QWebEnginePage::PermissionGrantedByUser);
if (feature == QWebEnginePage::Feature::MediaAudioCapture) {
if (!m_userScript.isVirtmicRunning()) {
2022-08-02 12:41:32 +02:00
qDebug(virtmicLog) << "Starting Virtmic with no target to make sure "
"Discord can find all the audio devices";
m_userScript.startVirtmic("None");
}
}
2022-07-09 22:07:14 +02:00
}
bool DiscordPage::acceptNavigationRequest(const QUrl &url,
QWebEnginePage::NavigationType type,
bool isMainFrame) {
if (type == QWebEnginePage::NavigationTypeLinkClicked) {
QDesktopServices::openUrl(url);
return false;
}
return true;
};
2022-07-27 14:53:16 +02:00
bool ExternalPage::acceptNavigationRequest(const QUrl &url,
QWebEnginePage::NavigationType type,
bool isMainFrame) {
QDesktopServices::openUrl(url);
deleteLater();
return false;
}
QWebEnginePage *DiscordPage::createWindow(QWebEnginePage::WebWindowType type) {
return new ExternalPage;
}
2023-02-15 01:30:22 +01:00
const QMap<QString, QString> cssAnsiColorMap = {{"black", "30"},
{"red", "31"},
{"green", "32"},
{"yellow", "33"},
{"blue", "34"},
{"magenta", "35"},
{"cyan", "36"},
{"white", "37"},
{"gray", "90"},
{"bright-red", "91"},
{"bright-green", "92"},
{"bright-yellow", "93"},
{"bright-blue", "94"},
{"bright-magenta", "95"},
{"bright-cyan", "96"},
{"bright-white", "97"},
{"orange", "38;5;208"},
{"pink", "38;5;205"},
{"brown", "38;5;94"},
{"light-gray", "38;5;251"},
{"dark-gray", "38;5;239"},
{"light-red", "38;5;203"},
{"light-green", "38;5;83"},
{"light-yellow", "38;5;227"},
{"light-blue", "38;5;75"},
{"light-magenta", "38;5;207"},
{"light-cyan", "38;5;87"},
{"turquoise", "38;5;80"},
{"violet", "38;5;92"},
{"purple", "38;5;127"},
{"lavender", "38;5;183"},
{"maroon", "38;5;124"},
{"beige", "38;5;230"},
{"olive", "38;5;142"},
{"indigo", "38;5;54"},
{"teal", "38;5;30"},
{"gold", "38;5;220"},
{"silver", "38;5;7"},
{"navy", "38;5;17"},
{"steel", "38;5;188"},
{"salmon", "38;5;173"},
{"peach", "38;5;217"},
{"khaki", "38;5;179"},
{"coral", "38;5;209"},
{"crimson", "38;5;160"}};
2022-07-09 22:07:14 +02:00
void DiscordPage::javaScriptConsoleMessage(
QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message,
int lineNumber, const QString &sourceID) {
2023-02-15 01:30:22 +01:00
auto colorSegments = message.split("%c");
for (auto segment : colorSegments.mid(1)) {
auto lines = segment.split("\n");
QString ansi;
uint endOfStyles = lines.length();
for (size_t line = 1; line < lines.length(); line++) {
if (!lines[line].endsWith(";")) {
endOfStyles = line;
break;
}
if (lines[line] == "font-weight: bold;")
ansi += "\033[1m";
else if (lines[line].startsWith("color: ")) {
auto color = lines[line].mid(7).chopped(1);
if (cssAnsiColorMap.find(color) != cssAnsiColorMap.end())
ansi += "\033[" + cssAnsiColorMap[color] + "m";
}
}
qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " +
lines[endOfStyles].trimmed())
.toUtf8()
.constData();
for (auto line : lines.mid(endOfStyles + 1)) {
qDebug(discordLog) << line.toUtf8().constData();
}
}
2022-10-10 19:50:26 +00:00
}