BAPSicle/baps_types/plan.py

284 lines
7.9 KiB
Python
Raw Normal View History

2020-11-01 02:35:14 +00:00
"""
BAPSicle Server
Next-gen audio playout server for University Radio York playout,
based on WebStudio interface.
Show Plan Items
Authors:
Michael Grace
Date:
November 2020
"""
2021-04-12 21:59:51 +00:00
import json
2021-09-11 16:48:57 +00:00
from typing import Any, Dict, List, Optional
2020-11-04 00:09:42 +00:00
import os
from time import time
2020-11-01 02:35:14 +00:00
2021-04-12 21:59:51 +00:00
from baps_types.marker import Marker
2021-04-08 19:53:51 +00:00
2021-09-11 15:49:08 +00:00
def _time_ms():
return round(time() * 1000)
2021-09-11 15:49:08 +00:00
class PlanItem:
_timeslotitemid: str = "0"
_weight: int = 0
_filename: Optional[str]
_title: str
_artist: Optional[str]
_trackid: Optional[int]
_managedid: Optional[int]
2021-04-12 21:59:51 +00:00
_markers: List[Marker] = []
2021-05-02 01:18:00 +00:00
_play_count: int
_played_at: int
2021-05-02 01:27:41 +00:00
_clean: bool
2020-11-01 02:35:14 +00:00
@property
def weight(self) -> int:
return self._weight
2021-03-13 22:32:04 +00:00
@weight.setter
def weight(self, value: int):
self._weight = value
@property
def timeslotitemid(self) -> str:
return self._timeslotitemid
2020-11-01 02:35:14 +00:00
@timeslotitemid.setter
def timeslotitemid(self, value):
self._timeslotitemid = str(value)
2020-11-01 02:35:14 +00:00
@property
def filename(self) -> Optional[str]:
2020-11-01 02:35:14 +00:00
return self._filename
@filename.setter
def filename(self, value: Optional[str]):
self._filename = value
2021-05-02 01:18:00 +00:00
@property
def play_count(self) -> int:
return self._play_count
@property
def played_at(self) -> int:
return self._played_at
2021-05-02 01:18:00 +00:00
def play_count_increment(self):
self._play_count += 1
self._played_at = _time_ms()
2021-05-02 01:18:00 +00:00
def play_count_decrement(self):
2021-09-11 15:49:08 +00:00
self._play_count = max(0, self._play_count - 1)
if self._play_count == 0:
self._played_at = 0
2021-05-02 01:18:00 +00:00
def play_count_reset(self):
self._play_count = 0
self._played_at = 0
2021-05-02 01:18:00 +00:00
2020-11-01 02:35:14 +00:00
@property
def name(self) -> str:
2021-04-08 19:53:51 +00:00
return (
"{0} - {1}".format(self._title, self._artist)
if self._artist
else self._title
)
2020-11-01 02:35:14 +00:00
@property
def trackid(self) -> Optional[int]:
return self._trackid
@property
def managedid(self) -> Optional[int]:
return self._managedid
@property
def title(self) -> Optional[str]:
return self._title
@property
def artist(self) -> Optional[str]:
return self._artist
@property
def length(self) -> Optional[str]:
return self._length
@property
def type(self) -> Optional[str]:
return "aux" if self.managedid else "central"
2021-05-02 01:27:41 +00:00
@property
def clean(self) -> bool:
return self._clean
2021-04-12 21:59:51 +00:00
@property
def intro(self) -> float:
2021-09-11 15:49:08 +00:00
markers = list(
filter(lambda m: m.position == "start" and m.section is None, self._markers)
)
2021-04-12 21:59:51 +00:00
# TODO: Handle multiple (shouldn't happen?)
if len(markers) > 0:
return markers[0].time
return 0
@property
def cue(self) -> float:
2021-09-11 15:49:08 +00:00
markers = list(
filter(lambda m: m.position == "mid" and m.section is None, self._markers)
)
2021-04-12 21:59:51 +00:00
# TODO: Handle multiple (shouldn't happen?)
if len(markers) > 0:
return markers[0].time
return 0
@property
def outro(self) -> float:
2021-09-11 15:49:08 +00:00
markers = list(
filter(lambda m: m.position == "end" and m.section is None, self._markers)
)
2021-04-12 21:59:51 +00:00
# TODO: Handle multiple (shouldn't happen?)
if len(markers) > 0:
return markers[0].time
return 0
@property
def markers(self) -> List[dict]:
return [repr.__dict__ for repr in self._markers]
@property
2020-12-19 14:57:37 +00:00
def __dict__(self):
2020-11-01 02:35:14 +00:00
return {
"weight": self.weight,
"timeslotitemid": self.timeslotitemid,
"trackid": self._trackid,
"type": self.type,
"managedid": self._managedid,
"title": self._title,
"artist": self._artist,
2020-11-01 02:35:14 +00:00
"name": self.name,
"filename": self.filename,
2021-04-08 19:53:51 +00:00
"length": self.length,
2021-04-10 21:56:53 +00:00
"intro": self.intro,
"cue": self.cue,
"outro": self.outro,
2021-05-02 01:18:00 +00:00
"markers": self.markers,
"played": self.play_count > 0,
"played_at": self.played_at,
2021-05-02 01:27:41 +00:00
"play_count": self.play_count,
2021-09-11 15:49:08 +00:00
"clean": self.clean,
}
2020-12-19 14:57:37 +00:00
def __init__(self, new_item: Dict[str, Any]):
self._timeslotitemid = str(new_item["timeslotitemid"])
self._managedid = new_item["managedid"] if "managedid" in new_item else None
2021-04-08 19:53:51 +00:00
self._trackid = (
int(new_item["trackid"])
if "trackid" in new_item and not self._managedid
else None
)
self._filename = (
new_item["filename"] if "filename" in new_item else None
) # This could be a temp dir for API-downloaded items, or a mapped drive.
2021-04-06 21:39:33 +00:00
self._weight = int(new_item["weight"])
self._title = new_item["title"]
self._artist = new_item["artist"] if "artist" in new_item else None
self._length = new_item["length"]
2021-04-12 21:59:51 +00:00
self._markers = (
2021-09-11 15:49:08 +00:00
[Marker(marker) for marker in new_item["markers"]]
if "markers" in new_item
else []
2021-04-12 21:59:51 +00:00
)
2021-05-02 01:18:00 +00:00
self._play_count = new_item["play_count"] if "play_count" in new_item else 0
self._played_at = new_item["played_at"] if "played_at" in new_item else 0
2021-05-02 01:27:41 +00:00
self._clean = new_item["clean"] if "clean" in new_item else True
2021-04-12 21:59:51 +00:00
# TODO: Edit this to handle markers when MyRadio supports them
2021-09-11 15:49:08 +00:00
if (
"intro" in new_item
and (
isinstance(new_item["intro"], int)
or isinstance(new_item["intro"], float)
)
and new_item["intro"] > 0
):
2021-04-12 21:59:51 +00:00
marker = {
"name": "Intro",
"time": new_item["intro"],
"position": "start",
2021-09-11 15:49:08 +00:00
"section": None,
2021-04-12 21:59:51 +00:00
}
self.set_marker(Marker(json.dumps(marker)))
2021-09-11 15:49:08 +00:00
if (
"cue" in new_item
and (isinstance(new_item["cue"], int) or isinstance(new_item["cue"], float))
and new_item["cue"] > 0
):
2021-04-12 21:59:51 +00:00
marker = {
"name": "Cue",
"time": new_item["cue"],
"position": "mid",
2021-09-11 15:49:08 +00:00
"section": None,
2021-04-12 21:59:51 +00:00
}
self.set_marker(Marker(json.dumps(marker)))
# TODO: Convert / handle outro being from end of item.
2021-09-11 15:49:08 +00:00
if (
"outro" in new_item
and (
isinstance(new_item["outro"], int)
or isinstance(new_item["outro"], float)
)
and new_item["outro"] > 0
):
2021-04-12 21:59:51 +00:00
marker = {
"name": "Outro",
"time": new_item["outro"],
"position": "end",
2021-09-11 15:49:08 +00:00
"section": None,
2021-04-12 21:59:51 +00:00
}
self.set_marker(Marker(json.dumps(marker)))
2020-11-04 00:09:42 +00:00
# Fix any OS specific / or \'s
if self.filename:
if os.path.sep == "/":
2021-04-08 19:53:51 +00:00
self._filename = self.filename.replace("\\", "/")
else:
2021-04-08 19:53:51 +00:00
self._filename = self.filename.replace("/", "\\")
2021-04-10 21:56:53 +00:00
2021-04-12 21:59:51 +00:00
def __eq__(self, o: object) -> bool:
if not isinstance(o, PlanItem):
return False
return o.__dict__ == self.__dict__
def set_marker(self, new_marker: Marker):
if not isinstance(new_marker, Marker):
2021-04-10 21:56:53 +00:00
raise ValueError("Marker provided is not of type Marker.")
2021-04-12 21:59:51 +00:00
replaced = False
new_markers = []
for marker in self._markers:
if marker.same_type(new_marker):
2021-04-26 00:01:58 +00:00
# Only add new marker if the marker is > 0 (to delete markers otherwise)
if new_marker.time != 0:
new_markers.append(new_marker)
2021-04-12 21:59:51 +00:00
# Replace marker
replaced = True
else:
new_markers.append(marker)
if not replaced:
new_markers.append(new_marker)
self._markers = new_markers
2021-04-10 21:56:53 +00:00
# Return updated item for easy chaining.
return self