Skip to content

Commit

Permalink
Add Api (#7)
Browse files Browse the repository at this point in the history
* Add REST API for federation

* update year to 2021

* Add GPL

* remove obsolete template parameter

* fix player

Co-authored by bsod <[email protected]>

* Update frontend/app/api.py

Co-authored-by: Christoph <[email protected]>

* Update frontend/app/api.py

Co-authored-by: Christoph <[email protected]>

* Update frontend/app/zomstream.py

Co-authored-by: Christoph <[email protected]>

* Update frontend/app/zomstream.py

Co-authored-by: Christoph <[email protected]>

* Update frontend/app/zomstream.py

Co-authored-by: Christoph <[email protected]>

* Update frontend/app/api.py

Co-authored-by: Christoph <[email protected]>

Co-authored-by: Jonas <[email protected]>
Co-authored-by: Christoph <[email protected]>
  • Loading branch information
3 people authored Apr 4, 2021
1 parent 1ed1765 commit 7e16ef2
Show file tree
Hide file tree
Showing 11 changed files with 795 additions and 56 deletions.
674 changes: 674 additions & 0 deletions COPYING

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ this does run the actual streaming, receives rtmp streams from OBS / ffmpeg etc.
this is a simple PSK based authentication module to provide authentication for source connections.

### frontend
this components provides the visible website containing an overview of the running streams, rtmp links for external players and a web based video player to watch the livestreams.
this components provides the visible website containing an overview of the running streams, a REST API, rtmp links for external players and a web based video player to watch the livestreams.

## How to use this
We tested this with OBS and ffmpeg but any steaming source supporting rtmp should work just fine.
Expand Down
4 changes: 2 additions & 2 deletions config/frontend/config.example.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# This is the title and Subtitle displayed on the Head of the Page
pagetitle: Zomstream
subtitle: v0.3
subtitle: v0.4
# the footer
footer: "&copy; 2020 by the zom.bi Team"
footer: "&copy; 2021 by the zom.bi Team"
# the ip or hostname used to generate rtmp URLs
rtmp_base: stream.zom.bi
# this is the base url used to generate internal links
Expand Down
4 changes: 2 additions & 2 deletions config/frontend/uwsgi.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ lazy-apps = true
processes = 4
threads = 2
protocol = http
wsgi-file = frontend.py
callable = frontend
wsgi-file = app.py
callable = web
offload-threads = 4
29 changes: 29 additions & 0 deletions frontend/app/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import flask
import json

from zomstream import Zomstream

api_version = "0.1"
api = flask.Blueprint('api', __name__)
zomstream = Zomstream()

def construct_response(r):
# Expecting a JSON-serializable object as an argument
# Returning a JSON string with the API response

# Add Version String
r.append({"version":api_version})
return flask.jsonify(r)


@api.route("/api/stream/", methods = ['GET'])
@api.route("/api/streams/", methods = ['GET'])
def api_list_streams():
return construct_response(zomstream.getStreams())


@api.route("/api/stream/<app_name>/<stream_name>/", methods = ['GET'])
def api_stream(app_name, stream_name):
# Filter for streams with 'name' == stream_name
stream = list(filter(lambda stream: stream['name'] == stream_name, zomstream.getStreams()))
return construct_response(stream)
11 changes: 11 additions & 0 deletions frontend/app/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import flask
import urllib
import frontend
import api

import logging
logging.basicConfig(level=logging.DEBUG)

web = flask.Flask(__name__)
web.register_blueprint(api.api)
web.register_blueprint(frontend.frontend)
58 changes: 10 additions & 48 deletions frontend/app/frontend.py
Original file line number Diff line number Diff line change
@@ -1,71 +1,33 @@
#!/usr/bin/env python
#!/usr/bin/env python3

# imports
import flask
import pathlib
import yaml
import sys
import xml.etree.ElementTree as etree
import urllib
import logging

logging.basicConfig(level=logging.DEBUG)

# load configuration from config.yml file
if pathlib.Path("config.yml").is_file():
stream = open('config.yml', 'r')
configuration = yaml.load(stream)
stream.close()
else:
print('missing configuration.')
sys.exit(1)

def getStreamNames(url):
streamnames = []
# get data from the streaming server
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
# parse the xml / walk the tree
tree = etree.fromstring(content)
server = tree.find('server')
applications = server.findall('application')
for application in applications:
appname = application.find('name')
if appname.text == "live" or appname.text == "rec":
streams = application.find('live').findall('stream')
for stream in streams:
name = stream.find('name')
rate = stream.find('bw_video')
if rate.text != "0":
streamnames.append( [appname.text, name.text] )

return streamnames
from zomstream import Zomstream

streamList = []
frontend = flask.Flask(__name__)
zomstream = Zomstream()

frontend = flask.Blueprint('frontend', __name__)

@frontend.route("/")
def start():
mainTemplate = '%s/main.html.j2' % configuration['template_folder']
streamList = getStreamNames(configuration['stat_url'])
mainTemplate = '%s/main.html.j2' % zomstream.configuration['template_folder']
streamList = zomstream.getStreamNames()
page = flask.render_template(
mainTemplate,
items=streamList,
configuration=configuration
configuration=zomstream.configuration
)
return page

@frontend.route("/player/<appname>/<streamname>")
def show_player(appname, streamname):
playerTemplate = '%s/player.html.j2' % configuration['template_folder']
playerTemplate = '%s/player.html.j2' % zomstream.configuration['template_folder']
page = flask.render_template(
playerTemplate,
streamname=streamname,
appname=appname,
hls_url='%s://%s/video/hls/%s.m3u8' % (
configuration['web_proto'],
configuration['base_url'],
streamname),
configuration=configuration
configuration=zomstream.configuration
)
return page
4 changes: 4 additions & 0 deletions frontend/app/locust-tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ def index(self):
def static_css(self):
self.client.get("/static/style.default.css")

@task
def api_list(self):
self.client.get("/api/streams/")

@task
def videoplayer(self):
self.client.get("/player/bsod")
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/templates/default/main.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</tr>
</tbody>
</table>
<a href="{{ url_for('show_player', streamname=item[1], appname=item[0]) }}"
<a href="{{ url_for('frontend.show_player', streamname=item[1], appname=item[0]) }}"
class="btn-large btn-green">
&#9655; Web Player
</a>
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/templates/default/player.html.j2
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
</head>
<body>
<header>
<a href="{{ url_for('start') }}"><h1>{{ configuration["pagetitle"] }}</h1></a>
<a href="{{ url_for('frontend.start') }}"><h1>{{ configuration["pagetitle"] }}</h1></a>
<h2>{{ configuration["subtitle"] }}</h2>
</header>
<div id="videocontainer">
Expand All @@ -29,4 +29,4 @@
}
</script>
</body>
</html>
</html>
59 changes: 59 additions & 0 deletions frontend/app/zomstream.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import pathlib
import xml.etree.ElementTree as etree
import sys
import yaml
import urllib


class Stream:
def __init__(self, url, name, streamType, app):
self.url = url
self.name = name
self.streamType = streamType
self.app = app


class Zomstream:
def __init__(self):
# load configuration from config.yml file
if pathlib.Path("config.yml").is_file():
stream = open('config.yml', 'r')
self.configuration = yaml.load(stream)
stream.close()
else:
print('missing configuration.')
sys.exit(1)
self.streamnames = []
def getStreamNames(self):
self.streamnames = []
# get data from the streaming server
response = urllib.request.urlopen(self.configuration['stat_url'])
content = response.read().decode('utf-8')
# parse the xml / walk the tree
tree = etree.fromstring(content)
server = tree.find('server')
applications = server.findall('application')
for application in applications:
appname = application.find('name')
if appname.text == "live" or appname.text == "rec":
streams = application.find('live').findall('stream')
for stream in streams:
name = stream.find('name')
rate = stream.find('bw_video')
if rate.text != "0":
self.streamnames.append( [appname.text, name.text] )

return self.streamnames


def getStreams(self):
streams = []
for streamName in self.getStreamNames():
stream_url = '%s://%s/flv?app=%s&stream=%s' % (
self.configuration['web_proto'],
self.configuration['base_url'],
streamName[0],
streamName[1])
stream = Stream(url=stream_url, app=streamName[0], name=streamName[1], streamType='http_flv')
streams.append(stream.__dict__)
return streams

0 comments on commit 7e16ef2

Please sign in to comment.