191 lines
6.6 KiB
Python
191 lines
6.6 KiB
Python
#!/usr/bin/env bash
|
|
import time, datetime, yweather, yahoo_finance, subprocess, os, json, urllib.request
|
|
day_of_week = time.localtime().tm_wday
|
|
now = time.time()
|
|
#now = time.time() + 60*28 + 60*60*13
|
|
tmp = "/tmp/"
|
|
|
|
voice = False
|
|
|
|
### A fucton of helpers
|
|
|
|
def time_period():
|
|
return "Morning" if time.localtime(now).tm_hour < 12 else "Afternoon"
|
|
|
|
# hours = 3
|
|
# str(hours) + " hours" + sp(hours) -> "3 hours"
|
|
# hours = 1
|
|
# str(hours) + " hours" + sp(hours) -> "1 hour"
|
|
def sp(a):
|
|
if a == 1:
|
|
return ""
|
|
return "s"
|
|
|
|
# "90" -> "90"
|
|
# "90.00" -> "90"
|
|
# "90.1" -> "90 point 1"
|
|
def format_float(s):
|
|
s = str(s)
|
|
if not "." in s: return s
|
|
while True:
|
|
if s[-1] == "0":
|
|
s = s[:-1]
|
|
elif s[-1] == ".":
|
|
s = s[:-1]
|
|
break
|
|
else:
|
|
break
|
|
if voice:
|
|
return s.replace(".", " point ")
|
|
return s
|
|
|
|
# "12" -> "12th"
|
|
# etc..
|
|
def ordinal(s):
|
|
if s[-1] == "1": return s + "st"
|
|
if s[-1] == "2": return s + "nd"
|
|
if s[-1] == "3": return s + "rd"
|
|
return s + "th"
|
|
|
|
# 1493353783.0026777 -> "Friday, April 28th"
|
|
# will replace leading zeroes in the day with a space, like April 01 becomes April 1st
|
|
def get_pretty_date(when = now):
|
|
l = time.localtime(when)
|
|
return ordinal(time.strftime("%A, %B %_d", l))
|
|
|
|
# 1493353783.0026777 -> "0:30"
|
|
# 1493352043.3361661 -> "0 hundred hours"
|
|
# 1493402438.1561348 -> "14 hundred
|
|
# Will replace leading zeroes in the hour with spaces, like 02:30 becomes 2 30
|
|
def get_pretty_time(when = now):
|
|
l = time.localtime(when)
|
|
start = time.strftime("%_H:%M", l)
|
|
if l.tm_min == 0:
|
|
if l.tm_hour < 10:
|
|
start = start.replace(":00", " hundred hours")
|
|
else:
|
|
start = start.replace(":00", " hundred")
|
|
return start
|
|
|
|
# *(0, 60*65) -> "1 hour 5 minutes"
|
|
# could use work, seems to floor any difference you give it instead of round,
|
|
# leads to "the time is 7 15 and your first class is in 44 minutes"
|
|
def get_pretty_interval(start, end):
|
|
diff = end - start
|
|
l = time.gmtime(diff)
|
|
hours = int(time.strftime("%H", l), 10)
|
|
minutes = int(time.strftime("%M", l), 10)
|
|
result = ""
|
|
if hours > 0:
|
|
result += str(hours) + " hour" + sp(hours) + " " # + ", "
|
|
return result + str(minutes) + " minute" + sp(minutes)
|
|
|
|
# todo: document
|
|
def today(hour, minute):
|
|
l = datetime.datetime.fromtimestamp(now)
|
|
l = l.replace(hour = hour)
|
|
l = l.replace(minute = minute)
|
|
l = l.replace(second = 0)
|
|
return l.timestamp()
|
|
|
|
def get_name(c): return c[0]
|
|
def get_time(c): return c[1]
|
|
|
|
### Actual commands
|
|
|
|
classes = [
|
|
[["Multivar", today(10, 10)], ["Physics", today(11, 15)], ["Physics again", today(12, 20)]] # monday is zero
|
|
, [["2505", today(14, 00)], ["Discrete", today(15, 30)], ["Seminar", today(17, 00)]]
|
|
, [["Multivar", today(10, 10)], ["Physics", today(12, 20)], ["Lab", today(14, 30)]]
|
|
, [["2505", today(14, 00)], ["Discrete", today(15, 30)]]
|
|
, [["Multivar", today(10, 10)], ["Physics", today(12, 20)]] # friday
|
|
, []
|
|
, [] # sunday
|
|
]
|
|
|
|
# TODO Update
|
|
alarms = [
|
|
[today(8, 15), today(15, 30)] # monday
|
|
, [today(7, 15), today(12, 00)]
|
|
, [today(8, 15), today(15, 30)]
|
|
, [today(7, 15), today(12, 00)]
|
|
, [today(15,30)] # friday
|
|
, []
|
|
, [] # sunday
|
|
]
|
|
for k in range(len(alarms)):
|
|
alarms[k].append(today(22, 0))
|
|
#alarms[k].append(today(23, 0))
|
|
|
|
# pass -1 for today
|
|
# 0 for tomorrow's forecast, 1 for the day after that, etc..
|
|
def weather(day = -1):
|
|
filename = tmp + "weather_" + str(day)
|
|
if os.path.exists(filename) and now - os.stat(filename).st_mtime < 60*60: # cache for a maximum of one hour
|
|
return open(filename, "r").read()
|
|
wid = "2365044" # BLACKSBURG
|
|
wid = "12798962" # SEATTLE
|
|
#url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%20%3D%20%22blacksburg%2C%20va%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
|
|
url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%20"+wid+"&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys"
|
|
data = json.loads(urllib.request.urlopen(url).read().decode("utf-8"))
|
|
if day == -1:
|
|
data = data["query"]["results"]["channel"]["item"]["condition"]
|
|
retval = data["text"] + ", " + data["temp"] + " degrees"
|
|
else:
|
|
forecast = data["query"]["results"]["channel"]["item"]["forecast"][day]
|
|
retval = forecast["text"] + ", " + format_float((float(forecast["low"])+float(forecast["high"]))/2) + " degrees"
|
|
open(filename, "w").write(retval)
|
|
return retval
|
|
|
|
def stock(stk):
|
|
filename = tmp + "stock_" + stk
|
|
if os.path.exists(filename) and now - os.stat(filename).st_mtime < 60*60: # cache for a maximum of one hour
|
|
return open(filename, "r").read()
|
|
yesterday = time.strftime("%Y-%m-%d", time.localtime(now - 24*60*60))
|
|
s = yahoo_finance.Share(stk)
|
|
#val = float(s.get_percent_change().replace("%", "")) # unstable as fuck
|
|
|
|
val = round(100 * (float(s.get_price())/float(s.get_prev_close()) - 1), 1)
|
|
|
|
#s_y = s.get_historical(yesterday, yesterday)
|
|
#price_now = float(s.data_set["Ask"])
|
|
#price_yesterday = float(s_y[0]["Close"])
|
|
#val = round(100 * ((price_now/price_yesterday) - 1), 1)
|
|
|
|
word = "up"
|
|
if val < 0:
|
|
word = "down"
|
|
retval = word + " " + format_float(abs(val)) + " percent"
|
|
open(filename, "w").write(retval)
|
|
return retval
|
|
|
|
todays_classes = classes[day_of_week]
|
|
todays_classes = [k for k in todays_classes if get_time(k) > now]
|
|
todays_alarms = alarms[day_of_week]
|
|
todays_alarms = [k for k in todays_alarms if k > now]
|
|
|
|
### Actual printed stuff
|
|
|
|
messages = [
|
|
["say", "Good " + time_period() + " Niles"]
|
|
, ["say", "Today is " + get_pretty_date()]
|
|
, ["say", "The time is " + get_pretty_time()]
|
|
, ["say", ("Your next class is " + get_name(todays_classes[0]) + " in " + get_pretty_interval(now, get_time(todays_classes[0])) if len(todays_classes) > 0 else "You have no classes today")]
|
|
, ["say", ("You have an alarm set for " + get_pretty_time(todays_alarms[0])) if len(todays_alarms) > 0 else "You have no alarms set for today"]
|
|
, ["say", "The SNP 500 is " + stock("^GSPC") + " and AMD is " + stock("AMD")]
|
|
, ["say", "The weather for Seattle is " + weather()]
|
|
, ["say", "Tommorow's weather is " + weather(0)]
|
|
#, ["exec", "npr"] # todo, skip 20 secs
|
|
]
|
|
|
|
### Does the actual printing
|
|
|
|
m = "\n".join([k[1] for k in messages])
|
|
|
|
print(m)
|
|
if voice:
|
|
import gtts
|
|
tts = gtts.gTTS(m)
|
|
tts.save("/tmp/temp.mp3")
|
|
subprocess.call(["mpv", "/tmp/temp.mp3"])
|