Compare commits

..

21 Commits

Author SHA1 Message Date
6d502ea67e fix source sliders 2023-12-23 16:10:20 +01:00
165879eb0d fix color buttons 2023-12-23 15:18:14 +01:00
ed851b0eed add source volume slider, add gui config flags, add gui menu 2023-12-23 14:36:36 +01:00
6abaf515ae fix config 2023-12-21 13:26:55 +01:00
b972354e97 first step for slider class 2023-12-19 21:43:21 +01:00
dec5642e26 fix volume input sinks to handle also mono streams 2023-12-10 04:19:05 +01:00
310d396407 fix static dir 2023-12-09 12:50:16 +01:00
4594b55bf4 change colors 2023-12-09 09:29:32 +01:00
d1581e866f add label class, move empty buton to empty label 2023-10-18 20:32:51 +02:00
c50b5e1ce9 command output 2023-05-29 19:35:55 +02:00
bbda532246 move test button to debug 2023-01-16 13:02:07 +01:00
ead2b06eca cli args for host and port 2023-01-16 12:51:54 +01:00
db0a3b1655 fix app name 2022-11-20 18:24:45 +01:00
180f571018 fix json load of string including an stderr output 2022-11-08 19:43:15 +01:00
707453a513 fix json load of string including an stderr output 2022-11-08 19:39:42 +01:00
21c91b0b9c fix justpy config overwrite 2022-11-06 15:51:47 +01:00
b32a63d9b4 fix config file variable 2022-10-30 16:55:18 +01:00
a9636a4112 fix static directory 2022-10-30 16:45:24 +01:00
18af7036bb comment out xdg ref and profile 2022-10-03 02:24:49 +02:00
310d31e98d fix controldeck entry 2022-10-01 13:35:39 +02:00
6a3995f69a change style to Quasar 2022-10-01 13:16:19 +02:00
8 changed files with 1220 additions and 592 deletions

1
README
View File

@@ -1,6 +1,7 @@
Install
Requirements:
- python package justpy, the framework: pip install justpy --upgrade
- (optionally) for volume buttons: libpulse
local:

View File

@@ -1 +1 @@
2021.08.24
2022.10.01

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@ import sys
import os
import argparse
from tkinter import Tk, messagebox
from webview import create_window, start
import webview
from controldeck import config_load, process
import threading
import time
@@ -14,20 +14,73 @@ def thread_function(name):
# print("Thread %s: finishing", name)
# p = process("xdotool search --name 'ControlDeck'")
# intersection of ControlDeck window name and empty classname
p = process("comm -12 <(xdotool search --name 'ControlDeck' | sort) <(xdotool search --classname '^$' | sort)")
p = process("comm -12 <(xdotool search --name 'ControlDeck' | sort) <(xdotool search --classname '^$' | sort)", shell=True)
if p:
# print(p)
# process("xdotool search --name 'ControlDeck' set_window --class 'controldeck'", output=False)
# process("xdotool search --name 'ControlDeck' set_window --classname 'controldeck' --class 'ControlDeck' windowunmap windowmap", output=False) # will find to many wrong ids
process(f"xdotool set_window --classname 'controldeck' --class 'ControlDeck' {p} windowunmap {p} windowmap {p}", output=False)
process(f"xdotool set_window --classname 'controldeck' --class 'ControlDeck' {p} windowunmap {p} windowmap {p}", shell=True, output=False)
time.sleep(0.1)
def main(args, pid=-1):
config = config_load(conf=args.config)
host = config.get('default', 'host', fallback='0.0.0.0')
port = config.get('default', 'port', fallback='8000')
url = f"http://{host}:{port}/?gui&pid={str(pid)}"
try:
width = config.getint('gui', 'width', fallback=800)
except ValueError as e:
width = 800
print(f"Error width: {e}. fallback to: {width}")
try:
height = config.getint('gui', 'height', fallback=600)
except ValueError as e:
width = 600
print(f"Error height: {e}. fallback to {width}")
try:
x = config.getint('gui', 'x', fallback='')
except ValueError as e:
x = None
print(f"Error x: {e}. fallback to {x}")
try:
y = config.getint('gui', 'y', fallback='')
except ValueError as e:
y = None
print(f"Error y: {e}. fallback to: {y}")
resizable = config.get('gui', 'resizable', fallback='True').title() == 'True'
fullscreen = config.get('gui', 'fullscreen', fallback='False').title() == 'True'
try:
min_width = config.getint('gui', 'min_width', fallback=200)
except ValueError as e:
min_width = 200
print(f"Error min_width: {e}. fallback to: {min_width}")
try:
min_height = config.getint('gui', 'min_height', fallback=100)
except ValueError as e:
min_height = 100
print(f"Error min_height: {e}. fallback to: {min_height}")
min_size = (min_width, min_height)
frameless = config.get('gui', 'frameless', fallback='False').title() == 'True'
minimized = config.get('gui', 'minimized', fallback='False').title() == 'True'
maximized = config.get('gui', 'maximized', fallback='False').title() == 'True'
on_top = config.get('gui', 'always_on_top', fallback='False').title() == 'True'
confirm_close = config.get('gui', 'confirm_close', fallback='False').title() == 'True'
transparent = config.get('gui', 'transparent', fallback='True').title() == 'True'
gui_type = config.get('gui', 'gui_type', fallback=None)
gui_type = gui_type if gui_type != "" else None
menu = config.get('gui', 'menu', fallback='True').title() == 'True'
if args.debug:
print(f"config file [default]: {config.items('default')}")
print(f"config file [gui]: {config.items('gui')}")
#controldeck_process = process("ps --no-headers -C controldeck")
controldeck_process = process("ps --no-headers -C controldeck || ps aux | grep -e 'python.*controldeck.py' | grep -v grep")
controldeck_process = process("ps --no-headers -C controldeck || ps aux | grep -e 'python.*controldeck.py' | grep -v grep", shell=True, output=True)
if args.start and controldeck_process == "":
process("controldeck &", output=False)
cmd = "controldeck"
cmd += " --config={args.config}" if args.config else ""
print(cmd)
process(cmd, shell=True, output=False)
elif controldeck_process == "":
# cli output
@@ -42,68 +95,101 @@ def main(args, pid=-1):
sys.exit(2)
config = config_load(conf=args.config)
url = config.get('gui', 'url', fallback='http://0.0.0.0:8000') + "/?gui&pid=" + str(pid)
try:
width = int(config.get('gui', 'width', fallback=800))
except ValueError as e:
print(f"{e}")
width = 800
try:
height = int(config.get('gui', 'height', fallback=600))
except ValueError as e:
print(f"{e}")
width = 600
try:
x = int(config.get('gui', 'x', fallback=''))
except ValueError as e:
print(f"{e}")
x = None
try:
y = int(config.get('gui', 'y', fallback=''))
except ValueError as e:
print(f"{e}")
y = None
resizable = config.get('gui', 'resizable', fallback='True').title() == 'True'
fullscreen = config.get('gui', 'fullscreen', fallback='False').title() == 'True'
try:
min_width = int(config.get('gui', 'min_width', fallback=200))
except ValueError as e:
print(f"{e}")
min_width = 200
try:
min_height = int(config.get('gui', 'min_height', fallback=100))
except ValueError as e:
print(f"{e}")
min_width = 100
min_size = (min_width, min_height)
frameless = config.get('gui', 'frameless', fallback='False').title() == 'True'
minimized = config.get('gui', 'minimized', fallback='False').title() == 'True'
on_top = config.get('gui', 'always_on_top', fallback='False').title() == 'True'
create_window("ControlDeck",
url=url,
html=None,
js_api=None,
width=width,
height=height,
x=x,
y=y,
resizable=resizable,
fullscreen=fullscreen,
min_size=min_size,
hidden=False,
frameless=frameless,
easy_drag=True,
minimized=minimized,
on_top=on_top,
confirm_close=False,
background_color='#000000',
transparent=True,
text_select=False)
window = webview.create_window(
title="ControlDeck",
url=url,
html=None,
js_api=None,
width=width,
height=height,
x=x,
y=y,
screen=None,
resizable=resizable,
fullscreen=fullscreen,
min_size=min_size,
hidden=False,
frameless=frameless,
easy_drag=True,
focus=True,
minimized=minimized,
maximized=maximized,
on_top=on_top,
confirm_close=confirm_close,
background_color='#000000',
transparent=transparent, # TODO: bug in qt; menu bar is transparent
text_select=False,
zoomable=False, # zoom via js
draggable=False,
vibrancy=False,
localization=None,
)
x = threading.Thread(target=thread_function, args=(1,))
x.start()
start()
def menu_reload():
window = webview.active_window()
if window:
url = window.get_current_url()
window.load_url(url)
print(window.get_current_url())
print(window)
print(dir(window))
def menu_zoomin():
window = webview.active_window()
if window:
zoom = window.evaluate_js('document.documentElement.style.zoom')
if zoom == "":
zoom = 1.0
else:
zoom = float(zoom)
zoom += 0.1
print(f"zoom-in: {zoom}")
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
print(f"set document.documentElement.style.zoom = {zoom}")
def menu_zoomout():
window = webview.active_window()
if window:
zoom = window.evaluate_js('document.documentElement.style.zoom')
if zoom == "":
zoom = 1.0
else:
zoom = float(zoom)
zoom -= 0.1
print(f"zoom-out: {zoom}")
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
print(f"set document.documentElement.style.zoom = {zoom}")
def menu_zoomreset():
window = webview.active_window()
if window:
zoom = 1.0
print(f"zoom-reset: {zoom}")
window.evaluate_js(f'document.documentElement.style.zoom = {zoom}')
print(f"set document.documentElement.style.zoom = {zoom}")
menu_items = []
if menu:
menu_items = [webview.menu.Menu(
'Main', [
webview.menu.MenuAction('Reload', menu_reload),
webview.menu.MenuAction('zoom +', menu_zoomin),
webview.menu.MenuAction('zoom -', menu_zoomout),
webview.menu.MenuAction('zoom reset', menu_zoomreset),
]
)]
# TODO: zoom reset on reload (both from menu and within justpy)
# TODO: add zoom in config
# TODO: move zoom logic to justpy but then it is fix for all,
# maybe better a zoom argument in url address
def win_func(window):
print(window.get_current_url())
webview.start(
func=win_func,
args=window,
gui=gui_type, # TODO: bug in qt; any menu action is always the last action
debug=args.debug,
menu=menu_items,
)
def cli():
parser = argparse.ArgumentParser(

View File

@@ -6,8 +6,8 @@ After=network.target
[Service]
Environment=PYTHONUNBUFFERED=1
TimeoutStartSec=30
ExecStartPre=/bin/sh -c 'source /etc/profile'
ExecStart=/usr/bin/controldeck
#ExecStartPre=/bin/sh -c 'source /etc/profile'
ExecStart=/usr/bin/controldeck -D
Restart=on-failure
RestartSec=4
StandardOutput=journal

View File

@@ -6,8 +6,8 @@ After=network.target
[Service]
Environment=PYTHONUNBUFFERED=1
TimeoutStartSec=30
ExecStartPre=/bin/sh -c 'source /etc/profile'
ExecStart=%h/.local/bin/controldeck
#ExecStartPre=/bin/sh -c 'source /etc/profile'
ExecStart=%h/.local/bin/controldeck -D
Restart=on-failure
RestartSec=4
StandardOutput=journal

View File

@@ -1,59 +1,66 @@
# Examples:
#
# [N.volume.NAME]
# name = sink_name
# color-fg = hex color code
# color-bg = hex color code
#
# : N. optional number to specify group/row
# : NAME id, name of the button
# : name sink name, see name with either:
# pactl list sinks short
# pamixer --list-sinks
# : color-bg background color
# : color-bg forground color
#
# [N.button.NAME]
# text-alt = name
# color-fg = hex color code
# color-bg = hex color code
# command = shell command
# second command
# ...
# command-alt = shell command ...
# state = normal state
# state-command = shell command ...
# icon = Font Awesome
# icon-alt = Font Awesom
# image = path to svg file
# image-alt = path to svg file
#
# : N. optional group/row specification
# : NAME id, name of the button
# : text-alt optional alternative button text
# : color-bg background color
# : color-bg forground color
# : command command(s) to run
# : command-alt optional back-switch command(s) to run
# : state string to define the normal state
# : state-command command to get the state
# : icon use icon instead of NAME (Font Awesome), e.g.: fas fa-play
# : icon-alt optional alternative icon
# : image absolute path to svg file
# : image-alt optional alternative image
#
# [N.empty.NAME]
#
# [TAB:N.empty.NAME]
# : TAB optional tab name to specify tab group
# : N. optional number to specify group/row
# : NAME id of the empty spot
#
# [TAB:N.label.NAME]
# : TAB optional tab name to specify tab group
# : N. optional number to specify group/row
# : NAME id, name of the label
#
# [TAB:N.sink.NAME]
# : TAB optional tab name to specify tab group
# : N. optional number to specify group/row
# : NAME sink id name, see name with either:
# pactl list sinks short
# pamixer --list-sinks
# description = text for the sink
#
# [TAB:N.source.NAME]
# : TAB optional tab name to specify tab group
# : N. optional number to specify group/row
# : NAME source id name, see name with either:
# pactl list sources short
# pamixer --list-sources
# description = text for the source
#
# [TAB:N.sink-inputs]
# : TAB optional tab name to specify tab group
# : N. optional number to specify group/row
#
# [TAB:N.button.NAME]
# : TAB optional tab name to specify tab group
# : N. optional group/row specification
# : NAME id, name of the button
# text-alt = optional alternative burron text
# color-fg = foreground color as hex color code, e.g. #aa5500
# color-bg = background color as hex color code, e.g. #0055aa
# command = command(s) to run, seperated by new lines: shell command
# second command ...
# command-alt = optinal back-switch command(s) to run: shell command ...
# state-alt = string to define the alternative state (pressed)
# state-command = command to get the state: shell command ...
# icon = add icon in front of NAME (Font Awesome), e.g. fas fa-play
# icon-alt = optional alternative icon
# image = absolte path to image file (svg, png)
# image-alt = optional alternative absolue path to image file
# [TAB:N.slider.NAME]
# : TAB optional tab name to specify tab group
# : N. optional group/row specification
# : NAME id, name of the button
# description = text for the slider
[default]
host = 0.0.0.0
port = 8000
# status = False
# volume-decrease-icon = fas fa-volume-down
# volume-increase-icon = fas fa-volume-up
# volume-mute-icon = fas fa-volume-off
# volume-mute-icon-alt = fas fa-volume-mute
# volume-mute-icon-alt =
# volume-decrease-image =
# volume-increase-image =
# volume-mute-image =
@@ -68,7 +75,6 @@
# mic-mute-image-alt =
[gui]
url = http://0.0.0.0:8000
width = 800
height = 600
# x and y specifying the window coordinate (empty = centered)
@@ -80,7 +86,13 @@ min_width = 200
min_height = 100
frameless = False
minimized = False
maximized = False
always_on_top = False
confirm_close = False
transparent = True
# gui_type: qt, gtk, cef, mshtml, edgechromium. or set env PYWEBVIEW_GUI
gui_type =
menu = True
[4.button.Test]
command = notify-send -a foo baz

View File

@@ -6,12 +6,11 @@ version = file: VERSION
install_requires =
justpy
pywebview
cairosvg
py_modules =
controldeck
controldeck_gui
[options.entry_points]
console_scripts =
controldeck = controldeck:main
controldeck = controldeck:cli
controldeck-gui = controldeck_gui:cli