-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmediakey-remote.py
133 lines (110 loc) · 3.23 KB
/
mediakey-remote.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# TODO
# mediakey-remote.py
#
# service install scripts
# - linux
# - windows
# - mac
#
# externalize config
# - controller:
#
# - global
# - volume step (default: 1)
# - refresh
#
# - media keys
# - lower volume key (default: 114)
# - raise volume key (default: 115)
#
# - sonos
# - scan for controller
#
# - spotify
# - ...
#import importlib
import time
from threading import Thread
import keyboard
import soco
import toml
# global vars
config_path="/home/kbouck/dev/mediakey-remote/mediakey-remote-config.toml"
config = {}
state = ""
# load config
def load_config():
global config_path
global config
with open(config_path, 'r') as f:
config = toml.load(f)
print("Loaded config from " + config_path)
# discover sonos devices on network
# - todo: error handling
# - todo: make reconnection loop
def connect():
global sonos
global state
global volume
global volume_step
global vol_init_max
#sonos_speakers = soco.discover()
#if (len(sonos_speakers) > 0):
# print("Discovered sonos speakers:")
# for speaker in sonos_speakers:
# print(speaker.name)
#else:
# # todo - need reconnection loop
# system.exit("No sonos speakers discovered")
#sonos = sonos_speakers.pop()
sonos = soco.discovery.any_soco()
print("Connected to '" + str(sonos.player_name) + "'")
# todo - error handling if unsuccessful
state = ""
volume = 0
volume_step = config['sonos']['vol_step']
vol_init_max = config['sonos']['vol_init_max']
def play_pause():
global sonos
global state
sonos.pause() if (state == "PLAYING") else sonos.play()
transport_info = sonos.get_current_transport_info()
state = transport_info['current_transport_state']
def poll_state():
global state
global volume
while True:
volume = sonos.volume
transport_info = sonos.get_current_transport_info()
state = transport_info['current_transport_state']
time.sleep(10)
# map keys to api calls
def map_hotkeys():
global config
global sonos
keyboard.add_hotkey(config['keys']['volume_down'], lambda: sonos.set_relative_volume(volume_step*-1), trigger_on_release=False)
keyboard.add_hotkey(config['keys']['volume_up'], lambda: sonos.set_relative_volume(volume_step), trigger_on_release=False)
keyboard.add_hotkey(config['keys']['next'], lambda: sonos.next(), trigger_on_release=False)
keyboard.add_hotkey(config['keys']['previous'], lambda: sonos.previous(), trigger_on_release=False)
keyboard.add_hotkey(config['keys']['play_pause'], lambda: play_pause(), trigger_on_release=False)
# todo: mute/seek?
load_config()
# main
while True:
try:
# connect, or reconnect after exception
connect()
map_hotkeys()
# start state-polling thread
poller = Thread(name="Polling Thread", target=poll_state)
poller.start()
# block app to wait for keyboard events
keyboard.wait()
except Exception as e:
print("Exception from main:")
print(e)
except Error as e:
print("Error from main:")
print(e)
# sleep a bit to avoid a fast loop during a persistent error situation
time.sleep(1)