1""" 2Display songs currently playing in DeaDBeeF. 3 4Configuration parameters: 5 cache_timeout: refresh interval for this module (default 5) 6 format: display format for this module (default '[{artist} - ][{title}]') 7 sleep_timeout: when deadbeef is not running, this interval will be used 8 to allow faster refreshes with time-related placeholders and/or 9 to refresh few times per minute rather than every few seconds 10 (default 20) 11 12Format placeholders: 13 {album} name of the album 14 {artist} name of the artist 15 {length} length time in [HH:]MM:SS 16 {playback_time} elapsed time in [HH:]MM:SS 17 {title} title of the track 18 {tracknumber} track number in two digits 19 {year} year in four digits 20 21 For more placeholders, see title formatting 2.0 in 'deadbeef --help' 22 or https://github.com/DeaDBeeF-Player/deadbeef/wiki/Title-formatting-2.0 23 Not all of Foobar2000 remapped metadata fields will work with deadbeef and 24 a quick reminder about using {placeholders} here instead of %placeholder%. 25 26Color options: 27 color_paused: Paused, defaults to color_degraded 28 color_playing: Playing, defaults to color_good 29 color_stopped: Stopped, defaults to color_bad 30 31Requires: 32 deadbeef: a GTK+ audio player for GNU/Linux 33 34Examples: 35``` 36# see 'deadbeef --help' for more buttons 37deadbeef { 38 on_click 1 = 'exec deadbeef --play-pause' 39 on_click 8 = 'exec deadbeef --random' 40} 41``` 42 43@author mrt-prodz 44 45SAMPLE OUTPUT 46{'color': '#00ff00', 'full_text': 'Music For Programming - Lackluster'} 47 48paused 49{'color': '#ffff00', 'full_text': 'Music For Programming - Lackluster'} 50""" 51 52STRING_NOT_INSTALLED = "not installed" 53 54 55class Py3status: 56 """ 57 """ 58 59 # available configuration parameters 60 cache_timeout = 5 61 format = "[{artist} - ][{title}]" 62 sleep_timeout = 20 63 64 class Meta: 65 deprecated = { 66 "remove": [{"param": "delimiter", "msg": "obsolete parameter"}], 67 "rename_placeholder": [ 68 { 69 "placeholder": "elapsed", 70 "new": "playback_time", 71 "format_strings": ["format"], 72 }, 73 { 74 "placeholder": "tracknum", 75 "new": "tracknumber", 76 "format_strings": ["format"], 77 }, 78 ], 79 } 80 81 def post_config_hook(self): 82 if not self.py3.check_commands("deadbeef"): 83 raise Exception(STRING_NOT_INSTALLED) 84 85 self.separator = "|SEPARATOR|" 86 self.placeholders = list( 87 set(self.py3.get_placeholders_list(self.format) + ["isplaying"]) 88 ) 89 self.deadbeef_command = 'deadbeef --nowplaying-tf "{}"'.format( 90 self.separator.join(f"%{x}%" for x in self.placeholders) 91 ) 92 self.color_paused = self.py3.COLOR_PAUSED or self.py3.COLOR_DEGRADED 93 self.color_playing = self.py3.COLOR_PLAYING or self.py3.COLOR_GOOD 94 self.color_stopped = self.py3.COLOR_STOPPED or self.py3.COLOR_BAD 95 96 def _is_running(self): 97 try: 98 self.py3.command_output(["pgrep", "deadbeef"]) 99 return True 100 except self.py3.CommandError: 101 return False 102 103 def _get_deadbeef_data(self): 104 # Deadbeef can generate lot of startup noises with or without error 105 # codes. Running command sometimes change how things behaves onscreen 106 # too. We used subprocess in the past to ignore error codes. We also 107 # use pgrep and hidden placeholders to dictate how status output and 108 # color should look... mainly to stay consistency in multiple versions 109 # (e.g., Python2.7 to Python3+ and nonstop deadbeef-git commits). 110 try: 111 return self.py3.command_output(self.deadbeef_command) 112 except self.py3.CommandError as ce: 113 return ce.output 114 115 def deadbeef(self): 116 beef_data = {} 117 cached_until = self.sleep_timeout 118 color = self.color_stopped 119 120 if self._is_running(): 121 line = self._get_deadbeef_data() 122 beef_data = dict(zip(self.placeholders, line.split(self.separator))) 123 cached_until = self.cache_timeout 124 125 if beef_data["isplaying"]: 126 color = self.color_playing 127 else: 128 color = self.color_paused 129 130 return { 131 "cached_until": self.py3.time_in(cached_until), 132 "full_text": self.py3.safe_format(self.format, beef_data), 133 "color": color, 134 } 135 136 137if __name__ == "__main__": 138 """ 139 Run module in test mode. 140 """ 141 from py3status.module_test import module_test 142 143 module_test(Py3status) 144