Passed
Push — master ( 518ae3...863c37 )
by manny
46s queued 12s
created

MediaTrigger.check_finish_place()   A

Complexity

Conditions 4

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 7
nop 2
dl 0
loc 9
rs 10
c 0
b 0
f 0
1
import asyncio
2
from asyncio.locks import Lock
3
from datetime import datetime, timedelta
4
import logging
5
from threading import Timer
6
from typing import List, Optional
7
from asyncio import Event
8
from helpers import timer_to_str
9
from models.race import Entrant, Race
10
11
12
class MediaTrigger:
13
    place: Optional[int] = None
14
    entrant_count_trigger: Optional[int] = None
15
    media_file_path: str = ""
16
    triggered: bool = False
17
    race_started_at: datetime = None
18
19
    def __init__(
20
        self, media_file_path: str, place_trigger: int = None,
21
        entrant_count_trigger: int = None
22
    ):
23
        self.media_file_path = media_file_path
24
        self.place = place_trigger
25
        self.entrant_count_trigger = entrant_count_trigger
26
27
    def check_trigger(self, race: Race, entrant: Entrant):
28
        if (
29
            self.triggered or self.media_file_path == "" or
30
            race is None or entrant is None
31
        ):
32
            return False
33
        else:
34
            if (
35
                self.check_finish_place_entrant_count(race, entrant) or
36
                self.check_finish_place(entrant)
37
            ):
38
                self.triggered = True
39
                return True
40
        return False
41
42
    def check_finish_place(self, entrant: Entrant):
43
        if (
44
            self.entrant_count_trigger is not None or entrant.user is None or
45
            entrant.place is None
46
        ):
47
            return False
48
        else:
49
            return (
50
                entrant.place <= self.place
51
            )
52
53
    def check_finish_place_entrant_count(self, race: Race, entrant: Entrant):
54
        if None in [
55
            self.entrant_count_trigger, entrant.user, entrant.place,
56
            race.entrants_count
57
        ]:
58
            return False
59
        else:
60
            return (
61
                entrant.place <= self.place and
62
                race.entrants_count <= self.entrant_count_trigger
63
            )
64
65
66
class MediaPlayer:
67
    logger: logging.Logger = logging.Logger("racetime-obs")
68
    enabled: bool = False
69
    triggers: List[MediaTrigger] = []
70
    timers: List[Timer] = []
71
    triggers_lock: Lock = Lock()
72
    race_update_event: Event()
73
    play_media_callback = None
74
    started_at: datetime = None
75
    ping_chat_messages: bool = False
76
    chat_media_file: str = None
77
    last_session_race: str = ""
78
    monitoring_type: int = 0
79
80
    def race_updated(self, race: Race, entrant_name: str):
81
        # so the sound doesn't play when the user starts obs next time
82
        if self.last_session_race == race.name:
83
            return
84
        self.started_at = race.started_at
85
        for trigger in self.triggers:
86
            self.logger.debug(trigger)
87
            if trigger.check_trigger(
88
                race, race.get_entrant_by_name(entrant_name)
89
            ):
90
                self.play_media_callback(
91
                    trigger.media_file_path, self.monitoring_type)
92
                self.logger.debug("trigger fired")
93
94
    def add_trigger(
95
        self, media_file_path: str, place_trigger: int = None,
96
        entrant_count_trigger: int = None
97
    ):
98
        async def add(
99
            media_file_path: str, place_trigger: int = None,
100
            entrant_count_trigger: int = None
101
        ):
102
            async with self.triggers_lock:
103
                self.triggers.append(MediaTrigger(
104
                    media_file_path, place_trigger=place_trigger,
105
                    entrant_count_trigger=entrant_count_trigger
106
                ))
107
108
        asyncio.ensure_future(add(
109
                media_file_path, place_trigger,
110
                entrant_count_trigger
111
        ))
112
113
    def add_timer(self, media_file_path: str, race_time: timedelta):
114
        # try to wake up a little early and get ready
115
        timer = Timer(
116
            self.time_to_start_play(race_time),
117
            self.timer_wake_up, media_file_path, race_time
118
        )
119
        self.timers.append(timer)
120
        timer.start()
121
122
    def time_to_start_play(self, race_time: timedelta) -> float:
123
        time_to_start_play = 10000000000000.0
124
        return time_to_start_play
125
126
    async def timer_wake_up(self, media_file_path: str, race_time: timedelta):
127
        asyncio.sleep(self.time_to_start_play(race_time))
128
        self.logger.debug(
129
            f"attempting to play {media_file_path} at "
130
            f"{timer_to_str(race_time)}"
131
        )
132
        asyncio.ensure_future(
133
            self.play_media_callback(
134
                media_file_path, self.monitoring_type))
135
136
    def remove_trigger(self, index: int):
137
        async def remove(index: int):
138
            async with self.triggers_lock:
139
                self.triggers.clear()
140
        asyncio.ensure_future(remove(index))
141