Skip to content

Commit 6f97e45

Browse files
committed
initial commit.
1 parent 6493d47 commit 6f97e45

File tree

4 files changed

+167
-0
lines changed

4 files changed

+167
-0
lines changed

README.md

+37
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,39 @@
11
# mediakey-remote
22
Forward media key events to remote streaming media control APIs
3+
4+
# install
5+
6+
```bash
7+
pip install
8+
9+
```
10+
11+
# start/stop
12+
```
13+
sudo systemctl start mediakey-remote.service
14+
sudo systemctl stop mediakey-remote.service
15+
```
16+
17+
# auto-start on boot
18+
```
19+
sudo systemctl enable mediakey-remote.service
20+
```
21+
22+
# config
23+
```bash
24+
/etc/opt/mediakey-remote/config.toml
25+
```
26+
27+
# logs
28+
```bash
29+
/var/opt/mediakey-remote/logs/mediakey-remote.log
30+
```
31+
32+
# build
33+
```bash
34+
# enable your venv
35+
# pip install keyboard soco pyinstaller
36+
pyinstaller mediakey-remote.py --onefile
37+
```
38+
39+

mediakey-remote-config.toml

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
[global]
2+
3+
4+
5+
[keys]
6+
volume_up = 115
7+
volume_down = 114
8+
play_pause = 164
9+
next = 163
10+
previous = 165
11+
12+
[sonos]
13+
vol_step = 1
14+
vol_init_max = 20 # if higher, lower to this volume before requesting play()
15+
# this is to avoid scaring the cat when volume is unexpectedly
16+
# high for whatever reason.
17+
# Note: this has no effect on the sonos max volume setting
18+
19+
20+
[spotify]
21+
22+

mediakey-remote.py

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# TODO
2+
# mediakey-remote.py
3+
#
4+
# service install scripts
5+
# - linux
6+
# - windows
7+
# - mac
8+
#
9+
# externalize config
10+
# - controller:
11+
#
12+
# - global
13+
# - volume step (default: 1)
14+
# - refresh
15+
#
16+
# - media keys
17+
# - lower volume key (default: 114)
18+
# - raise volume key (default: 115)
19+
#
20+
# - sonos
21+
# - scan for controller
22+
#
23+
# - spotify
24+
# - ...
25+
26+
27+
import time
28+
from threading import Thread
29+
import keyboard
30+
import soco
31+
import toml
32+
33+
34+
# load config
35+
config_path="/home/kbouck/dev/mediakey-remote/mediakey-remote-config.toml"
36+
config = {}
37+
with open(config_path, 'r') as f:
38+
config = toml.load(f)
39+
print("Loaded config from " + config_path)
40+
41+
42+
# discover sonos devices on network
43+
# - todo: error handling
44+
# - todo: make reconnection loop
45+
46+
#sonos_speakers = soco.discover()
47+
#if (len(sonos_speakers) > 0):
48+
# print("Discovered sonos speakers:")
49+
# for speaker in sonos_speakers:
50+
# print(speaker.name)
51+
#else:
52+
# # todo - need reconnection loop
53+
# system.exit("No sonos speakers discovered")
54+
#sonos = sonos_speakers.pop()
55+
56+
57+
sonos = soco.discovery.any_soco()
58+
print("Connected to '" + str(sonos.player_name) + "'")
59+
60+
state = ""
61+
volume = 0
62+
volume_step = config['sonos']['vol_step']
63+
vol_init_max = config['sonos']['vol_init_max']
64+
65+
def play_pause():
66+
global state
67+
sonos.pause() if (state == "PLAYING") else sonos.play()
68+
transport_info = sonos.get_current_transport_info()
69+
state = transport_info['current_transport_state']
70+
71+
def poll_state():
72+
global state
73+
while True:
74+
volume = sonos.volume
75+
transport_info = sonos.get_current_transport_info()
76+
state = transport_info['current_transport_state']
77+
time.sleep(10)
78+
79+
80+
# map keys to api calls
81+
keyboard.add_hotkey(config['keys']['volume_down'], lambda: sonos.set_relative_volume(volume_step*-1), trigger_on_release=False)
82+
keyboard.add_hotkey(config['keys']['volume_up'], lambda: sonos.set_relative_volume(volume_step), trigger_on_release=False)
83+
keyboard.add_hotkey(config['keys']['next'], lambda: sonos.next(), trigger_on_release=False)
84+
keyboard.add_hotkey(config['keys']['previous'], lambda: sonos.previous(), trigger_on_release=False)
85+
keyboard.add_hotkey(config['keys']['play_pause'], lambda: play_pause(), trigger_on_release=False)
86+
# todo: mute/seek?
87+
88+
# start state polling thread
89+
poller = Thread(target=poll_state)
90+
poller.start()
91+
92+
# block app to wait for keyboard events
93+
keyboard.wait()
94+
95+

mediakey-remote.service

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Unit]
2+
Description=mediakey-remote
3+
After=network.target
4+
StartLimitIntervalSec=0
5+
6+
[Service]
7+
Type=simple
8+
Restart=always
9+
RestartSec=1
10+
ExecStart=/home/kbouck/dev/mediakey-remote/dist/mediakey-remote
11+
12+
[Install]
13+
WantedBy=multi-user.target

0 commit comments

Comments
 (0)