streamrecord/app.py

292 lines
8.6 KiB
Python

#!/usr/bin/env python3
STREAM_STATUS_ACTIVE = 0
STREAM_STATUS_PAUSED = 1
STREAM_STATUS_ERROR = 2
import sys
import os
import os.path
import cherrypy
import json
import signal
from jinja2 import Environment, FileSystemLoader
from libs import database
from libs import recordTick
from datetime import datetime
if __name__ == '__main__' or 'uwsgi' in __name__:
appdir = os.path.abspath(os.path.normpath(os.path.dirname(__file__)))
appconf = {
'/': {
#'tools.proxy.on':True,
#'tools.proxy.base': conf["base"]["url"],
'tools.sessions.on':True,
'tools.sessions.storage_type':'file',
'tools.sessions.storage_path':appdir+'/sessions/',
'tools.sessions.timeout':525600,
'request.show_tracebacks': True
},
'/static': {
'tools.staticdir.on': True,
'tools.staticdir.dir': appdir+"/static/"
}
}
cherrypy.config.update({
'server.socket_port':3000,
'server.thread_pool':1,
'server.socket_host': '0.0.0.0',
'sessionFilter.on':True,
'server.show.tracebacks': True
})
cherrypy.server.socket_timeout = 5
# env - jinja2 template renderer
env = Environment(loader=FileSystemLoader(os.path.join(appdir, "templates")))
# db - slightly custom sqlite3 object. rows = db.execute(query, args)
db = database()
# REC - recorder thread - see recordTick.py
#REC = recordTick(db)
def render(template, args):
templatesCache = pysite.cacheTemplates()
defaults = {"templates":templatesCache}
for item in args:
defaults[item] = args[item]
return quickRender(template, defaults)
def quickRender(template, args):
template = env.get_template(template)
return template.render(args)
class siteRoot(object):
def __init__(self):
print("Siteroot init !")
self.templateCache = self.cacheTemplates()
def cacheTemplates(self):
templateFiles = os.listdir("jstemplates/")
templateList = []
nameList = []
for item in templateFiles:
name = item.split(".")
templateList.append({"name":name[0],"content":open("jstemplates/"+item,"r").read().replace("\t", "").replace("\n","")})
nameList.append(name[0])
return quickRender("templates.html", {"names":json.dumps(nameList), "templates":templateList})
@cherrypy.expose
def index(self):
return render("html.html", {})
@cherrypy.expose
def htmltest(self):
return render("html.tpl", {})
#index.exposed = True
@cherrypy.expose
def templates(self):
return self.templateCache
class api(object):
def __init__(self):
self.REC = recordTick(db)
@cherrypy.expose
def tick(self):
self.REC.tick()
return "OK"
@cherrypy.expose
def getStreams(self):
streamList = db.execute('SELECT * FROM "streams" ORDER BY "name" ASC;')
for stream in streamList:
stream["time"] = db.execute('SELECT * FROM "times" WHERE streamid=?', [stream["id"]])[0]
stream["files"] = self._getFiles(stream["id"])
stream["recorder_status"] = self.REC.streamStatus(stream["id"])
stream["is_running"] = stream["recorder_status"] not in [0, -1] # idle states
return json.dumps(streamList)
def _getStream(self,id):
streamList = db.execute('SELECT * FROM "streams" WHERE "id"=?', [int(id)])
for stream in streamList:
stream["time"] = db.execute('SELECT * FROM "times" WHERE streamid=?', [stream["id"]])[0]
stream["files"]=self._getFiles(id)
stream["recorder_status"] = self.REC.streamStatus(stream["id"])
stream["is_running"] = stream["recorder_status"] not in [0, -1] # idle states
return streamList[0]
@cherrypy.expose
def getStream(self, id):
return json.dumps(self._getStream(id))
@cherrypy.expose
def changeStatus(self, streamid, status):
streamid = int(streamid)
db.execute('UPDATE "streams" SET "status"=? WHERE "id"=? ;', [status, streamid])
return json.dumps({"result":True})
@cherrypy.expose
def changeTimeDay(self, streamid, day, value):
streamid = int(streamid)
value = value == "true"
col = ""
if day == "daysu":
col="su"
elif day == "daym":
col="m"
elif day == "dayt":
col="t"
elif day == "dayw":
col="w"
elif day == "dayr":
col="r"
elif day == "dayf":
col="f"
elif day == "daysa":
col="sa"
else:
raise cherrypy.HTTPError(500, message="Day not found")
db.execute('UPDATE "times" SET "'+col+'"=? WHERE "streamid"=? ;', [1 if value else 0,streamid])
return json.dumps({"result":True})
@cherrypy.expose
def changeName(self, streamid, value):
streamid = int(streamid)
db.execute('UPDATE "streams" SET "name"=? WHERE "id"=?', [value,streamid])
return json.dumps({"result":True})
@cherrypy.expose
def changeUrl(self, streamid, value):
streamid = int(streamid)
db.execute('UPDATE "streams" SET "url"=? WHERE "id"=?', [value,streamid])
return json.dumps({"result":True})
@cherrypy.expose
def changeTime(self, streamid, startHour, startMin, endHour, endMin):
startHour=int(startHour)
assert startHour>=0 and startHour<=23
startMin=int(startMin)
assert startMin>=0 and startMin<=59
endHour=int(endHour)
assert endHour>=0 and endHour<=23
endMin=int(endMin)
assert endMin>=0 and endMin<=59
db.execute('UPDATE "times" SET "starthour"=?, "startmin"=?, "endhour"=?, "endmin"=? WHERE "streamid"=? ;', [startHour, startMin, endHour, endMin, streamid])
return json.dumps({"result":True})
def _filterName(self, input):
allowed="abcdefghijklmnopqrstuvwxyz123456789-"
input = input.replace(" ", "-").lower()
output=[]
for i in range(0, len(allowed)):
if input[i:i+1] in allowed:
output.append(input[i:i+1])
return ''.join(output)
@cherrypy.expose
def createStream(self, data):
data = json.loads(data)
assert not data["name"] == ""
assert not data["url"] == ""
assert data["time"]["su"] or data["time"]["m"] or data["time"]["t"] or data["time"]["w"] or data["time"]["r"] or data["time"]["f"] or data["time"]["sa"]
dirName = self._filterName(data["name"])
rowid = db.execute('INSERT INTO "streams" ("user", "name", "url", "directory", "status", "message") VALUES (?, ?, ?, ?, ?, ?);', [0, data["name"], data["url"], dirName, data["status"], ""])
db.execute('INSERT INTO "times" ("streamid", "su", "m", "t", "w", "r", "f", "sa", "starthour", "startmin", "endhour", "endmin") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);', [
rowid,
data["time"]["su"],
data["time"]["m"],
data["time"]["t"],
data["time"]["w"],
data["time"]["r"],
data["time"]["f"],
data["time"]["sa"],
data["time"]["startHour"],
data["time"]["startMin"],
data["time"]["endHour"],
data["time"]["endMin"]
])
return json.dumps({"result":rowid})
def _getFiles(self, id):
stream = db.execute('SELECT * FROM "streams" WHERE "id"=?', [int(id)])[0]
recordingsDir = "files/output/"+stream["directory"]+"/"
files = []
if os.path.exists(recordingsDir):
files = os.listdir(recordingsDir)
files.sort()
allFiles = []
for i in range(0, len(files)):
item = files[i]
if item[0:1]==".":
continue;
size = os.path.getsize(recordingsDir+item)
allFiles.append({
"filename":item,
"directory":recordingsDir,
"streamdir":stream["directory"],
"filenum":i,
"bytes":size,
"mbytes":round(size/1024.0/1024.0, 2),
"date":os.path.getctime(recordingsDir+item)
})
return allFiles
@cherrypy.expose
def getFiles(self, id):
files = self._getFiles(id)
return json.dumps({"data":files})
@cherrypy.expose
def download(self, id, fn):
files = self._getFiles(id)
item = files[int(fn)]
raise cherrypy.HTTPRedirect("/static/output/"+item["streamdir"]+"/"+item["filename"], 302)
@cherrypy.expose
def getUrl(self, id, fn):
files = self._getFiles(id)
item = files[int(fn)]
return json.dumps({"result":"/static/output/"+item["streamdir"]+"/"+item["filename"]})
@cherrypy.expose
@cherrypy.tools.response_headers(headers=[('Content-Type', 'application/rss+xml')])
def getPodcast(self, id):
stream = self._getStream(id)
# Thu, 31 Jul 2014 07:13:48 +0000
for f in stream["files"]:
f["date"]=datetime.fromtimestamp(f["date"]).strftime("%a, %d %b %Y %H:%M:%S +0800")
return str.encode(render("podcast.html", {
"stream":stream,
"builddate": datetime.now().strftime("%a, %d %b %Y %H:%M:%S +0800")#Thu, 31 Jul 2014 07:13:48 +0000
}))
@cherrypy.expose
def getRecStatus(self, id):
return json.dumps({"data":self.REC.streamStatus(int(id))})
pysite = siteRoot()
pysite.api = api()
print( "Ready to start application" )
if(len(sys.argv)>1 and sys.argv[1]=="test"):
print("test!")
application = cherrypy.quickstart(pysite, '/', appconf)
else:
sys.stdout = sys.stderr
cherrypy.config.update({'environment': 'embedded'})
application = cherrypy.tree.mount(pysite, "/", appconf)