padavan.py 12.9 KB
Newer Older
1
#
David Trattnig's avatar
David Trattnig committed
2
# Aura Engine (https://gitlab.servus.at/aura/engine)
3
#
David Trattnig's avatar
David Trattnig committed
4
# Copyright (C) 2017-2020 - The Aura Engine Team.
5
#
David Trattnig's avatar
David Trattnig committed
6
7
8
9
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
10
#
David Trattnig's avatar
David Trattnig committed
11
12
13
14
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
15
#
David Trattnig's avatar
David Trattnig committed
16
17
18
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

19

20
import json
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
21

22
23
from modules.base.enum import RedisChannel
from modules.base.utils import TerminalColors
24
from modules.communication.redis.adapter import ClientRedisAdapter, ServerRedisAdapter
25
from modules.communication.redis.messenger import RedisMessenger
David Trattnig's avatar
David Trattnig committed
26
from modules.database.model import AuraDatabaseModel
27
28


Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
29
30
31
32
class Padavan:
    args = None
    config = None

David Trattnig's avatar
David Trattnig committed
33
    ss = None
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
34
    zmqclient = None
35
    redisclient = None
36
    stringreply = ""
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
37

38
    # ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
39
40
41
42
    def __init__(self, args, config):
        self.args = args
        self.config = config

43
    # ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
44
45
46
47
    def meditate(self):
        if self.args.fetch_new_programme:
            self.fetch_new_programme()

David Trattnig's avatar
David Trattnig committed
48
49
        elif self.args.mixer_channels_selected:
            self.mixer_channels_selected()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
50

David Trattnig's avatar
David Trattnig committed
51
52
        elif self.args.mixer_status:
            self.mixer_status()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
53

54
        elif self.args.get_act_programme:
55
            self.get_act_programme()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
56

David Trattnig's avatar
David Trattnig committed
57
58
59
        elif self.args.get_status:
            self.get_status()

60
61
62
        elif self.args.get_connection_status:
            self.get_connection_status()

63
64
        elif self.args.shutdown:
            self.shutdown()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
65

66
        elif self.args.redis_message:
67
68
            self.redis_message(self.args.redis_message[0], self.args.redis_message[1])

69
        elif self.args.select_mixer != -1:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
70
71
            self.select_mixer(self.args.select_mixer)

72
        elif self.args.deselect_mixer != -1:
73
            self.select_mixer(self.args.deselect_mixer, False)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
74

75
        elif self.args.set_volume:
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
76
77
            self.set_volume(self.args.set_volume[0], self.args.set_volume[1])

78
79
80
        elif self.args.print_message_queue:
            self.print_message_queue()

81
82
        elif self.args.get_file_for:
            self.get_next_file(self.args.get_file_for)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
83

84
85
        elif self.args.set_file_for:
            self.set_next_file(self.args.set_file_for[0], self.args.set_file_for[1])
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
86

87
        elif self.args.now_playing:
88
            print("")
89

90
91
92
        elif self.args.init_player:
            self.init_player()

93
94
        elif self.args.on_play:
            self.on_play(self.args.on_play)
95

96
97
98
        elif self.args.recreatedb:
            self.recreatedb()

99
100
        # else:
        #    raise Exception("")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
101
102

    # init liquid => faster exec time, when loading at runtime just what is needed
103
    # ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
104
105
    def init_liquidsoap_communication(self):
        # import
David Trattnig's avatar
David Trattnig committed
106
        from modules.core.engine import SoundSystem
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
107
108

        # init liquidsoap communication
David Trattnig's avatar
David Trattnig committed
109
        self.ss = SoundSystem(self.config)
110
        # enable connection
David Trattnig's avatar
David Trattnig committed
111
        self.ss.enable_transaction()
112

113
    # ------------------------------------------------------------------------------------------ #
114
115
    def destroy_liquidsoap_communication(self):
        # enable connection
David Trattnig's avatar
David Trattnig committed
116
        self.ss.disable_transaction()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
117

118
    # ------------------------------------------------------------------------------------------ #
119
    def init_redis_communication(self, with_server=False):
120
        self.redisclient = ClientRedisAdapter(self.config)
121
122

        if with_server:
123
            self.redisserver = ServerRedisAdapter(self.config)
124

125
    # ------------------------------------------------------------------------------------------ #
126
127
128
    def send_redis(self, channel, message):
        self.init_redis_communication()
        self.redisclient.publish(channel, message)
129

130
    # ------------------------------------------------------------------------------------------ #
131
    def send_and_wait_redis(self, channel, message, reply_channel):
132
        self.init_redis_communication(True)
133
        self.redisclient.publish(channel, message)
134
        return self.redisserver.listen_for_one_message(reply_channel.value)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
135

136
    # ------------------------------------------------------------------------------------------ #
137
138
139
140
    def shutdown(self):
        self.send_redis("aura", "shutdown")
        self.stringreply = "Shutdown message sent!"

141
    # ------------------------------------------------------------------------------------------ #
142
    def fetch_new_programme(self):
143
        json_reply = self.send_and_wait_redis("aura", "fetch_new_programme", RedisChannel.FNP_REPLY)
144
        if json_reply != "":
145
            actprogramme = json.loads(json_reply)
146
147
148
            self.print_programme(actprogramme)
        else:
            print("No programme fetched")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
149

150
    # ------------------------------------------------------------------------------------------ #
151
    def get_act_programme(self):
152
        json_reply = self.send_and_wait_redis("aura", "get_act_programme", RedisChannel.GAP_REPLY)
153
        actprogramme = json.loads(json_reply)
154
155
        self.print_programme(actprogramme)

David Trattnig's avatar
David Trattnig committed
156
157
158
159
160
161
162
163
164
165

    def get_status(self):
        """
        Retrieves the Engine's status information.
        """
        json_reply = self.send_and_wait_redis("aura", "get_status", RedisChannel.GS_REPLY)
        # status = json.loads(json_reply)
        self.stringreply = json_reply
        

166
    # ------------------------------------------------------------------------------------------ #
167
168
    def get_connection_status(self):
        json_reply = self.send_and_wait_redis("aura", "get_connection_status", RedisChannel.GCS_REPLY)
169
        connection_status = json.loads(json_reply)
170
171
        self.print_connection_status(connection_status)

172
    # ------------------------------------------------------------------------------------------ #
173
    def print_programme(self, programme):
174
175
176
177
178
179
180
181
182
        cnt = 1
        for show in programme:
            for entry in show["playlist"]:
                self.stringreply += str(cnt) + \
                    " --- schedule id #" + str(show["schedule_id"]) + "." + str(entry["entry_num"]) + \
                    " - show: " + show["show_name"] + \
                    " - starts @ " + entry["entry_start"] + \
                    " - plays " + str(entry["source"]) + "\n"
                cnt = cnt + 1
183

184
    # ------------------------------------------------------------------------------------------ #
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
    def print_connection_status(self, connection_status):

        if connection_status["pv"]:
            self.stringreply = "Connection to pv:    " + TerminalColors.GREEN.value + " " + str(connection_status["pv"]) + TerminalColors.ENDC.value
        else:
            self.stringreply = "Connection to pv:    " + TerminalColors.RED.value + " " + str(connection_status["pv"]) + TerminalColors.ENDC.value

        if connection_status["db"]:
            self.stringreply += "\nConnection to db:    " + TerminalColors.GREEN.value + " " + str(connection_status["db"]) + TerminalColors.ENDC.value
        else:
            self.stringreply += "\nConnection to db:    " + TerminalColors.RED.value + " " + str(connection_status["db"]) + TerminalColors.ENDC.value

        if connection_status["lqs"]:
            self.stringreply += "\nConnection to lqs:   " + TerminalColors.GREEN.value + " " + str(connection_status["lqs"]) + TerminalColors.ENDC.value
        else:
            self.stringreply += "\nConnection to lqs:   " + TerminalColors.RED.value + " " + str(connection_status["lqs"]) + TerminalColors.ENDC.value

202
203
204
205
206
        if connection_status["lqsr"]:
            self.stringreply += "\nConnection to lqsr:  " + TerminalColors.GREEN.value + " " + str(connection_status["lqsr"]) + TerminalColors.ENDC.value
        else:
            self.stringreply += "\nConnection to lqsr:  " + TerminalColors.RED.value + " " + str(connection_status["lqsr"]) + TerminalColors.ENDC.value

207
208
209
210
211
212
213
214
215
216
        if connection_status["tank"]:
            self.stringreply += "\nConnection to tank:  " + TerminalColors.GREEN.value + " " + str(connection_status["tank"]) + TerminalColors.ENDC.value
        else:
            self.stringreply += "\nConnection to tank:  " + TerminalColors.RED.value + " " + str(connection_status["tank"]) + TerminalColors.ENDC.value

        if connection_status["redis"]:
            self.stringreply += "\nConnection to redis: " + TerminalColors.GREEN.value + " " + str(connection_status["redis"]) + TerminalColors.ENDC.value
        else:
            self.stringreply += "\nConnection to redis: " + TerminalColors.RED.value + " " + str(connection_status["redis"]) + TerminalColors.ENDC.value

217
    # ------------------------------------------------------------------------------------------ #
218
219
    
    
220
    def init_player(self):
221
222
223
        """
        Initializes the player on Liquidsaop startup.
        """
224
        self.stringreply = self.send_and_wait_redis("aura", "init_player", RedisChannel.IP_REPLY)
225

226
227


228
    def on_play(self, info):
229
        """
230
        Event handler to be called when some entry started playing.
231
232
        """

233
        self.stringreply = self.send_and_wait_redis("aura", "on_play " + info, RedisChannel.GNF_REPLY)
234

235
    # ------------------------------------------------------------------------------------------ #
236
237
238
239
240
241
    def recreatedb(self):
        print("YOU WILL GET PROBLEMS DUE TO DATABASE BLOCKING IF aura.py IS RUNNING! NO CHECKS IMPLEMENTED SO FAR!")
        x = AuraDatabaseModel()
        x.recreate_db()
        self.stringreply = "Database recreated!"

242
    # ------------------------------------------------------------------------------------------ #
243
244
245
    def redis_message(self, channel, message):
        self.send_redis(channel, message)
        self.stringreply = "Message '"+message+"' sent to channel '"+channel+"'"
246

247
    # ------------------------------------------------------------------------------------------ #
248
    def print_message_queue(self):
249
        self.stringreply = self.send_and_wait_redis("aura", "print_message_queue", RedisChannel.PMQ_REPLY)
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
250

251
    # LIQUIDSOAP #
252
253

    # ------------------------------------------------------------------------------------------ #
254
255
    def select_mixer(self, mixername, activate=True):
        # init lqs
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
256
257
258
        self.init_liquidsoap_communication()

        # select mixer and return the feedback
David Trattnig's avatar
David Trattnig committed
259
        self.stringreply = self.ss.channel_activate(mixername, activate)
260
261
262

        # disable connection
        self.destroy_liquidsoap_communication()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
263

264
    # ------------------------------------------------------------------------------------------ #
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
265
    def set_volume(self, mixernumber, volume):
266
        # init lqs and enable comm
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
267
        self.init_liquidsoap_communication()
David Trattnig's avatar
David Trattnig committed
268
        self.stringreply = self.ss.channel_volume(mixernumber, volume)
269
270
        # disable connection
        self.destroy_liquidsoap_communication()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
271

272
    # ------------------------------------------------------------------------------------------ #
David Trattnig's avatar
David Trattnig committed
273
    def mixer_channels_selected(self):
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
274
        self.init_liquidsoap_communication()
David Trattnig's avatar
David Trattnig committed
275
        am = self.ss.mixer_channels_selected()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
276
277

        if len(am) == 0:
278
            self.destroy_liquidsoap_communication()
279
            raise Exception("Guru recognized a problem: No active source!!!")
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
280

281
282
        self.stringreply = str(am)

283
284
285
        # disable connection
        self.destroy_liquidsoap_communication()

286
    # ------------------------------------------------------------------------------------------ #
David Trattnig's avatar
David Trattnig committed
287
    def mixer_status(self):
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
288
289
        self.init_liquidsoap_communication()

David Trattnig's avatar
David Trattnig committed
290
        status = self.ss.mixer_status()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
291
292

        for k, v in status.items():
293
            self.stringreply += "source: " + k + "\t status: " + v + "\n"
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
294

295
296
297
        # disable connection
        self.destroy_liquidsoap_communication()

298
    # REDIS #
299
300

    # ------------------------------------------------------------------------------------------ #
301
    def get_next_file(self, type):
302
303
304
305
306
#        redis = RedisMessenger()
#        next_file = redis.get_next_file_for(type)
#        if next_file == "":
#            next_file = "/var/audio/blank.flac"
#        self.stringreply = next_file
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
307

308
        #self.send_redis("aura", "set_next_file " + type)
309

310
        next_file = self.send_and_wait_redis("aura", "get_next_file " + type, RedisChannel.GNF_REPLY)
311
312
        self.stringreply = next_file

313
    # ------------------------------------------------------------------------------------------ #
314
    def set_next_file(self, type, file):
315
316
        #from modules.communication.redis.messenger import RedisMessenger
        #redis = RedisMessenger()
Gottfried Gaisbauer's avatar
Gottfried Gaisbauer committed
317

318
319
        #redis.set_next_file_for(type, file)
        self.send_redis("aura", "set_next_file " + type + " " + file)
320
        self.stringreply = "Set "+file+" for fallback '"+type+"'"