2023-02-26 00:11:49 +01:00
|
|
|
from datetime import datetime
|
2022-07-01 12:40:24 +02:00
|
|
|
from enum import Enum
|
2023-03-04 21:50:12 +01:00
|
|
|
from pathlib import Path
|
2023-12-28 14:19:29 +01:00
|
|
|
from typing import Dict, Literal, Optional, Union
|
2023-02-19 18:16:07 +01:00
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
from dateutil.parser import isoparse
|
2023-12-28 14:19:29 +01:00
|
|
|
from pydantic import BaseModel, BeforeValidator, Field, parse_obj_as
|
2023-03-04 21:50:12 +01:00
|
|
|
from typing_extensions import Annotated
|
|
|
|
|
|
|
|
from ..config import CACHE_DIR
|
|
|
|
from ..utils import mime_guess_extension
|
|
|
|
|
2023-02-26 00:11:49 +01:00
|
|
|
EVENT_KEY_FORMAT = "%Y-%m-%d-%H-%M-%S"
|
|
|
|
|
|
|
|
|
|
|
|
def event_key_to_datetime(value: Union[str, datetime]) -> datetime:
|
2023-03-04 21:50:12 +01:00
|
|
|
if isinstance(value, str):
|
|
|
|
value = datetime.strptime(value, EVENT_KEY_FORMAT)
|
|
|
|
return value
|
2023-02-26 00:11:49 +01:00
|
|
|
|
|
|
|
|
|
|
|
def datetime_to_event_key(value: Union[str, datetime]) -> str:
|
2023-03-04 21:50:12 +01:00
|
|
|
if isinstance(value, datetime):
|
|
|
|
value = value.strftime(EVENT_KEY_FORMAT)
|
|
|
|
return value
|
|
|
|
|
|
|
|
|
|
|
|
def event_isoparse(value: str) -> datetime:
|
|
|
|
return isoparse(value).replace(tzinfo=None).replace(microsecond=0)
|
2023-02-26 00:11:49 +01:00
|
|
|
|
2022-07-01 12:40:24 +02:00
|
|
|
|
|
|
|
class EventKind(str, Enum):
|
|
|
|
FILE = "file"
|
2023-02-19 17:56:01 +01:00
|
|
|
ACTION = "event"
|
|
|
|
WEB_STREAM_BUFFER_START = "stream_buffer_start"
|
|
|
|
WEB_STREAM_OUTPUT_START = "stream_output_start"
|
|
|
|
WEB_STREAM_BUFFER_END = "stream_buffer_end"
|
|
|
|
WEB_STREAM_OUTPUT_END = "stream_output_end"
|
2023-02-19 18:16:07 +01:00
|
|
|
|
|
|
|
|
2023-12-28 14:19:29 +01:00
|
|
|
EventKeyDatetime = Annotated[datetime, BeforeValidator(event_key_to_datetime)]
|
2023-02-19 18:16:07 +01:00
|
|
|
|
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
class BaseEvent(BaseModel):
|
2023-12-28 14:19:29 +01:00
|
|
|
start: EventKeyDatetime
|
|
|
|
end: EventKeyDatetime
|
2023-03-04 21:50:12 +01:00
|
|
|
|
|
|
|
@property
|
|
|
|
def start_key(self) -> str:
|
|
|
|
return datetime_to_event_key(self.start)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def end_key(self) -> str:
|
|
|
|
return datetime_to_event_key(self.end)
|
2023-02-19 18:16:07 +01:00
|
|
|
|
2023-03-23 02:16:10 +01:00
|
|
|
def ended(self) -> bool:
|
|
|
|
return datetime.utcnow() > self.end
|
|
|
|
|
2023-02-19 18:16:07 +01:00
|
|
|
|
|
|
|
class FileEvent(BaseEvent):
|
|
|
|
type: Literal[EventKind.FILE]
|
|
|
|
|
|
|
|
# Schedule
|
|
|
|
row_id: int
|
2023-03-04 21:50:12 +01:00
|
|
|
uri: Optional[str] = None
|
2023-02-19 18:16:07 +01:00
|
|
|
id: int
|
|
|
|
|
|
|
|
# Show data
|
|
|
|
show_name: str
|
|
|
|
|
|
|
|
# File
|
|
|
|
fade_in: float
|
|
|
|
fade_out: float
|
|
|
|
cue_in: float
|
|
|
|
cue_out: float
|
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
track_title: Optional[str] = None
|
|
|
|
artist_name: Optional[str] = None
|
2023-02-19 18:16:07 +01:00
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
mime: str
|
|
|
|
replay_gain: Optional[float] = None
|
2023-02-19 18:16:07 +01:00
|
|
|
filesize: int
|
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
file_ready: bool = False
|
|
|
|
|
|
|
|
@property
|
|
|
|
def file_ext(self) -> str:
|
|
|
|
return mime_guess_extension(self.mime)
|
|
|
|
|
|
|
|
@property
|
|
|
|
def local_filepath(self) -> Path:
|
|
|
|
return CACHE_DIR / f"{self.id}{self.file_ext}"
|
2023-02-26 00:11:49 +01:00
|
|
|
|
2023-02-19 18:16:07 +01:00
|
|
|
|
|
|
|
class WebStreamEvent(BaseEvent):
|
|
|
|
type: Literal[
|
|
|
|
EventKind.WEB_STREAM_BUFFER_START,
|
|
|
|
EventKind.WEB_STREAM_OUTPUT_START,
|
|
|
|
EventKind.WEB_STREAM_BUFFER_END,
|
|
|
|
EventKind.WEB_STREAM_OUTPUT_END,
|
|
|
|
]
|
|
|
|
|
|
|
|
# Schedule
|
|
|
|
row_id: int
|
|
|
|
uri: str
|
|
|
|
id: int
|
|
|
|
|
|
|
|
# Show data
|
2023-03-04 21:50:12 +01:00
|
|
|
show_name: str
|
2023-02-19 18:16:07 +01:00
|
|
|
|
|
|
|
|
|
|
|
class ActionEventKind(str, Enum):
|
|
|
|
SWITCH_OFF = "switch_off"
|
|
|
|
KICK_OUT = "kick_out"
|
|
|
|
|
|
|
|
|
|
|
|
class ActionEvent(BaseEvent):
|
|
|
|
type: Literal[EventKind.ACTION]
|
|
|
|
# TODO: user ActionEventKind enum
|
|
|
|
event_type: str
|
|
|
|
|
|
|
|
|
2023-03-04 21:50:12 +01:00
|
|
|
AnyEvent = Annotated[
|
|
|
|
Union[FileEvent, WebStreamEvent, ActionEvent],
|
|
|
|
Field(discriminator="type"),
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
def parse_any_event(value: dict) -> AnyEvent:
|
|
|
|
return parse_obj_as(AnyEvent, value) # type: ignore
|
|
|
|
|
2023-02-26 00:11:49 +01:00
|
|
|
|
|
|
|
FileEvents = Dict[str, FileEvent]
|
2023-02-19 18:16:07 +01:00
|
|
|
Events = Dict[str, AnyEvent]
|