aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeuerfuchs <git@feuerfuchs.eu>2018-11-08 22:08:26 +0100
committerFeuerfuchs <git@feuerfuchs.eu>2018-11-08 22:08:26 +0100
commitf37972b197bb998980f934435bf89bfafd8e6aa4 (patch)
tree48b354ee3e6934a80d46937af52bd987641c894e
downloadmpris-to-text-f37972b197bb998980f934435bf89bfafd8e6aa4.tar.gz
mpris-to-text-f37972b197bb998980f934435bf89bfafd8e6aa4.tar.bz2
mpris-to-text-f37972b197bb998980f934435bf89bfafd8e6aa4.zip
Init
-rw-r--r--README8
-rwxr-xr-xmusic_update.py230
2 files changed, 238 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..862a09e
--- /dev/null
+++ b/README
@@ -0,0 +1,8 @@
1# MPRIS To Text
2
3A python script that fetches data from MPRIS-compliant media players and saves it into a text file.
4
5## Required packages
6
7- [blessed](https://github.com/jquast/blessed)
8- [dbussy](https://github.com/ldo/dbussy)
diff --git a/music_update.py b/music_update.py
new file mode 100755
index 0000000..da2635f
--- /dev/null
+++ b/music_update.py
@@ -0,0 +1,230 @@
1#!/usr/bin/python
2
3import sys
4import asyncio
5import re
6import threading
7
8from blessed import Terminal
9
10import dbussy as dbus
11import ravel
12
13
14loop = asyncio.get_event_loop()
15name_regex = re.compile("^org\.mpris\.MediaPlayer2\.")
16
17bus = None
18term = Terminal()
19refresh_cond = threading.Condition()
20refresh_flag = True
21exit_flag = False
22exit_task = asyncio.Future()
23
24players = []
25player_id_to_index = {}
26active_player = ""
27current_output = ""
28
29
30def track_string(metadata):
31 artist = metadata["xesam:artist"][1][0] if "xesam:artist" in metadata else ""
32 title = metadata["xesam:title"][1] if "xesam:title" in metadata else ""
33 album = metadata["xesam:album"][1] if "xesam:album" in metadata else ""
34
35 track = ""
36 if artist != "": track = artist + " "
37 track = track + "\"" + title + "\""
38 if album != "": track = track + " from \"" + album + "\""
39
40 return track + " "
41
42
43def write_track(track):
44 global current_output
45
46 current_output = track
47 f = open("/mnt/Data/stream_info.txt", "w")
48 f.write(track)
49 f.close()
50
51
52@ravel.signal(name = "PropertiesChanged", in_signature = "sa{sv}as", args_keyword = "args")
53def playing_song_changed(args):
54 global refresh_cond
55 global refresh_flag
56
57 [ player, changed_properties, invalidated_properties ] = args
58 if "Metadata" in changed_properties:
59 write_track(track_string(changed_properties["Metadata"][1]))
60 with refresh_cond:
61 refresh_flag = True
62 refresh_cond.notify()
63
64
65@ravel.signal(name = "NameOwnerChanged", in_signature = "sss", args_keyword = "args")
66def dbus_name_owner_changed(args):
67 global refresh_cond
68 global refresh_flag
69
70 [ name, old_owner, new_owner ] = args
71 if name_regex.match(name):
72 get_players()
73 with refresh_cond:
74 refresh_flag = True
75 refresh_cond.notify()
76
77
78def set_active_player(player_id):
79 global bus
80 global active_player
81
82 if player_id in player_id_to_index:
83 active_player = player_id
84 elif len(player_id_to_index) != 0:
85 active_player = next(iter(player_id_to_index))
86 else:
87 active_player = ""
88
89 for (name, player_id) in players:
90 bus.unlisten_propchanged(
91 path = "/org/mpris/MediaPlayer2",
92 interface = name,
93 func = playing_song_changed,
94 fallback = True
95 )
96
97 if active_player != "":
98 bus.listen_propchanged(
99 path = "/org/mpris/MediaPlayer2",
100 interface = active_player,
101 func = playing_song_changed,
102 fallback = True
103 )
104
105 player_path = bus[active_player]["/org/mpris/MediaPlayer2"]
106 player_props = player_path.get_interface("org.freedesktop.DBus.Properties")
107
108 write_track(track_string(player_props.Get("org.mpris.MediaPlayer2.Player", "Metadata")[0][1]))
109 else:
110 write_track("")
111
112
113def get_players():
114 global players
115 global player_id_to_index
116
117 players = []
118 player_id_to_index = {}
119 bus_proxy = bus["org.freedesktop.DBus"]["/org/freedesktop/DBus"].get_interface("org.freedesktop.DBus")
120 names = bus_proxy.ListNames()
121
122 for name in names[0]:
123 if name_regex.match(name):
124 split_name = name.split(".")
125 id_start_index = len(split_name[0]) + len(split_name[1]) + len(split_name[2]) + 3
126
127 player_path = bus[name]["/org/mpris/MediaPlayer2"]
128 player_proxy = player_path.get_interface("org.mpris.MediaPlayer2")
129 player_id = name[id_start_index:]
130 try:
131 player_id = player_proxy.Identity
132 except AttributeError:
133 pass
134
135 players.append((name, player_id))
136 player_id_to_index[name] = len(players) - 1
137
138 set_active_player(active_player)
139
140
141def draw_menu():
142 global term
143 global players
144 global refresh_cond
145 global refresh_flag
146 global exit_flag
147 global current_output
148
149 while not exit_flag:
150 with refresh_cond:
151 while not refresh_flag and not exit_flag:
152 refresh_cond.wait()
153
154 refresh_flag = False
155
156 with term.fullscreen():
157 print(term.move(0, 0) + term.bold("MPRIS to Text") + "\n")
158
159 for i in range(len(players)):
160 player = players[i]
161 output = "%d: %s" % (i, player[1])
162
163 if players[player_id_to_index[active_player]][0] == player[0]:
164 print(term.move_x(8) + term.standout_bold(output))
165 else:
166 print(term.move_x(8) + output)
167
168 print(term.move_x(0) + "\n" + term.bold("Current output:") + " " + current_output)
169
170 print(term.move_x(0) + "\n\nEnter number to select player or q to exit." + term.move_up())
171
172 with term.fullscreen():
173 print(term.move(0, 0) + "Exiting...")
174
175
176def init_dbus():
177 global bus
178 global loop
179
180 bus = ravel.session_bus()
181 bus.attach_asyncio(loop)
182 bus.listen_signal(
183 path = "/org/freedesktop/DBus",
184 interface = "org.freedesktop.DBus",
185 name = "NameOwnerChanged",
186 func = dbus_name_owner_changed,
187 fallback = True
188 )
189
190 get_players()
191
192
193def init_blessed():
194 global bus
195 global term
196 global refresh_cond
197 global refresh_flag
198 global exit_flag
199
200 with term.cbreak():
201 val = None
202
203 while val not in (u'q', u'Q',):
204 val = term.inkey(timeout=5)
205
206 if not val or val.is_sequence or not val.isnumeric():
207 continue
208
209 if int(val) < len(players):
210 set_active_player(players[int(val)][0])
211 with refresh_cond:
212 refresh_flag = True
213 refresh_cond.notify()
214
215 with refresh_cond:
216 exit_flag = True
217 refresh_cond.notify()
218
219 exit_task.set_result(True)
220
221
222init_dbus()
223
224blessed_thread = threading.Thread(target=init_blessed)
225blessed_thread.start()
226
227menu_thread = threading.Thread(target=draw_menu)
228menu_thread.start()
229
230loop.run_until_complete(exit_task)