Compare commits

..

9 Commits

Author SHA1 Message Date
Malte Jürgens e3d87e8202 v1.7.0
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEA093du9eDGE9L3k00p+9X5PAz8MFAmPsN6oACgkQ0p+9X5PA
 z8O8pg//UBo01WAv4NwK17gLIMMjwbXIcWCcC46RaJKo0gBSJy9wFvHCQfR3qLb4
 AJDlfnbSkkJ5w3xnEruUwmgbTkBOWnxYUX/Uaq2jI7JfxYWi1AdMINg0E7GirLqs
 T1AraC5bjaIlrfohgspi9BYw8g2fBE/doQKrUC5a4vTwPYmjZZmCOkwILPTKx8Ig
 L5CmBQPnpOMtfOvwyM7h3I4FT32M2WwW79gW9XYKNf3kiXDRqqTQODMzU0iNjHq3
 STDu3lrCgpdEyNuBsZQilfCWTPCVHTggYQGv0Brv+YPRE/ELzcfFuqqQcpvZC843
 hobJIuCNfCfJN7Bu6gc2RUfNZkDQUj7Ar62j+J7PS5CVfQjpwomfeDeX94vaq8hK
 JWret1lHzabbBmeEcX41wq/WcHMGfFzk30PlLK3f1EQqdu/QUvprXV3pQDWkrqdn
 gtamTz3TIxUBWd2dbC8oaOQLB9YKPLCJy+zbPNObNMII5PU3nmHSFMafTefjjiwA
 x1t5hwxwM6ND+YsDU3XTvMVLo87enQgnNhsfQyrIRPqaIRerB02w2j++b2SCluX1
 npsJhVK/ND9aih+x/dopMXDqJTVJhLqH31KOaRz2l7KTAubY/c8gVSnVBKDTp4ez
 /RuOjBys5qXNKU/RRn9cA09xuXCkDZK7WBtHpU6vqKmEuP18ND4=
 =vRVO
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEA093du9eDGE9L3k00p+9X5PAz8MFAmPw5voACgkQ0p+9X5PA
 z8PoCg//T+mXN0/wp0/nh8T44nptqBDy28RJzzWrbxyNLx5uazU0Nq97jToiY3QI
 3XnjtqN1pv+6DQeBKpJcHX3jsUQOXXqDWeVR4gsqjBe3w54mgRTUmzFUcnUsERud
 D/HI04vV2Z2+ky5opS3eQFhy9sVPwGvEMZRTsSNMkGYESGzvOzl3SXCDW4ftNm8Q
 9Qu11BlxYxu4NNKBtvbDPVICcXk2YRdjBBQ8dN66nyrHLa3AO/tbOP9mh8mLJuDB
 WjEaG29+Xpsx5l9woLg0JakGyf2HkYuHG/G/oEUknsCJ7/MUb0iknwFWy9BdaiO+
 Dnh4ABoK0PGDpzHAR5OUomyvAfOd8AOXcFaOztT/NJ6Tj1RNZgbPKbsS+wJxYzGN
 x8xsUXhGIY/y9EqEcKolRh3JKMihtvdVjfOaeRFse0juNErewsurSx+oxcSS8jj/
 ULABMR/SpDp+h0j9HGexqNnI7htGe2egabRIMUfqfN/kKO4i5onvTbq7gpIaak6B
 W3BAzPnAes81VKgcLIcEqrPBSTuAxb1L3tNeKU3dHMeFQz2P6p3CFx/UPObIdwzv
 GdX6hzQKIg/IGh+5i31Heyh6wB1e5FhEUKxqDrE1wVOPVDkP6bHlZEW0lI2feSYM
 xjk1/w5onEOKiXvXkgC64f7wZY/VCXOaa3Ptp2hZSLuypDgNxdY=
 =D7Pe
 -----END PGP SIGNATURE-----

Merge tag 'v1.7.0' into vencord

v1.7.0
2023-02-18 15:55:54 +01:00
Malte Jürgens 700d576ff8
update vencord 2023-02-18 15:46:56 +01:00
Malte Jürgens 906deee580
vencord fixes 2022-10-25 20:27:22 +02:00
Malte Jürgens 9d9e57df1e
add about message again 2022-10-25 20:25:47 +02:00
Malte Jürgens 9eae8bbe4f
further work on vencord 2022-10-22 23:56:49 +02:00
Malte Jürgens 0493a76117
working 2022-10-15 00:15:19 +02:00
Malte Jürgens 100f9bf58e
testing 2022-10-14 23:16:34 +02:00
Malte Jürgens 1eda9d75b0
Merge branch 'master' into vencord 2022-10-11 22:21:14 +02:00
Malte Jürgens f750b76068
testing vencord 2022-10-11 19:51:09 +02:00
32 changed files with 677 additions and 1079 deletions

23
.gitignore vendored
View File

@ -1,20 +1,3 @@
# Ignore build and output directories /build
/build/ .vscode
/.flatpak-builder/ /submodules/Vencord
# Ignore flatpak-builder cache
/.flatpak-builder-cache/
# Ignore flatpak-builder log files
/*.log
# Ignore flatpak-builder generated files
/*.flatpak
/*.flatpak-builder
/*.flatpak-origin
# Ignore specific files or directories
/override.json
/metadata/
/manifest.json
/CMakeLists.txt.user

View File

@ -44,16 +44,6 @@ set(discord-screenaudio_SRC
src/streamdialog.cpp src/streamdialog.cpp
src/log.cpp src/log.cpp
src/userscript.cpp src/userscript.cpp
src/centralwidget.cpp
src/localserver.cpp
src/centralwidget.h
src/discordpage.h
src/localserver.h
src/log.h
src/mainwindow.h
src/streamdialog.h
src/userscript.h
src/virtmic.h
resources.qrc resources.qrc
) )

View File

@ -9,7 +9,7 @@ of [@edisionnano](https://github.com/edisionnano) and the
Unlike a lot of other solutions, the audio here is directly fed into the Unlike a lot of other solutions, the audio here is directly fed into the
screenshare and not passed to the user microphone screenshare and not passed to the user microphone
([see explanation](#how-does-this-work)). ([see explanation](#how-it-works)).
![Screenshot_20221211_185028](https://user-images.githubusercontent.com/48161361/206920213-58a8091a-d8f9-4bb7-ae3d-3f8581b84d24.png) ![Screenshot_20221211_185028](https://user-images.githubusercontent.com/48161361/206920213-58a8091a-d8f9-4bb7-ae3d-3f8581b84d24.png)
@ -62,9 +62,6 @@ 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:
@ -109,11 +106,9 @@ allowing access to "All system files" under the "Filesystem" section.
### Is there any way to add custom CSS / a theme? ### Is there any way to add custom CSS / a theme?
Yes, you can add all your styles into Yes, you can add all your styles into
`~/.config/discord-screenaudio/userstyles.css` (or `~/.config/discord-screenaudio/userstyles.css`. But please note that due to
`~/.var/app/de.shorsh.discord-screenaudio/config/discord-screenaudio/userstyles.css` QtWebEngine limitations concerning content security policies, you can't use any
if you are using the Flatpak). But please note that due to QtWebEngine external files (like `@import` or `url()`).
limitations concerning content security policies, you can't use any external
files (like `@import` or `url()`).
## License ## License

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
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);

View File

@ -28,7 +28,7 @@ function setGetDisplayMedia(video = true, overrideArgs = undefined) {
var id; var id;
try { try {
let myDiscordAudioSink = await getAudioDevice( let myDiscordAudioSink = await getAudioDevice(
"discord-awesomeaudio-virtmic" "discord-screenaudio-virtmic"
); );
id = myDiscordAudioSink.deviceId; id = myDiscordAudioSink.deviceId;
} catch (error) { } catch (error) {
@ -139,12 +139,10 @@ setTimeout(() => {
function main() { function main() {
userscript.muteToggled.connect(() => { userscript.muteToggled.connect(() => {
console.log("Toggling mute");
muteBtn && muteBtn.click(); muteBtn && muteBtn.click();
}); });
userscript.deafenToggled.connect(() => { userscript.deafenToggled.connect(() => {
console.log("Toggling deafen");
deafenBtn && deafenBtn.click(); deafenBtn && deafenBtn.click();
}); });
@ -159,25 +157,6 @@ function main() {
streamStartBtnClone.remove(); streamStartBtnClone.remove();
}); });
function updateUserstyles() {
userscript.log("Loading userstyles...");
userscript.loadingMessage = "Loading userstyles...";
let stylesheet = document.getElementById("discordScreenaudioUserstyles");
if (stylesheet) {
userscript.log("Removing old userstyles...");
stylesheet.remove();
}
stylesheet = document.createElement("style");
stylesheet.id = "discordScreenaudioUserstyles";
stylesheet.innerText = userscript.userstyles;
document.head.appendChild(stylesheet);
userscript.log("Finished loading userstyles");
userscript.loadingMessage = "";
}
userscript.userstylesChanged.connect(updateUserstyles);
setTimeout(() => updateUserstyles());
setInterval(async () => { setInterval(async () => {
const streamActive = const streamActive =
document.getElementsByClassName("panel-2ZFCRb activityPanel-9icbyU") document.getElementsByClassName("panel-2ZFCRb activityPanel-9icbyU")
@ -240,7 +219,7 @@ function main() {
} else { } else {
aboutEl = document.createElement("div"); aboutEl = document.createElement("div");
} }
aboutEl.innerText = `discord-awesomeaudio ${userscript.version}`; aboutEl.innerText = `discord-screenaudio ${userscript.version}`;
aboutEl.style.fontSize = "12px"; aboutEl.style.fontSize = "12px";
aboutEl.style.color = "var(--text-muted)"; aboutEl.style.color = "var(--text-muted)";
aboutEl.style.textTransform = "none"; aboutEl.style.textTransform = "none";
@ -287,11 +266,15 @@ function main() {
} }
muteBtn = buttonContainer muteBtn = buttonContainer
? buttonContainer.getElementsByTagName("button")[0] ? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[0]
: null; : null;
deafenBtn = buttonContainer deafenBtn = buttonContainer
? buttonContainer.getElementsByTagName("button")[1] ? buttonContainer.getElementsByClassName(
"button-12Fmur enabled-9OeuTA button-f2h6uQ lookBlank-21BCro colorBrand-I6CyqQ grow-2sR_-F"
)[1]
: null; : null;
if (resolutionString) { if (resolutionString) {
@ -319,7 +302,7 @@ function main() {
const title = document.createElement("h2"); const title = document.createElement("h2");
title.className = title.className =
"h1-3iMExa title-lXcL8p defaultColor-3Olr-9 defaultMarginh1-1UYutH"; "h1-3iMExa title-lXcL8p defaultColor-3Olr-9 defaultMarginh1-1UYutH";
title.innerText = "discord-awesomeaudio"; title.innerText = "discord-screenaudio";
section.appendChild(title); section.appendChild(title);
section.appendChild( section.appendChild(
@ -328,31 +311,9 @@ function main() {
}) })
); );
// section.appendChild(
// createButton("Install Theme", () => {
// userscript.showThemeDialog();
// })
// );
// section.appendChild(
// createButton("Uninstall Theme", () => {
// userscript.installUserStyles("");
// })
// );
section.appendChild( section.appendChild(
createSwitch( createSwitch(
"Allow audio from your mic (and audio you pass through) to become stereo", "Move discord-screenaudio to the system tray instead of closing",
await userscript.getBoolPref("stereoMic", false),
(enabled) => {
userscript.setStereoMic(enabled);
}
)
);
section.appendChild(
createSwitch(
"Move discord-awesomeaudio to the system tray instead of closing",
await userscript.getBoolPref("trayIcon", false), await userscript.getBoolPref("trayIcon", false),
(enabled) => { (enabled) => {
userscript.setTrayIcon(enabled); userscript.setTrayIcon(enabled);
@ -362,7 +323,7 @@ function main() {
section.appendChild( section.appendChild(
createSwitch( createSwitch(
"Start discord-awesomeaudio hidden to tray", "Start discord-screenaudio hidden to tray",
await userscript.getPref("startHidden", false), await userscript.getPref("startHidden", false),
(hidden) => { (hidden) => {
userscript.setPref("startHidden", hidden); userscript.setPref("startHidden", hidden);

View File

@ -1,85 +1,43 @@
/* let webclass;
* Vencord, a modification for Discord's desktop app
* Copyright (c) 2022 Vendicated and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
/// <reference path="../src/modules.d.ts" /> const promise = new Promise((resolve) => {
/// <reference path="../src/globals.d.ts" /> setTimeout(() => {
new QWebChannel(qt.webChannelTransport, function (channel) {
webclass = channel.objects.webclass;
resolve();
});
});
});
import monacoHtml from "~fileContent/../src/components/monacoWin.html"; async function prepareWebclass() {
import * as DataStore from "../src/api/DataStore"; if (!webclass) await promise;
import { debounce } from "../src/utils"; }
import { getTheme, Theme } from "../src/utils/discord";
// Discord deletes this so need to store in variable
const { localStorage } = window;
// listeners for ipc.on
const cssListeners = new Set<(css: string) => void>();
const NOOP = () => { };
const NOOP_ASYNC = async () => { };
const setCssDebounced = debounce((css: string) => VencordNative.quickCss.set(css));
// probably should make this less cursed at some point
window.VencordNative = { window.VencordNative = {
native: {
getVersions: () => ({}), getVersions: () => ({}),
openExternal: async (url) => void open(url, "_blank") ipc: {
send: async (event: string, ...args: any[]) => {
await prepareWebclass();
webclass.vencordSend(event, args);
}, },
sendSync: (event: string, ...args: any[]) => {
updater: { // We need this hack because Vencord requires its settings right when it starts
getRepo: async () => ({ ok: true, value: "https://github.com/Vendicated/Vencord" }), if (event === "VencordGetSettings") {
getUpdates: async () => ({ ok: true, value: [] }), return window.discordScreenaudioVencordSettings || "{}";
update: async () => ({ ok: true, value: false }), } else throw new Error("Synchroneous IPC not implemented");
rebuild: async () => ({ ok: true, value: true }),
}, },
on(event: string, listener: () => {}) {
quickCss: { // TODO quickCss
get: () => DataStore.get("VencordQuickCss").then(s => s ?? ""),
set: async (css: string) => {
await DataStore.set("VencordQuickCss", css);
cssListeners.forEach(l => l(css));
}, },
addChangeListener(cb) { off(event: string, listener: () => {}) {
cssListeners.add(cb); // not used for now
}, },
openFile: NOOP_ASYNC, invoke: async (event: string, ...args: any[]) => {
async openEditor() { await prepareWebclass();
const features = `popup,width=${Math.min(window.innerWidth, 1000)},height=${Math.min(window.innerHeight, 1000)}`; if (event === "VencordSetSettings") {
const win = open("about:blank", "VencordQuickCss", features); window.discordScreenaudioVencordSettings = args[0];
if (!win) {
alert("Failed to open QuickCSS popup. Make sure to allow popups!");
return;
} }
return webclass.vencordSend(event, args);
win.setCss = setCssDebounced;
win.getCurrentCss = () => VencordNative.quickCss.get();
win.getTheme = () =>
getTheme() === Theme.Light
? "vs-light"
: "vs-dark";
win.document.write(monacoHtml);
}, },
}, },
settings: {
get: () => localStorage.getItem("VencordSettings") || "{}",
set: async (s: string) => localStorage.setItem("VencordSettings", s),
getSettingsDir: async () => "LocalStorage"
}
}; };

View File

@ -1,11 +1,11 @@
import definePlugin from "../utils/types"; import definePlugin from "../utils/types";
export default definePlugin({ export default definePlugin({
name: "discord-awesomeaudio", name: "discord-screenaudio",
authors: [ authors: [
{ {
name: "retard", name: "maltejur",
id: 205966226709676099n, id: 205966226709676032n,
}, },
], ],
required: true, required: true,

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@ -1,42 +0,0 @@
#!/bin/bash
is_package_installed() {
if command -v "$1" >/dev/null 2>&1; then
return 0
else
return 1
fi
}
if [[ -f /etc/os-release ]]; then
. /etc/os-release
if [[ "$ID" == "ubuntu" || "$ID_LIKE" == "ubuntu" ]]; then
if ! is_package_installed flatpak-builder; then
sudo apt update
sudo apt install -y flatpak-builder
fi
elif [[ "$ID" == "fedora" || "$ID_LIKE" == "fedora" ]]; then
if ! is_package_installed flatpak-builder; then
sudo dnf install -y flatpak-builder
fi
elif [[ "$ID" == "void" ]]; then
if ! is_package_installed flatpak-builder; then
sudo xbps-install -Sy flatpak-builder
fi
fi
fi
flatpak install flathub org.kde.Sdk//5.15-22.08
flatpak install flathub io.qt.qtwebengine.BaseApp//5.15-22.08
flatpak-builder build-dir lol.deadzone.discord-awesomeaudio.json --install --user --force-clean
echo "[Desktop Entry]
Name=Discord Awesome Audio
Exec=flatpak run lol.deadzone.discord-awesomeaudio
Icon=/path/to/application/icon.png
Type=Application
Categories=AudioVideo;Network;" > ~/.local/share/applications/discord-awesomeaudio.desktop
chmod +x ~/.local/share/applications/discord-awesomeaudio.desktop

View File

@ -1,44 +0,0 @@
{
"app-id": "lol.deadzone.discord-awesomeaudio",
"runtime": "org.kde.Platform",
"runtime-version": "5.15-22.08",
"sdk": "org.kde.Sdk",
"base": "io.qt.qtwebengine.BaseApp",
"base-version": "5.15-22.08",
"command": "discord-screenaudio",
"finish-args": [
"--share=ipc",
"--share=network",
"--socket=wayland",
"--socket=fallback-x11",
"--socket=pulseaudio",
"--filesystem=xdg-videos:ro",
"--filesystem=xdg-pictures:ro",
"--filesystem=xdg-download",
"--filesystem=xdg-run/pipewire-0",
"--device=all",
"--talk-name=org.kde.StatusNotifierWatcher",
"--env=QTWEBENGINEPROCESS_PATH=/app/bin/QtWebEngineProcess",
"--talk-name=org.freedesktop.Notifications",
"--talk-name=org.kde.kglobalaccel"
],
"modules": [
{
"name": "discord-screenaudio",
"buildsystem": "cmake-ninja",
"config-opts": [
"-DCMAKE_BUILD_TYPE=RelWithDebInfo",
"-DGIT_SUBMODULE=OFF"
],
"sources": [
{
"type": "dir",
"path": "."
}
]
}
],
"finish-install": {
"desktop-file": "[Desktop Entry]\nName=Discord Awesome Audio\nExec=flatpak run lol.deadzone.discord-awesomeaudio\nIcon=/path/to/application/icon.png\nType=Application\nCategories=AudioVideo;Network;"
}
}

View File

@ -1,12 +1,8 @@
<!DOCTYPE RCC>
<RCC> <RCC>
<qresource prefix="/"> <qresource>
<file>assets/userscript.js</file> <file>assets/userscript.js</file>
<file>assets/arrpc_bridge_mod.js</file>
<file>assets/arrpc.js</file>
<file>assets/de.shorsh.discord-screenaudio.png</file>
<file>assets/vencord/vencord.js</file> <file>assets/vencord/vencord.js</file>
<file>assets/vencord/settings.patch</file> <file>assets/de.shorsh.discord-screenaudio.png</file>
<file>assets/vencord/plugin.js</file>
<file>assets/vencord/VencordNativeStub.ts</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -1,36 +0,0 @@
#!/usr/bin/bash
set -e
cd "$(dirname "$0")/../submodules"
echo_status() {
echo
echo
echo "-> $1..."
}
if [ ! -d "arrpc" ]; then
echo_status "Cloning arRPC"
git clone https://github.com/OpenAsar/arrpc.git
cd arrpc
else
echo_status "Fetching arRPC changes"
cd arrpc
git fetch
fi
echo_status "Checking out latest commit"
git reset --hard HEAD
git checkout main
echo_status "Installing dependencies"
pnpm i -D @vercel/ncc
echo_status "Patching arRPC"
sed -i 's/"type": "module",//' package.json
echo_status "Building arRPC"
pnpm exec ncc build -m src/index.js
echo_status "Copying built file"
cp -v ./dist/index.js ../../assets/arrpc.js

View File

@ -22,7 +22,7 @@ fi
echo_status "Checking out latest commit" echo_status "Checking out latest commit"
git reset --hard HEAD git reset --hard HEAD
git checkout main git checkout main
#git reset --hard devbuild git reset --hard devbuild
echo_status "Installing dependencies" echo_status "Installing dependencies"
pnpm i pnpm i

View File

@ -1,85 +0,0 @@
#include "centralwidget.h"
#include "discordpage.h"
#include "mainwindow.h"
#include <QWebEngineNotification>
#include <QWebEngineProfile>
#include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
#include <QWebEngineView>
CentralWidget::CentralWidget(QWidget *parent) : QWidget(parent) {
setStyleSheet("background-color:#313338;");
m_layout = new QVBoxLayout(this);
m_layout->setMargin(0);
m_layout->setSpacing(0);
setupWebView();
}
void CentralWidget::setupWebView() {
auto page = new DiscordPage(this);
m_webView = new QWebEngineView(this);
m_webView->setPage(page);
bool useNotifySend = MainWindow::instance()
->settings()
->value("useNotifySend", false)
.toBool();
if (m_useKF5Notifications || useNotifySend)
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
if (useNotifySend) {
auto title = notificationInfo->title();
auto message = notificationInfo->message();
auto image_path =
QString("/tmp/discord-screenaudio-%1.png").arg(title);
notificationInfo->icon().save(image_path);
QProcess::execute("notify-send",
{"--icon", image_path, "--app-name",
"discord-screenaudio", title, message});
} else if (m_useKF5Notifications) {
#ifdef KNOTIFICATIONS
KNotification *notification =
new KNotification("discordNotification");
notification->setTitle(notificationInfo->title());
notification->setText(notificationInfo->message());
notification->setPixmap(
QPixmap::fromImage(notificationInfo->icon()));
notification->setDefaultAction("View");
connect(notification, &KNotification::defaultActivated,
[&, notificationInfo = std::move(notificationInfo)]() {
notificationInfo->click();
show();
activateWindow();
});
notification->sendEvent();
#endif
}
});
connect(page->userScript(), &UserScript::loadingMessageChanged, this,
&CentralWidget::setLoadingIndicator);
m_layout->addWidget(m_webView);
}
void CentralWidget::setLoadingIndicator(QString text) {
if (text != "") {
if (m_loadingLabel == nullptr) {
m_loadingLabel = new QLabel(this);
m_loadingLabel->setMaximumHeight(20);
m_loadingLabel->setAlignment(Qt::AlignHCenter);
m_loadingLabel->setStyleSheet("color:#dedede;");
m_layout->addWidget(m_loadingLabel);
}
m_loadingLabel->setText(text.mid(0, 100));
} else {
if (m_loadingLabel != nullptr) {
m_layout->removeWidget(m_loadingLabel);
m_loadingLabel->deleteLater();
m_loadingLabel = nullptr;
}
}
}

View File

@ -1,35 +0,0 @@
#ifndef CENTRALWIDGET_H
#define CENTRALWIDGET_H
#include <QLabel>
#include <QVBoxLayout>
#include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QWebEngineView>
#include <QWidget>
#ifdef KNOTIFICATIONS
constexpr bool USE_KF5_NOTIFICATIONS = true;
#else
constexpr bool USE_KF5_NOTIFICATIONS = false;
#endif
class CentralWidget : public QWidget {
Q_OBJECT
public:
CentralWidget(QWidget *parent = nullptr);
public slots:
void setLoadingIndicator(QString text);
private:
void setupWebView();
QVBoxLayout *m_layout;
QWebEngineView *m_webView;
QLabel *m_loadingLabel;
bool m_useKF5Notifications;
};
#endif // CENTRALWIDGET_H

View File

@ -9,7 +9,6 @@
#include <QFileInfo> #include <QFileInfo>
#include <QMessageBox> #include <QMessageBox>
#include <QNetworkReply> #include <QNetworkReply>
#include <QTemporaryFile>
#include <QTimer> #include <QTimer>
#include <QWebChannel> #include <QWebChannel>
#include <QWebEngineScript> #include <QWebEngineScript>
@ -17,12 +16,10 @@
#include <QWebEngineSettings> #include <QWebEngineSettings>
DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) { DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
setBackgroundColor(QColor("#313338")); setBackgroundColor(QColor("#202225"));
connect(this, &QWebEnginePage::featurePermissionRequested, this, connect(this, &QWebEnginePage::featurePermissionRequested, this,
&DiscordPage::featurePermissionRequested); &DiscordPage::featurePermissionRequested);
connect(this, &DiscordPage::fullScreenRequested, MainWindow::instance(),
&MainWindow::fullScreenRequested);
setupPermissions(); setupPermissions();
@ -34,6 +31,9 @@ DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
setWebChannel(new QWebChannel(this)); setWebChannel(new QWebChannel(this));
webChannel()->registerObject("userscript", &m_userScript); webChannel()->registerObject("userscript", &m_userScript);
injectFile(&DiscordPage::injectScript, "userscript.js",
":/assets/userscript.js");
injectFile(&DiscordPage::injectScript, "userscript.js", injectFile(&DiscordPage::injectScript, "userscript.js",
":/assets/userscript.js"); ":/assets/userscript.js");
QFile vencord(":/assets/vencord/vencord.js"); QFile vencord(":/assets/vencord/vencord.js");
@ -46,8 +46,8 @@ DiscordPage::DiscordPage(QWidget *parent) : QWebEnginePage(parent) {
.arg(m_userScript.vencordSend("VencordGetSettings", {}).toString(), .arg(m_userScript.vencordSend("VencordGetSettings", {}).toString(),
vencord.readAll())); vencord.readAll()));
vencord.close(); vencord.close();
setupUserStyles(); setupUserStyles();
setupArrpc();
} }
void DiscordPage::setupPermissions() { void DiscordPage::setupPermissions() {
@ -65,79 +65,13 @@ void DiscordPage::setupPermissions() {
} }
void DiscordPage::setupUserStyles() { void DiscordPage::setupUserStyles() {
qDebug(userstylesLog).noquote() QString file =
<< "Looking for userstyles in" << m_configLocation.absolutePath(); QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) +
m_userStylesFile = "/userstyles.css";
new QFile(m_configLocation.absoluteFilePath("userstyles.css")); if (QFileInfo(file).exists()) {
if (m_userStylesFile->exists()) { qDebug(mainLog) << "Found userstyles:" << file;
qDebug(userstylesLog).noquote() injectFile(&DiscordPage::injectStylesheet, "userstyles.js", file);
<< "Found userstyles:" << m_userStylesFile->fileName();
m_userStylesFile->open(QIODevice::ReadOnly);
m_userStylesContent = m_userStylesFile->readAll();
m_userStylesFile->close();
fetchUserStyles();
} }
connect(&m_userScript, &UserScript::shouldInstallUserStyles, this,
&DiscordPage::getUserStyles);
}
const QRegularExpression importRegex(
R"r(@import (?:url\(|)['"]{0,1}(?!.*usrbgs?\.css)([^'"]+?)['"]{0,1}(?:|\));)r");
const QRegularExpression urlRegex(
R"r(url\(['"]{0,1}((?!https:\/\/fonts.gstatic.com)(?!data:)(?!.*\.woff2)(?!.*\.ttf)[^'"]+?)['"]{0,1}\))r");
void DiscordPage::fetchUserStyles() {
m_userScript.setProperty(
"loadingMessage", "Loading userstyles: Fetching additional resources...");
bool foundImport = true;
auto match = importRegex.match(m_userStylesContent);
if (!match.hasMatch()) {
foundImport = false;
match = urlRegex.match(m_userStylesContent);
}
if (match.hasMatch()) {
auto url = match.captured(1);
qDebug(userstylesLog) << "Fetching" << url;
m_userScript.setProperty(
"loadingMessage",
QString("Loading userstyles: Fetching %1...").arg(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();
reply->deleteLater();
m_userStylesContent = m_userStylesContent.replace(
match.captured(0), foundImport
? content
: "url(data:application/octet-stream;base64," +
content.toBase64() + ")");
fetchUserStyles();
});
return;
}
qDebug(userstylesLog) << "Injecting userstyles";
m_userScript.setProperty("userstyles", m_userStylesContent);
m_userScript.setProperty("loadingMessage", "");
if (!m_configLocation.exists())
m_configLocation.mkpath(".");
m_userStylesFile->open(QIODevice::WriteOnly);
m_userStylesFile->write(m_userStylesContent.toUtf8());
m_userStylesFile->close();
}
void DiscordPage::getUserStyles(QString url) {
m_userStylesContent = url == "" ? "" : QString("@import url(%1);").arg(url);
fetchUserStyles();
} }
void DiscordPage::injectScript( void DiscordPage::injectScript(
@ -162,6 +96,7 @@ void DiscordPage::injectScript(QString name, QString content) {
void DiscordPage::injectStylesheet(QString name, QString content) { void DiscordPage::injectStylesheet(QString name, QString content) {
auto script = QString(R"(const stylesheet = document.createElement("style"); auto script = QString(R"(const stylesheet = document.createElement("style");
stylesheet.type = "text/css";
stylesheet.id = "%1"; stylesheet.id = "%1";
stylesheet.innerText = `%2`; stylesheet.innerText = `%2`;
document.head.appendChild(stylesheet); document.head.appendChild(stylesheet);
@ -270,15 +205,11 @@ void DiscordPage::javaScriptConsoleMessage(
QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message, QWebEnginePage::JavaScriptConsoleMessageLevel level, const QString &message,
int lineNumber, const QString &sourceID) { int lineNumber, const QString &sourceID) {
auto colorSegments = message.split("%c"); auto colorSegments = message.split("%c");
if (colorSegments[0] != "") {
for (auto line : colorSegments[0].split("\n"))
qDebug(discordLog) << line.toUtf8().constData();
}
for (auto segment : colorSegments.mid(1)) { for (auto segment : colorSegments.mid(1)) {
auto lines = segment.split("\n"); auto lines = segment.split("\n");
QString ansi; QString ansi;
uint endOfStyles = lines.length(); uint endOfStyles = lines.length();
for (auto line = 1; line < lines.length(); line++) { for (size_t line = 1; line < lines.length(); line++) {
if (!lines[line].endsWith(";")) { if (!lines[line].endsWith(";")) {
endOfStyles = line; endOfStyles = line;
break; break;
@ -291,9 +222,10 @@ void DiscordPage::javaScriptConsoleMessage(
ansi += "\033[" + cssAnsiColorMap[color] + "m"; ansi += "\033[" + cssAnsiColorMap[color] + "m";
} }
} }
if (endOfStyles < lines.length())
qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " + qDebug(discordLog) << (ansi + lines[0].trimmed() + "\033[0m " +
lines[endOfStyles].trimmed()) ((lines.length() > endOfStyles)
? lines[endOfStyles].trimmed()
: ""))
.toUtf8() .toUtf8()
.constData(); .constData();
for (auto line : lines.mid(endOfStyles + 1)) { for (auto line : lines.mid(endOfStyles + 1)) {
@ -301,21 +233,3 @@ void DiscordPage::javaScriptConsoleMessage(
} }
} }
} }
UserScript *DiscordPage::userScript() { return &m_userScript; }
void DiscordPage::setupArrpc() {
QFile nodejs("/usr/bin/node");
if (nodejs.exists()) {
auto arrpcSource = QTemporaryFile::createNativeFile(":/assets/arrpc.js");
qDebug(mainLog).noquote()
<< "NodeJS found, starting arRPC located at" << arrpcSource->fileName();
m_arrpcProcess.setProcessChannelMode(QProcess::ForwardedChannels);
m_arrpcProcess.setProgram(nodejs.fileName());
m_arrpcProcess.setArguments(QStringList{arrpcSource->fileName()});
m_arrpcProcess.start();
injectFile(&DiscordPage::injectScript, "arrpc_bridge_mod.js",
":/assets/arrpc_bridge_mod.js");
}
}

View File

@ -1,12 +1,9 @@
#pragma once #pragma once
#include "streamdialog.h"
#include "userscript.h" #include "userscript.h"
#include "virtmic.h"
#include <QDir>
#include <QFile>
#include <QNetworkAccessManager>
#include <QProcess>
#include <QStandardPaths>
#include <QWebEngineFullScreenRequest> #include <QWebEngineFullScreenRequest>
#include <QWebEnginePage> #include <QWebEnginePage>
#include <QWebEngineScript> #include <QWebEngineScript>
@ -16,20 +13,11 @@ class DiscordPage : public QWebEnginePage {
public: public:
explicit DiscordPage(QWidget *parent = nullptr); explicit DiscordPage(QWidget *parent = nullptr);
UserScript *userScript();
private: private:
UserScript m_userScript; UserScript m_userScript;
QFile *m_userStylesFile;
QString m_userStylesContent;
QNetworkAccessManager m_networkAccessManager;
QProcess m_arrpcProcess;
const QDir m_configLocation =
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
void setupPermissions(); void setupPermissions();
void setupUserStyles(); void setupUserStyles();
void setupArrpc();
void fetchUserStyles();
bool acceptNavigationRequest(const QUrl &url, bool acceptNavigationRequest(const QUrl &url,
QWebEnginePage::NavigationType type, QWebEnginePage::NavigationType type,
bool isMainFrame) override; bool isMainFrame) override;
@ -48,9 +36,6 @@ private:
private Q_SLOTS: private Q_SLOTS:
void featurePermissionRequested(const QUrl &securityOrigin, void featurePermissionRequested(const QUrl &securityOrigin,
QWebEnginePage::Feature feature); QWebEnginePage::Feature feature);
public Q_SLOTS:
void getUserStyles(QString url);
}; };
// Will immediately get destroyed again but is needed for navigation to // Will immediately get destroyed again but is needed for navigation to

View File

@ -1,22 +0,0 @@
#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();
}

View File

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

View File

@ -5,4 +5,3 @@ Q_LOGGING_CATEGORY(discordLog, "discord");
Q_LOGGING_CATEGORY(userscriptLog, "userscript"); Q_LOGGING_CATEGORY(userscriptLog, "userscript");
Q_LOGGING_CATEGORY(virtmicLog, "virtmic"); Q_LOGGING_CATEGORY(virtmicLog, "virtmic");
Q_LOGGING_CATEGORY(shortcutLog, "shortcut"); Q_LOGGING_CATEGORY(shortcutLog, "shortcut");
Q_LOGGING_CATEGORY(userstylesLog, "userstyles");

View File

@ -7,4 +7,3 @@ Q_DECLARE_LOGGING_CATEGORY(discordLog);
Q_DECLARE_LOGGING_CATEGORY(userscriptLog); Q_DECLARE_LOGGING_CATEGORY(userscriptLog);
Q_DECLARE_LOGGING_CATEGORY(virtmicLog); Q_DECLARE_LOGGING_CATEGORY(virtmicLog);
Q_DECLARE_LOGGING_CATEGORY(shortcutLog); Q_DECLARE_LOGGING_CATEGORY(shortcutLog);
Q_DECLARE_LOGGING_CATEGORY(userstylesLog);

View File

@ -1,4 +1,3 @@
#include "localserver.h"
#include "mainwindow.h" #include "mainwindow.h"
#include "virtmic.h" #include "virtmic.h"
@ -8,19 +7,15 @@
#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-awesomeaudio");
QApplication::setWindowIcon( QApplication::setWindowIcon(
QIcon(":assets/de.shorsh.discord-screenaudio.png")); QIcon(":assets/de.shorsh.discord-screenaudio.png"));
QApplication::setApplicationVersion(DISCORD_SCEENAUDIO_VERSION_FULL); QApplication::setApplicationVersion(DISCORD_SCEENAUDIO_VERSION_FULL);
QApplication::setDesktopFileName("lol.deadzone.discord-awesomeaudio"); QApplication::setDesktopFileName("de.shorsh.discord-screenaudio");
qSetMessagePattern("[%{category}] %{message}"); qSetMessagePattern("[%{category}] %{message}");
@ -55,20 +50,6 @@ 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-awesomeaudio";
if (isProgramRunning(program_name)) {
// if running show error message
showErrorMessage("discord-awesomeaudio 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,53 +12,29 @@
#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>
#include <QUrl> #include <QUrl>
#include <QWebEngineFullScreenRequest> #include <QWebEngineNotification>
#include <QWebEngineProfile> #include <QWebEngineProfile>
#include <QWebEngineUrlRequestInterceptor> #include <QWebEngineScript>
#include <QWebEngineScriptCollection>
#include <QWebEngineSettings>
#include <QWidget> #include <QWidget>
// Custom network interceptor class
class NetworkInterceptor : public QWebEngineUrlRequestInterceptor {
public:
NetworkInterceptor(QObject* parent = nullptr) : QWebEngineUrlRequestInterceptor(parent) {}
void interceptRequest(QWebEngineUrlRequestInfo& info) override {
// Modify the request headers here as needed
info.setHttpHeader("Access-Control-Allow-Origin", "*");
info.setHttpHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
}
};
MainWindow *MainWindow::m_instance = nullptr; MainWindow *MainWindow::m_instance = nullptr;
MainWindow::MainWindow(bool useNotifySend, QWidget *parent) MainWindow::MainWindow(bool useNotifySend, QWidget *parent)
: QMainWindow(parent) { : QMainWindow(parent) {
assert(MainWindow::m_instance == nullptr); assert(MainWindow::m_instance == nullptr);
MainWindow::m_instance = this; MainWindow::m_instance = this;
m_useNotifySend = useNotifySend;
setupSettings(); setupSettings();
m_settings->setValue("useNotifySend", useNotifySend); setupWebView();
m_centralWidget = new CentralWidget(this);
setCentralWidget(m_centralWidget);
// Create and install the network interceptor
NetworkInterceptor* networkInterceptor = new NetworkInterceptor(this);
QWebEngineProfile::defaultProfile()->setRequestInterceptor(networkInterceptor);
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")) {
restoreGeometry(m_settings->value("geometry").toByteArray());
} else {
resize(1000, 700); resize(1000, 700);
showMaximized(); showMaximized();
}
if (m_settings->value("trayIcon", false).toBool() && if (m_settings->value("trayIcon", false).toBool() &&
m_settings->value("startHidden", false).toBool()) { m_settings->value("startHidden", false).toBool()) {
hide(); hide();
@ -66,14 +42,54 @@ MainWindow::MainWindow(bool useNotifySend, QWidget *parent)
} }
} }
void MainWindow::setupWebView() {
auto page = new DiscordPage(this);
connect(page, &QWebEnginePage::fullScreenRequested, this,
&MainWindow::fullScreenRequested);
m_webView = new QWebEngineView(this);
m_webView->setPage(page);
if (m_useKF5Notifications || m_useNotifySend)
QWebEngineProfile::defaultProfile()->setNotificationPresenter(
[&](std::unique_ptr<QWebEngineNotification> notificationInfo) {
if (m_useNotifySend) {
auto title = notificationInfo->title();
auto message = notificationInfo->message();
auto image_path =
QString("/tmp/discord-screenaudio-%1.png").arg(title);
notificationInfo->icon().save(image_path);
QProcess::execute("notify-send",
{"--icon", image_path, "--app-name",
"discord-screenaudio", title, message});
} else if (m_useKF5Notifications) {
#ifdef KNOTIFICATIONS
KNotification *notification =
new KNotification("discordNotification");
notification->setTitle(notificationInfo->title());
notification->setText(notificationInfo->message());
notification->setPixmap(
QPixmap::fromImage(notificationInfo->icon()));
notification->setDefaultAction("View");
connect(notification, &KNotification::defaultActivated,
[&, notificationInfo = std::move(notificationInfo)]() {
notificationInfo->click();
show();
activateWindow();
});
notification->sendEvent();
#endif
}
});
setCentralWidget(m_webView);
}
void MainWindow::fullScreenRequested( void MainWindow::fullScreenRequested(
QWebEngineFullScreenRequest fullScreenRequest) { QWebEngineFullScreenRequest fullScreenRequest) {
fullScreenRequest.accept(); fullScreenRequest.accept();
if (fullScreenRequest.toggleOn()) { if (fullScreenRequest.toggleOn()) {
m_wasMaximized = isMaximized(); m_wasMaximized = isMaximized();
if (!m_wasMaximized) {
showNormal();
}
showFullScreen(); showFullScreen();
} else { } else {
m_wasMaximized ? showMaximized() : showNormal(); m_wasMaximized ? showMaximized() : showNormal();
@ -86,7 +102,7 @@ void MainWindow::setupTrayIcon() {
return; return;
auto aboutAction = new QAction( auto aboutAction = new QAction(
"discord-awesomeaudio v" + QString(DISCORD_SCEENAUDIO_VERSION_FULL), this); "discord-screenaudio v" + QString(DISCORD_SCEENAUDIO_VERSION_FULL), this);
aboutAction->setIcon(QIcon(":assets/de.shorsh.discord-screenaudio.png")); aboutAction->setIcon(QIcon(":assets/de.shorsh.discord-screenaudio.png"));
aboutAction->setEnabled(false); aboutAction->setEnabled(false);
@ -104,7 +120,12 @@ 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) {
toggleOrCloseWindow(); if (isVisible()) {
hide();
} else {
show();
activateWindow();
}
} }
}); });
} }
@ -120,8 +141,7 @@ void MainWindow::cleanTrayIcon() {
} }
void MainWindow::setupSettings() { void MainWindow::setupSettings() {
m_settings = m_settings = new QSettings("maltejur", "discord-screenaudio", this);
new QSettings("discord-awesomeaudio", "discord-awesomeaudio", this);
m_settings->beginGroup("settings"); m_settings->beginGroup("settings");
m_settings->endGroup(); m_settings->endGroup();
} }
@ -140,26 +160,8 @@ void MainWindow::setTrayIcon(bool enabled) {
void MainWindow::closeEvent(QCloseEvent *event) { void MainWindow::closeEvent(QCloseEvent *event) {
if (m_settings->value("trayIcon", false).toBool()) { if (m_settings->value("trayIcon", false).toBool()) {
hide(); hide();
} else { } else
m_settings->setValue("geometry", saveGeometry());
QApplication::quit(); QApplication::quit();
}
} }
MainWindow *MainWindow::instance() { return m_instance; } MainWindow *MainWindow::instance() { return m_instance; }
CentralWidget *MainWindow::centralWidget() {
return instance()->m_centralWidget;
};
void MainWindow::toggleOrCloseWindow() {
if (isVisible()) {
if (m_trayIcon == nullptr)
QApplication::quit();
else
hide();
} else {
show();
activateWindow();
}
}

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "centralwidget.h" #include "discordpage.h"
#include <QMainWindow> #include <QMainWindow>
#include <QMenu> #include <QMenu>
@ -8,9 +8,10 @@
#include <QSettings> #include <QSettings>
#include <QString> #include <QString>
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#include <QVBoxLayout>
#include <QVector> #include <QVector>
#include <QWebEngineUrlRequestInterceptor> #include <QWebEnginePage>
#include <QWebEngineProfile>
#include <QWebEngineView>
class MainWindow : public QMainWindow { class MainWindow : public QMainWindow {
Q_OBJECT Q_OBJECT
@ -19,22 +20,31 @@ public:
explicit MainWindow(bool useNotifySend = false, QWidget *parent = nullptr); explicit MainWindow(bool useNotifySend = false, QWidget *parent = nullptr);
static MainWindow *instance(); static MainWindow *instance();
QSettings *settings() const; QSettings *settings() const;
static CentralWidget *centralWidget();
private: private:
void setupWebView();
void setupTrayIcon(); void setupTrayIcon();
void cleanTrayIcon(); void cleanTrayIcon();
void setupSettings(); void setupSettings();
QWebEngineView *m_webView;
QWebEngineProfile *prepareProfile();
DiscordPage *m_discordPage;
void closeEvent(QCloseEvent *event) override; void closeEvent(QCloseEvent *event) override;
QSystemTrayIcon *m_trayIcon = nullptr; QSystemTrayIcon *m_trayIcon = nullptr;
QMenu *m_trayIconMenu; QMenu *m_trayIconMenu;
QSettings *m_settings; QSettings *m_settings;
bool m_wasMaximized; bool m_wasMaximized;
static MainWindow *m_instance; static MainWindow *m_instance;
CentralWidget *m_centralWidget; bool m_useNotifySend;
#ifdef KNOTIFICATIONS
bool m_useKF5Notifications = true;
#else
bool m_useKF5Notifications = false;
#endif
public Q_SLOTS: public Q_SLOTS:
void setTrayIcon(bool enabled); void setTrayIcon(bool enabled);
private Q_SLOTS:
void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest); void fullScreenRequested(QWebEngineFullScreenRequest fullScreenRequest);
void toggleOrCloseWindow();
}; };

View File

@ -4,9 +4,9 @@
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#include <QDesktopServices>
#include <QDir>
#include <QFile> #include <QFile>
#include <QInputDialog>
#include <QMessageBox>
#include <QStandardPaths> #include <QStandardPaths>
#include <QTimer> #include <QTimer>
@ -21,7 +21,6 @@ UserScript::UserScript() : QObject() {
setupVirtmic(); setupVirtmic();
} }
void UserScript::setupHelpMenu() { void UserScript::setupHelpMenu() {
#ifdef KXMLGUI #ifdef KXMLGUI
m_kxmlgui = true; m_kxmlgui = true;
@ -45,10 +44,6 @@ 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
} }
@ -67,7 +62,7 @@ void UserScript::setupShortcutsDialog() {
auto toggleDeafenAction = new QAction(this); auto toggleDeafenAction = new QAction(this);
toggleDeafenAction->setText("Toggle Deafen"); toggleDeafenAction->setText("Toggle Deafen");
toggleDeafenAction->setIcon(QIcon::fromTheme("audio-volume-muted")); toggleDeafenAction->setIcon(QIcon::fromTheme("audio-volume-muted"));
connect(toggleDeafenAction, &QAction::triggered, this, connect(toggleMuteAction, &QAction::triggered, this,
&UserScript::deafenToggled); &UserScript::deafenToggled);
m_actionCollection = new KActionCollection(this); m_actionCollection = new KActionCollection(this);
@ -84,7 +79,8 @@ void UserScript::setupShortcutsDialog() {
void UserScript::setupStreamDialog() { void UserScript::setupStreamDialog() {
m_streamDialog = new StreamDialog(MainWindow::instance()); m_streamDialog = new StreamDialog(MainWindow::instance());
connect(m_streamDialog, &StreamDialog::requestedStreamStart, this, &UserScript::startStream); connect(m_streamDialog, &StreamDialog::requestedStreamStart, this,
&UserScript::startStream);
} }
void UserScript::setupVirtmic() { void UserScript::setupVirtmic() {
@ -155,13 +151,13 @@ void UserScript::startVirtmic(QString target) {
m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target}); m_virtmicProcess.start(QApplication::arguments()[0], {"--virtmic", target});
} }
void UserScript::startStream(bool video, bool audio, int width, int height, int frameRate, QString target) { void UserScript::startStream(bool video, bool audio, int width, int height,
int frameRate, QString target) {
stopVirtmic(); stopVirtmic();
startVirtmic(audio ? target : "[None]"); startVirtmic(audio ? target : "[None]");
// Wait a bit for the virtmic to start // Wait a bit for the virtmic to start
QTimer::singleShot(200, [=]() { QTimer::singleShot(
emit streamStarted(video, width, height, frameRate); 200, [=]() { emit streamStarted(video, width, height, frameRate); });
});
} }
void UserScript::showStreamDialog() { void UserScript::showStreamDialog() {
@ -172,16 +168,6 @@ void UserScript::showStreamDialog() {
m_streamDialog->updateTargets(); m_streamDialog->updateTargets();
} }
void UserScript::showThemeDialog() {
auto url = QInputDialog::getText(MainWindow::instance(), "Theme Installation", "Please enter the URL of the Theme");
if (url != "")
emit shouldInstallUserStyles(url);
}
void UserScript::installUserStyles(QString url) {
emit shouldInstallUserStyles(url);
}
QVariant UserScript::vencordSend(QString event, QVariantList args) { QVariant UserScript::vencordSend(QString event, QVariantList args) {
QString configFolder = QString configFolder =
QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) + QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation) +

View File

@ -1,10 +1,9 @@
#pragma once #pragma once
#include "streamdialog.h" #include "streamdialog.h"
#include <QProcess>
#include <QObject> #include <QObject>
#include <QDir> #include <QProcess>
#include <QDesktopServices>
#ifdef KXMLGUI #ifdef KXMLGUI
#include <KAboutData> #include <KAboutData>
@ -19,53 +18,38 @@
#endif #endif
#ifdef KNOTIFICATIONS
#include <KNotification>
#endif
class UserScript : public QObject { class UserScript : public QObject {
Q_OBJECT Q_OBJECT
public: public:
UserScript(); UserScript();
bool isVirtmicRunning(); bool isVirtmicRunning();
Q_PROPERTY(QString version READ version CONSTANT) Q_PROPERTY(QString version READ version CONSTANT);
Q_PROPERTY(bool kxmlgui MEMBER m_kxmlgui CONSTANT) Q_PROPERTY(bool kxmlgui MEMBER m_kxmlgui CONSTANT);
Q_PROPERTY(bool kglobalaccel MEMBER m_kglobalaccel CONSTANT) Q_PROPERTY(bool kglobalaccel MEMBER m_kglobalaccel CONSTANT);
Q_PROPERTY(QString userstyles MEMBER m_userstyles NOTIFY userstylesChanged)
Q_PROPERTY(QString loadingMessage MEMBER m_loadingMessage NOTIFY loadingMessageChanged)
private: private:
QProcess m_virtmicProcess; QProcess m_virtmicProcess;
StreamDialog *m_streamDialog; StreamDialog *m_streamDialog;
bool m_kxmlgui = false; bool m_kxmlgui = false;
bool m_kglobalaccel = false; bool m_kglobalaccel = false;
QString m_userstyles;
QString m_loadingMessage;
QString m_vencordSettings;
void setupHelpMenu();
void setupShortcutsDialog();
void setupStreamDialog();
void setupVirtmic();
#ifdef KXMLGUI #ifdef KXMLGUI
KHelpMenu *m_helpMenu; KHelpMenu *m_helpMenu;
#ifdef KGLOBALACCEL #ifdef KGLOBALACCEL
KActionCollection *m_actionCollection; KActionCollection *m_actionCollection;
KShortcutsDialog *m_shortcutsDialog; KShortcutsDialog *m_shortcutsDialog;
#endif #endif
#endif #endif
QString m_vencordSettings;
void setupHelpMenu();
void setupShortcutsDialog();
void setupStreamDialog();
void setupVirtmic();
Q_SIGNALS: Q_SIGNALS:
void muteToggled(); void muteToggled();
void deafenToggled(); void deafenToggled();
void streamStarted(bool video, int width, int height, int frameRate); void streamStarted(bool video, int width, int height, int frameRate);
void userstylesChanged();
void loadingMessageChanged(QString message);
void shouldInstallUserStyles(QString url);
public Q_SLOTS: public Q_SLOTS:
void log(QString message); void log(QString message);
@ -79,11 +63,9 @@ public Q_SLOTS:
void showStreamDialog(); void showStreamDialog();
void stopVirtmic(); void stopVirtmic();
void startVirtmic(QString target); void startVirtmic(QString target);
void showThemeDialog();
void installUserStyles(QString url);
QVariant vencordSend(QString event, QVariantList args); QVariant vencordSend(QString event, QVariantList args);
private Q_SLOTS: private Q_SLOTS:
void startStream(bool video, bool audio, int width, int height, int frameRate, QString target); void startStream(bool video, bool audio, int width, int height, int frameRate,
QString target);
}; };

View File

@ -6,26 +6,7 @@
namespace Virtmic { namespace Virtmic {
const QStringList EXCLUDE_TARGETS{"Chromium input", "discord-awesomeaudio", "pavucontrol", "PulseAudio Volume Control", "OBS", "OBS-Monitor", "OBS/OBS-MONITOR"}; 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();
@ -41,7 +22,14 @@ 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 = qGetTarget(info.props); QString name;
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);
@ -85,12 +73,12 @@ void start(QString _target) {
continue; continue;
auto &parent = nodes.at(parent_id); auto &parent = nodes.at(parent_id);
std::string name = getTarget(parent.props); std::string name;
if (EXCLUDE_TARGETS.contains(QString::fromStdString(name))) if (parent.props.count("application.name") &&
continue; parent.props["application.name"] != "")
name = parent.props["application.name"];
if (parent.props.count("media.class") && (parent.props.at("media.class") == "Audio/Source" || parent.props.at("media.class") == "Audio/Source/Virtual")) else
continue; name = parent.props["application.process.binary"];
if (name == target || if (name == target ||
(target == "[All Desktop Audio]" && (target == "[All Desktop Audio]" &&
@ -111,10 +99,10 @@ void start(QString _target) {
} }
}; };
std::string target = _target.toUtf8().toStdString(); std::string target = _target.toLatin1().toStdString();
auto virtual_mic = core.create("adapter", auto virtual_mic = core.create("adapter",
{{"node.name", "discord-awesomeaudio-virtmic"}, {{"node.name", "discord-screenaudio-virtmic"},
{"media.class", "Audio/Source/Virtual"}, {"media.class", "Audio/Source/Virtual"},
{"factory.name", "support.null-audio-sink"}, {"factory.name", "support.null-audio-sink"},
{"audio.channels", "2"}, {"audio.channels", "2"},
@ -135,8 +123,13 @@ 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 = getTarget(info.props); std::string name;
if (name == nullstr) if (info.props.count("application.name") &&
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))
@ -175,9 +168,12 @@ 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 = getTarget(info.props); std::string name;
if (name == nullstr) if (info.props.count("application.name") &&
return; info.props["application.name"] != "")
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()

@ -1 +0,0 @@
Subproject commit 62b2acebe6806c7b0e2ca6a43c6b2419a627b8dc

View File

@ -1,2 +0,0 @@
flatpak remove lol.deadzone.discord-awesomeaudio
rm ~/.local/share/applications/discord-awesomeaudio.desktop

View File

@ -1,3 +0,0 @@
git pull
./uninstall.sh
./install.sh