1""" 2Control Audacious or VLC media player. 3 4Provides an icon to control simple functions of audio/video players: 5 - start (left click) 6 - stop (left click) 7 - pause (middle click) 8 9Configuration parameters: 10 cache_timeout: how often to update in seconds (default 10) 11 debug: enable verbose logging (bool) (default False) 12 format: format of the output (default "{icon}") 13 pause_icon: (default '❚❚') 14 play_icon: (default '▶') 15 stop_icon: (default '◼') 16 supported_players: supported players (str) (comma separated list) 17 (default 'audacious,vlc') 18 volume_tick: percentage volume change on mouse wheel (int) (positive number 19 or None to disable it) (default 1) 20 21Format placeholders: 22 {icon} an icon to control music/video players 23 24@author Federico Ceratto <federico.ceratto@gmail.com>, rixx 25@license BSD 26 27SAMPLE OUTPUT 28{'full_text': u'\u25b6'} 29 30stop 31{'full_text': u'\u25fc'} 32 33pause 34{'full_text': u'\u275a\u275a'} 35""" 36# Any contributor to this module should add his/her name to the @author 37# line, comma separated. 38 39from pathlib import Path 40 41try: 42 import dbus 43 44 dbus_available = True 45except: # noqa e722 // (ImportError, ModuleNotFoundError): # (py2, assumed py3) 46 dbus_available = False 47 48 49class Py3status: 50 """ 51 """ 52 53 # available configuration parameters 54 cache_timeout = 10 55 debug = False 56 format = "{icon}" 57 pause_icon = "❚❚" 58 play_icon = "▶" 59 stop_icon = "◼" 60 supported_players = "audacious,vlc" 61 volume_tick = 1 62 63 def post_config_hook(self): 64 self.status = "stop" 65 self.icon = self.play_icon 66 67 def on_click(self, event): 68 """ 69 """ 70 buttons = (None, "left", "middle", "right", "up", "down") 71 try: 72 button = buttons[event["button"]] 73 except IndexError: 74 return 75 76 if button in ("up", "down"): 77 if self.volume_tick is None: 78 return 79 80 self._change_volume(button == "up") 81 return 82 83 if self.status == "play": 84 if button == "left": 85 self._stop() 86 87 elif button == "middle": 88 self._pause() 89 90 elif self.status == "stop": 91 if button == "left": 92 self._play() 93 94 elif self.status == "pause": 95 if button in ("left", "right"): 96 self._play() 97 98 def _run(self, command): 99 if self.debug: 100 self.py3.log(f"running {command}") 101 self.py3.command_run(command) 102 103 def _play(self): 104 self.status = "play" 105 self.icon = self.stop_icon 106 player_name = self._detect_running_player() 107 if player_name == "audacious": 108 self._run(["audacious", "-p"]) 109 elif player_name == "vlc": 110 player = self._get_vlc() 111 if player: 112 player.Play() 113 114 def _stop(self): 115 self.status = "stop" 116 self.icon = self.play_icon 117 player_name = self._detect_running_player() 118 if player_name == "audacious": 119 self._run(["audacious", "-s"]) 120 elif player_name == "vlc": 121 player = self._get_vlc() 122 if player: 123 player.Stop() 124 125 def _pause(self): 126 self.status = "pause" 127 self.icon = self.pause_icon 128 player_name = self._detect_running_player() 129 if player_name == "audacious": 130 self._run(["audacious", "-u"]) 131 elif player_name == "vlc": 132 player = self._get_vlc() 133 if player: 134 player.Pause() 135 136 def _change_volume(self, increase): 137 """Change volume using amixer 138 """ 139 sign = "+" if increase else "-" 140 delta = f"{self.volume_tick}%{sign}" 141 self._run(["amixer", "-q", "sset", "Master", delta]) 142 143 def _detect_running_player(self): 144 """Detect running player process, if any 145 """ 146 supported_players = self.supported_players.split(",") 147 running_players = [] 148 for pid in Path("/proc").iterdir(): 149 if not pid.name.isdigit(): 150 continue 151 try: 152 player_name = (pid / "comm").read_bytes().decode().rstrip() 153 except: # noqa e722 154 # (IOError, FileNotFoundError): # (assumed py2, assumed py3) 155 continue 156 157 if player_name in supported_players: 158 running_players.append(player_name) 159 160 # Pick which player to use based on the order in self.supported_players 161 for player_name in supported_players: 162 if player_name in running_players: 163 if self.debug: 164 self.py3.log(f"found player: {player_name}") 165 166 # those players need the dbus module 167 if player_name == "vlc" and not dbus_available: 168 self.py3.log(f"{player_name} requires the dbus python module") 169 return None 170 171 return player_name 172 173 return None 174 175 def _get_vlc(self): 176 mpris = "org.mpris.MediaPlayer2" 177 mpris_slash = "/" + mpris.replace(".", "/") 178 bus = dbus.SessionBus() 179 proxy = bus.get_object(mpris + ".vlc", mpris_slash) 180 return dbus.Interface(proxy, dbus_interface=mpris + ".Player") 181 182 def player_control(self): 183 return dict( 184 full_text=self.py3.safe_format(self.format, {"icon": self.icon}), 185 cached_until=self.py3.time_in(self.cache_timeout), 186 ) 187 188 189if __name__ == "__main__": 190 """ 191 Run module in test mode. 192 """ 193 from py3status.module_test import module_test 194 195 module_test(Py3status) 196