-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstream_monitor.py
149 lines (119 loc) · 5.77 KB
/
stream_monitor.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
This script was written by Hamish Nicholson (/koala) in June 2019
If it detects silence in any two consecutive 30 second blocks of the stream
then it sends out an email to the important @whrb emails
Additionally the recovery email for the gmail used here is [email protected]
WARNING!!!!
This DOES NOT detect every possible failure path at WHRB. For example
if we have issues with the transmitter, such as the microwave transmiter
on smith going down this will not detect it. This only detects dead air as
a result of issues in the studio. It is also entirely possible that the
stream could be broadcasting deadair and the FM broadcast is fine.
This is to be used as one of many debugging/warning tools.
"""
import time
import requests
import os
# this sets up th environment and is needed if being run by a daemon/starup process, not needed if running from an interactive shell
from pydub import AudioSegment
import smtplib, ssl
import datetime
import json
# old imports for working with email below
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
# We get the slack webhook URL from an environment variable called SLACK_WEBHOOK, this is set on the Heroku dashboard
# to set an environment variable on Linux/OSX use `export SLACK_WEBHOOK=<the web hook here>`
slack_emergencies_url = os.environ['SLACK_WEBHOOK']
def capture_stream(filename):
#This function captures a segment of the stream and saves it to filename.
stream_url = "http://stream.whrb.org:8000/whrb-mp3"
r = requests.get(stream_url, stream=True)
timer = 0
with open(filename, 'wb') as f:
for block in r.iter_content(1024):
f.write(block)
# roughly 30 seconds 350
if timer > 1000:
break
timer += 1
def send_slack(text):
print("sending slack message")
payload = {"text": text}
response = requests.post(slack_emergencies_url, data=json.dumps(
payload), headers={'Content-Type': 'application/json'})
# print(response.text) #TEXT/HTML
# print(response.status_code, response.reason)
# deprecated. Doesn't seem to work anymore, possibly google not liking our automated emails
def send_email():
# This function sends the deadair email to all relevent whrb emails
# it is sent from [email protected]
port = 465
password = "Set password here"
sender_email = "[email protected]"
receiver_emails = ["[email protected]", "[email protected]", "[email protected]", "[email protected]", "[email protected]"]
# Create a secure SSL context
context = ssl.create_default_context()
message = MIMEMultipart("alternative")
message["Subject"] = "STREAM OFFAIR ALARM"
message["From"] = sender_email
message_text = """\
Subject: STREAM OFF AIR ALARM
The stream appears to be broadcasting silence as of {0:%Y-%m-%d %H:%M:%S}
This message is an automated message sent from Python.""".format(datetime.datetime.now())
part1 = MIMEText(message_text, "plain")
message.attach(part1)
# for some reason googles smtp only worked without using the context
# this is less secure, but it really doesn't matter who sees this message
# context = ssl.create_default_context()
server = smtplib.SMTP_SSL("smtp.gmail.com", port)
server.set_debuglevel(1)
server.login(sender_email, password)
for receiver_email in receiver_emails:
message["To"] = receiver_email
server.sendmail(sender_email, receiver_email, message.as_string())
server.quit()
if __name__ == "__main__":
print("starting whrb off air alarm")
#send_slack("test message from the offair bot")
prev_silent = False
prev_failed = False
email_last_sent = time.time() - 1800
# After a little bit of testing -50 dBFS seems reasonable. Classical is mostly is in the -30 range
# and goes down to -40 occasionally. Absolute silence/static is -65.
while True:
try:
capture_stream("/tmp/whrb_capture.mp3")
capture_segment = AudioSegment.from_mp3("/tmp/whrb_capture.mp3")
if capture_segment.dBFS < -55.0 and prev_silent == True:
# only want to send an email at most every 30 minutes
if time.time() - email_last_sent > 1800:
warning_message = """WARNING: The stream appears to be broadcasting silence as of {0:%Y-%m-%d %H:%M:%S}""".format(datetime.datetime.now())
print(warning_message)
send_slack(warning_message)
email_last_sent = time.time()
if capture_segment.dBFS < -55.0:
prev_silent = True
else:
prev_silent = False
print("INFO: dbfs", capture_segment.dBFS)
# if we have gotten to here we haven't failed. The stream is online and not silent
if prev_failed == True:
prev_failed = False
try:
os.remove("/tmp/whrb_capture.mp3")
except:
continue
except:
# if we have failed twice in a row, there is probably a legitimate issue.
if time.time() - email_last_sent > 1800 and prev_failed == True:
warning_message = """WARNING: Unable to connect to the stream as of {0:%Y-%m-%d %H:%M:%S}""".format(
datetime.datetime.now())
print(warning_message)
send_slack(warning_message)
email_last_sent = time.time()
# wait 30 seconds to try again
time.sleep(30)
prev_failed = True
print("Failed to capture stream, the stream may be down")
continue