#!/usr/bin/env python """pywmnop.py WindowMaker dockapp internet radio player Copyright (C) 2006 Mario Frasca Licensed under the GNU General Public License. """ from codecs import open from fcntl import fcntl, F_GETFL, F_SETFL from os import environ, sep, O_NONBLOCK from re import compile from select import select from signal import signal, SIGCHLD from subprocess import Popen, DEVNULL, PIPE from wmdocklib import wmoo as wmoo class Application(wmoo.Application): def reset(self): self._cacheLevel = -50 self.child = None self._paused = None self._buffering = 0 self._flash = 0 self._muting = 0 self.showCacheLevel() def __init__(self, *args, **kwargs): wmoo.Application.__init__(self, *args, **kwargs) self.radioList = [] self.currentRadio = 0 self._count = 0 self._expectdying = 0 self.reset() self._buffered = '' self._feedback = compile(r'.+A:.*?% ([0-9\.]+)%') configfile = sep.join([environ['HOME'], '.pyradiorc']) with open(configfile, 'r', 'utf-8') as f: t = f.read() for i in t.split(u'\n'): radiodef = i.split('\t') radioname = radiodef[0].lower() if len(radiodef) != 3 or i[0] == '#': continue if radioname == '': globals()[radiodef[1]] = radiodef[2] pass else: self.radioList.append( (radioname, radiodef[1], radiodef[2]) ) def handler(self, num, frame): if self._expectdying: self._expectdying -= 1 else: self.reset() self._flash = 4 self._colour = 1 def startPlayer(self): commandline = [mplayer, '-cache', str(abs(int(self.radioList[self.currentRadio][2]))), self.radioList[self.currentRadio][1] ] # if cache is negative then this is a playlist if int(self.radioList[self.currentRadio][2]) < 0: commandline.insert(2, '-playlist') self.child = Popen(commandline, stdin =PIPE, stdout=PIPE, stderr=DEVNULL) signal(SIGCHLD, self.handler) self._flash = 0 self._paused = False self._buffered = '' self._buffering = 1 self._cacheLevel = 0 flags = fcntl(self.child.stdout, F_GETFL) fcntl(self.child.stdout, F_SETFL, flags | O_NONBLOCK) flags = fcntl(self.child.stdin, F_GETFL) fcntl(self.child.stdin, F_SETFL, flags | O_NONBLOCK) def stopPlayer(self): if self.child: # print(self._expectdying) self.child.stdin.write(b'q') self.child.stdin.flush() self._expectdying += 1 self.child = None def muteStream(self, event): if self.child and self._buffering == 0: self.child.stdin.write(b'm') self.child.stdin.flush() self.putPattern(9*self._muting, 0, 9, 11, 30, 29) self._muting = 1 - self._muting def printevent(self, event): print(event) def previousRadio(self, event): if self.currentRadio == 0: self.currentRadio = len(self.radioList) self.currentRadio -= 1 self.setLabelText('name', self.radioList[self.currentRadio][0]) if self.child: self.stopPlayer() self.startPlayer() def nextRadio(self, event): self.currentRadio += 1 if self.currentRadio == len(self.radioList): self.currentRadio = 0 self.setLabelText('name', self.radioList[self.currentRadio][0]) if self.child: self.stopPlayer() self.startPlayer() def playStream(self, event): self.startPlayer() def stopStream(self, event): self.stopPlayer() self.reset() def pauseStream(self, event): if self.child and not self._buffering: self.child.stdin.write(b' ') self.child.stdin.flush() self._paused = not self._paused if self._paused: self._colour = 1 return True return False def showCacheLevel(self): if self._buffering: self._cacheLevel += 1 if self._cacheLevel >= 25: self._cacheLevel -= 25 for i in range(-1, 25): if abs(i - self._cacheLevel) <= 1: self.putPattern(54, self._buffering, 3, 1, 52, 54-i) else: self.putPattern(54, 0, 3, 1, 52, 54-i) else: if self._paused or self._flash: colour = self._colour = 3 - self._colour self._flash = max(0, self._flash - 1) else: colour = 2 for i in range(-1, 25): if (i*4 < self._cacheLevel) or self._flash: self.putPattern(54, colour, 3, 1, 52, 54-i) else: self.putPattern(54, 0, 3, 1, 52, 54-i) def update(self): wmoo.Application.update(self) self._count += 1 if self._count <= 3: return self._count = 0 if self.child: [i, o, e] = select([self.child.stdout], [], [], 0) if i: line = self.child.stdout.read(102400).decode("utf-8") self._buffered += line npos = self._buffered.rfind('\n')+1 rpos = self._buffered.rfind('\r')+1 if npos != 0: self._buffered = self._buffered[npos:] if rpos != 0: if self._buffered.startswith('Cache fill:'): self._buffering = 2 else: match = self._feedback.match(self._buffered[rpos-90:rpos]) if match: self._buffering = 0 self._cacheLevel = float(match.group(1)) self._buffered = self._buffered[rpos:] if self.child or self._flash: self.showCacheLevel() palette = { '-': "#000000", ".": "#868682", "X": "#AEAEAA", "o": "#F7F7F3", "r": "#F73020", "i": "#00F700", } background = [ " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "----------------------------------------------------------------", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", " ", " ", " ", " ", " XXXX. ", " XXXXXXXX. XXXXXXXX. XXXXXXXX. X--- ", " X-------- X-------- X-------- X--- ", " X-------- X-------- X-----o-- X--- ", " X--o--o-- X--o--o-- X----oo-- X--- ", " X--o-oo-- X--oo-o-- X-ooooo-- X--- ", " X--oooo-- X--oooo-- X-ooooo-- X--- ", " X--o-oo-- X--oo-o-- X----oo-- X--- ", " X--o--o-- X--o--o-- X-----o-- X--- ", " X-------- X-------- X-------- X--- ", " X-------- X-------- X-------- X--- ", " .-------- .-------- .-------- X--- ", " X--- ", " X--- ", " X.---.. ", " XXXXXXXX. XXXXXXXX. XXXXXXXX. X--- ", " X-------- X-------- X-------- X--- ", " X-------- X-------- X-------- X--- ", " X--o----- X-oo-oo-- X-ooooo-- X--- ", " X--oo---- X-oo-oo-- X-ooooo-- X--- ", " X--ooo--- X-oo-oo-- X-ooooo-- X--- ", " X--oo---- X-oo-oo-- X-ooooo-- X--- ", " X--o----- X-oo-oo-- X-ooooo-- X--- ", " X-------- X-------- X-------- X--- ", " X-------- X-------- X-------- X--- ", " .-------- .-------- .-------- X--- ", " X--- ", " .--- ", " ", " ", " ", " ", " ", " ", " ", " ", ] patterns = [ "XXXXXXXX.XXXXXXXX.XXXXXXXX.XXXXXXXX.XXXXXXXX.XXXXXXXX.--- ", "X--------X--------X--------X--------X--------X--------rrr ", "X-----rr-X-----o--X-----o--X--------X--------X--------iii ", "X----rr--X----oo--X----oo--X-oo-oo--X--o-----X--r----- ", "X-oorro--X-ooooo--X-ooooo--X-oo-oo--X--oo----X--rr---- ", "X-ooroo--X-ooooo--X-ooooo--X-oo-oo--X--ooo---X--rrr--- ", "X--rroo--X----oo--X----oo--X-oo-oo--X--oo----X--rr---- ", "X-rr--o--X-----o--X-----o--X-oo-oo--X--o-----X--r----- ", "X- ------X--------X--------X--------X--------X-------- ", "X--------X--------X--------X--------X--------X-------- ", ".--------.--------.--------.--------.--------.-------- ", ] def main(): global char_width, char_height, maxCharsPerLine, antialiased app = Application(font_name='5x8', margin = 3, bg=0, fg=2, palette = palette, background = background, patterns = patterns) # maxCharsPerLine = (width-2*xOffset) / char width app.addLabel('name', (3, 13), (58, 10), app.radioList[app.currentRadio][0]) # app.addCallback(printevent) app.addCallback(app.previousRadio, 'buttonrelease', area=( 6,29,15,38)) app.addCallback(app.nextRadio, 'buttonrelease', area=(18,29,27,38)) app.addCallback(app.muteStream, 'buttonrelease', area=(30,29,39,38)) app.addCallback(app.playStream, 'buttonrelease', area=( 6,43,15,52)) app.addCallback(app.pauseStream, 'buttonrelease', area=(18,43,27,52)) app.addCallback(app.stopStream, 'buttonrelease', area=(30,43,39,52)) app.run() if __name__ == '__main__': main()