Compare commits

..

17 Commits

Author SHA1 Message Date
Malte Jürgens
94b27f5b6a implement ctrl+q keybind 2023-06-23 17:48:54 +02:00
Malte Jürgens
8a6f49b949 Merge pull request #149 from Vitalya-code/master
Move two functions into separate file
2023-04-27 18:04:34 +00:00
Malte Jürgens
47fd620876 fix formatting 2023-04-27 20:04:04 +02:00
Vitalya
c15250498b Move server function to the bottom and change "utils" file name to "localserver" 2023-04-27 19:52:28 +03:00
Vitalya
6f0303206e Move two functions into separate file 2023-04-27 17:21:03 +03:00
Malte Jürgens
6e86647c95 Merge pull request #148 from Vitalya-code/master
Shows error message to user if discord is running
2023-04-25 16:33:21 +00:00
Vitalya
798fb3d5e4 Minor change in error message
Change "Discord" to "discord-screenaudio" in error message
2023-04-25 15:07:25 +03:00
Malte Jürgens
6c9b76ed90 format code 2023-04-24 22:41:36 +02:00
Vitalya
b582584c69 Shows error message to user if discord is running 2023-04-24 19:58:56 +03:00
Malte Jürgens
7b6e8fc473 fix segfault in console code 2023-04-18 21:31:22 +02:00
Malte Jürgens
8f0a810539 virtmic: also use nodes which only have a node.name 2023-04-17 15:42:19 +02:00
Malte Jürgens
a6eb82948f add dnf dependencies 2023-04-17 09:51:10 +02:00
Malte Jürgens
24727f398a Merge pull request #133 from mensinda/latin2utf8
Do not convert to Latin1 and use UTF-8 instead
2023-04-03 17:26:55 +00:00
Daniel Mensinger
c43e9953a5 Do not convert to Latin1 and use UTF-8 instead 2023-04-03 17:20:53 +02:00
Malte Jürgens
08cb713e8c add arRPC component to about 2023-03-23 23:14:00 +01:00
Malte Jürgens
27faed4a3a set minimum window size 2023-03-19 14:44:25 +01:00
Malte Jürgens
10fff86ca4 minify js assets 2023-03-13 11:59:28 +01:00
14 changed files with 129 additions and 5758 deletions

View File

@@ -14,29 +14,28 @@ string(TIMESTAMP TIMESTAMP %s)
# set(CMAKE_AUTOUIC ON) # set(CMAKE_AUTOUIC ON)
find_package(Qt5 COMPONENTS Widgets) find_package(Qt5 COMPONENTS Widgets)
if (Qt5_FOUND AND NOT DEFINED USE_QT6) if (Qt5_FOUND)
message(STATUS "Using Qt 5")
find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets) find_package(Qt5 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets)
find_package(KF5Notifications)
if(KF5Notifications_FOUND)
add_definitions( -DKNOTIFICATIONS )
endif()
find_package(KF5XmlGui)
if(KF5XmlGui_FOUND)
add_definitions( -DKXMLGUI )
endif()
find_package(KF5GlobalAccel)
if(KF5GlobalAccel_FOUND)
add_definitions( -DKGLOBALACCEL )
endif()
else() else()
message(STATUS "Using Qt 6") message(WARNING "Qt 5 was not found on your system and Qt 6 will be used. You will not be able to use any features using KDE Frameworks.")
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets) find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets WebEngineWidgets)
endif() endif()
find_package(KF5Notifications)
if(KF5Notifications_FOUND)
add_definitions( -DKNOTIFICATIONS )
endif()
find_package(KF5XmlGui)
if(KF5XmlGui_FOUND)
add_definitions( -DKXMLGUI )
endif()
find_package(KF5GlobalAccel)
if(KF5GlobalAccel_FOUND)
add_definitions( -DKGLOBALACCEL )
endif()
set(discord-screenaudio_SRC set(discord-screenaudio_SRC
src/main.cpp src/main.cpp
src/mainwindow.cpp src/mainwindow.cpp
@@ -46,6 +45,7 @@ set(discord-screenaudio_SRC
src/log.cpp src/log.cpp
src/userscript.cpp src/userscript.cpp
src/centralwidget.cpp src/centralwidget.cpp
src/localserver.cpp
resources.qrc resources.qrc
) )

View File

@@ -62,6 +62,9 @@ You have multiple options:
With apt: With apt:
`apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev libkf5xmlgui-dev libkf5globalaccel-dev pkg-config libpipewire-0.3-dev git` `apt install -y build-essential cmake qtbase5-dev qtwebengine5-dev libkf5notifications-dev libkf5xmlgui-dev libkf5globalaccel-dev pkg-config libpipewire-0.3-dev git`
With dnf:
`dnf install @development-tools cmake qt5-qtbase-devel qt5-qtwebengine-devel kf5-knotifications-devel kf5-kxmlgui-devel kf5-kglobalaccel-devel pkgconfig pipewire-devel git`
### Building ### Building
First, clone the repository: First, clone the repository:

File diff suppressed because one or more lines are too long

View File

@@ -1,65 +1 @@
setTimeout(e => { setTimeout((i=>{let t,a,s,e={};new WebSocket("ws://127.0.0.1:1337").onmessage=async i=>{if(msg=JSON.parse(i.data),console.log(msg),!t){const i=window.webpackChunkdiscord_app.push([[Symbol()],{},i=>i]),e=i.c;window.webpackChunkdiscord_app.pop();for(const i in e){let a=e[i].exports;if(a=a&&(a.Z??a.ZP),a&&a.register&&a.wait){t=a;break}}const n=i.m;for(const t in n)if(n[t].toString().includes("getAssetImage: size must === [number, number] for Twitch")){const s=i(t),e=Object.values(s).find((i=>"function"==typeof i&&i.toString().includes("apply(")));a=async(i,t)=>(await e(i,[t,void 0]))[0];break}for(const t in n)if(n[t].toString().includes("e.application={")){const a=i(t),e=Object.values(a).find((i=>"function"==typeof i&&i.toString().includes("e.application={")));s=async i=>{let t={};return await e(t,i),t.application};break}}if(msg.activity?.assets?.large_image&&(msg.activity.assets.large_image=await a(msg.activity.application_id,msg.activity.assets.large_image)),msg.activity?.assets?.small_image&&(msg.activity.assets.small_image=await a(msg.activity.application_id,msg.activity.assets.small_image)),msg.activity){const i=msg.activity.application_id;e[i]||(e[i]=await s(i));const t=e[i];msg.activity.name||(msg.activity.name=t.name)}t.dispatch({type:"LOCAL_ACTIVITY_UPDATE",...msg})}}),1e4);
let Dispatcher, lookupAsset, lookupApp, apps = {};
const ws = new WebSocket('ws://127.0.0.1:1337'); // connect to arRPC bridge websocket
ws.onmessage = async x => {
msg = JSON.parse(x.data);
console.log(msg);
if (!Dispatcher) {
const wpRequire = window.webpackChunkdiscord_app.push([[Symbol()], {}, x => x]);
const cache = wpRequire.c;
window.webpackChunkdiscord_app.pop();
for (const id in cache) {
let mod = cache[id].exports;
mod = mod && (mod.Z ?? mod.ZP);
if (mod && mod.register && mod.wait) {
Dispatcher = mod;
break;
}
}
const factories = wpRequire.m;
for (const id in factories) {
if (factories[id].toString().includes('getAssetImage: size must === [number, number] for Twitch')) {
const mod = wpRequire(id);
const _lookupAsset = Object.values(mod).find(e => typeof e === "function" && e.toString().includes("apply("));
lookupAsset = async (appId, name) => (await _lookupAsset(appId, [name, undefined]))[0];
break;
}
}
for (const id in factories) {
if (factories[id].toString().includes(`e.application={`)) {
const mod = wpRequire(id);
const _lookupApp = Object.values(mod).find(e => typeof e === "function" && e.toString().includes(`e.application={`));
lookupApp = async appId => {
let socket = {};
await _lookupApp(socket, appId);
return socket.application;
};
break;
}
}
}
if (msg.activity?.assets?.large_image) msg.activity.assets.large_image = await lookupAsset(msg.activity.application_id, msg.activity.assets.large_image);
if (msg.activity?.assets?.small_image) msg.activity.assets.small_image = await lookupAsset(msg.activity.application_id, msg.activity.assets.small_image);
if (msg.activity) {
const appId = msg.activity.application_id;
if (!apps[appId]) apps[appId] = await lookupApp(appId);
const app = apps[appId];
if (!msg.activity.name) msg.activity.name = app.name;
}
Dispatcher.dispatch({ type: "LOCAL_ACTIVITY_UPDATE", ...msg }); // set RPC status
};
}, 10000)

View File

@@ -30,7 +30,7 @@ echo_status "Patching arRPC"
sed -i 's/"type": "module",//' package.json sed -i 's/"type": "module",//' package.json
echo_status "Building arRPC" echo_status "Building arRPC"
pnpm exec ncc build src/index.js pnpm exec ncc build -m src/index.js
echo_status "Copying built file" echo_status "Copying built file"
cp -v ./dist/index.js ../../assets/arrpc.js cp -v ./dist/index.js ../../assets/arrpc.js

View File

@@ -11,6 +11,7 @@
CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) { CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) {
setStyleSheet("background-color:#313338;"); setStyleSheet("background-color:#313338;");
m_layout = new QVBoxLayout(this); m_layout = new QVBoxLayout(this);
m_layout->setMargin(0);
m_layout->setSpacing(0); m_layout->setSpacing(0);
setupWebView(); setupWebView();
} }

View File

@@ -282,10 +282,11 @@ void DiscordPage::javaScriptConsoleMessage(
ansi += "\033[" + cssAnsiColorMap[color] + "m"; ansi += "\033[" + cssAnsiColorMap[color] + "m";
} }
} }
qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " + if (endOfStyles < lines.length())
lines[endOfStyles].trimmed()) qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " +
.toUtf8() lines[endOfStyles].trimmed())
.constData(); .toUtf8()
.constData();
for (auto line : lines.mid(endOfStyles + 1)) { for (auto line : lines.mid(endOfStyles + 1)) {
qDebug(discordLog) << line.toUtf8().constData(); qDebug(discordLog) << line.toUtf8().constData();
} }

22
src/localserver.cpp Normal file
View File

@@ -0,0 +1,22 @@
#include "localserver.h"
bool isProgramRunning(const QString &program_name) {
QLocalSocket socket;
socket.connectToServer(program_name);
if (socket.waitForConnected()) {
return true; // program is already running
}
return false;
}
void showErrorMessage(const char *text) {
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setText(text);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setWindowIcon(QIcon(":assets/de.shorsh.discord-screenaudio.png"));
msgBox.exec();
}

9
src/localserver.h Normal file
View File

@@ -0,0 +1,9 @@
#pragma once
#include "mainwindow.h"
#include <QLocalServer>
#include <QLocalSocket>
#include <QMessageBox>
bool isProgramRunning(const QString &program_name);
void showErrorMessage(const char *text);

View File

@@ -1,3 +1,4 @@
#include "localserver.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "virtmic.h" #include "virtmic.h"
@@ -7,10 +8,14 @@
#include <QApplication> #include <QApplication>
#include <QCommandLineParser> #include <QCommandLineParser>
#include <QLocalServer>
#include <QLocalSocket>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QMessageBox>
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
QApplication app(argc, argv); QApplication app(argc, argv);
QApplication::setApplicationName("discord-screenaudio"); QApplication::setApplicationName("discord-screenaudio");
QApplication::setWindowIcon( QApplication::setWindowIcon(
QIcon(":assets/de.shorsh.discord-screenaudio.png")); QIcon(":assets/de.shorsh.discord-screenaudio.png"));
@@ -50,6 +55,20 @@ int main(int argc, char *argv[]) {
qgetenv("QTWEBENGINE_CHROMIUM_FLAGS")); qgetenv("QTWEBENGINE_CHROMIUM_FLAGS"));
MainWindow w(parser.isSet(notifySendOption)); MainWindow w(parser.isSet(notifySendOption));
// Check if discord is already running
QString program_name = "discord-screenaudio";
if (isProgramRunning(program_name)) {
// if running show error message
showErrorMessage("discord-screenaudio is already running");
return 1;
}
// open server so we can check if discord is running
QLocalServer server;
server.listen(program_name);
QObject::connect(&server, &QLocalServer::newConnection, []() {});
w.show(); w.show();
return app.exec(); return app.exec();

View File

@@ -12,6 +12,7 @@
#include <QGridLayout> #include <QGridLayout>
#include <QLabel> #include <QLabel>
#include <QPushButton> #include <QPushButton>
#include <QShortcut>
#include <QSpacerItem> #include <QSpacerItem>
#include <QThread> #include <QThread>
#include <QTimer> #include <QTimer>
@@ -30,6 +31,9 @@ MainWindow::MainWindow(bool useNotifySend, QWidget *parent)
m_centralWidget = new CentralWidget(this); m_centralWidget = new CentralWidget(this);
setCentralWidget(m_centralWidget); setCentralWidget(m_centralWidget);
setupTrayIcon(); setupTrayIcon();
setMinimumSize(800, 300);
connect(new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q), this),
&QShortcut::activated, this, &MainWindow::toggleOrCloseWindow);
if (m_settings->contains("geometry")) { if (m_settings->contains("geometry")) {
restoreGeometry(m_settings->value("geometry").toByteArray()); restoreGeometry(m_settings->value("geometry").toByteArray());
} else { } else {
@@ -78,12 +82,7 @@ void MainWindow::setupTrayIcon() {
connect(m_trayIcon, &QSystemTrayIcon::activated, [this](auto reason) { connect(m_trayIcon, &QSystemTrayIcon::activated, [this](auto reason) {
if (reason == QSystemTrayIcon::Trigger) { if (reason == QSystemTrayIcon::Trigger) {
if (isVisible()) { toggleOrCloseWindow();
hide();
} else {
show();
activateWindow();
}
} }
}); });
} }
@@ -130,3 +129,15 @@ MainWindow *MainWindow::instance() { return m_instance; }
CentralWidget *MainWindow::centralWidget() { CentralWidget *MainWindow::centralWidget() {
return instance()->m_centralWidget; return instance()->m_centralWidget;
}; };
void MainWindow::toggleOrCloseWindow() {
if (isVisible()) {
if (m_trayIcon == nullptr)
QApplication::quit();
else
hide();
} else {
show();
activateWindow();
}
}

View File

@@ -36,4 +36,5 @@ private:
public Q_SLOTS: public Q_SLOTS:
void setTrayIcon(bool enabled); void setTrayIcon(bool enabled);
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
void toggleOrCloseWindow();
}; };

View File

@@ -44,6 +44,10 @@ void UserScript::setupHelpMenu() {
QString(), "https://github.com/Curve"); QString(), "https://github.com/Curve");
aboutData.addComponent("Rohrkabel", "A C++ RAII Pipewire-API Wrapper", "1.3", aboutData.addComponent("Rohrkabel", "A C++ RAII Pipewire-API Wrapper", "1.3",
"https://github.com/Soundux/rohrkabel"); "https://github.com/Soundux/rohrkabel");
aboutData.addComponent("arRPC",
"An open implementation of Discord's local RPC "
"servers<br>Copyright (c) 2022 OpenAsar",
nullptr, "https://github.com/OpenAsar/arrpc");
m_helpMenu = new KHelpMenu(MainWindow::instance(), aboutData); m_helpMenu = new KHelpMenu(MainWindow::instance(), aboutData);
#endif #endif
} }

View File

@@ -8,6 +8,25 @@ namespace Virtmic {
const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-screenaudio"}; const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-screenaudio"};
const std::string nullstr = "";
const std::string &getTarget(const pipewire::spa::dict &props) {
if (props.count("media.class") &&
props.at("media.class") == "Stream/Output/Audio") {
if (props.count("application.name") && props.at("application.name") != "")
return props.at("application.name");
else if (props.count("application.process.binary") &&
props.at("application.process.binary") != "")
return props.at("application.process.binary");
else
return props.at("node.name");
} else
return nullstr;
}
QString qGetTarget(const pipewire::spa::dict &props) {
return QString::fromStdString(getTarget(props));
}
QVector<QString> getTargets() { QVector<QString> getTargets() {
auto main_loop = pipewire::main_loop(); auto main_loop = pipewire::main_loop();
auto context = pipewire::context(main_loop); auto context = pipewire::context(main_loop);
@@ -22,14 +41,7 @@ QVector<QString> getTargets() {
if (global.type == pipewire::node::type) { if (global.type == pipewire::node::type) {
auto node = reg.bind<pipewire::node>(global.id); auto node = reg.bind<pipewire::node>(global.id);
auto info = node.info(); auto info = node.info();
QString name; QString name = qGetTarget(info.props);
if (info.props.count("application.name") &&
info.props["application.name"] != "")
name = QString::fromStdString(info.props["application.name"]);
else
name = QString::fromStdString(
info.props["application.process.binary"]);
if (name != "" && !EXCLUDE_TARGETS.contains(name) && if (name != "" && !EXCLUDE_TARGETS.contains(name) &&
!targets.contains(name)) { !targets.contains(name)) {
targets.append(name); targets.append(name);
@@ -73,13 +85,7 @@ void start(QString _target) {
continue; continue;
auto &parent = nodes.at(parent_id); auto &parent = nodes.at(parent_id);
std::string name; std::string name = getTarget(parent.props);
if (parent.props.count("application.name") &&
parent.props["application.name"] != "")
name = parent.props["application.name"];
else
name = parent.props["application.process.binary"];
if (name == target || if (name == target ||
(target == "[All Desktop Audio]" && (target == "[All Desktop Audio]" &&
!EXCLUDE_TARGETS.contains(QString::fromStdString(name)))) { !EXCLUDE_TARGETS.contains(QString::fromStdString(name)))) {
@@ -99,7 +105,7 @@ void start(QString _target) {
} }
}; };
std::string target = _target.toLatin1().toStdString(); std::string target = _target.toUtf8().toStdString();
auto virtual_mic = core.create("adapter", auto virtual_mic = core.create("adapter",
{{"node.name", "discord-screenaudio-virtmic"}, {{"node.name", "discord-screenaudio-virtmic"},
@@ -123,13 +129,8 @@ void start(QString _target) {
if (global.type == pipewire::node::type) { if (global.type == pipewire::node::type) {
auto node = reg.bind<pipewire::node>(global.id); auto node = reg.bind<pipewire::node>(global.id);
auto info = node.info(); auto info = node.info();
std::string name; std::string name = getTarget(info.props);
if (info.props.count("application.name") && if (name == nullstr)
info.props["application.name"] != "")
name = info.props["application.name"];
else if (info.props.count("application.process.binary")) {
name = info.props["application.process.binary"];
} else
return; return;
qDebug(virtmicLog) << QString("Added: %1") qDebug(virtmicLog) << QString("Added: %1")
.arg(QString::fromStdString(name)) .arg(QString::fromStdString(name))
@@ -168,12 +169,9 @@ void start(QString _target) {
[&](const std::uint32_t id) { [&](const std::uint32_t id) {
if (nodes.count(id)) { if (nodes.count(id)) {
auto info = nodes.at(id); auto info = nodes.at(id);
std::string name; std::string name = getTarget(info.props);
if (info.props.count("application.name") && if (name == nullstr)
info.props["application.name"] != "") return;
name = info.props["application.name"];
else
name = info.props["application.process.binary"];
qDebug(virtmicLog) << QString("Removed: %1") qDebug(virtmicLog) << QString("Removed: %1")
.arg(QString::fromStdString(name)) .arg(QString::fromStdString(name))
.toUtf8() .toUtf8()