You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

210 lines
6.6 KiB
Python

import urllib.request
import kode256
import requests
import gi
from gi.repository import TotemPlParser
from gsp import GstreamerPlayer
from bureau import Bureau, add_command, add_webview
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.
"""
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:
print("stream uri", url)
self.player.queue(url)
self.current_uri = url
@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 = """
<html><head><title>screenless office - internet radio admin</title></head>
<body>
<h1>Audio Department</h1>
"""
if data:
if data["addurl"]:
self.save_url(data["addurl"])
ret += "<div>New station " + data["addurl"] + " saved!</div>\n"
ret += "<h2>Radio Stations<h2>\n <ul>\n"
with self.urldb.env.begin(db=self.urldb.db) as txn:
for sh_code, url in txn.cursor():
ret += "<li>" + url.decode("utf-8") + "</li>\n"
ret += "</ul>\n"
ret += """
<form action='/AU/radio' method='POST'>
<ul>
<li>
<label for="addurl">Add Radio Station URL:</label>
<input type="text" id="addurl" name="addurl" />
</li>
<li class="button">
<button type="submit">Save</button>
</li>
</ul>
</form>
</body></html>"""
return ret
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: support #EXTINF: extended attributes - logo or #EXTIMG or #PLAYLIST
# TODO: support XSPF?? does anyone use this?
# TODO: what to do with unwrapped links - raw mp3 or whateva - use vlc info?
# if line startswith #EXTINF: title = first comma to EOL
# if line startswith Title then title = first '=' to EOL
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()
# TODO: create barcode
# 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()