refactor: move rtmp, restream into config, portal into core
This commit is contained in:
		
							parent
							
								
									ba03d9be1a
								
							
						
					
					
						commit
						72824d32d4
					
				| 
						 | 
					@ -1,8 +1,8 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 17:25
 | 
					# Generated by Django 5.0.2 on 2024-02-27 19:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					import django.db.models.deletion
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,7 @@ class Migration(migrations.Migration):
 | 
				
			||||||
    initial = True
 | 
					    initial = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    dependencies = [
 | 
					    dependencies = [
 | 
				
			||||||
        ('rtmp', '0002_stream_publish_counter'),
 | 
					        ('config', '0001_initial'),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    operations = [
 | 
					    operations = [
 | 
				
			||||||
| 
						 | 
					@ -18,27 +18,22 @@ class Migration(migrations.Migration):
 | 
				
			||||||
            name='Identity',
 | 
					            name='Identity',
 | 
				
			||||||
            fields=[
 | 
					            fields=[
 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
                ('identity', models.CharField(default=uuid.uuid4, max_length=36, unique=True)),
 | 
					                ('identity', models.UUIDField(default=uuid.uuid4, unique=True)),
 | 
				
			||||||
                ('name', models.CharField(max_length=100)),
 | 
					                ('name', models.CharField(max_length=100)),
 | 
				
			||||||
                ('notes', models.TextField()),
 | 
					                ('notes', models.TextField(blank=True)),
 | 
				
			||||||
                ('heartbeat', models.DateTimeField(blank=True)),
 | 
					                ('heartbeat', models.DateTimeField(blank=True, null=True)),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        migrations.CreateModel(
 | 
					        migrations.CreateModel(
 | 
				
			||||||
            name='Task',
 | 
					            name='Task',
 | 
				
			||||||
            fields=[
 | 
					            fields=[
 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('uuid', models.UUIDField(default=uuid.uuid4, unique=True)),
 | 
				
			||||||
                ('type', models.CharField(max_length=100)),
 | 
					                ('type', models.CharField(max_length=100)),
 | 
				
			||||||
 | 
					                ('config_id', models.IntegerField()),
 | 
				
			||||||
                ('configuration', models.TextField()),
 | 
					                ('configuration', models.TextField()),
 | 
				
			||||||
                ('stream', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rtmp.Stream')),
 | 
					                ('claimed_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='concierge.identity')),
 | 
				
			||||||
            ],
 | 
					                ('stream', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='config.stream')),
 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.CreateModel(
 | 
					 | 
				
			||||||
            name='Claim',
 | 
					 | 
				
			||||||
            fields=[
 | 
					 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					 | 
				
			||||||
                ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='concierge.Identity')),
 | 
					 | 
				
			||||||
                ('task', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='concierge.Task')),
 | 
					 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
    ]
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 18:34
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('concierge', '0001_initial'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='claim',
 | 
					 | 
				
			||||||
            name='id',
 | 
					 | 
				
			||||||
            field=models.CharField(default=uuid.uuid4, max_length=36, primary_key=True, serialize=False, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,23 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 18:35
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('concierge', '0002_auto_20200426_1834'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='identity',
 | 
					 | 
				
			||||||
            name='heartbeat',
 | 
					 | 
				
			||||||
            field=models.DateTimeField(blank=True, null=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='identity',
 | 
					 | 
				
			||||||
            name='notes',
 | 
					 | 
				
			||||||
            field=models.TextField(blank=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,28 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 19:12
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('concierge', '0003_auto_20200426_1835'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AddField(
 | 
					 | 
				
			||||||
            model_name='task',
 | 
					 | 
				
			||||||
            name='claimed_by',
 | 
					 | 
				
			||||||
            field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='concierge.Identity'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AddField(
 | 
					 | 
				
			||||||
            model_name='task',
 | 
					 | 
				
			||||||
            name='uuid',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, serialize=False, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.DeleteModel(
 | 
					 | 
				
			||||||
            name='Claim',
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,30 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 20:07
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('concierge', '0004_auto_20200426_1912'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='identity',
 | 
					 | 
				
			||||||
            name='identity',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='task',
 | 
					 | 
				
			||||||
            name='claimed_by',
 | 
					 | 
				
			||||||
            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='concierge.Identity'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='task',
 | 
					 | 
				
			||||||
            name='uuid',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.6 on 2020-05-31 09:51
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('concierge', '0005_auto_20200426_2007'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AddField(
 | 
					 | 
				
			||||||
            model_name='task',
 | 
					 | 
				
			||||||
            name='config_id',
 | 
					 | 
				
			||||||
            field=models.IntegerField(default=0),
 | 
					 | 
				
			||||||
            preserve_default=False,
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from rtmp.models import Stream
 | 
					from config.models import Stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Identity(models.Model):
 | 
					class Identity(models.Model):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
from django.dispatch import receiver
 | 
					from django.dispatch import receiver
 | 
				
			||||||
from rtmp.signals import stream_inactive
 | 
					 | 
				
			||||||
from .models import Task
 | 
					from .models import Task
 | 
				
			||||||
from rtmp.models import Stream
 | 
					from config.signals import stream_inactive
 | 
				
			||||||
 | 
					from config.models import Stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(stream_inactive)
 | 
					@receiver(stream_inactive)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.test import TestCase  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Create your tests here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					from django.contrib import admin
 | 
				
			||||||
 | 
					from guardian.admin import GuardedModelAdmin
 | 
				
			||||||
 | 
					from .models import Stream, Restream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@admin.register(Stream)
 | 
				
			||||||
 | 
					class StreamAdmin(GuardedModelAdmin):
 | 
				
			||||||
 | 
					    fields = ['stream', 'name', 'publish_counter']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@admin.register(Restream)
 | 
				
			||||||
 | 
					class RestreamAdmin(GuardedModelAdmin):
 | 
				
			||||||
 | 
					    fields = ['name', 'active', 'stream', 'format', 'target']
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					from django.apps import AppConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigConfig(AppConfig):
 | 
				
			||||||
 | 
					    default_auto_field = 'django.db.models.BigAutoField'
 | 
				
			||||||
 | 
					    name = 'config'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ready(self):
 | 
				
			||||||
 | 
					        import config.signals, config.signals_shared  # noqa
 | 
				
			||||||
| 
						 | 
					@ -3,9 +3,9 @@ from guardian.shortcuts import get_objects_for_user
 | 
				
			||||||
from . import models
 | 
					from . import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RestreamConfigFilteredStreamForm(ModelForm):
 | 
					class RestreamFilteredStreamForm(ModelForm):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = models.RestreamConfig
 | 
					        model = models.Restream
 | 
				
			||||||
        fields = ['name', 'stream', 'target', 'format', 'active']
 | 
					        fields = ['name', 'stream', 'target', 'format', 'active']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					    def __init__(self, *args, **kwargs):
 | 
				
			||||||
| 
						 | 
					@ -13,4 +13,4 @@ class RestreamConfigFilteredStreamForm(ModelForm):
 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					        super().__init__(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # limit the stream selection to user-accessible streams
 | 
					        # limit the stream selection to user-accessible streams
 | 
				
			||||||
        self.fields['stream'].queryset = get_objects_for_user(user, 'rtmp.view_stream')
 | 
					        self.fields['stream'].queryset = get_objects_for_user(user, 'config.view_stream')
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,40 @@
 | 
				
			||||||
 | 
					# Generated by Django 5.0.2 on 2024-02-27 19:20
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import django.db.models.deletion
 | 
				
			||||||
 | 
					import uuid
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    initial = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='Stream',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('stream', models.UUIDField(default=uuid.uuid4, help_text='Stream ID for this stream', unique=True)),
 | 
				
			||||||
 | 
					                ('name', models.CharField(help_text='Name for this stream', max_length=100)),
 | 
				
			||||||
 | 
					                ('publish_counter', models.PositiveIntegerField(default=0)),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        migrations.CreateModel(
 | 
				
			||||||
 | 
					            name='Restream',
 | 
				
			||||||
 | 
					            fields=[
 | 
				
			||||||
 | 
					                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
				
			||||||
 | 
					                ('target', models.CharField(help_text='restream_target_help', max_length=500)),
 | 
				
			||||||
 | 
					                ('name', models.CharField(help_text='restream_name_help', max_length=100)),
 | 
				
			||||||
 | 
					                ('active', models.BooleanField(help_text='restream_activate_help')),
 | 
				
			||||||
 | 
					                ('format', models.CharField(choices=[('flv', 'flv (RTMP)'), ('mpegts', 'mpegts (SRT)')], default='flv', help_text='restream_format_help', max_length=6)),
 | 
				
			||||||
 | 
					                ('stream', models.ForeignKey(help_text='restream_stream_help', on_delete=django.db.models.deletion.CASCADE, to='config.stream')),
 | 
				
			||||||
 | 
					            ],
 | 
				
			||||||
 | 
					            options={
 | 
				
			||||||
 | 
					                'verbose_name': 'restream_verbose_name',
 | 
				
			||||||
 | 
					                'verbose_name_plural': 'restream_verbose_name_plural',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
| 
						 | 
					@ -1,30 +1,16 @@
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
import uuid
 | 
					import uuid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.conf import settings
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
from django.urls import reverse
 | 
					from django.urls import reverse
 | 
				
			||||||
from django.utils.translation import gettext as _
 | 
					from django.utils.translation import gettext as _
 | 
				
			||||||
from django.db.models.signals import pre_delete
 | 
					from django.db.models.signals import pre_delete
 | 
				
			||||||
from portier.common import handlers
 | 
					from portier.common import handlers
 | 
				
			||||||
 | 
					from . import signals_shared
 | 
				
			||||||
from . import signals
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Application(models.Model):
 | 
					 | 
				
			||||||
    name = models.CharField(max_length=100, unique=True, help_text=_("rtmp_application_name"))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        verbose_name = _('application_verbose_name')
 | 
					 | 
				
			||||||
        verbose_name_plural = _('application_verbose_name_plural')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def class_name(self):
 | 
					 | 
				
			||||||
        return _('aplication_class_name')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __str__(self):
 | 
					 | 
				
			||||||
        return self.name
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Stream(models.Model):
 | 
					class Stream(models.Model):
 | 
				
			||||||
    application = models.ForeignKey(Application, on_delete=models.CASCADE, help_text=_('stream_application_help'))
 | 
					 | 
				
			||||||
    stream = models.UUIDField(unique=True, default=uuid.uuid4, help_text=_('stream_stream_help'))
 | 
					    stream = models.UUIDField(unique=True, default=uuid.uuid4, help_text=_('stream_stream_help'))
 | 
				
			||||||
    name = models.CharField(max_length=100, help_text=_('stream_name_help'))
 | 
					    name = models.CharField(max_length=100, help_text=_('stream_name_help'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +24,7 @@ class Stream(models.Model):
 | 
				
			||||||
        # if so far there were less than one incoming streams, this stream
 | 
					        # if so far there were less than one incoming streams, this stream
 | 
				
			||||||
        # is now being considered active
 | 
					        # is now being considered active
 | 
				
			||||||
        if self.publish_counter < 1:
 | 
					        if self.publish_counter < 1:
 | 
				
			||||||
            signals.stream_active.send(sender=self.__class__,
 | 
					            signals_shared.stream_active.send(sender=self.__class__,
 | 
				
			||||||
                                       stream=str(self.stream),
 | 
					                                       stream=str(self.stream),
 | 
				
			||||||
                                       param=param
 | 
					                                       param=param
 | 
				
			||||||
                                       )
 | 
					                                       )
 | 
				
			||||||
| 
						 | 
					@ -55,14 +41,14 @@ class Stream(models.Model):
 | 
				
			||||||
        # if we now have less than one incoming stream, this stream is being
 | 
					        # if we now have less than one incoming stream, this stream is being
 | 
				
			||||||
        # considered inactive
 | 
					        # considered inactive
 | 
				
			||||||
        if self.publish_counter < 1:
 | 
					        if self.publish_counter < 1:
 | 
				
			||||||
            signals.stream_inactive.send(sender=self.__class__,
 | 
					            signals_shared.stream_inactive.send(sender=self.__class__,
 | 
				
			||||||
                                         stream=str(self.stream),
 | 
					                                         stream=str(self.stream),
 | 
				
			||||||
                                         param=param
 | 
					                                         param=param
 | 
				
			||||||
                                         )
 | 
					                                         )
 | 
				
			||||||
        self.save()
 | 
					        self.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_absolute_url(self):
 | 
					    def get_absolute_url(self):
 | 
				
			||||||
        return reverse('rtmp:stream_detail', kwargs={'pk': self.pk})
 | 
					        return reverse('config:stream_detail', kwargs={'pk': self.pk})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def class_name(self):
 | 
					    def class_name(self):
 | 
				
			||||||
        return _('stream_class_name')
 | 
					        return _('stream_class_name')
 | 
				
			||||||
| 
						 | 
					@ -71,5 +57,41 @@ class Stream(models.Model):
 | 
				
			||||||
        return self.name
 | 
					        return self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Application)
 | 
					 | 
				
			||||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Stream)
 | 
					pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Stream)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Restream(models.Model):
 | 
				
			||||||
 | 
					    FORMATS = (
 | 
				
			||||||
 | 
					        ('flv', 'flv (RTMP)'),
 | 
				
			||||||
 | 
					        ('mpegts', 'mpegts (SRT)'),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    stream = models.ForeignKey(Stream, on_delete=models.CASCADE, help_text=_('restream_stream_help'))
 | 
				
			||||||
 | 
					    target = models.CharField(max_length=500, help_text=_('restream_target_help'))
 | 
				
			||||||
 | 
					    name = models.CharField(max_length=100, help_text=_('restream_name_help'))
 | 
				
			||||||
 | 
					    active = models.BooleanField(help_text=_('restream_activate_help'))
 | 
				
			||||||
 | 
					    format = models.CharField(max_length=6, choices=FORMATS, default='flv', help_text=_('restream_format_help'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Meta:
 | 
				
			||||||
 | 
					        verbose_name = _('restream_verbose_name')
 | 
				
			||||||
 | 
					        verbose_name_plural = _('restream_verbose_name_plural')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def class_name(self):
 | 
				
			||||||
 | 
					        return _('restream_class_name')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_absolute_url(self):
 | 
				
			||||||
 | 
					        return reverse('config:restream_detail', kwargs={'pk': self.pk})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __str__(self):
 | 
				
			||||||
 | 
					        return '{} to {}'.format(self.stream, self.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_json_config(self):
 | 
				
			||||||
 | 
					        config = {
 | 
				
			||||||
 | 
					            'name': self.name,
 | 
				
			||||||
 | 
					            'app': settings.GLOBAL_STREAM_NAMESPACE,
 | 
				
			||||||
 | 
					            'stream': str(self.stream.stream),
 | 
				
			||||||
 | 
					            'target': self.target,
 | 
				
			||||||
 | 
					            'format': self.format
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return json.dumps(config)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=Restream)
 | 
				
			||||||
| 
						 | 
					@ -1,22 +1,20 @@
 | 
				
			||||||
from django.dispatch import receiver
 | 
					from django.dispatch import receiver
 | 
				
			||||||
from django.db.models.signals import post_save, post_delete
 | 
					from django.db.models.signals import post_save, post_delete
 | 
				
			||||||
from rtmp.signals import stream_active
 | 
					from .models import Restream, Stream
 | 
				
			||||||
from .models import RestreamConfig
 | 
					 | 
				
			||||||
from rtmp.models import Stream
 | 
					 | 
				
			||||||
from concierge.models import Task
 | 
					from concierge.models import Task
 | 
				
			||||||
 | 
					from .signals_shared import stream_active, stream_inactive
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(stream_active)
 | 
					@receiver(stream_active)
 | 
				
			||||||
def create_tasks(sender, **kwargs):
 | 
					def create_tasks(sender, **kwargs):
 | 
				
			||||||
    stream = Stream.objects.get(stream=kwargs['stream'])
 | 
					    stream = Stream.objects.get(stream=kwargs['stream'])
 | 
				
			||||||
    instances = RestreamConfig.objects.filter(active=True, stream=stream)
 | 
					    instances = Restream.objects.filter(active=True, stream=stream)
 | 
				
			||||||
    for instance in instances:
 | 
					    for instance in instances:
 | 
				
			||||||
        task = Task(stream=instance.stream, type='restream', config_id=instance.id,
 | 
					        task = Task(stream=instance.stream, type='restream', config_id=instance.id,
 | 
				
			||||||
                    configuration=instance.get_json_config())
 | 
					                    configuration=instance.get_json_config())
 | 
				
			||||||
        task.save()
 | 
					        task.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(post_save, sender=RestreamConfig)
 | 
					@receiver(post_save, sender=Restream)
 | 
				
			||||||
def update_tasks(sender, **kwargs):
 | 
					def update_tasks(sender, **kwargs):
 | 
				
			||||||
    instance = kwargs['instance']
 | 
					    instance = kwargs['instance']
 | 
				
			||||||
    # TODO: check for breaking changes using update_fields. This needs custom save_model functions though.
 | 
					    # TODO: check for breaking changes using update_fields. This needs custom save_model functions though.
 | 
				
			||||||
| 
						 | 
					@ -35,7 +33,7 @@ def update_tasks(sender, **kwargs):
 | 
				
			||||||
        task.save()
 | 
					        task.save()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@receiver(post_delete, sender=RestreamConfig)
 | 
					@receiver(post_delete, sender=Restream)
 | 
				
			||||||
def delete_tasks(sender, **kwargs):
 | 
					def delete_tasks(sender, **kwargs):
 | 
				
			||||||
    instance = kwargs['instance']
 | 
					    instance = kwargs['instance']
 | 
				
			||||||
    # Get the current task instance if it exists, and remove it
 | 
					    # Get the current task instance if it exists, and remove it
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,4 @@
 | 
				
			||||||
from django.dispatch import Signal
 | 
					from django.dispatch import Signal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
stream_active = Signal()
 | 
					stream_active = Signal()
 | 
				
			||||||
stream_inactive = Signal()
 | 
					stream_inactive = Signal()
 | 
				
			||||||
| 
						 | 
					@ -9,7 +9,7 @@
 | 
				
			||||||
  <div class="col-sm border-right">
 | 
					  <div class="col-sm border-right">
 | 
				
			||||||
    <form method="post">
 | 
					    <form method="post">
 | 
				
			||||||
      {% csrf_token %}
 | 
					      {% csrf_token %}
 | 
				
			||||||
      <p>{% blocktrans with restreamconfig_config_name=object.name %}are_you_sure_you_want_to_delete_"{{ restreamconfig_config_name }}"?{% endblocktrans %}</p>
 | 
					      <p>{% blocktrans with restream_config_name=object.name %}are_you_sure_you_want_to_delete_"{{ restream_config_name }}"?{% endblocktrans %}</p>
 | 
				
			||||||
      {% buttons %}
 | 
					      {% buttons %}
 | 
				
			||||||
        <button type="submit" class="btn btn-danger" value="login">
 | 
					        <button type="submit" class="btn btn-danger" value="login">
 | 
				
			||||||
          {% fa5_icon 'trash' %} {% trans "delete" %}
 | 
					          {% fa5_icon 'trash' %} {% trans "delete" %}
 | 
				
			||||||
| 
						 | 
					@ -9,15 +9,15 @@
 | 
				
			||||||
{% block 'content' %}
 | 
					{% block 'content' %}
 | 
				
			||||||
<div class="row  justify-content-between">
 | 
					<div class="row  justify-content-between">
 | 
				
			||||||
  <div class="col">
 | 
					  <div class="col">
 | 
				
			||||||
    <h6>{% trans "restreamconfig_configuration_details_header" %}</h6>
 | 
					    <h6>{% trans "restream_configuration_details_header" %}</h6>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  {% get_obj_perms user for object as "obj_perms" %}
 | 
					  {% get_obj_perms user for object as "obj_perms" %}
 | 
				
			||||||
  <div class="col-auto">
 | 
					  <div class="col-auto">
 | 
				
			||||||
  {% if "change_restreamconfig" in obj_perms %}
 | 
					  {% if "change_restream" in obj_perms %}
 | 
				
			||||||
  <a href="{% url 'restream:restreamconfig_change' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'edit' %} {% trans 'change' %}</a>
 | 
					  <a href="{% url 'config:restream_change' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'edit' %} {% trans 'change' %}</a>
 | 
				
			||||||
  {% endif %}
 | 
					  {% endif %}
 | 
				
			||||||
  {% if "delete_restreamconfig" in obj_perms %}
 | 
					  {% if "delete_restream" in obj_perms %}
 | 
				
			||||||
  <a href="{% url 'restream:restreamconfig_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-danger">{% fa5_icon 'trash' %} {% trans 'delete' %}</a>
 | 
					  <a href="{% url 'config:restream_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-danger">{% fa5_icon 'trash' %} {% trans 'delete' %}</a>
 | 
				
			||||||
  {% endif %}
 | 
					  {% endif %}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@
 | 
				
			||||||
      <dt class="col-sm-3">{% trans "name" %}</dt>
 | 
					      <dt class="col-sm-3">{% trans "name" %}</dt>
 | 
				
			||||||
      <dd class="col-sm-9">{{ object.name }}</dd>
 | 
					      <dd class="col-sm-9">{{ object.name }}</dd>
 | 
				
			||||||
      <dt class="col-sm-3">{% trans "stream" %}</dt>
 | 
					      <dt class="col-sm-3">{% trans "stream" %}</dt>
 | 
				
			||||||
      <dd class="col-sm-9"><a href="{% url 'rtmp:stream_detail' pk=object.stream.pk %}">{{ object.stream.name }}</a></dd>
 | 
					      <dd class="col-sm-9"><a href="{% url 'config:stream_detail' pk=object.stream.pk %}">{{ object.stream.name }}</a></dd>
 | 
				
			||||||
      <dt class="col-sm-3">{% trans "active" %}</dt>
 | 
					      <dt class="col-sm-3">{% trans "active" %}</dt>
 | 
				
			||||||
      <dd class="col-sm-9">
 | 
					      <dd class="col-sm-9">
 | 
				
			||||||
        {% if object.active %}
 | 
					        {% if object.active %}
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% load bootstrap4 %}
 | 
					{% load bootstrap4 %}
 | 
				
			||||||
{% block 'content' %}
 | 
					{% block 'content' %}
 | 
				
			||||||
<h6>{% trans "update_restreamconfig_configuration_header" %}</h6>
 | 
					<h6>{% trans "create_new_restream_configuration_header" %}</h6>
 | 
				
			||||||
<hr class="my-4">
 | 
					<hr class="my-4">
 | 
				
			||||||
<div class="row">
 | 
					<div class="row">
 | 
				
			||||||
  <div class="col-sm border-right">
 | 
					  <div class="col-sm border-right">
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="col-sm">
 | 
					  <div class="col-sm">
 | 
				
			||||||
    {% trans "restreamconfig_configuration_text_html" %}
 | 
					    {% trans "restream_configuration_text_html" %}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
| 
						 | 
					@ -8,12 +8,12 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="row justify-content-between">
 | 
					<div class="row justify-content-between">
 | 
				
			||||||
  <div class="col">
 | 
					  <div class="col">
 | 
				
			||||||
    <h6>{% trans "restreamconfig_configuration_header" %}</h6>
 | 
					    <h6>{% trans "restream_configuration_header" %}</h6>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="col-auto">
 | 
					  <div class="col-auto">
 | 
				
			||||||
    <div class="btn-toolbar" role="toolbar">
 | 
					    <div class="btn-toolbar" role="toolbar">
 | 
				
			||||||
      <div class="btn-group" role="group">
 | 
					      <div class="btn-group" role="group">
 | 
				
			||||||
        <a href="{% url 'restream:restreamconfig_create' %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'plus' %} {% trans "create" %}</a>
 | 
					        <a href="{% url 'config:restream_create' %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'plus' %} {% trans "create" %}</a>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
| 
						 | 
					@ -59,5 +59,5 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="{% static 'js/vue.min.js' %}"></script>
 | 
					<script src="{% static 'js/vue.min.js' %}"></script>
 | 
				
			||||||
<script src="{% static 'js/axios.min.js' %}"></script>
 | 
					<script src="{% static 'js/axios.min.js' %}"></script>
 | 
				
			||||||
<script src="{% static 'js/restreamconfig-list.js' %}"></script>
 | 
					<script src="{% static 'js/restream-list.js' %}"></script>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
| 
						 | 
					@ -2,7 +2,7 @@
 | 
				
			||||||
{% load i18n %}
 | 
					{% load i18n %}
 | 
				
			||||||
{% load bootstrap4 %}
 | 
					{% load bootstrap4 %}
 | 
				
			||||||
{% block 'content' %}
 | 
					{% block 'content' %}
 | 
				
			||||||
<h6>{% trans "create_new_restreamconfig_configuration_header" %}</h6>
 | 
					<h6>{% trans "update_restream_configuration_header" %}</h6>
 | 
				
			||||||
<hr class="my-4">
 | 
					<hr class="my-4">
 | 
				
			||||||
<div class="row">
 | 
					<div class="row">
 | 
				
			||||||
  <div class="col-sm border-right">
 | 
					  <div class="col-sm border-right">
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@
 | 
				
			||||||
    </form>
 | 
					    </form>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
  <div class="col-sm">
 | 
					  <div class="col-sm">
 | 
				
			||||||
    {% trans "restreamconfig_configuration_text_html" %}
 | 
					    {% trans "restream_configuration_text_html" %}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
{% endblock %}
 | 
					{% endblock %}
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,10 @@
 | 
				
			||||||
  {% get_obj_perms user for object as "obj_perms" %}
 | 
					  {% get_obj_perms user for object as "obj_perms" %}
 | 
				
			||||||
  <div class="col-auto">
 | 
					  <div class="col-auto">
 | 
				
			||||||
    {% if "change_stream" in obj_perms %}
 | 
					    {% if "change_stream" in obj_perms %}
 | 
				
			||||||
    <a href="{% url 'rtmp:stream_change' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'edit' %} {% trans 'change' %}</a>
 | 
					    <a href="{% url 'config:stream_change' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'edit' %} {% trans 'change' %}</a>
 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
    {% if "delete_stream" in obj_perms %}
 | 
					    {% if "delete_stream" in obj_perms %}
 | 
				
			||||||
    <a href="{% url 'rtmp:stream_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-danger">{% fa5_icon 'trash' %} {% trans 'delete' %}</a>
 | 
					    <a href="{% url 'config:stream_delete' pk=object.pk %}" type="button" class="btn btn-sm btn-outline-danger">{% fa5_icon 'trash' %} {% trans 'delete' %}</a>
 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
| 
						 | 
					@ -27,8 +27,6 @@
 | 
				
			||||||
    <dl class="row">
 | 
					    <dl class="row">
 | 
				
			||||||
      <dt class="col-sm-3">{% trans "name" %}</dt>
 | 
					      <dt class="col-sm-3">{% trans "name" %}</dt>
 | 
				
			||||||
      <dd class="col-sm-9">{{ object.name }}</dd>
 | 
					      <dd class="col-sm-9">{{ object.name }}</dd>
 | 
				
			||||||
      <dt class="col-sm-3">{% trans "application" %}</dt>
 | 
					 | 
				
			||||||
      <dd class="col-sm-9">{{ object.application }}</dd>
 | 
					 | 
				
			||||||
    </dl>
 | 
					    </dl>
 | 
				
			||||||
    <h6>{% trans "how_to_configure_your_encoder_header" %}</h6>
 | 
					    <h6>{% trans "how_to_configure_your_encoder_header" %}</h6>
 | 
				
			||||||
    <hr class="my-4">
 | 
					    <hr class="my-4">
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@
 | 
				
			||||||
  <div class="col-auto">
 | 
					  <div class="col-auto">
 | 
				
			||||||
    <div class="btn-toolbar" role="toolbar">
 | 
					    <div class="btn-toolbar" role="toolbar">
 | 
				
			||||||
      <div class="btn-group" role="group">
 | 
					      <div class="btn-group" role="group">
 | 
				
			||||||
        <a href="{% url 'rtmp:stream_create' %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'plus' %} {% trans "create" %}</a>
 | 
					        <a href="{% url 'config:stream_create' %}" type="button" class="btn btn-sm btn-outline-primary">{% fa5_icon 'plus' %} {% trans "create" %}</a>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					from django.test import TestCase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Create your tests here.
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,7 @@
 | 
				
			||||||
from django.urls import path
 | 
					from django.urls import path
 | 
				
			||||||
from . import views
 | 
					from . import views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app_name = 'rtmp'
 | 
					app_name = 'config'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    path('callback/srs', views.callback_srs, name='callback_srs'),
 | 
					    path('callback/srs', views.callback_srs, name='callback_srs'),
 | 
				
			||||||
| 
						 | 
					@ -10,4 +10,9 @@ urlpatterns = [
 | 
				
			||||||
    path('streams/<int:pk>/change', views.StreamChange.as_view(), name='stream_change'),
 | 
					    path('streams/<int:pk>/change', views.StreamChange.as_view(), name='stream_change'),
 | 
				
			||||||
    path('streams/<int:pk>/delete', views.StreamDelete.as_view(), name='stream_delete'),
 | 
					    path('streams/<int:pk>/delete', views.StreamDelete.as_view(), name='stream_delete'),
 | 
				
			||||||
    path('streams/create', views.StreamCreate.as_view(), name='stream_create'),
 | 
					    path('streams/create', views.StreamCreate.as_view(), name='stream_create'),
 | 
				
			||||||
 | 
					    path('restream/', views.RestreamList.as_view(), name='restream_list'),
 | 
				
			||||||
 | 
					    path('restream/<int:pk>/', views.RestreamDetail.as_view(), name='restream_detail'),
 | 
				
			||||||
 | 
					    path('restream/<int:pk>/change', views.RestreamUpdate.as_view(), name='restream_change'),
 | 
				
			||||||
 | 
					    path('restream/<int:pk>/delete', views.RestreamDelete.as_view(), name='restream_delete'),
 | 
				
			||||||
 | 
					    path('restream/create', views.RestreamCreate.as_view(), name='restream_create'),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					@ -7,13 +7,12 @@ from django.urls import reverse_lazy
 | 
				
			||||||
from django.contrib.auth.decorators import login_required
 | 
					from django.contrib.auth.decorators import login_required
 | 
				
			||||||
from django.contrib.admin.utils import NestedObjects
 | 
					from django.contrib.admin.utils import NestedObjects
 | 
				
			||||||
from django.utils.decorators import method_decorator
 | 
					from django.utils.decorators import method_decorator
 | 
				
			||||||
from django.views.decorators.csrf import csrf_exempt
 | 
					from django.views.decorators.csrf import csrf_exempt, ensure_csrf_cookie
 | 
				
			||||||
from django.views.generic import ListView, DetailView, CreateView, DeleteView, UpdateView
 | 
					from django.views.generic import ListView, DetailView, CreateView, DeleteView, UpdateView
 | 
				
			||||||
from guardian.decorators import permission_required_or_403
 | 
					from guardian.decorators import permission_required_or_403
 | 
				
			||||||
from guardian.shortcuts import assign_perm
 | 
					from guardian.shortcuts import assign_perm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import models
 | 
					from . import models, forms
 | 
				
			||||||
from . import forms
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,8 +39,7 @@ def callback_srs(request):
 | 
				
			||||||
    except KeyError:
 | 
					    except KeyError:
 | 
				
			||||||
        return HttpResponse('1', status=401)
 | 
					        return HttpResponse('1', status=401)
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        application = models.Application.objects.get(name=app_name)
 | 
					        stream = models.Stream.objects.get(stream=stream_name)
 | 
				
			||||||
        stream = models.Stream.objects.get(stream=stream_name, application=application)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    except ObjectDoesNotExist:
 | 
					    except ObjectDoesNotExist:
 | 
				
			||||||
        return HttpResponse('1', status=401)
 | 
					        return HttpResponse('1', status=401)
 | 
				
			||||||
| 
						 | 
					@ -56,14 +54,14 @@ def callback_srs(request):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
@method_decorator(permission_required_or_403('rtmp.add_stream'),
 | 
					@method_decorator(permission_required_or_403('config.add_stream'),
 | 
				
			||||||
                  name='dispatch')
 | 
					                  name='dispatch')
 | 
				
			||||||
class StreamList(ListView):
 | 
					class StreamList(ListView):
 | 
				
			||||||
    model = models.Stream
 | 
					    model = models.Stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
@method_decorator(permission_required_or_403('rtmp.view_stream',
 | 
					@method_decorator(permission_required_or_403('config.view_stream',
 | 
				
			||||||
                  (models.Stream, 'pk', 'pk')),
 | 
					                  (models.Stream, 'pk', 'pk')),
 | 
				
			||||||
                  name='dispatch')
 | 
					                  name='dispatch')
 | 
				
			||||||
class StreamDetail(DetailView):
 | 
					class StreamDetail(DetailView):
 | 
				
			||||||
| 
						 | 
					@ -71,12 +69,11 @@ class StreamDetail(DetailView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
@method_decorator(permission_required_or_403('rtmp.change_stream',
 | 
					@method_decorator(permission_required_or_403('config.change_stream',
 | 
				
			||||||
                  (models.Stream, 'pk', 'pk')),
 | 
					                  (models.Stream, 'pk', 'pk')),
 | 
				
			||||||
                  name='dispatch')
 | 
					                  name='dispatch')
 | 
				
			||||||
class StreamChange(UpdateView):
 | 
					class StreamChange(UpdateView):
 | 
				
			||||||
    model = models.Stream
 | 
					    model = models.Stream
 | 
				
			||||||
    form_class = forms.StreamFilteredApplicationForm
 | 
					 | 
				
			||||||
    template_name_suffix = '_update_form'
 | 
					    template_name_suffix = '_update_form'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_form_kwargs(self):
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
| 
						 | 
					@ -86,16 +83,11 @@ class StreamChange(UpdateView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
@method_decorator(permission_required_or_403('rtmp.add_stream'),
 | 
					@method_decorator(permission_required_or_403('config.add_stream'),
 | 
				
			||||||
                  name='dispatch')
 | 
					                  name='dispatch')
 | 
				
			||||||
class StreamCreate(CreateView):
 | 
					class StreamCreate(CreateView):
 | 
				
			||||||
    model = models.Stream
 | 
					    model = models.Stream
 | 
				
			||||||
    form_class = forms.StreamFilteredApplicationForm
 | 
					    fields = ['name']
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_form_kwargs(self):
 | 
					 | 
				
			||||||
        kwargs = super().get_form_kwargs()
 | 
					 | 
				
			||||||
        kwargs['user'] = self.request.user
 | 
					 | 
				
			||||||
        return kwargs
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def form_valid(self, form):
 | 
					    def form_valid(self, form):
 | 
				
			||||||
        valid = super().form_valid(form)
 | 
					        valid = super().form_valid(form)
 | 
				
			||||||
| 
						 | 
					@ -108,12 +100,12 @@ class StreamCreate(CreateView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
@method_decorator(permission_required_or_403('rtmp.delete_stream',
 | 
					@method_decorator(permission_required_or_403('config.delete_stream',
 | 
				
			||||||
                  (models.Stream, 'pk', 'pk')),
 | 
					                  (models.Stream, 'pk', 'pk')),
 | 
				
			||||||
                  name='dispatch')
 | 
					                  name='dispatch')
 | 
				
			||||||
class StreamDelete(DeleteView):
 | 
					class StreamDelete(DeleteView):
 | 
				
			||||||
    model = models.Stream
 | 
					    model = models.Stream
 | 
				
			||||||
    success_url = reverse_lazy('rtmp:stream_list')
 | 
					    success_url = reverse_lazy('config:stream_list')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        context = super().get_context_data(**kwargs)
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
| 
						 | 
					@ -125,3 +117,65 @@ class StreamDelete(DeleteView):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        print(context['to_delete'])
 | 
					        print(context['to_delete'])
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(permission_required_or_403('config.add_restream'),
 | 
				
			||||||
 | 
					                  name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(ensure_csrf_cookie, name='dispatch')
 | 
				
			||||||
 | 
					class RestreamList(ListView):
 | 
				
			||||||
 | 
					    model = models.Restream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(permission_required_or_403('config.view_restream',
 | 
				
			||||||
 | 
					                  (models.Restream, 'pk', 'pk')),
 | 
				
			||||||
 | 
					                  name='dispatch')
 | 
				
			||||||
 | 
					class RestreamDetail(DetailView):
 | 
				
			||||||
 | 
					    model = models.Restream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(permission_required_or_403('config.change_restream',
 | 
				
			||||||
 | 
					                  (models.Restream, 'pk', 'pk')),
 | 
				
			||||||
 | 
					                  name='dispatch')
 | 
				
			||||||
 | 
					class RestreamUpdate(UpdateView):
 | 
				
			||||||
 | 
					    model = models.Restream
 | 
				
			||||||
 | 
					    form_class = forms.RestreamFilteredStreamForm
 | 
				
			||||||
 | 
					    template_name_suffix = '_update_form'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
 | 
					        kwargs = super().get_form_kwargs()
 | 
				
			||||||
 | 
					        kwargs['user'] = self.request.user
 | 
				
			||||||
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(permission_required_or_403('config.add_restream'),
 | 
				
			||||||
 | 
					                  name='dispatch')
 | 
				
			||||||
 | 
					class RestreamCreate(CreateView):
 | 
				
			||||||
 | 
					    model = models.Restream
 | 
				
			||||||
 | 
					    form_class = forms.RestreamFilteredStreamForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_form_kwargs(self):
 | 
				
			||||||
 | 
					        kwargs = super().get_form_kwargs()
 | 
				
			||||||
 | 
					        kwargs['user'] = self.request.user
 | 
				
			||||||
 | 
					        return kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def form_valid(self, form):
 | 
				
			||||||
 | 
					        valid = super().form_valid(form)
 | 
				
			||||||
 | 
					        if valid:
 | 
				
			||||||
 | 
					            user = self.request.user
 | 
				
			||||||
 | 
					            assign_perm('view_restream', user, self.object)
 | 
				
			||||||
 | 
					            assign_perm('change_restream', user, self.object)
 | 
				
			||||||
 | 
					            assign_perm('delete_restream', user, self.object)
 | 
				
			||||||
 | 
					        return valid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@method_decorator(login_required, name='dispatch')
 | 
				
			||||||
 | 
					@method_decorator(permission_required_or_403('config.delete_restream',
 | 
				
			||||||
 | 
					                  (models.Restream, 'pk', 'pk')),
 | 
				
			||||||
 | 
					                  name='dispatch')
 | 
				
			||||||
 | 
					class RestreamDelete(DeleteView):
 | 
				
			||||||
 | 
					    model = models.Restream
 | 
				
			||||||
 | 
					    success_url = reverse_lazy('config:restream_list')
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,7 @@ from django.conf import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PERMISSIONS = [
 | 
					PERMISSIONS = [
 | 
				
			||||||
    'add_stream',
 | 
					    'add_stream',
 | 
				
			||||||
    'add_restreamconfig'
 | 
					    'add_restream'
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					from django.shortcuts import render
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def index(request):
 | 
				
			||||||
 | 
					    return render(request, 'core/index.html')
 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.contrib import admin  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Register your models here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,5 +0,0 @@
 | 
				
			||||||
from django.apps import AppConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PortalConfig(AppConfig):
 | 
					 | 
				
			||||||
    name = 'portal'
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.db import models  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Create your models here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.test import TestCase  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Create your tests here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
from django.shortcuts import render
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def index(request):
 | 
					 | 
				
			||||||
    # do fancy stuff here maybe
 | 
					 | 
				
			||||||
    return render(request, 'portal/index.html')
 | 
					 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ CSRF_TRUSTED_ORIGINS = os.environ.get("DJANGO_CSRF_TRUSTED_ORIGINS", default="ht
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFAULT_GROUP = 'default'
 | 
					DEFAULT_GROUP = 'default'
 | 
				
			||||||
DEFAULT_RTMP_APPPLICATION = 'live'
 | 
					GLOBAL_STREAM_NAMESPACE = 'live'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Application definition
 | 
					# Application definition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,10 +47,8 @@ INSTALLED_APPS = [
 | 
				
			||||||
    'bootstrap4',
 | 
					    'bootstrap4',
 | 
				
			||||||
    'fontawesome_5',
 | 
					    'fontawesome_5',
 | 
				
			||||||
    'core.apps.CoreConfig',
 | 
					    'core.apps.CoreConfig',
 | 
				
			||||||
    'portal.apps.PortalConfig',
 | 
					    'config.apps.ConfigConfig',
 | 
				
			||||||
    'rtmp.apps.RtmpConfig',
 | 
					 | 
				
			||||||
    'concierge.apps.ConciergeConfig',
 | 
					    'concierge.apps.ConciergeConfig',
 | 
				
			||||||
    'restream.apps.RestreamConfig',
 | 
					 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MIDDLEWARE = [
 | 
					MIDDLEWARE = [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,3 @@
 | 
				
			||||||
"""portier URL Configuration
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
The `urlpatterns` list routes URLs to views. For more information please see:
 | 
					 | 
				
			||||||
    https://docs.djangoproject.com/en/3.0/topics/http/urls/
 | 
					 | 
				
			||||||
Examples:
 | 
					 | 
				
			||||||
Function views
 | 
					 | 
				
			||||||
    1. Add an import:  from my_app import views
 | 
					 | 
				
			||||||
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
 | 
					 | 
				
			||||||
Class-based views
 | 
					 | 
				
			||||||
    1. Add an import:  from other_app.views import Home
 | 
					 | 
				
			||||||
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
 | 
					 | 
				
			||||||
Including another URLconf
 | 
					 | 
				
			||||||
    1. Import the include() function: from django.urls import include, path
 | 
					 | 
				
			||||||
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
 | 
					 | 
				
			||||||
"""
 | 
					 | 
				
			||||||
from django.contrib import admin
 | 
					from django.contrib import admin
 | 
				
			||||||
from django.urls import include, path
 | 
					from django.urls import include, path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,9 +6,8 @@ urlpatterns = [
 | 
				
			||||||
    path('accounts/', include('django.contrib.auth.urls')),
 | 
					    path('accounts/', include('django.contrib.auth.urls')),
 | 
				
			||||||
    path('i18n/', include('django.conf.urls.i18n')),
 | 
					    path('i18n/', include('django.conf.urls.i18n')),
 | 
				
			||||||
    path('admin/', admin.site.urls),
 | 
					    path('admin/', admin.site.urls),
 | 
				
			||||||
    path('rtmp/', include('rtmp.urls')),
 | 
					    path('config/', include('config.urls')),
 | 
				
			||||||
    path('restream/', include('restream.urls')),
 | 
					 | 
				
			||||||
    path('concierge/', include('concierge.urls')),
 | 
					    path('concierge/', include('concierge.urls')),
 | 
				
			||||||
    path('api/v1/', include('restapi.urls')),
 | 
					    path('api/v1/', include('restapi.urls')),
 | 
				
			||||||
    path('', include('portal.urls')),
 | 
					    path('', include('core.urls')),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,12 @@
 | 
				
			||||||
from django.urls import path, include
 | 
					from django.urls import path, include
 | 
				
			||||||
from rest_framework import routers
 | 
					from rest_framework import routers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .views import ApplicationViewSet, StreamViewSet, RestreamConfigViewSet
 | 
					from .views import StreamViewSet, RestreamViewSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
router = routers.DefaultRouter()
 | 
					router = routers.DefaultRouter()
 | 
				
			||||||
router.register(r'applications', ApplicationViewSet)
 | 
					 | 
				
			||||||
router.register(r'streams', StreamViewSet)
 | 
					router.register(r'streams', StreamViewSet)
 | 
				
			||||||
router.register(r'restreamconfigs', RestreamConfigViewSet)
 | 
					router.register(r'restreams', RestreamViewSet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app_name = 'restapi'
 | 
					app_name = 'restapi'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,7 @@
 | 
				
			||||||
from rest_framework_guardian.serializers import ObjectPermissionsAssignmentMixin
 | 
					from rest_framework_guardian.serializers import ObjectPermissionsAssignmentMixin
 | 
				
			||||||
from rest_framework import serializers, viewsets
 | 
					from rest_framework import serializers, viewsets
 | 
				
			||||||
from rest_framework_guardian import filters
 | 
					from rest_framework_guardian import filters
 | 
				
			||||||
from rtmp.models import Application, Stream
 | 
					from config.models import Stream, Restream
 | 
				
			||||||
from restream.models import RestreamConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ApplicationSerializer(serializers.HyperlinkedModelSerializer):
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = Application
 | 
					 | 
				
			||||||
        fields = ['id', 'name']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ApplicationViewSet(viewsets.ReadOnlyModelViewSet):
 | 
					 | 
				
			||||||
    queryset = Application.objects.all()
 | 
					 | 
				
			||||||
    serializer_class = ApplicationSerializer
 | 
					 | 
				
			||||||
    filter_backends = [filters.ObjectPermissionsFilter]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StreamSerializer(ObjectPermissionsAssignmentMixin, serializers.ModelSerializer):
 | 
					class StreamSerializer(ObjectPermissionsAssignmentMixin, serializers.ModelSerializer):
 | 
				
			||||||
| 
						 | 
					@ -38,9 +25,9 @@ class StreamViewSet(viewsets.ModelViewSet):
 | 
				
			||||||
    filter_backends = [filters.ObjectPermissionsFilter]
 | 
					    filter_backends = [filters.ObjectPermissionsFilter]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RestreamConfigSerializer(ObjectPermissionsAssignmentMixin, serializers.ModelSerializer):
 | 
					class RestreamSerializer(ObjectPermissionsAssignmentMixin, serializers.ModelSerializer):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        model = RestreamConfig
 | 
					        model = Restream
 | 
				
			||||||
        fields = '__all__'
 | 
					        fields = '__all__'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_permissions_map(self, created):
 | 
					    def get_permissions_map(self, created):
 | 
				
			||||||
| 
						 | 
					@ -53,12 +40,12 @@ class RestreamConfigSerializer(ObjectPermissionsAssignmentMixin, serializers.Mod
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def validate_stream(self, value):
 | 
					    def validate_stream(self, value):
 | 
				
			||||||
        request = self.context['request']
 | 
					        request = self.context['request']
 | 
				
			||||||
        if not request.user.has_perm('rtmp.view_stream', value):
 | 
					        if not request.user.has_perm('config.view_stream', value):
 | 
				
			||||||
            raise serializers.ValidationError('Access to stream is not authorized')
 | 
					            raise serializers.ValidationError('Access to stream is not authorized')
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RestreamConfigViewSet(viewsets.ModelViewSet):
 | 
					class RestreamViewSet(viewsets.ModelViewSet):
 | 
				
			||||||
    queryset = RestreamConfig.objects.all()
 | 
					    queryset = Restream.objects.all()
 | 
				
			||||||
    serializer_class = RestreamConfigSerializer
 | 
					    serializer_class = RestreamSerializer
 | 
				
			||||||
    filter_backends = [filters.ObjectPermissionsFilter]
 | 
					    filter_backends = [filters.ObjectPermissionsFilter]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,10 +0,0 @@
 | 
				
			||||||
from django.contrib import admin
 | 
					 | 
				
			||||||
from guardian.admin import GuardedModelAdmin
 | 
					 | 
				
			||||||
from .models import RestreamConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@admin.register(RestreamConfig)
 | 
					 | 
				
			||||||
class RestreamConfigAdmin(GuardedModelAdmin):
 | 
					 | 
				
			||||||
    fields = ['name', 'active', 'stream', 'format', 'target']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,8 +0,0 @@
 | 
				
			||||||
from django.apps import AppConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RestreamConfig(AppConfig):
 | 
					 | 
				
			||||||
    name = 'restream'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def ready(self):
 | 
					 | 
				
			||||||
        import restream.signals  # noqa
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,26 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-23 19:04
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    initial = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0001_initial'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.CreateModel(
 | 
					 | 
				
			||||||
            name='RestreamConfig',
 | 
					 | 
				
			||||||
            fields=[
 | 
					 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					 | 
				
			||||||
                ('target', models.CharField(max_length=500)),
 | 
					 | 
				
			||||||
                ('name', models.CharField(max_length=100)),
 | 
					 | 
				
			||||||
                ('active', models.BooleanField()),
 | 
					 | 
				
			||||||
                ('stream', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rtmp.Stream')),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,39 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-05-01 13:02
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0004_auto_20200501_1302'),
 | 
					 | 
				
			||||||
        ('restream', '0001_initial'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterModelOptions(
 | 
					 | 
				
			||||||
            name='restreamconfig',
 | 
					 | 
				
			||||||
            options={'verbose_name': 'restreamconfig_verbose_name', 'verbose_name_plural': 'restreamconfig_verbose_name_plural'},
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='restreamconfig',
 | 
					 | 
				
			||||||
            name='active',
 | 
					 | 
				
			||||||
            field=models.BooleanField(help_text='restreamconfig_activate_help'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='restreamconfig',
 | 
					 | 
				
			||||||
            name='name',
 | 
					 | 
				
			||||||
            field=models.CharField(help_text='restreamconfig_name_help', max_length=100),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='restreamconfig',
 | 
					 | 
				
			||||||
            name='stream',
 | 
					 | 
				
			||||||
            field=models.ForeignKey(help_text='restreamconfig_stream_help', on_delete=django.db.models.deletion.CASCADE, to='rtmp.Stream'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='restreamconfig',
 | 
					 | 
				
			||||||
            name='target',
 | 
					 | 
				
			||||||
            field=models.CharField(help_text='restreamconfig_target_help', max_length=500),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.1.13 on 2021-12-14 17:35
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('restream', '0002_auto_20200501_1302'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AddField(
 | 
					 | 
				
			||||||
            model_name='restreamconfig',
 | 
					 | 
				
			||||||
            name='format',
 | 
					 | 
				
			||||||
            field=models.CharField(choices=[('flv', 'flv (RTMP)'), ('mpegts', 'mpegts (SRT)')], default='flv', help_text='restreamconfig_format_help', max_length=6),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,46 +0,0 @@
 | 
				
			||||||
from django.db import models
 | 
					 | 
				
			||||||
from django.urls import reverse
 | 
					 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					 | 
				
			||||||
from django.db.models.signals import pre_delete
 | 
					 | 
				
			||||||
from portier.common import handlers
 | 
					 | 
				
			||||||
import json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from rtmp.models import Stream
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RestreamConfig(models.Model):
 | 
					 | 
				
			||||||
    FORMATS = (
 | 
					 | 
				
			||||||
        ('flv', 'flv (RTMP)'),
 | 
					 | 
				
			||||||
        ('mpegts', 'mpegts (SRT)'),
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    stream = models.ForeignKey(Stream, on_delete=models.CASCADE, help_text=_('restreamconfig_stream_help'))
 | 
					 | 
				
			||||||
    target = models.CharField(max_length=500, help_text=_('restreamconfig_target_help'))
 | 
					 | 
				
			||||||
    name = models.CharField(max_length=100, help_text=_('restreamconfig_name_help'))
 | 
					 | 
				
			||||||
    active = models.BooleanField(help_text=_('restreamconfig_activate_help'))
 | 
					 | 
				
			||||||
    format = models.CharField(max_length=6, choices=FORMATS, default='flv', help_text=_('restreamconfig_format_help'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        verbose_name = _('restreamconfig_verbose_name')
 | 
					 | 
				
			||||||
        verbose_name_plural = _('restreamconfig_verbose_name_plural')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def class_name(self):
 | 
					 | 
				
			||||||
        return _('restreamconfig_class_name')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_absolute_url(self):
 | 
					 | 
				
			||||||
        return reverse('restream:restreamconfig_detail', kwargs={'pk': self.pk})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __str__(self):
 | 
					 | 
				
			||||||
        return '{} to {}'.format(self.stream, self.name)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_json_config(self):
 | 
					 | 
				
			||||||
        config = {
 | 
					 | 
				
			||||||
            'name': self.name,
 | 
					 | 
				
			||||||
            'app': self.stream.application.name,
 | 
					 | 
				
			||||||
            'stream': str(self.stream.stream),
 | 
					 | 
				
			||||||
            'target': self.target,
 | 
					 | 
				
			||||||
            'format': self.format
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return json.dumps(config)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pre_delete.connect(handlers.remove_obj_perms_connected_with_user, sender=RestreamConfig)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.test import TestCase  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Create your tests here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,12 +0,0 @@
 | 
				
			||||||
from django.urls import path
 | 
					 | 
				
			||||||
from . import views
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
app_name = 'restream'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
urlpatterns = [
 | 
					 | 
				
			||||||
    path('restreamconfig/', views.RestreamConfigList.as_view(), name='restreamconfig_list'),
 | 
					 | 
				
			||||||
    path('restreamconfig/<int:pk>/', views.RestreamConfigDetail.as_view(), name='restreamconfig_detail'),
 | 
					 | 
				
			||||||
    path('restreamconfig/<int:pk>/change', views.RestreamConfigChange.as_view(), name='restreamconfig_change'),
 | 
					 | 
				
			||||||
    path('restreamconfig/<int:pk>/delete', views.RestreamConfigDelete.as_view(), name='restreamconfig_delete'),
 | 
					 | 
				
			||||||
    path('restreamconfig/create', views.RestreamConfigCreate.as_view(), name='restreamconfig_create'),
 | 
					 | 
				
			||||||
]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,72 +0,0 @@
 | 
				
			||||||
from django.urls import reverse_lazy
 | 
					 | 
				
			||||||
from django.contrib.auth.decorators import login_required
 | 
					 | 
				
			||||||
from django.views.decorators.csrf import ensure_csrf_cookie
 | 
					 | 
				
			||||||
from django.utils.decorators import method_decorator
 | 
					 | 
				
			||||||
from django.views.generic import ListView, DetailView, CreateView, DeleteView, UpdateView
 | 
					 | 
				
			||||||
from guardian.decorators import permission_required_or_403
 | 
					 | 
				
			||||||
from guardian.shortcuts import assign_perm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from . import models
 | 
					 | 
				
			||||||
from . import forms
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(permission_required_or_403('restream.add_restreamconfig'),
 | 
					 | 
				
			||||||
                  name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
 | 
					 | 
				
			||||||
class RestreamConfigList(ListView):
 | 
					 | 
				
			||||||
    model = models.RestreamConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(permission_required_or_403('restream.view_restreamconfig',
 | 
					 | 
				
			||||||
                  (models.RestreamConfig, 'pk', 'pk')),
 | 
					 | 
				
			||||||
                  name='dispatch')
 | 
					 | 
				
			||||||
class RestreamConfigDetail(DetailView):
 | 
					 | 
				
			||||||
    model = models.RestreamConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(permission_required_or_403('restream.change_restreamconfig',
 | 
					 | 
				
			||||||
                  (models.RestreamConfig, 'pk', 'pk')),
 | 
					 | 
				
			||||||
                  name='dispatch')
 | 
					 | 
				
			||||||
class RestreamConfigChange(UpdateView):
 | 
					 | 
				
			||||||
    model = models.RestreamConfig
 | 
					 | 
				
			||||||
    form_class = forms.RestreamConfigFilteredStreamForm
 | 
					 | 
				
			||||||
    template_name_suffix = '_update_form'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_form_kwargs(self):
 | 
					 | 
				
			||||||
        kwargs = super().get_form_kwargs()
 | 
					 | 
				
			||||||
        kwargs['user'] = self.request.user
 | 
					 | 
				
			||||||
        return kwargs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(permission_required_or_403('restream.add_restreamconfig'),
 | 
					 | 
				
			||||||
                  name='dispatch')
 | 
					 | 
				
			||||||
class RestreamConfigCreate(CreateView):
 | 
					 | 
				
			||||||
    model = models.RestreamConfig
 | 
					 | 
				
			||||||
    form_class = forms.RestreamConfigFilteredStreamForm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_form_kwargs(self):
 | 
					 | 
				
			||||||
        kwargs = super().get_form_kwargs()
 | 
					 | 
				
			||||||
        kwargs['user'] = self.request.user
 | 
					 | 
				
			||||||
        return kwargs
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def form_valid(self, form):
 | 
					 | 
				
			||||||
        valid = super().form_valid(form)
 | 
					 | 
				
			||||||
        if valid:
 | 
					 | 
				
			||||||
            user = self.request.user
 | 
					 | 
				
			||||||
            assign_perm('view_restreamconfig', user, self.object)
 | 
					 | 
				
			||||||
            assign_perm('change_restreamconfig', user, self.object)
 | 
					 | 
				
			||||||
            assign_perm('delete_restreamconfig', user, self.object)
 | 
					 | 
				
			||||||
        return valid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@method_decorator(login_required, name='dispatch')
 | 
					 | 
				
			||||||
@method_decorator(permission_required_or_403('restream.delete_restreamconfig',
 | 
					 | 
				
			||||||
                  (models.RestreamConfig, 'pk', 'pk')),
 | 
					 | 
				
			||||||
                  name='dispatch')
 | 
					 | 
				
			||||||
class RestreamConfigDelete(DeleteView):
 | 
					 | 
				
			||||||
    model = models.RestreamConfig
 | 
					 | 
				
			||||||
    success_url = reverse_lazy('restream:restreamconfig_list')
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,15 +0,0 @@
 | 
				
			||||||
from django.contrib import admin
 | 
					 | 
				
			||||||
from guardian.admin import GuardedModelAdmin
 | 
					 | 
				
			||||||
from .models import Application, Stream
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@admin.register(Application)
 | 
					 | 
				
			||||||
class ApplicationAdmin(GuardedModelAdmin):
 | 
					 | 
				
			||||||
    fields = ['name']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
@admin.register(Stream)
 | 
					 | 
				
			||||||
class StreamAdmin(GuardedModelAdmin):
 | 
					 | 
				
			||||||
    fields = ['application', 'stream', 'name', 'publish_counter']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,8 +0,0 @@
 | 
				
			||||||
from django.apps import AppConfig
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class RtmpConfig(AppConfig):
 | 
					 | 
				
			||||||
    name = 'rtmp'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def ready(self):
 | 
					 | 
				
			||||||
        import rtmp.signals  # noqa
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,16 +0,0 @@
 | 
				
			||||||
from django.forms import ModelForm
 | 
					 | 
				
			||||||
from guardian.shortcuts import get_objects_for_user
 | 
					 | 
				
			||||||
from . import models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StreamFilteredApplicationForm(ModelForm):
 | 
					 | 
				
			||||||
    class Meta:
 | 
					 | 
				
			||||||
        model = models.Stream
 | 
					 | 
				
			||||||
        fields = ['name', 'application']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def __init__(self, *args, **kwargs):
 | 
					 | 
				
			||||||
        user = kwargs.pop('user', None)
 | 
					 | 
				
			||||||
        super().__init__(*args, **kwargs)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # limit the stream selection to user-accessible streams
 | 
					 | 
				
			||||||
        self.fields['application'].queryset = get_objects_for_user(user, 'rtmp.view_application')
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,16 +0,0 @@
 | 
				
			||||||
from django.core.management.base import BaseCommand
 | 
					 | 
				
			||||||
from django.contrib.auth.models import Group
 | 
					 | 
				
			||||||
from django.conf import settings
 | 
					 | 
				
			||||||
from guardian.shortcuts import assign_perm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from rtmp import models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Command(BaseCommand):
 | 
					 | 
				
			||||||
    help = 'Creates a default RTMP application that is available to all users in the default group'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def handle(self, *args, **options):
 | 
					 | 
				
			||||||
        default_group, _ = Group.objects.get_or_create(name=settings.DEFAULT_GROUP)
 | 
					 | 
				
			||||||
        default_app, _ = models.Application.objects.get_or_create(name=settings.DEFAULT_RTMP_APPPLICATION)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        assign_perm('view_application', default_group, default_app)
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,32 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-23 19:04
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    initial = True
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.CreateModel(
 | 
					 | 
				
			||||||
            name='Application',
 | 
					 | 
				
			||||||
            fields=[
 | 
					 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					 | 
				
			||||||
                ('name', models.CharField(help_text='rtmp_application_name', max_length=100, unique=True)),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.CreateModel(
 | 
					 | 
				
			||||||
            name='Stream',
 | 
					 | 
				
			||||||
            fields=[
 | 
					 | 
				
			||||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
					 | 
				
			||||||
                ('stream', models.CharField(default=uuid.uuid4, max_length=64, unique=True)),
 | 
					 | 
				
			||||||
                ('name', models.CharField(max_length=100)),
 | 
					 | 
				
			||||||
                ('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rtmp.Application')),
 | 
					 | 
				
			||||||
            ],
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,18 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 17:25
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0001_initial'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AddField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='publish_counter',
 | 
					 | 
				
			||||||
            field=models.PositiveIntegerField(default=0),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,19 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-04-26 18:34
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0002_stream_publish_counter'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='stream',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,34 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.5 on 2020-05-01 13:02
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0003_auto_20200426_1834'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterModelOptions(
 | 
					 | 
				
			||||||
            name='application',
 | 
					 | 
				
			||||||
            options={'verbose_name': 'application_verbose_name', 'verbose_name_plural': 'application_verbose_name_plural'},
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='application',
 | 
					 | 
				
			||||||
            field=models.ForeignKey(help_text='stream_application_help', on_delete=django.db.models.deletion.CASCADE, to='rtmp.Application'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='name',
 | 
					 | 
				
			||||||
            field=models.CharField(help_text='stream_name_help', max_length=100),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='stream',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, help_text='stream_stream_help', unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,39 +0,0 @@
 | 
				
			||||||
# Generated by Django 3.0.6 on 2020-05-31 09:51
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from django.db import migrations, models
 | 
					 | 
				
			||||||
import django.db.models.deletion
 | 
					 | 
				
			||||||
import uuid
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Migration(migrations.Migration):
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    dependencies = [
 | 
					 | 
				
			||||||
        ('rtmp', '0004_auto_20200501_1302'),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    operations = [
 | 
					 | 
				
			||||||
        migrations.AlterModelOptions(
 | 
					 | 
				
			||||||
            name='application',
 | 
					 | 
				
			||||||
            options={'verbose_name': 'RTMP application', 'verbose_name_plural': 'RTMP applications'},
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='application',
 | 
					 | 
				
			||||||
            name='name',
 | 
					 | 
				
			||||||
            field=models.CharField(help_text='RTMP application name', max_length=100, unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='application',
 | 
					 | 
				
			||||||
            field=models.ForeignKey(help_text='Application which the stream is assigned to', on_delete=django.db.models.deletion.CASCADE, to='rtmp.Application'),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='name',
 | 
					 | 
				
			||||||
            field=models.CharField(help_text='Name for this stream', max_length=100),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
        migrations.AlterField(
 | 
					 | 
				
			||||||
            model_name='stream',
 | 
					 | 
				
			||||||
            name='stream',
 | 
					 | 
				
			||||||
            field=models.UUIDField(default=uuid.uuid4, help_text='Stream ID for this stream', unique=True),
 | 
					 | 
				
			||||||
        ),
 | 
					 | 
				
			||||||
    ]
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,3 +0,0 @@
 | 
				
			||||||
from django.test import TestCase  # noqa
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
# Create your tests here.
 | 
					 | 
				
			||||||
| 
						 | 
					@ -25,7 +25,6 @@ migrate() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
initialize() {
 | 
					initialize() {
 | 
				
			||||||
  python manage.py createdefaultgroup
 | 
					  python manage.py createdefaultgroup
 | 
				
			||||||
  python manage.py createdefaultapplication
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
wait_for_redis
 | 
					wait_for_redis
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ var app = new Vue({
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    toggleActive(cfg) {
 | 
					    toggleActive(cfg) {
 | 
				
			||||||
      axios
 | 
					      axios
 | 
				
			||||||
        .patch('/api/v1/restreamconfigs/' + cfg.id + '/', { active: !cfg.active })
 | 
					        .patch('/api/v1/restream/' + cfg.id + '/', { active: !cfg.active })
 | 
				
			||||||
        .then(response => {
 | 
					        .then(response => {
 | 
				
			||||||
            i = this.cfgs.findIndex((obj => obj.id == cfg.id))
 | 
					            i = this.cfgs.findIndex((obj => obj.id == cfg.id))
 | 
				
			||||||
            Vue.set(this.cfgs, i, response.data)
 | 
					            Vue.set(this.cfgs, i, response.data)
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ var app = new Vue({
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    fetchData() {
 | 
					    fetchData() {
 | 
				
			||||||
      axios
 | 
					      axios
 | 
				
			||||||
        .get('/api/v1/restreamconfigs/')
 | 
					        .get('/api/v1/restreams/')
 | 
				
			||||||
        .then(response => {
 | 
					        .then(response => {
 | 
				
			||||||
          this.cfgs = response.data
 | 
					          this.cfgs = response.data
 | 
				
			||||||
          this.isLoading = false
 | 
					          this.isLoading = false
 | 
				
			||||||
| 
						 | 
					@ -39,8 +39,8 @@
 | 
				
			||||||
                {% trans "navbar_streaming" %}
 | 
					                {% trans "navbar_streaming" %}
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
              <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarStreamingDropdown">
 | 
					              <div class="dropdown-menu dropdown-menu-right" aria-labelledby="navbarStreamingDropdown">
 | 
				
			||||||
                <a class="dropdown-item{% if not perms.rtmp.add_stream %} disabled{% endif %}" href="{% url 'rtmp:stream_list' %}">{% trans "navbar_configuration_streams" %}</a>
 | 
					                <a class="dropdown-item{% if not perms.config.add_stream %} disabled{% endif %}" href="{% url 'config:stream_list' %}">{% trans "navbar_configuration_streams" %}</a>
 | 
				
			||||||
                <a class="dropdown-item{% if not perms.restream.add_restreamconfig %} disabled{% endif %}" href="{% url 'restream:restreamconfig_list' %}">{% trans "navbar_configuration_restreams" %}</a>
 | 
					                <a class="dropdown-item{% if not perms.config.add_restream %} disabled{% endif %}" href="{% url 'config:restream_list' %}">{% trans "navbar_configuration_restreams" %}</a>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </li>
 | 
					            </li>
 | 
				
			||||||
          {% endif %}
 | 
					          {% endif %}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue