292 lines
8.6 KiB
Python
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)
|