diff --git a/CHANGELOG b/CHANGELOG index 895d43a..d657806 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,7 @@ [Alexandr Topilski] - User agents - Subscribers +- Proxy streams 1.1.0 / June 6, 2019 [Alexandr Topilski] diff --git a/app/constants.py b/app/constants.py index 75f61a0..ff38248 100644 --- a/app/constants.py +++ b/app/constants.py @@ -2,14 +2,15 @@ from enum import IntEnum class StreamType(IntEnum): - RELAY = 0 - ENCODE = 1 - TIMESHIFT_PLAYER = 2 - TIMESHIFT_RECORDER = 3 - CATCHUP = 4 - TEST_LIFE = 5, - VOD_RELAY = 6, - VOD_ENCODE = 7 + PROXY = 0, + RELAY = 1 + ENCODE = 2 + TIMESHIFT_PLAYER = 3 + TIMESHIFT_RECORDER = 4 + CATCHUP = 5 + TEST_LIFE = 6, + VOD_RELAY = 7, + VOD_ENCODE = 8 @classmethod def choices(cls): @@ -69,11 +70,6 @@ DEFAULT_LOCALE = 'en' AVAILABLE_LOCALES = DEFAULT_LOCALE, 'ru' AVAILABLE_LOCALES_PAIRS = [(DEFAULT_LOCALE, 'English'), ('ru', 'Russian')] -AVAILABLE_STREAM_TYPES_PAIRS = [(StreamType.RELAY, 'relay'), (StreamType.ENCODE, 'encode'), - (StreamType.TIMESHIFT_PLAYER, 'timeshift_player'), - (StreamType.TIMESHIFT_RECORDER, 'timeshift_record'), (StreamType.CATCHUP, 'catchup'), - (StreamType.TEST_LIFE, 'test_life'), (StreamType.VOD_RELAY, 'vod_relay'), - (StreamType.VOD_ENCODE, 'vod_encode')] AVAILABLE_LOG_LEVELS_PAIRS = [(StreamLogLevel.LOG_LEVEL_EMERG, 'EVERG'), (StreamLogLevel.LOG_LEVEL_ALERT, 'ALERT'), (StreamLogLevel.LOG_LEVEL_CRIT, 'CRITICAL'), (StreamLogLevel.LOG_LEVEL_ERR, 'ERROR'), diff --git a/app/service/forms.py b/app/service/forms.py index b201921..640d902 100644 --- a/app/service/forms.py +++ b/app/service/forms.py @@ -55,7 +55,8 @@ class ActivateForm(FlaskForm): class UploadM3uForm(FlaskForm): - AVAILABLE_STREAM_TYPES_FOR_UPLOAD = [(constants.StreamType.RELAY, 'Relay'), (constants.StreamType.ENCODE, 'Encode'), + AVAILABLE_STREAM_TYPES_FOR_UPLOAD = [(constants.StreamType.PROXY, 'Proxy'), (constants.StreamType.RELAY, 'Relay'), + (constants.StreamType.ENCODE, 'Encode'), (constants.StreamType.CATCHUP, 'Catchup'), (constants.StreamType.TEST_LIFE, 'Test life'), (constants.StreamType.VOD_RELAY, 'Vod relay'), diff --git a/app/service/service.py b/app/service/service.py index 03a89b0..16ddfe2 100644 --- a/app/service/service.py +++ b/app/service/service.py @@ -1,9 +1,8 @@ from bson.objectid import ObjectId -from app.stream.stream_entry import Stream, EncodeStream, RelayStream, TimeshiftRecorderStream, CatchupStream, \ - TimeshiftPlayerStream, TestLifeStream, make_encode_stream, make_relay_stream, make_timeshift_recorder_stream, \ - make_catchup_stream, make_timeshift_player_stream, make_test_life_stream, make_vod_encode_stream, \ - make_vod_relay_stream +from app.stream.stream_entry import IStream, ProxyStream, EncodeStream, RelayStream, TimeshiftRecorderStream, \ + CatchupStream, \ + TimeshiftPlayerStream, TestLifeStream, VodRelayStream, VodEncodeStream from app.client.client_constants import ClientStatus from app.service.service_entry import ServiceSettings @@ -216,29 +215,32 @@ class Service(IStreamHandler): ServiceFields.VERSION: self.version, ServiceFields.UPTIME: self._uptime, ServiceFields.TIMESTAMP: self._timestamp, ServiceFields.STATUS: self.status} - def make_relay_stream(self) -> RelayStream: - return make_relay_stream(self._settings) + def make_proxy_stream(self) -> ProxyStream: + return ProxyStream.make_stream(self._settings) - def make_vod_relay_stream(self) -> RelayStream: - return make_vod_relay_stream(self._settings) + def make_relay_stream(self) -> RelayStream: + return RelayStream.make_stream(self._settings) + + def make_vod_relay_stream(self) -> VodRelayStream: + return VodRelayStream.make_stream(self._settings) def make_encode_stream(self) -> EncodeStream: - return make_encode_stream(self._settings) + return EncodeStream.make_stream(self._settings) def make_vod_encode_stream(self) -> EncodeStream: - return make_vod_encode_stream(self._settings) + return VodEncodeStream.make_stream(self._settings) def make_timeshift_recorder_stream(self) -> TimeshiftRecorderStream: - return make_timeshift_recorder_stream(self._settings) + return TimeshiftRecorderStream.make_stream(self._settings) def make_catchup_stream(self) -> CatchupStream: - return make_catchup_stream(self._settings) + return CatchupStream.make_stream(self._settings) def make_timeshift_player_stream(self) -> TimeshiftPlayerStream: - return make_timeshift_player_stream(self._settings) + return TimeshiftPlayerStream.make_stream(self._settings) def make_test_life_stream(self) -> TestLifeStream: - return make_test_life_stream(self._settings) + return TestLifeStream.make_stream(self._settings) # handler def on_stream_statistic_received(self, params: dict): @@ -303,7 +305,7 @@ class Service(IStreamHandler): self._uptime = stats[ServiceFields.UPTIME] self._timestamp = stats[ServiceFields.TIMESTAMP] - def __init_stream_runtime_fields(self, stream: Stream): + def __init_stream_runtime_fields(self, stream: IStream): stream.set_server_settings(self._settings) def __reload_from_db(self): diff --git a/app/service/service_entry.py b/app/service/service_entry.py index 348e766..205c872 100644 --- a/app/service/service_entry.py +++ b/app/service/service_entry.py @@ -3,7 +3,7 @@ from mongoengine import Document, ListField, EmbeddedDocumentField, ReferenceFie import app.constants as constants from app.service.server_entry import ServerSettings -from app.stream.stream_entry import Stream +from app.stream.stream_entry import IStream # #EXTM3U @@ -18,7 +18,7 @@ class UserPair(EmbeddedDocument): class ServiceSettings(Document, ServerSettings): meta = {'collection': 'services', 'auto_create_index': False} - streams = ListField(EmbeddedDocumentField(Stream), default=[]) + streams = ListField(EmbeddedDocumentField(IStream), default=[]) users = ListField(EmbeddedDocumentField(UserPair), default=[]) subscribers = ListField(ReferenceField('Subscriber'), default=[]) diff --git a/app/service/view.py b/app/service/view.py index c7d8cd6..48b5f45 100644 --- a/app/service/view.py +++ b/app/service/view.py @@ -37,7 +37,9 @@ class ServiceView(FlaskView): m3u_parser.parse() for file in m3u_parser.files: - if stream_type == constants.StreamType.RELAY: + if stream_type == constants.StreamType.PROXY: + stream = server.make_proxy_stream() + elif stream_type == constants.StreamType.RELAY: stream = server.make_relay_stream() stream.output.urls[0] = stream.generate_http_link() elif stream_type == constants.StreamType.ENCODE: diff --git a/app/stream/stream_entry.py b/app/stream/stream_entry.py index aecf015..2019864 100644 --- a/app/stream/stream_entry.py +++ b/app/stream/stream_entry.py @@ -105,22 +105,66 @@ class ChannelInfo: ChannelInfo.AUDIO_ENABLE_FIELD: self.have_audio} -class Stream(EmbeddedDocument): +class IStream(EmbeddedDocument): meta = {'allow_inheritance': True, 'auto_create_index': True} id = ObjectIdField(required=True, default=ObjectId, - unique=True, primary_key=True) + unique=True, primary_key=True) # name = StringField(default=constants.DEFAULT_STREAM_NAME, max_length=constants.MAX_STREAM_NAME_LENGTH, - min_length=constants.MIN_STREAM_NAME_LENGTH, required=True) + min_length=constants.MIN_STREAM_NAME_LENGTH, required=True) # icon = StringField(default=constants.DEFAULT_STREAM_ICON_URL, max_length=constants.MAX_URL_LENGTH, - min_length=constants.MIN_URL_LENGTH, required=True) + min_length=constants.MIN_URL_LENGTH, required=True) # group = StringField(default=constants.DEFAULT_STREAM_GROUP_TITLE, min_length=constants.MIN_STREAM_GROUP_TITLE, max_length=constants.MAX_STREAM_GROUP_TITLE, required=False) created_date = DateTimeField(default=datetime.now) # for inner use + output = EmbeddedDocumentField(OutputUrls, default=OutputUrls()) # + + _settings = ServerSettings() + + def __init__(self, *args, **kwargs): + super(IStream, self).__init__(*args, **kwargs) + + def set_server_settings(self, settings: ServerSettings): + self._settings = settings + + def get_type(self): + raise NotImplementedError('subclasses must override get_type()!') + + def get_id(self) -> str: + return str(self.id) + + def to_channel_info(self) -> [ChannelInfo]: + ch = [] + for out in self.output.urls: + epg = EpgInfo(self.get_id(), out.uri, self.name, self.icon) + ch.append(ChannelInfo(epg)) + return ch + + def to_front(self) -> dict: + return {StreamFields.NAME: self.name, StreamFields.ID: self.get_id(), StreamFields.TYPE: self.get_type()} + + def fixup_output_urls(self): + return + + +class ProxyStream(IStream): + def __init__(self, *args, **kwargs): + super(ProxyStream, self).__init__(*args, **kwargs) + + def get_type(self): + return constants.StreamType.PROXY + + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + return stream + + +class HardwareStream(IStream): log_level = IntField(default=constants.StreamLogLevel.LOG_LEVEL_INFO, required=True) input = EmbeddedDocumentField(InputUrls, default=InputUrls()) - output = EmbeddedDocumentField(OutputUrls, default=OutputUrls()) have_video = BooleanField(default=constants.DEFAULT_HAVE_VIDEO, required=True) have_audio = BooleanField(default=constants.DEFAULT_HAVE_AUDIO, required=True) audio_select = IntField(default=constants.INVALID_AUDIO_SELECT, required=True) @@ -139,13 +183,12 @@ class Stream(EmbeddedDocument): _start_time = 0 _input_streams = str() _output_streams = str() - _settings = ServerSettings() def __init__(self, *args, **kwargs): - super(Stream, self).__init__(*args, **kwargs) + super(HardwareStream, self).__init__(*args, **kwargs) - def set_server_settings(self, settings: ServerSettings): - self._settings = settings + def get_type(self): + raise NotImplementedError('subclasses must override get_type()!') def reset(self): self._status = constants.StreamStatus.NEW @@ -172,11 +215,17 @@ class Stream(EmbeddedDocument): self._output_streams = params[StreamFields.OUTPUT_STREAMS] def to_front(self) -> dict: - return {StreamFields.NAME: self.name, StreamFields.ID: self.get_id(), StreamFields.TYPE: self.get_type(), - StreamFields.STATUS: self._status, StreamFields.CPU: self._cpu, StreamFields.TIMESTAMP: self._timestamp, - StreamFields.RSS: self._rss, StreamFields.LOOP_START_TIME: self._loop_start_time, - StreamFields.RESTARTS: self._restarts, StreamFields.START_TIME: self._start_time, - StreamFields.INPUT_STREAMS: self._input_streams, StreamFields.OUTPUT_STREAMS: self._output_streams} + front = super(HardwareStream, self).to_front() + front[StreamFields.STATUS] = self._status + front[StreamFields.CPU] = self._cpu + front[StreamFields.TIMESTAMP] = self._timestamp + front[StreamFields.RSS] = self._rss + front[StreamFields.LOOP_START_TIME] = self._loop_start_time + front[StreamFields.RESTARTS] = self._restarts + front[StreamFields.START_TIME] = self._start_time + front[StreamFields.INPUT_STREAMS] = self._input_streams + front[StreamFields.OUTPUT_STREAMS] = self._output_streams + return front def config(self) -> dict: conf = { @@ -199,13 +248,6 @@ class Stream(EmbeddedDocument): conf[AUDIO_SELECT_FIELD] = audio_select return conf - def to_channel_info(self) -> [ChannelInfo]: - ch = [] - for out in self.output.urls: - epg = EpgInfo(self.get_id(), out.uri, self.name, self.icon) - ch.append(ChannelInfo(epg)) - return ch - def generate_feedback_dir(self): return '{0}/{1}/{2}'.format(self._settings.feedback_directory, self.get_type(), self.get_id()) @@ -233,12 +275,6 @@ class Stream(EmbeddedDocument): def get_have_audio(self): return self.have_audio - def get_id(self) -> str: - return str(self.id) - - def get_type(self): - raise NotImplementedError('subclasses must override get_type()!') - def get_loop(self): return self.loop @@ -251,9 +287,6 @@ class Stream(EmbeddedDocument): def get_auto_exit_time(self): return self.auto_exit_time - def fixup_output_urls(self): - return - # private def _generate_http_root_dir(self, oid: int): return '{0}/{1}/{2}/{3}'.format(self._settings.hls_directory, self.get_type(), self.get_id(), oid) @@ -284,10 +317,9 @@ class Stream(EmbeddedDocument): self.output.urls[idx] = self.generate_vod_link(filename) -class RelayStream(Stream): +class RelayStream(HardwareStream): def __init__(self, *args, **kwargs): super(RelayStream, self).__init__(*args, **kwargs) - # super(RelayStream, self).type = constants.StreamType.RELAY video_parser = StringField(default=constants.DEFAULT_VIDEO_PARSER, required=True) audio_parser = StringField(default=constants.DEFAULT_AUDIO_PARSER, required=True) @@ -310,8 +342,16 @@ class RelayStream(Stream): def fixup_output_urls(self): return self._fixup_http_output_urls() + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) + return stream -class EncodeStream(Stream): + +class EncodeStream(HardwareStream): def __init__(self, *args, **kwargs): super(EncodeStream, self).__init__(*args, **kwargs) @@ -395,6 +435,14 @@ class EncodeStream(Stream): def fixup_output_urls(self): return self._fixup_http_output_urls() + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) + return stream + class TimeshiftRecorderStream(RelayStream): def __init__(self, *args, **kwargs): @@ -422,6 +470,13 @@ class TimeshiftRecorderStream(RelayStream): def fixup_output_urls(self): return + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + return stream + class CatchupStream(TimeshiftRecorderStream): def __init__(self, *args, **kwargs): @@ -432,6 +487,13 @@ class CatchupStream(TimeshiftRecorderStream): def get_type(self): return constants.StreamType.CATCHUP + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + return stream + class TimeshiftPlayerStream(RelayStream): timeshift_dir = StringField(required=True) # FIXME default @@ -449,6 +511,14 @@ class TimeshiftPlayerStream(RelayStream): conf[TIMESHIFT_DELAY] = self.timeshift_delay return conf + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) + return stream + class TestLifeStream(RelayStream): def __init__(self, *args, **kwargs): @@ -464,6 +534,14 @@ class TestLifeStream(RelayStream): def fixup_output_urls(self): return + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id(), uri=constants.DEFAULT_TEST_URL)]) + return stream + class VodRelayStream(RelayStream): def __init__(self, *args, **kwargs): @@ -481,6 +559,14 @@ class VodRelayStream(RelayStream): def fixup_output_urls(self): return self._fixup_vod_output_urls() + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) + return stream + class VodEncodeStream(EncodeStream): def __init__(self, *args, **kwargs): @@ -498,66 +584,10 @@ class VodEncodeStream(EncodeStream): def fixup_output_urls(self): return self._fixup_vod_output_urls() - -def make_relay_stream(settings: ServerSettings) -> RelayStream: - stream = RelayStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) - return stream - - -# loop false, input file, output vod folder hls -def make_vod_relay_stream(settings: ServerSettings) -> VodRelayStream: - stream = VodRelayStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) - return stream - - -def make_encode_stream(settings: ServerSettings) -> EncodeStream: - stream = EncodeStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) - return stream - - -# loop false, input file, output vod folder hls -def make_vod_encode_stream(settings: ServerSettings) -> VodEncodeStream: - stream = VodEncodeStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) - return stream - - -def make_timeshift_recorder_stream(settings: ServerSettings) -> TimeshiftRecorderStream: - stream = TimeshiftRecorderStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - return stream - - -def make_catchup_stream(settings: ServerSettings) -> CatchupStream: - stream = CatchupStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - return stream - - -def make_timeshift_player_stream(settings: ServerSettings) -> TimeshiftPlayerStream: - stream = TimeshiftPlayerStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) - return stream - - -def make_test_life_stream(settings: ServerSettings) -> TestLifeStream: - stream = TestLifeStream() - stream._settings = settings - stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) - stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id(), uri=constants.DEFAULT_TEST_URL)]) - return stream + @classmethod + def make_stream(cls, settings: ServerSettings): + stream = cls() + stream._settings = settings + stream.input = InputUrls(urls=[InputUrl(id=InputUrl.generate_id())]) + stream.output = OutputUrls(urls=[OutputUrl(id=OutputUrl.generate_id())]) + return stream diff --git a/app/stream/stream_forms.py b/app/stream/stream_forms.py index 9ae9208..0d6153e 100644 --- a/app/stream/stream_forms.py +++ b/app/stream/stream_forms.py @@ -5,12 +5,12 @@ from wtforms.validators import InputRequired, Length, NumberRange from wtforms.fields import StringField, SubmitField, SelectField, IntegerField, FormField, BooleanField, FloatField import app.constants as constants -from app.stream.stream_entry import Stream, RelayStream, EncodeStream, TimeshiftRecorderStream, CatchupStream, \ - TimeshiftPlayerStream, TestLifeStream, VodRelayStream, VodEncodeStream +from app.stream.stream_entry import ProxyStream, HardwareStream, RelayStream, EncodeStream, TimeshiftRecorderStream, \ + CatchupStream, TimeshiftPlayerStream, TestLifeStream, VodRelayStream, VodEncodeStream from app.common_forms import InputUrlsForm, OutputUrlsForm, SizeForm, LogoForm, RationalForm -class StreamForm(FlaskForm): +class IStreamForm(FlaskForm): name = StringField(lazy_gettext(u'Name:'), validators=[InputRequired(), Length(min=constants.MIN_STREAM_NAME_LENGTH, max=constants.MAX_STREAM_NAME_LENGTH)]) @@ -18,8 +18,24 @@ class StreamForm(FlaskForm): validators=[InputRequired(), Length(min=constants.MIN_URL_LENGTH, max=constants.MAX_URL_LENGTH)]) group = StringField(lazy_gettext(u'Group:'), validators=[Length(min=constants.MIN_STREAM_GROUP_TITLE, max=constants.MAX_STREAM_GROUP_TITLE)]) - input = FormField(InputUrlsForm, lazy_gettext(u'Input:')) output = FormField(OutputUrlsForm, lazy_gettext(u'Output:')) + submit = SubmitField(lazy_gettext(u'Confirm')) + + +class ProxyStreamForm(IStreamForm): + def make_entry(self): + return self.update_entry(ProxyStream()) + + def update_entry(self, entry: ProxyStream): + entry.name = self.name.data + entry.icon = self.icon.data + entry.group = self.group.data + entry.output = self.output.get_data() + return entry + + +class HardwareStreamForm(IStreamForm): + input = FormField(InputUrlsForm, lazy_gettext(u'Input:')) log_level = SelectField(lazy_gettext(u'Log level:'), validators=[], choices=constants.AVAILABLE_LOG_LEVELS_PAIRS, coerce=constants.StreamLogLevel.coerce) audio_select = IntegerField(lazy_gettext(u'Audio select:'), @@ -31,15 +47,12 @@ class StreamForm(FlaskForm): restart_attempts = IntegerField(lazy_gettext(u'Max restart attempts and frozen:'), validators=[NumberRange(1, 1000)]) auto_exit_time = IntegerField(lazy_gettext(u'Auto exit time:'), validators=[]) - submit = SubmitField(lazy_gettext(u'Confirm')) def make_entry(self): - return self.update_entry(Stream()) + return self.update_entry(HardwareStream()) - def update_entry(self, entry: Stream): - entry.name = self.name.data + def update_entry(self, entry: HardwareStream): entry.input = self.input.get_data() - entry.output = self.output.get_data() entry.audio_select = self.audio_select.data entry.have_video = self.have_video.data @@ -52,7 +65,7 @@ class StreamForm(FlaskForm): return entry -class RelayStreamForm(StreamForm): +class RelayStreamForm(HardwareStreamForm): video_parser = SelectField(lazy_gettext(u'Video parser:'), validators=[], choices=constants.AVAILABLE_VIDEO_PARSERS) audio_parser = SelectField(lazy_gettext(u'Audio parser:'), validators=[], @@ -67,7 +80,7 @@ class RelayStreamForm(StreamForm): return super(RelayStreamForm, self).update_entry(entry) -class EncodeStreamForm(StreamForm): +class EncodeStreamForm(HardwareStreamForm): relay_video = BooleanField(lazy_gettext(u'Relay video:'), validators=[]) relay_audio = BooleanField(lazy_gettext(u'Relay audio:'), validators=[]) deinterlace = BooleanField(lazy_gettext(u'Deinterlace:'), validators=[]) diff --git a/app/stream/view.py b/app/stream/view.py index 3dd99f3..61c9fcb 100644 --- a/app/stream/view.py +++ b/app/stream/view.py @@ -6,8 +6,8 @@ from flask_login import login_required, current_user import app.constants as constants from app import get_runtime_stream_folder -from app.stream.stream_forms import EncodeStreamForm, RelayStreamForm, TimeshiftRecorderStreamForm, CatchupStreamForm, \ - TimeshiftPlayerStreamForm, TestLifeStreamForm, VodEncodeStreamForm, VodRelayStreamForm +from app.stream.stream_forms import ProxyStreamForm, EncodeStreamForm, RelayStreamForm, TimeshiftRecorderStreamForm, \ + CatchupStreamForm, TimeshiftPlayerStreamForm, TestLifeStreamForm, VodEncodeStreamForm, VodRelayStreamForm # routes @@ -100,6 +100,21 @@ class StreamView(FlaskView): # broadcast routes + @login_required + @route('/add/proxy', methods=['GET', 'POST']) + def add_proxy(self): + server = current_user.get_current_server() + if server: + stream = server.make_relay_stream() + form = ProxyStreamForm(obj=stream) + if request.method == 'POST' and form.validate_on_submit(): + new_entry = form.make_entry() + server.add_stream(new_entry) + return jsonify(status='ok'), 200 + + return render_template('stream/proxy/add.html', form=form, feedback_dir=stream.generate_feedback_dir()) + return jsonify(status='failed'), 404 + @login_required @route('/add/relay', methods=['GET', 'POST']) def add_relay(self): @@ -234,7 +249,16 @@ class StreamView(FlaskView): stream = server.find_stream_by_id(sid) if stream: type = stream.get_type() - if type == constants.StreamType.RELAY: + if type == constants.StreamType.PROXY: + form = ProxyStreamForm(obj=stream) + + if request.method == 'POST' and form.validate_on_submit(): + stream = form.update_entry(stream) + server.update_stream(stream) + return jsonify(status='ok'), 200 + + return render_template('stream/proxy/edit.html', form=form) + elif type == constants.StreamType.RELAY: form = RelayStreamForm(obj=stream) if request.method == 'POST' and form.validate_on_submit(): diff --git a/app/templates/stream/proxy/add.html b/app/templates/stream/proxy/add.html new file mode 100644 index 0000000..058a934 --- /dev/null +++ b/app/templates/stream/proxy/add.html @@ -0,0 +1,4 @@ +{% extends 'stream/proxy/base.html' %} +{% block title %} +Add proxy stream +{% endblock %} \ No newline at end of file diff --git a/app/templates/stream/proxy/base.html b/app/templates/stream/proxy/base.html new file mode 100644 index 0000000..5c99937 --- /dev/null +++ b/app/templates/stream/proxy/base.html @@ -0,0 +1,47 @@ +{% from 'bootstrap/wtf.html' import form_field %} +{% macro render_bootstrap_field(field) %} +
# | +{% trans %}Name{% endtrans %} | +{% trans %}Type{% endtrans %} | +{% trans %}Actions{% endtrans %} | +
---|---|---|---|
{{ loop.index }} | +{{ proxy.name }} | ++ {{ ['PROXY','RELAY', 'ENCODE', 'TIMESHIFT_PLAYER', 'TIMESHIFT_RECORDER', + 'CATCHUP', + 'TEST_LIFE', + 'VOD_RELAY', 'VOD_ENCODE'][proxy.type] }} + | ++ + + | +