feat(api): split api into multiple apps (#1626)
Fixes #1622 - split the api into 4 apps: core, history, schedule, storage - exploded the settings into testing/prod
This commit is contained in:
parent
87d2da9d84
commit
fce988aef1
120 changed files with 1499 additions and 1078 deletions
0
api/libretime_api/schedule/__init__.py
Normal file
0
api/libretime_api/schedule/__init__.py
Normal file
7
api/libretime_api/schedule/apps.py
Normal file
7
api/libretime_api/schedule/apps.py
Normal file
|
@ -0,0 +1,7 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ScheduleConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "libretime_api.schedule"
|
||||
verbose_name = "LibreTime Schedule API"
|
6
api/libretime_api/schedule/models/__init__.py
Normal file
6
api/libretime_api/schedule/models/__init__.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from .playlist import Playlist, PlaylistContent
|
||||
from .podcast import ImportedPodcast, Podcast, PodcastEpisode, StationPodcast
|
||||
from .schedule import Schedule
|
||||
from .show import Show, ShowDays, ShowHost, ShowInstance, ShowRebroadcast
|
||||
from .smart_block import SmartBlock, SmartBlockContent, SmartBlockCriteria
|
||||
from .webstream import Webstream, WebstreamMetadata
|
39
api/libretime_api/schedule/models/playlist.py
Normal file
39
api/libretime_api/schedule/models/playlist.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Playlist(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
mtime = models.DateTimeField(blank=True, null=True)
|
||||
utime = models.DateTimeField(blank=True, null=True)
|
||||
creator = models.ForeignKey("core.User", models.DO_NOTHING, blank=True, null=True)
|
||||
description = models.CharField(max_length=512, blank=True, null=True)
|
||||
length = models.DurationField(blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
return self.creator
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_playlist"
|
||||
|
||||
|
||||
class PlaylistContent(models.Model):
|
||||
playlist = models.ForeignKey("Playlist", models.DO_NOTHING, blank=True, null=True)
|
||||
file = models.ForeignKey("storage.File", models.DO_NOTHING, blank=True, null=True)
|
||||
block = models.ForeignKey("SmartBlock", models.DO_NOTHING, blank=True, null=True)
|
||||
stream_id = models.IntegerField(blank=True, null=True)
|
||||
type = models.SmallIntegerField()
|
||||
position = models.IntegerField(blank=True, null=True)
|
||||
trackoffset = models.FloatField()
|
||||
cliplength = models.DurationField(blank=True, null=True)
|
||||
cuein = models.DurationField(blank=True, null=True)
|
||||
cueout = models.DurationField(blank=True, null=True)
|
||||
fadein = models.TimeField(blank=True, null=True)
|
||||
fadeout = models.TimeField(blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
return self.playlist.owner
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_playlistcontents"
|
83
api/libretime_api/schedule/models/podcast.py
Normal file
83
api/libretime_api/schedule/models/podcast.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Podcast(models.Model):
|
||||
url = models.CharField(max_length=4096)
|
||||
title = models.CharField(max_length=4096)
|
||||
creator = models.CharField(max_length=4096, blank=True, null=True)
|
||||
description = models.CharField(max_length=4096, blank=True, null=True)
|
||||
language = models.CharField(max_length=4096, blank=True, null=True)
|
||||
copyright = models.CharField(max_length=4096, blank=True, null=True)
|
||||
link = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_author = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_keywords = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_summary = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_subtitle = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_category = models.CharField(max_length=4096, blank=True, null=True)
|
||||
itunes_explicit = models.CharField(max_length=4096, blank=True, null=True)
|
||||
owner = models.ForeignKey(
|
||||
"core.User", models.DO_NOTHING, db_column="owner", blank=True, null=True
|
||||
)
|
||||
|
||||
def get_owner(self):
|
||||
return self.owner
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "podcast"
|
||||
permissions = [
|
||||
("change_own_podcast", "Change the podcasts where they are the owner"),
|
||||
("delete_own_podcast", "Delete the podcasts where they are the owner"),
|
||||
]
|
||||
|
||||
|
||||
class PodcastEpisode(models.Model):
|
||||
file = models.ForeignKey("storage.File", models.DO_NOTHING, blank=True, null=True)
|
||||
podcast = models.ForeignKey("Podcast", models.DO_NOTHING)
|
||||
publication_date = models.DateTimeField()
|
||||
download_url = models.CharField(max_length=4096)
|
||||
episode_guid = models.CharField(max_length=4096)
|
||||
episode_title = models.CharField(max_length=4096)
|
||||
episode_description = models.TextField()
|
||||
|
||||
def get_owner(self):
|
||||
return self.podcast.owner
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "podcast_episodes"
|
||||
permissions = [
|
||||
(
|
||||
"change_own_podcastepisode",
|
||||
"Change the episodes of podcasts where they are the owner",
|
||||
),
|
||||
(
|
||||
"delete_own_podcastepisode",
|
||||
"Delete the episodes of podcasts where they are the owner",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class StationPodcast(models.Model):
|
||||
podcast = models.ForeignKey("Podcast", models.DO_NOTHING)
|
||||
|
||||
def get_owner(self):
|
||||
return self.podcast.owner
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "station_podcast"
|
||||
|
||||
|
||||
class ImportedPodcast(models.Model):
|
||||
auto_ingest = models.BooleanField()
|
||||
auto_ingest_timestamp = models.DateTimeField(blank=True, null=True)
|
||||
album_override = models.BooleanField()
|
||||
podcast = models.ForeignKey("Podcast", models.DO_NOTHING)
|
||||
|
||||
def get_owner(self):
|
||||
return self.podcast.owner
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "imported_podcast"
|
83
api/libretime_api/schedule/models/schedule.py
Normal file
83
api/libretime_api/schedule/models/schedule.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Schedule(models.Model):
|
||||
starts = models.DateTimeField()
|
||||
ends = models.DateTimeField()
|
||||
file = models.ForeignKey("storage.File", models.DO_NOTHING, blank=True, null=True)
|
||||
stream = models.ForeignKey("Webstream", models.DO_NOTHING, blank=True, null=True)
|
||||
clip_length = models.DurationField(blank=True, null=True)
|
||||
fade_in = models.TimeField(blank=True, null=True)
|
||||
fade_out = models.TimeField(blank=True, null=True)
|
||||
cue_in = models.DurationField()
|
||||
cue_out = models.DurationField()
|
||||
media_item_played = models.BooleanField(blank=True, null=True)
|
||||
instance = models.ForeignKey("ShowInstance", models.DO_NOTHING)
|
||||
playout_status = models.SmallIntegerField()
|
||||
broadcasted = models.SmallIntegerField()
|
||||
position = models.IntegerField()
|
||||
|
||||
def get_owner(self):
|
||||
return self.instance.get_owner()
|
||||
|
||||
def get_cueout(self):
|
||||
"""
|
||||
Returns a scheduled item cueout that is based on the current show instance.
|
||||
|
||||
Cueout of a specific item can potentially overrun the show that it is
|
||||
scheduled in. In that case, the cueout should be the end of the show.
|
||||
This prevents the next show having overlapping items playing.
|
||||
|
||||
Cases:
|
||||
- When the schedule ends before the end of the show instance,
|
||||
return the stored cueout.
|
||||
|
||||
- When the schedule starts before the end of the show instance
|
||||
and ends after the show instance ends,
|
||||
return timedelta between schedule starts and show instance ends.
|
||||
|
||||
- When the schedule starts after the end of the show instance,
|
||||
return the stored cue_out even if the schedule WILL NOT BE PLAYED.
|
||||
"""
|
||||
if self.starts < self.instance.ends and self.instance.ends < self.ends:
|
||||
return self.instance.ends - self.starts
|
||||
return self.cue_out
|
||||
|
||||
def get_ends(self):
|
||||
"""
|
||||
Returns a scheduled item ends that is based on the current show instance.
|
||||
|
||||
End of a specific item can potentially overrun the show that it is
|
||||
scheduled in. In that case, the end should be the end of the show.
|
||||
This prevents the next show having overlapping items playing.
|
||||
|
||||
Cases:
|
||||
- When the schedule ends before the end of the show instance,
|
||||
return the scheduled item ends.
|
||||
|
||||
- When the schedule starts before the end of the show instance
|
||||
and ends after the show instance ends,
|
||||
return the show instance ends.
|
||||
|
||||
- When the schedule starts after the end of the show instance,
|
||||
return the show instance ends.
|
||||
"""
|
||||
if self.instance.ends < self.ends:
|
||||
return self.instance.ends
|
||||
return self.ends
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
"""
|
||||
A schedule item is valid if it starts before the end of the show instance
|
||||
it is in
|
||||
"""
|
||||
return self.starts < self.instance.ends
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_schedule"
|
||||
permissions = [
|
||||
("change_own_schedule", "Change the content on their shows"),
|
||||
("delete_own_schedule", "Delete the content on their shows"),
|
||||
]
|
94
api/libretime_api/schedule/models/show.py
Normal file
94
api/libretime_api/schedule/models/show.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class Show(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
url = models.CharField(max_length=255, blank=True, null=True)
|
||||
genre = models.CharField(max_length=255, blank=True, null=True)
|
||||
description = models.CharField(max_length=8192, blank=True, null=True)
|
||||
color = models.CharField(max_length=6, blank=True, null=True)
|
||||
background_color = models.CharField(max_length=6, blank=True, null=True)
|
||||
live_stream_using_airtime_auth = models.BooleanField(blank=True, null=True)
|
||||
live_stream_using_custom_auth = models.BooleanField(blank=True, null=True)
|
||||
live_stream_user = models.CharField(max_length=255, blank=True, null=True)
|
||||
live_stream_pass = models.CharField(max_length=255, blank=True, null=True)
|
||||
linked = models.BooleanField()
|
||||
is_linkable = models.BooleanField()
|
||||
image_path = models.CharField(max_length=255, blank=True, null=True)
|
||||
has_autoplaylist = models.BooleanField()
|
||||
autoplaylist = models.ForeignKey(
|
||||
"Playlist", models.DO_NOTHING, blank=True, null=True
|
||||
)
|
||||
autoplaylist_repeat = models.BooleanField()
|
||||
|
||||
def get_owner(self):
|
||||
return self.showhost_set.all()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_show"
|
||||
|
||||
|
||||
class ShowDays(models.Model):
|
||||
first_show = models.DateField()
|
||||
last_show = models.DateField(blank=True, null=True)
|
||||
start_time = models.TimeField()
|
||||
timezone = models.CharField(max_length=1024)
|
||||
duration = models.CharField(max_length=1024)
|
||||
day = models.SmallIntegerField(blank=True, null=True)
|
||||
repeat_type = models.SmallIntegerField()
|
||||
next_pop_date = models.DateField(blank=True, null=True)
|
||||
show = models.ForeignKey("Show", models.DO_NOTHING)
|
||||
record = models.SmallIntegerField(blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
return self.show.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_show_days"
|
||||
|
||||
|
||||
class ShowHost(models.Model):
|
||||
show = models.ForeignKey("Show", models.DO_NOTHING)
|
||||
subjs = models.ForeignKey("core.User", models.DO_NOTHING)
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_show_hosts"
|
||||
|
||||
|
||||
class ShowInstance(models.Model):
|
||||
description = models.CharField(max_length=8192, blank=True, null=True)
|
||||
starts = models.DateTimeField()
|
||||
ends = models.DateTimeField()
|
||||
show = models.ForeignKey("Show", models.DO_NOTHING)
|
||||
record = models.SmallIntegerField(blank=True, null=True)
|
||||
rebroadcast = models.SmallIntegerField(blank=True, null=True)
|
||||
instance = models.ForeignKey("self", models.DO_NOTHING, blank=True, null=True)
|
||||
file = models.ForeignKey("storage.File", models.DO_NOTHING, blank=True, null=True)
|
||||
time_filled = models.DurationField(blank=True, null=True)
|
||||
created = models.DateTimeField()
|
||||
last_scheduled = models.DateTimeField(blank=True, null=True)
|
||||
modified_instance = models.BooleanField()
|
||||
autoplaylist_built = models.BooleanField()
|
||||
|
||||
def get_owner(self):
|
||||
return show.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_show_instances"
|
||||
|
||||
|
||||
class ShowRebroadcast(models.Model):
|
||||
day_offset = models.CharField(max_length=1024)
|
||||
start_time = models.TimeField()
|
||||
show = models.ForeignKey("Show", models.DO_NOTHING)
|
||||
|
||||
def get_owner(self):
|
||||
return show.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_show_rebroadcast"
|
83
api/libretime_api/schedule/models/smart_block.py
Normal file
83
api/libretime_api/schedule/models/smart_block.py
Normal file
|
@ -0,0 +1,83 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class SmartBlock(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
mtime = models.DateTimeField(blank=True, null=True)
|
||||
utime = models.DateTimeField(blank=True, null=True)
|
||||
creator = models.ForeignKey("core.User", models.DO_NOTHING, blank=True, null=True)
|
||||
description = models.CharField(max_length=512, blank=True, null=True)
|
||||
length = models.DurationField(blank=True, null=True)
|
||||
type = models.CharField(max_length=7, blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
return self.creator
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_block"
|
||||
permissions = [
|
||||
(
|
||||
"change_own_smartblock",
|
||||
"Change the smartblocks where they are the owner",
|
||||
),
|
||||
(
|
||||
"delete_own_smartblock",
|
||||
"Delete the smartblocks where they are the owner",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class SmartBlockContent(models.Model):
|
||||
block = models.ForeignKey("SmartBlock", models.DO_NOTHING, blank=True, null=True)
|
||||
file = models.ForeignKey("storage.File", models.DO_NOTHING, blank=True, null=True)
|
||||
position = models.IntegerField(blank=True, null=True)
|
||||
trackoffset = models.FloatField()
|
||||
cliplength = models.DurationField(blank=True, null=True)
|
||||
cuein = models.DurationField(blank=True, null=True)
|
||||
cueout = models.DurationField(blank=True, null=True)
|
||||
fadein = models.TimeField(blank=True, null=True)
|
||||
fadeout = models.TimeField(blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
return self.block.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_blockcontents"
|
||||
permissions = [
|
||||
(
|
||||
"change_own_smartblockcontent",
|
||||
"Change the content of smartblocks where they are the owner",
|
||||
),
|
||||
(
|
||||
"delete_own_smartblockcontent",
|
||||
"Delete the content of smartblocks where they are the owner",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
class SmartBlockCriteria(models.Model):
|
||||
criteria = models.CharField(max_length=32)
|
||||
modifier = models.CharField(max_length=16)
|
||||
value = models.CharField(max_length=512)
|
||||
extra = models.CharField(max_length=512, blank=True, null=True)
|
||||
criteriagroup = models.IntegerField(blank=True, null=True)
|
||||
block = models.ForeignKey("SmartBlock", models.DO_NOTHING)
|
||||
|
||||
def get_owner(self):
|
||||
return self.block.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_blockcriteria"
|
||||
permissions = [
|
||||
(
|
||||
"change_own_smartblockcriteria",
|
||||
"Change the criteria of smartblocks where they are the owner",
|
||||
),
|
||||
(
|
||||
"delete_own_smartblockcriteria",
|
||||
"Delete the criteria of smartblocks where they are the owner",
|
||||
),
|
||||
]
|
39
api/libretime_api/schedule/models/webstream.py
Normal file
39
api/libretime_api/schedule/models/webstream.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Webstream(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
url = models.CharField(max_length=512)
|
||||
length = models.DurationField()
|
||||
creator_id = models.IntegerField()
|
||||
mtime = models.DateTimeField()
|
||||
utime = models.DateTimeField()
|
||||
lptime = models.DateTimeField(blank=True, null=True)
|
||||
mime = models.CharField(max_length=1024, blank=True, null=True)
|
||||
|
||||
def get_owner(self):
|
||||
User = get_user_model()
|
||||
return User.objects.get(pk=self.creator_id)
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_webstream"
|
||||
permissions = [
|
||||
("change_own_webstream", "Change the webstreams where they are the owner"),
|
||||
("delete_own_webstream", "Delete the webstreams where they are the owner"),
|
||||
]
|
||||
|
||||
|
||||
class WebstreamMetadata(models.Model):
|
||||
instance = models.ForeignKey("Schedule", models.DO_NOTHING)
|
||||
start_time = models.DateTimeField()
|
||||
liquidsoap_data = models.CharField(max_length=1024)
|
||||
|
||||
def get_owner(self):
|
||||
return self.instance.get_owner()
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = "cc_webstream_metadata"
|
40
api/libretime_api/schedule/router.py
Normal file
40
api/libretime_api/schedule/router.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from rest_framework import routers
|
||||
|
||||
from .views import (
|
||||
ImportedPodcastViewSet,
|
||||
PlaylistContentViewSet,
|
||||
PlaylistViewSet,
|
||||
PodcastEpisodeViewSet,
|
||||
PodcastViewSet,
|
||||
ScheduleViewSet,
|
||||
ShowDaysViewSet,
|
||||
ShowHostViewSet,
|
||||
ShowInstanceViewSet,
|
||||
ShowRebroadcastViewSet,
|
||||
ShowViewSet,
|
||||
SmartBlockContentViewSet,
|
||||
SmartBlockCriteriaViewSet,
|
||||
SmartBlockViewSet,
|
||||
StationPodcastViewSet,
|
||||
WebstreamMetadataViewSet,
|
||||
WebstreamViewSet,
|
||||
)
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register("playlist-contents", PlaylistContentViewSet)
|
||||
router.register("playlists", PlaylistViewSet)
|
||||
router.register("podcast-episodes", PodcastEpisodeViewSet)
|
||||
router.register("podcasts", PodcastViewSet)
|
||||
router.register("station-podcasts", StationPodcastViewSet)
|
||||
router.register("imported-podcasts", ImportedPodcastViewSet)
|
||||
router.register("schedule", ScheduleViewSet)
|
||||
router.register("show-days", ShowDaysViewSet)
|
||||
router.register("show-hosts", ShowHostViewSet)
|
||||
router.register("show-instances", ShowInstanceViewSet)
|
||||
router.register("show-rebroadcasts", ShowRebroadcastViewSet)
|
||||
router.register("shows", ShowViewSet)
|
||||
router.register("smart-block-contents", SmartBlockContentViewSet)
|
||||
router.register("smart-block-criteria", SmartBlockCriteriaViewSet)
|
||||
router.register("smart-blocks", SmartBlockViewSet)
|
||||
router.register("webstream-metadata", WebstreamMetadataViewSet)
|
||||
router.register("webstreams", WebstreamViewSet)
|
21
api/libretime_api/schedule/serializers/__init__.py
Normal file
21
api/libretime_api/schedule/serializers/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from .playlist import PlaylistContentSerializer, PlaylistSerializer
|
||||
from .podcast import (
|
||||
ImportedPodcastSerializer,
|
||||
PodcastEpisodeSerializer,
|
||||
PodcastSerializer,
|
||||
StationPodcastSerializer,
|
||||
)
|
||||
from .schedule import ScheduleSerializer
|
||||
from .show import (
|
||||
ShowDaysSerializer,
|
||||
ShowHostSerializer,
|
||||
ShowInstanceSerializer,
|
||||
ShowRebroadcastSerializer,
|
||||
ShowSerializer,
|
||||
)
|
||||
from .smart_block import (
|
||||
SmartBlockContentSerializer,
|
||||
SmartBlockCriteriaSerializer,
|
||||
SmartBlockSerializer,
|
||||
)
|
||||
from .webstream import WebstreamMetadataSerializer, WebstreamSerializer
|
15
api/libretime_api/schedule/serializers/playlist.py
Normal file
15
api/libretime_api/schedule/serializers/playlist.py
Normal file
|
@ -0,0 +1,15 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import Playlist, PlaylistContent
|
||||
|
||||
|
||||
class PlaylistSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Playlist
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class PlaylistContentSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = PlaylistContent
|
||||
fields = "__all__"
|
27
api/libretime_api/schedule/serializers/podcast.py
Normal file
27
api/libretime_api/schedule/serializers/podcast.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import ImportedPodcast, Podcast, PodcastEpisode, StationPodcast
|
||||
|
||||
|
||||
class PodcastSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Podcast
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class PodcastEpisodeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = PodcastEpisode
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class StationPodcastSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = StationPodcast
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class ImportedPodcastSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = ImportedPodcast
|
||||
fields = "__all__"
|
35
api/libretime_api/schedule/serializers/schedule.py
Normal file
35
api/libretime_api/schedule/serializers/schedule.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import Schedule
|
||||
|
||||
|
||||
class ScheduleSerializer(serializers.HyperlinkedModelSerializer):
|
||||
file_id = serializers.IntegerField(source="file.id", read_only=True)
|
||||
stream_id = serializers.IntegerField(source="stream.id", read_only=True)
|
||||
instance_id = serializers.IntegerField(source="instance.id", read_only=True)
|
||||
cue_out = serializers.DurationField(source="get_cueout", read_only=True)
|
||||
ends = serializers.DateTimeField(source="get_ends", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Schedule
|
||||
fields = [
|
||||
"item_url",
|
||||
"id",
|
||||
"starts",
|
||||
"ends",
|
||||
"file",
|
||||
"file_id",
|
||||
"stream",
|
||||
"stream_id",
|
||||
"clip_length",
|
||||
"fade_in",
|
||||
"fade_out",
|
||||
"cue_in",
|
||||
"cue_out",
|
||||
"media_item_played",
|
||||
"instance",
|
||||
"instance_id",
|
||||
"playout_status",
|
||||
"broadcasted",
|
||||
"position",
|
||||
]
|
69
api/libretime_api/schedule/serializers/show.py
Normal file
69
api/libretime_api/schedule/serializers/show.py
Normal file
|
@ -0,0 +1,69 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import Show, ShowDays, ShowHost, ShowInstance, ShowRebroadcast
|
||||
|
||||
|
||||
class ShowSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Show
|
||||
fields = [
|
||||
"item_url",
|
||||
"id",
|
||||
"name",
|
||||
"url",
|
||||
"genre",
|
||||
"description",
|
||||
"color",
|
||||
"background_color",
|
||||
"linked",
|
||||
"is_linkable",
|
||||
"image_path",
|
||||
"has_autoplaylist",
|
||||
"autoplaylist_repeat",
|
||||
"autoplaylist",
|
||||
]
|
||||
|
||||
|
||||
class ShowDaysSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = ShowDays
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class ShowHostSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = ShowHost
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class ShowInstanceSerializer(serializers.HyperlinkedModelSerializer):
|
||||
show_id = serializers.IntegerField(source="show.id", read_only=True)
|
||||
file_id = serializers.IntegerField(source="file.id", read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = ShowInstance
|
||||
fields = [
|
||||
"item_url",
|
||||
"id",
|
||||
"description",
|
||||
"starts",
|
||||
"ends",
|
||||
"record",
|
||||
"rebroadcast",
|
||||
"time_filled",
|
||||
"created",
|
||||
"last_scheduled",
|
||||
"modified_instance",
|
||||
"autoplaylist_built",
|
||||
"show",
|
||||
"show_id",
|
||||
"instance",
|
||||
"file",
|
||||
"file_id",
|
||||
]
|
||||
|
||||
|
||||
class ShowRebroadcastSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = ShowRebroadcast
|
||||
fields = "__all__"
|
21
api/libretime_api/schedule/serializers/smart_block.py
Normal file
21
api/libretime_api/schedule/serializers/smart_block.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import SmartBlock, SmartBlockContent, SmartBlockCriteria
|
||||
|
||||
|
||||
class SmartBlockSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = SmartBlock
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SmartBlockContentSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = SmartBlockContent
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class SmartBlockCriteriaSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = SmartBlockCriteria
|
||||
fields = "__all__"
|
17
api/libretime_api/schedule/serializers/webstream.py
Normal file
17
api/libretime_api/schedule/serializers/webstream.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from ..models import Webstream, WebstreamMetadata
|
||||
|
||||
|
||||
class WebstreamSerializer(serializers.HyperlinkedModelSerializer):
|
||||
id = serializers.IntegerField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Webstream
|
||||
fields = "__all__"
|
||||
|
||||
|
||||
class WebstreamMetadataSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = WebstreamMetadata
|
||||
fields = "__all__"
|
0
api/libretime_api/schedule/tests/__init__.py
Normal file
0
api/libretime_api/schedule/tests/__init__.py
Normal file
0
api/libretime_api/schedule/tests/models/__init__.py
Normal file
0
api/libretime_api/schedule/tests/models/__init__.py
Normal file
57
api/libretime_api/schedule/tests/models/test_schedule.py
Normal file
57
api/libretime_api/schedule/tests/models/test_schedule.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
from datetime import datetime, timedelta
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from ...models import Schedule, ShowInstance
|
||||
|
||||
|
||||
class TestSchedule(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.show_instance = ShowInstance(
|
||||
created=datetime(year=2021, month=10, day=1, hour=12),
|
||||
starts=datetime(year=2021, month=10, day=2, hour=1),
|
||||
ends=datetime(year=2021, month=10, day=2, hour=2),
|
||||
)
|
||||
cls.length = timedelta(minutes=10)
|
||||
cls.cue_in = timedelta(seconds=1)
|
||||
cls.cue_out = cls.length - timedelta(seconds=4)
|
||||
|
||||
def create_schedule(self, starts):
|
||||
return Schedule(
|
||||
starts=starts,
|
||||
ends=starts + self.length,
|
||||
cue_in=self.cue_in,
|
||||
cue_out=self.cue_out,
|
||||
instance=self.show_instance,
|
||||
)
|
||||
|
||||
def test_get_cueout(self):
|
||||
# No overlapping schedule datetimes, normal usecase:
|
||||
s1_starts = datetime(year=2021, month=10, day=2, hour=1, minute=30)
|
||||
s1 = self.create_schedule(s1_starts)
|
||||
self.assertEqual(s1.get_cueout(), self.cue_out)
|
||||
self.assertEqual(s1.get_ends(), s1_starts + self.length)
|
||||
|
||||
# Mixed overlapping schedule datetimes (only ends is overlapping):
|
||||
s2_starts = datetime(year=2021, month=10, day=2, hour=1, minute=55)
|
||||
s2 = self.create_schedule(s2_starts)
|
||||
self.assertEqual(s2.get_cueout(), timedelta(minutes=5))
|
||||
self.assertEqual(s2.get_ends(), self.show_instance.ends)
|
||||
|
||||
# Fully overlapping schedule datetimes (starts and ends are overlapping):
|
||||
s3_starts = datetime(year=2021, month=10, day=2, hour=2, minute=1)
|
||||
s3 = self.create_schedule(s3_starts)
|
||||
self.assertEqual(s3.get_cueout(), self.cue_out)
|
||||
self.assertEqual(s3.get_ends(), self.show_instance.ends)
|
||||
|
||||
def test_is_valid(self):
|
||||
# Starts before the schedule ends
|
||||
s1_starts = datetime(year=2021, month=10, day=2, hour=1, minute=30)
|
||||
s1 = self.create_schedule(s1_starts)
|
||||
self.assertTrue(s1.is_valid)
|
||||
|
||||
# Starts after the schedule ends
|
||||
s2_starts = datetime(year=2021, month=10, day=2, hour=3)
|
||||
s2 = self.create_schedule(s2_starts)
|
||||
self.assertFalse(s2.is_valid)
|
0
api/libretime_api/schedule/tests/views/__init__.py
Normal file
0
api/libretime_api/schedule/tests/views/__init__.py
Normal file
186
api/libretime_api/schedule/tests/views/test_schedule.py
Normal file
186
api/libretime_api/schedule/tests/views/test_schedule.py
Normal file
|
@ -0,0 +1,186 @@
|
|||
import os
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils import dateparse
|
||||
from model_bakery import baker
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from ...._fixtures import AUDIO_FILENAME, fixture_path
|
||||
|
||||
|
||||
class TestScheduleViewSet(APITestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
cls.path = "/api/v2/schedule/"
|
||||
cls.token = settings.CONFIG.general.api_key
|
||||
|
||||
def test_schedule_item_full_length(self):
|
||||
music_dir = baker.make(
|
||||
"storage.MusicDir",
|
||||
directory=str(fixture_path),
|
||||
)
|
||||
f = baker.make(
|
||||
"storage.File",
|
||||
directory=music_dir,
|
||||
mime="audio/mp3",
|
||||
filepath=AUDIO_FILENAME,
|
||||
length=timedelta(seconds=40.86),
|
||||
cuein=timedelta(seconds=0),
|
||||
cueout=timedelta(seconds=40.8131),
|
||||
)
|
||||
show = baker.make(
|
||||
"schedule.ShowInstance",
|
||||
starts=datetime.now(tz=timezone.utc) - timedelta(minutes=5),
|
||||
ends=datetime.now(tz=timezone.utc) + timedelta(minutes=5),
|
||||
)
|
||||
scheduleItem = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=datetime.now(tz=timezone.utc),
|
||||
ends=datetime.now(tz=timezone.utc) + f.length,
|
||||
cue_out=f.cueout,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Api-Key {self.token}")
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
result = response.json()
|
||||
self.assertEqual(dateparse.parse_datetime(result[0]["ends"]), scheduleItem.ends)
|
||||
self.assertEqual(dateparse.parse_duration(result[0]["cue_out"]), f.cueout)
|
||||
|
||||
def test_schedule_item_trunc(self):
|
||||
music_dir = baker.make(
|
||||
"storage.MusicDir",
|
||||
directory=str(fixture_path),
|
||||
)
|
||||
f = baker.make(
|
||||
"storage.File",
|
||||
directory=music_dir,
|
||||
mime="audio/mp3",
|
||||
filepath=AUDIO_FILENAME,
|
||||
length=timedelta(seconds=40.86),
|
||||
cuein=timedelta(seconds=0),
|
||||
cueout=timedelta(seconds=40.8131),
|
||||
)
|
||||
show = baker.make(
|
||||
"schedule.ShowInstance",
|
||||
starts=datetime.now(tz=timezone.utc) - timedelta(minutes=5),
|
||||
ends=datetime.now(tz=timezone.utc) + timedelta(seconds=20),
|
||||
)
|
||||
scheduleItem = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=datetime.now(tz=timezone.utc),
|
||||
ends=datetime.now(tz=timezone.utc) + f.length,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Api-Key {self.token}")
|
||||
response = self.client.get(self.path)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
result = response.json()
|
||||
self.assertEqual(dateparse.parse_datetime(result[0]["ends"]), show.ends)
|
||||
expected = show.ends - scheduleItem.starts
|
||||
self.assertEqual(dateparse.parse_duration(result[0]["cue_out"]), expected)
|
||||
self.assertNotEqual(
|
||||
dateparse.parse_datetime(result[0]["ends"]), scheduleItem.ends
|
||||
)
|
||||
|
||||
def test_schedule_item_invalid(self):
|
||||
music_dir = baker.make(
|
||||
"storage.MusicDir",
|
||||
directory=str(fixture_path),
|
||||
)
|
||||
f = baker.make(
|
||||
"storage.File",
|
||||
directory=music_dir,
|
||||
mime="audio/mp3",
|
||||
filepath=AUDIO_FILENAME,
|
||||
length=timedelta(seconds=40.86),
|
||||
cuein=timedelta(seconds=0),
|
||||
cueout=timedelta(seconds=40.8131),
|
||||
)
|
||||
show = baker.make(
|
||||
"schedule.ShowInstance",
|
||||
starts=datetime.now(tz=timezone.utc) - timedelta(minutes=5),
|
||||
ends=datetime.now(tz=timezone.utc) + timedelta(minutes=5),
|
||||
)
|
||||
schedule_item = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=datetime.now(tz=timezone.utc),
|
||||
ends=datetime.now(tz=timezone.utc) + f.length,
|
||||
cue_out=f.cueout,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
invalid_schedule_item = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=show.ends + timedelta(minutes=1),
|
||||
ends=show.ends + timedelta(minutes=1) + f.length,
|
||||
cue_out=f.cueout,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Api-Key {self.token}")
|
||||
response = self.client.get(self.path, {"is_valid": True})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
result = response.json()
|
||||
# The invalid item should be filtered out and not returned
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(
|
||||
dateparse.parse_datetime(result[0]["ends"]), schedule_item.ends
|
||||
)
|
||||
self.assertEqual(dateparse.parse_duration(result[0]["cue_out"]), f.cueout)
|
||||
|
||||
def test_schedule_item_range(self):
|
||||
music_dir = baker.make(
|
||||
"storage.MusicDir",
|
||||
directory=str(fixture_path),
|
||||
)
|
||||
f = baker.make(
|
||||
"storage.File",
|
||||
directory=music_dir,
|
||||
mime="audio/mp3",
|
||||
filepath=AUDIO_FILENAME,
|
||||
length=timedelta(seconds=40.86),
|
||||
cuein=timedelta(seconds=0),
|
||||
cueout=timedelta(seconds=40.8131),
|
||||
)
|
||||
filter_point = datetime.now(tz=timezone.utc)
|
||||
|
||||
show = baker.make(
|
||||
"schedule.ShowInstance",
|
||||
starts=filter_point - timedelta(minutes=5),
|
||||
ends=filter_point + timedelta(minutes=5),
|
||||
)
|
||||
schedule_item = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=filter_point,
|
||||
ends=filter_point + f.length,
|
||||
cue_out=f.cueout,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
previous_item = baker.make(
|
||||
"schedule.Schedule",
|
||||
starts=filter_point - timedelta(minutes=5),
|
||||
ends=filter_point - timedelta(minutes=5) + f.length,
|
||||
cue_out=f.cueout,
|
||||
instance=show,
|
||||
file=f,
|
||||
)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Api-Key {self.token}")
|
||||
range_start = (filter_point - timedelta(minutes=1)).isoformat(
|
||||
timespec="seconds"
|
||||
)
|
||||
range_end = (filter_point + timedelta(minutes=1)).isoformat(timespec="seconds")
|
||||
response = self.client.get(
|
||||
self.path, {"starts__range": f"{range_start},{range_end}"}
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
result = response.json()
|
||||
# The previous_item should be filtered out and not returned
|
||||
self.assertEqual(len(result), 1)
|
||||
self.assertEqual(
|
||||
dateparse.parse_datetime(result[0]["starts"]), schedule_item.starts
|
||||
)
|
21
api/libretime_api/schedule/views/__init__.py
Normal file
21
api/libretime_api/schedule/views/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from .playlist import PlaylistContentViewSet, PlaylistViewSet
|
||||
from .podcast import (
|
||||
ImportedPodcastViewSet,
|
||||
PodcastEpisodeViewSet,
|
||||
PodcastViewSet,
|
||||
StationPodcastViewSet,
|
||||
)
|
||||
from .schedule import ScheduleViewSet
|
||||
from .show import (
|
||||
ShowDaysViewSet,
|
||||
ShowHostViewSet,
|
||||
ShowInstanceViewSet,
|
||||
ShowRebroadcastViewSet,
|
||||
ShowViewSet,
|
||||
)
|
||||
from .smart_block import (
|
||||
SmartBlockContentViewSet,
|
||||
SmartBlockCriteriaViewSet,
|
||||
SmartBlockViewSet,
|
||||
)
|
||||
from .webstream import WebstreamMetadataViewSet, WebstreamViewSet
|
16
api/libretime_api/schedule/views/playlist.py
Normal file
16
api/libretime_api/schedule/views/playlist.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from ..models import Playlist, PlaylistContent
|
||||
from ..serializers import PlaylistContentSerializer, PlaylistSerializer
|
||||
|
||||
|
||||
class PlaylistViewSet(viewsets.ModelViewSet):
|
||||
queryset = Playlist.objects.all()
|
||||
serializer_class = PlaylistSerializer
|
||||
model_permission_name = "playlist"
|
||||
|
||||
|
||||
class PlaylistContentViewSet(viewsets.ModelViewSet):
|
||||
queryset = PlaylistContent.objects.all()
|
||||
serializer_class = PlaylistContentSerializer
|
||||
model_permission_name = "playlistcontent"
|
33
api/libretime_api/schedule/views/podcast.py
Normal file
33
api/libretime_api/schedule/views/podcast.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from ..models import ImportedPodcast, Podcast, PodcastEpisode, StationPodcast
|
||||
from ..serializers import (
|
||||
ImportedPodcastSerializer,
|
||||
PodcastEpisodeSerializer,
|
||||
PodcastSerializer,
|
||||
StationPodcastSerializer,
|
||||
)
|
||||
|
||||
|
||||
class PodcastViewSet(viewsets.ModelViewSet):
|
||||
queryset = Podcast.objects.all()
|
||||
serializer_class = PodcastSerializer
|
||||
model_permission_name = "podcast"
|
||||
|
||||
|
||||
class PodcastEpisodeViewSet(viewsets.ModelViewSet):
|
||||
queryset = PodcastEpisode.objects.all()
|
||||
serializer_class = PodcastEpisodeSerializer
|
||||
model_permission_name = "podcastepisode"
|
||||
|
||||
|
||||
class StationPodcastViewSet(viewsets.ModelViewSet):
|
||||
queryset = StationPodcast.objects.all()
|
||||
serializer_class = StationPodcastSerializer
|
||||
model_permission_name = "station"
|
||||
|
||||
|
||||
class ImportedPodcastViewSet(viewsets.ModelViewSet):
|
||||
queryset = ImportedPodcast.objects.all()
|
||||
serializer_class = ImportedPodcastSerializer
|
||||
model_permission_name = "importedpodcast"
|
41
api/libretime_api/schedule/views/schedule.py
Normal file
41
api/libretime_api/schedule/views/schedule.py
Normal file
|
@ -0,0 +1,41 @@
|
|||
from django.db.models import F
|
||||
from drf_spectacular.utils import OpenApiParameter, extend_schema, extend_schema_view
|
||||
from rest_framework import viewsets
|
||||
|
||||
from ..._constants import FILTER_NUMERICAL_LOOKUPS
|
||||
from ..models import Schedule
|
||||
from ..serializers import ScheduleSerializer
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
list=extend_schema(
|
||||
parameters=[
|
||||
OpenApiParameter(
|
||||
name="is_valid",
|
||||
description="Filter on valid instances",
|
||||
required=False,
|
||||
type=bool,
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
class ScheduleViewSet(viewsets.ModelViewSet):
|
||||
queryset = Schedule.objects.all()
|
||||
serializer_class = ScheduleSerializer
|
||||
filter_fields = {
|
||||
"starts": FILTER_NUMERICAL_LOOKUPS,
|
||||
"ends": FILTER_NUMERICAL_LOOKUPS,
|
||||
"playout_status": FILTER_NUMERICAL_LOOKUPS,
|
||||
"broadcasted": FILTER_NUMERICAL_LOOKUPS,
|
||||
}
|
||||
model_permission_name = "schedule"
|
||||
|
||||
def get_queryset(self):
|
||||
filter_valid = self.request.query_params.get("is_valid")
|
||||
if filter_valid is None:
|
||||
return self.queryset.all()
|
||||
filter_valid = filter_valid.strip().lower() in ("true", "yes", "1")
|
||||
if filter_valid:
|
||||
return self.queryset.filter(starts__lt=F("instance__ends"))
|
||||
else:
|
||||
return self.queryset.filter(starts__gte=F("instance__ends"))
|
40
api/libretime_api/schedule/views/show.py
Normal file
40
api/libretime_api/schedule/views/show.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from ..models import Show, ShowDays, ShowHost, ShowInstance, ShowRebroadcast
|
||||
from ..serializers import (
|
||||
ShowDaysSerializer,
|
||||
ShowHostSerializer,
|
||||
ShowInstanceSerializer,
|
||||
ShowRebroadcastSerializer,
|
||||
ShowSerializer,
|
||||
)
|
||||
|
||||
|
||||
class ShowViewSet(viewsets.ModelViewSet):
|
||||
queryset = Show.objects.all()
|
||||
serializer_class = ShowSerializer
|
||||
model_permission_name = "show"
|
||||
|
||||
|
||||
class ShowDaysViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShowDays.objects.all()
|
||||
serializer_class = ShowDaysSerializer
|
||||
model_permission_name = "showdays"
|
||||
|
||||
|
||||
class ShowHostViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShowHost.objects.all()
|
||||
serializer_class = ShowHostSerializer
|
||||
model_permission_name = "showhost"
|
||||
|
||||
|
||||
class ShowInstanceViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShowInstance.objects.all()
|
||||
serializer_class = ShowInstanceSerializer
|
||||
model_permission_name = "showinstance"
|
||||
|
||||
|
||||
class ShowRebroadcastViewSet(viewsets.ModelViewSet):
|
||||
queryset = ShowRebroadcast.objects.all()
|
||||
serializer_class = ShowRebroadcastSerializer
|
||||
model_permission_name = "showrebroadcast"
|
26
api/libretime_api/schedule/views/smart_block.py
Normal file
26
api/libretime_api/schedule/views/smart_block.py
Normal file
|
@ -0,0 +1,26 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from ..models import SmartBlock, SmartBlockContent, SmartBlockCriteria
|
||||
from ..serializers import (
|
||||
SmartBlockContentSerializer,
|
||||
SmartBlockCriteriaSerializer,
|
||||
SmartBlockSerializer,
|
||||
)
|
||||
|
||||
|
||||
class SmartBlockViewSet(viewsets.ModelViewSet):
|
||||
queryset = SmartBlock.objects.all()
|
||||
serializer_class = SmartBlockSerializer
|
||||
model_permission_name = "smartblock"
|
||||
|
||||
|
||||
class SmartBlockContentViewSet(viewsets.ModelViewSet):
|
||||
queryset = SmartBlockContent.objects.all()
|
||||
serializer_class = SmartBlockContentSerializer
|
||||
model_permission_name = "smartblockcontent"
|
||||
|
||||
|
||||
class SmartBlockCriteriaViewSet(viewsets.ModelViewSet):
|
||||
queryset = SmartBlockCriteria.objects.all()
|
||||
serializer_class = SmartBlockCriteriaSerializer
|
||||
model_permission_name = "smartblockcriteria"
|
16
api/libretime_api/schedule/views/webstream.py
Normal file
16
api/libretime_api/schedule/views/webstream.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from rest_framework import viewsets
|
||||
|
||||
from ..models import Webstream, WebstreamMetadata
|
||||
from ..serializers import WebstreamMetadataSerializer, WebstreamSerializer
|
||||
|
||||
|
||||
class WebstreamViewSet(viewsets.ModelViewSet):
|
||||
queryset = Webstream.objects.all()
|
||||
serializer_class = WebstreamSerializer
|
||||
model_permission_name = "webstream"
|
||||
|
||||
|
||||
class WebstreamMetadataViewSet(viewsets.ModelViewSet):
|
||||
queryset = WebstreamMetadata.objects.all()
|
||||
serializer_class = WebstreamMetadataSerializer
|
||||
model_permission_name = "webstreametadata"
|
Loading…
Add table
Add a link
Reference in a new issue