import glob import urllib.request import kode256 import requests import gi from gi.repository import TotemPlParser from gsp import GstreamerPlayer from tinytag import TinyTag from bureau import Bureau, add_command, add_webview, add_api class Audio(Bureau): """ The Audio Services department provides for playback and recording of sound within the office environment. """ name = "Audio Services Dept." prefix = "AU" version = 0 def __init__(self): Bureau.__init__(self) self.urldb = self.open_db("urldb") self.player = GstreamerPlayer(None) self.current_uri = None @add_command("p", "Play an album, track or a live stream.") def play(self, data): """ Initiates playback of a media reference. This could be a song or album stored on the local office or remote URLs for live playback. Currently, only supports line-out signals on the default DAC. """ self.stop() shortcode, _ = data.split(".") self.log.debug("looking up shortcode " + shortcode) pl_url = self.urldb.get(shortcode) self.log.debug(" playing url " + pl_url) pl_file, _ = urllib.request.urlretrieve(pl_url) pl_file = "file://" + pl_file parser = TotemPlParser.Parser() urls = [] def parsercb(parser, uri, metadata, urls): #TODO: would be nice to use the metadata when adding the station # and for now-playing urls.append(uri) parser.connect("entry-parsed", parsercb, urls) parser.parse(pl_file, False) for url in urls: self.player.queue(url) self.current_uri = urls[0] @add_command("stop", "Halt audio playback.") def stop(self): """ Stops all audio currently playing audio output. """ self.player.stop() @add_command("resu", "Resume playback.") def resume(self): """ Resume playback of paused audio. """ if self.current_uri: self.player.queue(self.current_uri) @add_command("next", "Play the next song.") def play_next(self): """ Skip to the next song in the playlist or album. """ #subprocess.call(["mocp", "-f"]) # TODO self.print_small("SORRY! playlist->next is not yet implemented.") @add_command("prev", "Play the previous song.") def play_prev(self): """ Skip to the previous song in the playlist or album. """ #subprocess.call(["mocp", "-r"]) # TODO self.print_small("SORRY! playlist->prev is not yet implemented.") @add_command("nowp", "Now Playing") def now_playing(self): """ Prints the currently playing song or stream on the small printer. """ out = "Now Playing: " if self.player.title: out += self.player.title + "\n" if self.player.artist: out += "by " + self.player.artist + "\n" if self.player.album: out += "from the album '" + self.player.album + "'\n" # TODO: add fields for "organization" and "location" for gstreamer-player # so we can get the station ID stuff self.log.debug("info output:" + out) self.print_small(out) @add_webview("radio", "radio") def radio_webview(self, data=None): """ Edit internet radio stations. """ #TODO: allow deletes #TODO: print out any new station #TODO: use some kind of nicer templates? ret = """ screenless office - internet radio admin

Audio Department

""" if data: if data["addurl"]: self.save_url(data["addurl"]) ret += "
New station " + data["addurl"] + " saved!
\n" ret += "

Radio Stations

\n \n" ret += """
""" return ret @add_api("add_album", "Add a music album.") def add_album(self, data): """ add a local folder with music or audio """ try: im_dir = data["album_dir"] store = data["music_dir"] except KeyError as e: self.log.error("you must specify a directory to import") # scan to find out the name(s) of artist/albums and track order # create necessary folders and copy the files over # create a playlist and add the files in the right order # save the url # print a nice card for perusal and playing def save_url(self, url): """ saves an url for a local file or network audio stream. """ # TODO: might be nice to save some station info: title, perhaps a logo, etc. code = self.urldb.store_and_get_shortcode(url) self.print_url(code) print("saved url with shortcode: ", code) def print_url(self, shortcode): url = self.urldb.get(shortcode) # download the url headers = {'User-Agent': 'Mozilla/5.0'} try: resp = requests.get(url, timeout=20.0, headers=headers) except requests.ReadTimeout: self.log.warning("Timeout reading url %s", url) self.print_small("Error: timed out reading " + url) return except requests.ConnectionError as e: self.log.warning("Error reading url %s", url) self.print_small("Error: connect error on " + url) return # TODO: get rid of this stuff and use the playlist parser # TODO: what to do with unwrapped links - raw mp3 or whateva - use vlc info? title = "" for line in resp.text.splitlines(): if line.startswith("#EXTINF:"): # this is m3u playlist - title is from first comma to EOL title = line[(line.find(',') + 1):].strip() elif line.startswith("Title"): # this looks like a pls playlist - title is from first '=' to EOL title = line[(line.find('=') + 1):].strip() # small print title, url, barcode prn = self._get_small_printer() prn.textln("RADIO STATION:") prn.textln(title) prn.textln(url) prn.soft_barcode("code128", "AUp." + shortcode) prn.print_and_feed() #TODO: cut prn.close() def main(): au = Audio() au.run() if __name__ == "__main__": main()