Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
640 changes: 639 additions & 1 deletion .pylintrc

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions CODING
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Attempts have been made to keep this project meeting PEP8 standards. While
meeting this standard would be nice pull request & patch acceptance will
Attempts have been made to keep this project readable, using pylint and python black.
While meeting this standard would be nice pull request & patch acceptance will
be based on merit first and coding standard second.

Due to a quirk in the way pygobject functions and the fact we use soft
Expand Down
17 changes: 3 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,29 +147,18 @@ It is advised to install python-gobject from your system's own package manager.

#### Debian/Ubuntu

`apt install python3-gi python3-gi-cairo libappindicator3-dev`
`apt install python4-gi gtk4-layer-shell libgtk4-layer-shell-dev`

Libappindicator might conflict with other installed packages, but is optional

with Wayland support

`apt install gtk-layer-shell libgtk-layer-shell-dev`

#### Arch

`pacman -S python-gobject libappindicator-gtk3`

with Wayland support

`pacman -S gtk-layer-shell`
`pacman -S python-gobject gtk4-layer-shell`

#### Fedora

`dnf install python3-pip python3-gobject gtk3-devel python3-cairo python-devel python-gobject python-gobject-devel`

with Wayland support
`dnf install python3-pip python3-gobject gtk4-devel python3-cairo python-devel python-gobject python-gobject-devel gtk4-layer-shell`

`dnf install gtk-layer-shell`

## Usage

Expand Down
1 change: 1 addition & 0 deletions _version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.8.0"
25 changes: 14 additions & 11 deletions discover_overlay/audio_assist.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@ def __init__(self, discover):

self.thread = None
self.enabled = False
self.source = None # String containing the name of the PA/PW microphone or other input

# String containing the name of the PA/PW microphone or other input
self.source = None

self.sink = None # String containing the name of the PA/PW output

self.discover = discover
Expand Down Expand Up @@ -68,9 +71,9 @@ def thread_loop(self):
async def listen(self):
"""Async to connect to pulse and listen for events"""
try:
async with pulsectl_asyncio.PulseAsync('Discover-Monitor') as pulse:
async with pulsectl_asyncio.PulseAsync("Discover-Monitor") as pulse:
await self.get_device_details(pulse)
async for event in pulse.subscribe_events('all'):
async for event in pulse.subscribe_events("all"):
await self.handle_events(pulse, event)
except pulsectl.pulsectl.PulseDisconnected:
log.info("Pulse has gone away")
Expand Down Expand Up @@ -118,28 +121,28 @@ async def get_device_details(self, pulse):
self.discover.set_mute_async(mute)

async def handle_events(self, pulse, ev):
""" `Sink` and `Source` events are fired for changes to output and inputs
`Server` is fired when default sink or source changes."""
"""`Sink` and `Source` events are fired for changes to output and inputs
`Server` is fired when default sink or source changes."""
if not self.enabled:
return

match ev.facility:
case 'sink':
case "sink":
await self.get_device_details(pulse)

case 'source':
case "source":
await self.get_device_details(pulse)

case 'server':
case "server":
await self.get_device_details(pulse)

case 'source_output':
case "source_output":
pass

case 'sink_input':
case "sink_input":
pass

case 'client':
case "client":
pass

case _:
Expand Down
57 changes: 11 additions & 46 deletions discover_overlay/autostart.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"""A class to assist auto-start"""
import os
import logging
import shutil

try:
from xdg.BaseDirectory import xdg_config_home, xdg_data_home
except ModuleNotFoundError:
Expand All @@ -30,14 +30,17 @@ def __init__(self, app_name):
if not app_name.endswith(".desktop"):
app_name = f"{app_name}.desktop"
self.app_name = app_name
self.auto_locations = [os.path.join(
xdg_config_home, 'autostart/'), '/etc/xdg/autostart/']
self.desktop_locations = [os.path.join(
xdg_data_home, 'applications/'), '/usr/share/applications/']
self.auto_locations = [
os.path.join(xdg_config_home, "autostart/"),
"/etc/xdg/autostart/",
]
self.desktop_locations = [
os.path.join(xdg_data_home, "applications/"),
"/usr/share/applications/",
]
self.auto = self.find_auto()
self.desktop = self.find_desktop()
log.info("Autostart info : desktop %s auto %s",
self.desktop, self.auto)
log.info("Autostart info : desktop %s auto %s", self.desktop, self.auto)

def find_auto(self):
"""Check all known locations for auto-started apps"""
Expand All @@ -59,7 +62,7 @@ def set_autostart(self, enable):
"""Set or Unset auto-start state"""
if enable and not self.auto:
# Enable
directory = os.path.join(xdg_config_home, 'autostart')
directory = os.path.join(xdg_config_home, "autostart")
self.auto = os.path.join(directory, self.app_name)
os.makedirs(directory, exist_ok=True)
os.symlink(self.desktop, self.auto)
Expand All @@ -71,41 +74,3 @@ def set_autostart(self, enable):
def is_auto(self):
"""Check if it's already set to auto-start"""
return True if self.auto else False


class BazziteAutostart:
"""A class to assist auto-start"""

def __init__(self):
self.auto = False
with open("/etc/default/discover-overlay", encoding="utf-8") as f:
content = f.readlines()
for line in content:
if line.startswith("AUTO_LAUNCH_DISCOVER_OVERLAY="):
self.auto = int(line.split("=")[1]) > 0
log.info("Bazzite Autostart info : %s",
self.auto)

def set_autostart(self, enable):
"""Set or Unset auto-start state"""
if enable and not self.auto:
self.change_file("1")
elif not enable and self.auto:
self.change_file("0")
self.auto = enable

def change_file(self, value):
"""Alter bazzite config via pkexec and sed"""
root = ''
if shutil.which('pkexec'):
root = 'pkexec'
else:
log.error("No ability to request root privs. Cancel")
return
command = f" sed -i 's/AUTO_LAUNCH_DISCOVER_OVERLAY=./AUTO_LAUNCH_DISCOVER_OVERLAY={value}/g' /etc/default/discover-overlay"
command_with_permissions = root + command
os.system(command_with_permissions)

def is_auto(self):
"""Check if it's already set to auto-start"""
return self.auto
13 changes: 13 additions & 0 deletions discover_overlay/connection_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Enum of states of discover connection to discord"""

from enum import Enum


class ConnectionState(Enum):
"""Possible states of service"""

NO_DISCORD = 0 # We havn't managed to reach Discord on localhost
DISCORD_INVALID = 1 # Port connection works but turns away RPC.
NO_VOICE_CHAT = 2 # We're connected but the user is not in a room
VOICE_CHAT_NOT_CONNECTED = 3 # We've chosen a room but not successfully connected to it yet (or connection has degraded)
CONNECTED = 4 # Connected and working
56 changes: 56 additions & 0 deletions discover_overlay/css_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# 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/>.
"""Functions to assist font picking"""
import gi
import json

gi.require_version("Gtk", "4.0")
from gi.repository import Gtk, Pango


# https://toshiocp.github.io/Gtk4-tutorial/sec23.html
# TODO Weights, Italics
def desc_to_css_font(desc):
"""Formats a font description into a CSS rule"""
if desc.get_size_is_absolute():
size = f"{desc.get_size() / Pango.SCALE}px"
else:
size = f"{desc.get_size() / Pango.SCALE}pt"
mods = ""
family = desc.get_family()
font = f'{size} {mods} "{family}"'
return font


def font_string_to_css_font_string(string_in):
"""Takes a string of uncertain origin and feeds it into a
Gtk.FontButton in the hopes of turning it into a font
description, then turning that into a CSS rule"""
if string_in[0].isnumeric(): # If it starts with a number it is Probably correct
return string_in
# It might be an old-style font string...
fb = Gtk.FontButton()
fb.set_font(string_in)
return desc_to_css_font(fb.get_font_desc())


def col_to_css(col):
"""Convert a JSON-encoded string or a tuple into a CSS colour"""
if isinstance(col, str):
col = json.loads(col)
assert len(col) == 4
red = int(col[0] * 255)
green = int(col[1] * 255)
blue = int(col[2] * 255)
alpha = col[3]
return f"rgba({red},{green},{blue},{alpha:2.2f})"
Loading