#!/usr/bin/env python # -*- coding: Latin-1 -*- # # Author: Andr� Kelpe fs111 at web dot de # : Jonas Drewsen kde at xspect dot dk # : Peter Ndikuwera pndiku at gmail dot com # # License: GPL # import user import os from xml.dom import minidom import time import string import Globals # the current.xml file PLAYLISTFILE = "%s/.trinity/share/apps/amarok/current.xml"%(user.home) # the fields to be shown via http FIELDS = ("TrackNo", "Title", "Artist", "Album", "Length", "Rating") class Track(object): """Class that holds the information of one track in the current playlist""" __Q_SLOTS__ = FIELDS max_field_value_lengths = [(0,"")] * len(FIELDS) def __init__(self, **kwargs): for key,value in kwargs.iteritems(): setattr(self, key, value) def toRow(self, style='', id=None, trackno=None, reqid=None, sesid = None): """Returns the a html-table-row with member values of this class""" trno = str(trackno) astart = "") aend = "" tmp = [ '' + astart + i + aend +'' for i in [getattr(self,f) for f in self.__Q_SLOTS__ ] ] index = 0 # for f in self.__Q_SLOTS__ : # print string.strip(f) for i in [getattr(self,f) for f in self.__Q_SLOTS__ ]: if len(string.strip(i)) > Track.max_field_value_lengths[index][0]: Track.max_field_value_lengths[index] = (len(string.strip(i)),i) index += 1 tr_style = '' tr_id = '' if style: tr_style='class="%s"'%(style) if trackno == 0: tr_id = 'id="trackone"' if id: tr_id = 'id="%s"'%(id) return '%s'%(tr_style, tr_id, ''.join(tmp)) class Playlist: """The Playlist class represents the Playlist as one object. It holds all needed information and does most of the work""" def __init__(self): """The Constructor takes no arguments.""" self.tracks = [] self.encoding = "UTF-8" #"ISO-8859-15" self.fullPage = "" self.templateFilename = "template.thtml" self.templateLastChanged = -1 self.templateLastChanged = self._loadHtmlTemplate() def _loadHtmlTemplate(self): """Loads the global string template variables that are used for rendering the page. The template can be changed by setting self.templateFilename to a template file.""" ep = Globals.EXEC_PATH st = os.stat(ep + "/" + self.templateFilename)[8] if self.templateLastChanged != st: tmp = open(ep + "/" + self.templateFilename).read() a = compile(tmp, "", 'exec') eval(a) return st def toHtml(self, status): """Returns a html representation of the whole Playlist""" self.templateLastChanged = self._loadHtmlTemplate() self.sync() self.tracks = [] self.mtime = self._getMtime() self._buildDoc() self._setFullPage(status) return self.fullPage def _createButton(self, name, action, reqid, sesid): """Return a button to be used as an action""" return ("") def _createVolume(self, vol_val, reqid, sesid): """Return a HTML volume seletor.""" volume = '' volume += ""; button = "
"; for i in range(1,vol_val+1): volume += ("") for i in range(vol_val+1, 11): volume += ("") volume += "
" + "" + button + "" + "" + button + "
" return volume def _createTimeStr(self, status): """Returns the string representation of the the remaining time of the current song.""" _gmtime = time.gmtime(status.timeLeft()) hours = status.timeLeft() / (60*60) mins = (status.timeLeft() % (60*60)) / 60 secs = status.timeLeft() - 60 * mins - 60 * 60 * hours hours_str = str(hours) + ":" if hours < 10: hours_str = "0" + hours_str if hours == 0: hours_str = "" mins_str = str(mins) + ":" if mins < 10: mins_str = "0" + mins_str secs_str = str(secs) if secs < 10: secs_str = "0" + secs_str return hours_str + mins_str + secs_str def _trackTimeStr(self, trackTime): """Returns the string representation of the track time of a song.""" _time = int(trackTime) hours = _time / (60*60) mins = (_time % (60*60)) / 60 secs = _time - 60 * mins - 60 * 60 * hours hours_str = str(hours) + ":" if hours < 10: hours_str = "0" + hours_str if hours == 0: hours_str = "" mins_str = str(mins) + ":" if mins < 10: mins_str = "0" + mins_str secs_str = str(secs) if secs < 10: secs_str = "0" + secs_str return hours_str + mins_str + secs_str def _ratingStars(self, rating): """Returns a number of stars showing the rating of a song.""" _rating = int(rating) _numBig = _rating / 2 _numSmall = _rating % 2 img_str="" for i in range(1,_numBig+1): img_str = img_str + "" if _numSmall> 0: img_str = img_str + "" return img_str def _createActions(self, status): """Returns HTML for allactions that can be performed and for the time counter""" if not status.controlsEnabled(): return "" reqid = "&reqid=" + str(status.reqid) sesid = "&sesid=" + str(status.sesid) playpause = self._createButton("play", "play", reqid, sesid) if status.isPlaying(): playpause = self._createButton("pause", "pause", reqid, sesid) buttons = (playpause + " " + self._createButton("stop", "stop", reqid, sesid) + " " + self._createButton("start", "prev", reqid, sesid) + " " + self._createButton("end", "next", reqid, sesid)) vol_val = int(float(status.getVolume()) / 10.0 + 0.5) volume = self._createVolume(vol_val, reqid, sesid) return actions % ( buttons, volume, self._createTimeStr(status) ) def _setFullPage(self, status): """Renders the fullpage into the varialbe self.fullPage""" counter = "" if status.isPlaying(): counter = "countdown(" + str(status.timeLeft()) + ");" self.fullPage = code % ( counter, self._createActions(status).encode(self.encoding,'replace'), os.environ['LOGNAME'], self._createTable(status).encode(self.encoding,'replace') ) def _getMtime(self): """gets the mtime from the current.xml file, to check if the current.xml has been modified or not""" return os.stat(PLAYLISTFILE)[-2] def _buildDoc(self): """Build the DOM-doc and calls the _extractTracks-Method""" self.doc = minidom.parse(PLAYLISTFILE) self._extractTracks() def _extractTracks(self): """extracts all "item"-elements from the doc and creates an Track-object to store the associated information""" append = self.tracks.append i = 1 for item in self.doc.getElementsByTagName("item"): curTrack = Track() for elem in FIELDS: try: value = item.getElementsByTagName(elem)[0].firstChild.nodeValue except: value = ' ' if elem == "Title": value = value.strip() if elem == "Length": value = self._trackTimeStr(value); if elem == "Rating": value = self._ratingStars(value); if elem == "TrackNo": value = str(i) i = i + 1 setattr(curTrack, elem, value) append(curTrack) def _createTable(self, status): """Returns the HTML-Table""" tbl = tblhead rows = self._createRows(status) thead = "" + "".join(['%s'%(i) for i in FIELDS]) + "" rowsstr = "".join(rows) return tbl%("tracks", "" + thead + "" + rowsstr + "") def _createRows(self, status): """Returns the table rows""" retval = [] i = 1 reqid = "&reqid=" + str(status.reqid) sesid = "&sesid=" + str(status.sesid) curindex = status.getActiveIndex() id = None for track in self.tracks: style = 'tr_one' if i %2 == 0: style = 'tr_two' if curindex == (i-1): id = "nowplaying" retval.append(track.toRow(style=style, id=id, trackno=(i-1), reqid=reqid, sesid=sesid)) i = i+1 return retval def sync(self): """Saves the current Amarok-Playlist to the current.xml file. Calls amarok via dcop""" os.system("dcop amarok playlist saveCurrentPlaylist")