aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFeuerfuchs <git@feuerfuchs.eu>2018-11-20 23:11:58 +0100
committerFeuerfuchs <git@feuerfuchs.eu>2018-11-20 23:11:58 +0100
commitf61ef2fa53df9449845f4523f469d3a3a696f45f (patch)
tree46971e4aaf8b6d155a8ad35d32182c7f2c01e6c8
parentRemove dependency on dbussy/ravel (diff)
downloadmpris-to-text-f61ef2fa53df9449845f4523f469d3a3a696f45f.tar.gz
mpris-to-text-f61ef2fa53df9449845f4523f469d3a3a696f45f.tar.bz2
mpris-to-text-f61ef2fa53df9449845f4523f469d3a3a696f45f.zip
Cleanup
-rwxr-xr-xmpris_to_text.py374
1 files changed, 186 insertions, 188 deletions
diff --git a/mpris_to_text.py b/mpris_to_text.py
index 16ee1e0..24baabf 100755
--- a/mpris_to_text.py
+++ b/mpris_to_text.py
@@ -16,230 +16,227 @@ from blessed import Terminal
16dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 16dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
17 17
18 18
19name_regex = re.compile("^org\.mpris\.MediaPlayer2\.") 19class MetaWriter:
20bus = dbus.SessionBus() 20 filename = ""
21term = Terminal() 21 output_format = ""
22 output_format_artist = ""
23 output_format_title = ""
24 output_format_album = ""
25 last_output = ""
22 26
23refresh_cond = threading.Condition() 27 def __init__(self, filename, output_format, output_format_artist, output_format_title, output_format_album):
24refresh_flag = True 28 self.filename = filename
25exit_flag = False 29 self.output_format = output_format
30 self.output_format_album = output_format_album
31 self.output_format_artist = output_format_artist
32 self.output_format_title = output_format_title
26 33
27players = [] 34 def write_meta(self, metadata):
28player_id_to_index = {} 35 artist = metadata["xesam:artist"][0] if "xesam:artist" in metadata else ""
29active_player = "" 36 title = metadata["xesam:title"] if "xesam:title" in metadata else ""
30current_output = "" 37 album = metadata["xesam:album"] if "xesam:album" in metadata else ""
31playing_song_changed_signal_receiver = None
32 38
33filename = "" 39 self.write(self.output_format.format(
34meta_format = "" 40 artist = self.output_format_artist.format(artist) if artist != "" else "",
35meta_format_artist = "" 41 title = self.output_format_title.format(title) if title != "" else "",
36meta_format_title = "" 42 album = self.output_format_album.format(album) if album != "" else ""
37meta_format_album = "" 43 ))
38 44
45 def write(self, text):
46 self.last_output = text
47 f = open(self.filename, "w")
48 f.write(text)
49 f.close()
39 50
40def track_string(metadata):
41 artist = metadata["xesam:artist"][0] if "xesam:artist" in metadata else ""
42 title = metadata["xesam:title"] if "xesam:title" in metadata else ""
43 album = metadata["xesam:album"] if "xesam:album" in metadata else ""
44 51
45 return meta_format.format( 52class PlayerSelector(threading.Thread):
46 artist = meta_format_artist.format(artist) if artist != "" else "", 53 service_regex = re.compile("^org\.mpris\.MediaPlayer2\.")
47 title = meta_format_title.format(title) if title != "" else "", 54 bus = None
48 album = meta_format_album.format(album) if album != "" else "" 55 loop = None
49 ) 56 signal_receiver = None
50 57 players = {}
51 58 players_indexes = []
52def write_track(track): 59 active_player = ""
53 global filename 60 menu = None
54 global current_output 61 meta_writer = None
55
56 current_output = track
57 f = open(filename, "w")
58 f.write(track)
59 f.close()
60 62
63 def __init__(self, meta_writer, menu=None):
64 super().__init__()
61 65
62def playing_song_changed(player, changed_properties, invalidated_properties): 66 self.bus = dbus.SessionBus()
63 global refresh_cond 67 self.meta_writer = meta_writer
64 global refresh_flag 68 self.menu = menu
65 69
66 if "Metadata" in changed_properties: 70 def set_menu(self, menu):
67 write_track(track_string(changed_properties["Metadata"])) 71 self.menu = menu
68 with refresh_cond: 72
69 refresh_flag = True 73 def get_players(self):
70 refresh_cond.notify() 74 self.players = {}
71 75 self.players_indexes = []
72
73def dbus_name_owner_changed(name, old_owner, new_owner):
74 global refresh_cond
75 global refresh_flag
76
77 if name_regex.match(name):
78 get_players()
79 with refresh_cond:
80 refresh_flag = True
81 refresh_cond.notify()
82 76
77 bus_path = self.bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus")
78 bus_proxy = dbus.Interface(bus_path, "org.freedesktop.DBus")
83 79
84def set_active_player(player_id): 80 for service in bus_proxy.ListNames():
85 global bus 81 if self.service_regex.match(service):
86 global players 82 split_service = service.split(".")
87 global player_id_to_index 83 name_start_index = len(split_service[0]) + len(split_service[1]) + len(split_service[2]) + 3
88 global active_player
89 global playing_song_changed_signal_receiver
90 84
91 if player_id in player_id_to_index: 85 player_path = self.bus.get_object(service, "/org/mpris/MediaPlayer2")
92 active_player = player_id 86 player_props = dbus.Interface(player_path, "org.freedesktop.DBus.Properties")
93 elif len(player_id_to_index) != 0: 87 player_name = service[name_start_index:]
94 active_player = next(iter(player_id_to_index)) 88 try:
95 else: 89 player_name = player_props.Get("org.mpris.MediaPlayer2.Player", "Identity")
96 active_player = "" 90 except dbus.exceptions.DBusException:
91 pass
97 92
98 if playing_song_changed_signal_receiver is not None: 93 self.players[service] = player_name
99 playing_song_changed_signal_receiver.remove() 94 self.players_indexes.append(service)
100 95
101 if active_player != "": 96 self.set_active_player(self.active_player)
102 playing_song_changed_signal_receiver = bus.add_signal_receiver(
103 handler_function = playing_song_changed,
104 bus_name = active_player,
105 dbus_interface = "org.freedesktop.DBus.Properties",
106 signal_name = "PropertiesChanged",
107 path = "/org/mpris/MediaPlayer2"
108 )
109 97
110 player_path = bus.get_object(active_player, "/org/mpris/MediaPlayer2") 98 def set_active_player_index(self, player_index):
111 player_props = dbus.Interface(player_path, "org.freedesktop.DBus.Properties") 99 if player_index < len(self.players_indexes):
100 self.set_active_player(self.players_indexes[player_index])
112 101
113 write_track(track_string(player_props.Get("org.mpris.MediaPlayer2.Player", "Metadata"))) 102 def set_active_player(self, player_id):
114 else: 103 if player_id in self.players:
115 write_track("") 104 self.active_player = player_id
105 elif len(self.players) != 0:
106 self.active_player = next(iter(self.players.keys()))
107 else:
108 self.active_player = ""
116 109
110 if self.signal_receiver is not None:
111 self.signal_receiver.remove()
117 112
118def get_players(): 113 if self.active_player != "":
119 global players 114 self.signal_receiver = self.bus.add_signal_receiver(
120 global player_id_to_index 115 handler_function = self.playing_song_changed,
121 global active_player 116 bus_name = self.active_player,
117 dbus_interface = "org.freedesktop.DBus.Properties",
118 signal_name = "PropertiesChanged",
119 path = "/org/mpris/MediaPlayer2"
120 )
122 121
123 players = [] 122 player_path = self.bus.get_object(self.active_player, "/org/mpris/MediaPlayer2")
124 player_id_to_index = {} 123 player_props = dbus.Interface(player_path, "org.freedesktop.DBus.Properties")
125 bus_path = bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus")
126 bus_proxy = dbus.Interface(bus_path, "org.freedesktop.DBus")
127 names = bus_proxy.ListNames()
128 124
129 for name in names: 125 self.meta_writer.write_meta(player_props.Get("org.mpris.MediaPlayer2.Player", "Metadata"))
130 if name_regex.match(name): 126 else:
131 split_name = name.split(".") 127 self.meta_writer.write("")
132 id_start_index = len(split_name[0]) + len(split_name[1]) + len(split_name[2]) + 3
133 128
134 player_path = bus.get_object(name, "/org/mpris/MediaPlayer2")
135 player_props = dbus.Interface(player_path, "org.freedesktop.DBus.Properties")
136 player_id = name[id_start_index:]
137 try:
138 player_id = player_props.Get("org.mpris.MediaPlayer2.Player", "Identity")
139 except dbus.exceptions.DBusException:
140 pass
141 129
142 players.append((name, player_id)) 130 def run(self):
143 player_id_to_index[name] = len(players) - 1 131 bus_path = self.bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus")
132 bus_proxy = dbus.Interface(bus_path, "org.freedesktop.DBus")
133 bus_proxy.connect_to_signal("NameOwnerChanged", self.dbus_name_owner_changed)
144 134
145 set_active_player(active_player) 135 self.get_players()
136 self.menu.refresh()
146 137
138 self.loop = GLib.MainLoop()
139 self.loop.run()
140
141 def quit(self):
142 self.loop.quit()
143
144 def dbus_name_owner_changed(self, name, old_owner, new_owner):
145 if self.service_regex.match(name):
146 self.get_players()
147 self.menu.refresh()
147 148
148def draw_menu(): 149 def playing_song_changed(self, player, changed_properties, invalidated_properties):
149 global term 150 if "Metadata" in changed_properties:
150 global players 151 self.meta_writer.write_meta(changed_properties["Metadata"])
151 global refresh_cond 152 self.menu.refresh()
152 global refresh_flag
153 global exit_flag
154 global current_output
155 global filename
156 153
157 while not exit_flag:
158 with refresh_cond:
159 while not refresh_flag and not exit_flag:
160 refresh_cond.wait()
161 154
162 refresh_flag = False 155class Menu(threading.Thread):
156 refresh_cond = threading.Condition()
157 refresh_flag = True
158 exit_flag = False
159 player_selector = None
160 meta_writer = None
163 161
164 with term.fullscreen(): 162 def __init__(self, term, player_selector, meta_writer):
165 print(term.move(0, 0) + term.bold_bright_white_on_bright_black(("{0:<{width}}").format("MPRIS To Text", width=term.width)) + "\n") 163 super().__init__()
166 print(term.move_x(2) + term.bold("Player: ") + term.move_up())
167
168 for i in range(len(players)):
169 player = players[i]
170 output = "%d: %s" % (i, player[1])
171 164
172 if players[player_id_to_index[active_player]][0] == player[0]: 165 self.player_selector = player_selector
173 print(term.move_x(10) + term.standout(output)) 166 self.meta_writer = meta_writer
174 else:
175 print(term.move_x(10) + output)
176 167
177 print(term.move_x(2) + term.bold("File: ") + filename) 168 def refresh(self, exit_flag=False):
178 print(term.move_x(2) + term.bold("Output: ") + "\n".join(term.wrap(current_output, width=term.width - 10, subsequent_indent=" " * 10))) 169 with self.refresh_cond:
170 self.refresh_flag = True
171 self.exit_flag = self.exit_flag or exit_flag
172 self.refresh_cond.notify()
179 173
180 print(term.move_x(0) + "\nEnter number to select player or q to exit." + term.move_up()) 174 def run(self):
175 while not self.exit_flag:
176 with self.refresh_cond:
177 while not self.refresh_flag and not self.exit_flag:
178 self.refresh_cond.wait()
181 179
182 with term.fullscreen(): 180 self.refresh_flag = False
183 print(term.move(0, 0) + "Exiting...")
184 181
182 with term.fullscreen():
183 print(term.move(0, 0) + term.bold_bright_white_on_bright_black(("{0:<{width}}").format("MPRIS To Text", width=term.width)) + "\n")
184 print(term.move_x(2) + term.bold("Player: ") + term.move_up())
185
186 for i, (id, name) in enumerate(self.player_selector.players.items()):
187 output = "%d: %s" % (i, name)
185 188
186def on_resize(*args): 189 if id == self.player_selector.active_player:
187 global refresh_cond 190 print(term.move_x(10) + term.standout(output))
188 global refresh_flag 191 else:
192 print(term.move_x(10) + output)
189 193
190 with refresh_cond: 194 print(term.move_x(2) + term.bold("File: ") + self.meta_writer.filename)
191 refresh_flag = True 195 print(term.move_x(2) + term.bold("Output: ") + "\n".join(term.wrap(self.meta_writer.last_output, width=term.width - 10, subsequent_indent=" " * 10)))
192 refresh_cond.notify()
193 196
197 print(term.move_x(0) + "\nEnter number to select player or q to exit." + term.move_up())
194 198
195def init_dbus(): 199 with term.fullscreen():
196 global bus 200 print(term.move(0, 0) + "Exiting...")
197 201
198 bus_path = bus.get_object("org.freedesktop.DBus", "/org/freedesktop/DBus")
199 bus_proxy = dbus.Interface(bus_path, "org.freedesktop.DBus")
200 202
201 bus_proxy.connect_to_signal("NameOwnerChanged", dbus_name_owner_changed) 203class Input(threading.Thread):
204 player_selector = None
205 meta_writer = None
206 menu = None
202 207
203 get_players() 208 def __init__(self, term, player_selector, meta_writer, menu):
209 super().__init__()
204 210
211 self.player_selector = player_selector
212 self.meta_writer = meta_writer
213 self.menu = menu
205 214
206def init_blessed(): 215 def run(self):
207 global bus 216 with term.cbreak():
208 global term 217 val = None
209 global refresh_cond
210 global refresh_flag
211 global exit_flag
212 global loop
213 218
214 with term.cbreak(): 219 while val not in (u'q', u'Q',):
215 val = None 220 val = term.inkey(timeout=5)
216 221
217 while val not in (u'q', u'Q',): 222 if not val or val.is_sequence or not val.isnumeric():
218 val = term.inkey(timeout=5) 223 continue
219 224
220 if not val or val.is_sequence or not val.isnumeric(): 225 if int(val) < len(self.player_selector.players):
221 continue 226 self.player_selector.set_active_player_index(int(val))
227 self.menu.refresh()
222 228
223 if int(val) < len(players): 229 self.menu.refresh(True)
224 set_active_player(players[int(val)][0]) 230 self.player_selector.quit()
225 with refresh_cond:
226 refresh_flag = True
227 refresh_cond.notify()
228 231
229 with refresh_cond:
230 exit_flag = True
231 refresh_cond.notify()
232 232
233 loop.quit() 233def on_resize(*args):
234 global menu_thread
234 235
236 menu_thread.refresh()
235 237
236def read_args():
237 global filename
238 global meta_format
239 global meta_format_artist
240 global meta_format_title
241 global meta_format_album
242 238
239def create_writer():
243 parser = argparse.ArgumentParser(description="Write metadata from MPRIS-compliant media players into a text file.") 240 parser = argparse.ArgumentParser(description="Write metadata from MPRIS-compliant media players into a text file.")
244 parser.add_argument("--file", 241 parser.add_argument("--file",
245 type = str, 242 type = str,
@@ -272,26 +269,27 @@ def read_args():
272 help = "Full format string (default: \"{artist}{title}{album} \")" 269 help = "Full format string (default: \"{artist}{title}{album} \")"
273 ) 270 )
274 271
275 args = parser.parse_args() 272 args = parser.parse_args()
276 filename = args.filename
277 meta_format = args.format
278 meta_format_artist = args.format_artist
279 meta_format_title = args.format_title
280 meta_format_album = args.format_album
281 273
274 return MetaWriter(
275 filename = args.filename,
276 output_format = args.format,
277 output_format_artist = args.format_artist,
278 output_format_title = args.format_title,
279 output_format_album = args.format_album
280 )
282 281
283 282
284read_args() 283term = Terminal()
284meta_writer = create_writer()
285 285
286signal.signal(signal.SIGWINCH, on_resize) 286signal.signal(signal.SIGWINCH, on_resize)
287 287
288init_dbus() 288player_selector = PlayerSelector(meta_writer)
289 289menu_thread = Menu(term, player_selector, meta_writer)
290blessed_thread = threading.Thread(target=init_blessed) 290player_selector.set_menu(menu_thread)
291blessed_thread.start() 291input_thread = Input(term, player_selector, meta_writer, menu_thread)
292 292
293menu_thread = threading.Thread(target=draw_menu) 293player_selector.start()
294menu_thread.start() 294menu_thread.start()
295 295input_thread.start()
296loop = GLib.MainLoop()
297loop.run()