horas (6737B)
1 #!/usr/bin/python 2 HELP_MSG = ''' 3 Usage: 4 -h show this help message and exit 5 -n show when the noonday devil attacks today, i.e. from the 6 fourth hour to the eighth hour 7 -s print only sunrise and sunset times for today 8 -t print only the dawn and dusk times for today 9 -c print the times of dawn and all twelve hours for today 10 -p print today's prayer hours (Lauds, Prime, Terce, etc.) 11 -a print everything for today. This is the default 12 -w print times in 12-hour time instead of 24-hour 13 If any argument except -h or -w is capitalized, 14 data for the whole month will be returned''' 15 ARGS_LIST = "ACNPSTachnopstw" 16 DATE_FMT = "%Y-%m-%d" 17 18 import json 19 import re 20 import os 21 import urllib.request, urllib.error, urllib.parse 22 from datetime import date 23 from sys import argv 24 from time import localtime, mktime, strftime, strptime 25 26 CACHE_DIR = (os.environ["XDG_CACHE_HOME"] if "XDG_CACHE_HOME" in os.environ else (os.environ["HOME"] + "/.cache")) + "/horas" 27 DATA_FILE = CACHE_DIR + "/horas.json" 28 TMP_DIR = (os.environ["TMPDIR"] if "TMPDIR" in os.environ else "/tmp") + "/horas" 29 WEBPAGE = TMP_DIR + "/horas.html" 30 31 32 def downloadData(): 33 todayTime = date.today().timetuple() 34 print(f"Downloading sunlight times for Minneapolis, MN for the month of {strftime('%B %Y', todayTime)}...") 35 req = urllib.request.Request( 36 'https://sunrise-sunset.org/us/minneapolis-mn', 37 data=None, 38 headers={ 39 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17' 40 } 41 ) 42 if not os.path.exists(TMP_DIR): 43 os.mkdir(TMP_DIR) 44 with open(WEBPAGE, 'w') as file: 45 file.write(urllib.request.urlopen(req).read().decode('UTF-8')) 46 print('Download successful. Recording data as an object...') 47 recordData() 48 49 def recordData(): 50 TIME_RE = r"(1?\d:[0-5]\d):[0-5]\d( am| pm)" 51 DATE_RE = r"\d{4}-\d{2}-\d{2}" 52 days = [] 53 with open(WEBPAGE, 'r') as file: 54 lastTimeFound="" 55 day = {} 56 getNext = False 57 for line in file: 58 if re.search("<td>", line): 59 if getNext: 60 # This is dusk (the record right after sunset) 61 match = re.search(TIME_RE, line) 62 day['dusk'] = match[1] + match[2] 63 getNext = False 64 # One day down ... 65 days.append(day) 66 day = {} 67 elif re.search(r"Sunrise", line): 68 day['date'] = re.search(DATE_RE, line)[0] 69 # The record before sunrise is always dawn 70 day['dawn'] = lastTimeFound 71 match = re.search(TIME_RE, line) 72 day['sunrise'] = match[1] + match[2] 73 elif re.search(r"Sunset", line): 74 match = re.search(TIME_RE, line) 75 day['sunset'] = match[1] + match[2] 76 # Next record will be dusk 77 getNext = True 78 else: 79 match = re.search(TIME_RE, line) 80 if match: 81 lastTimeFound = match[1] + match[2] 82 if not os.path.exists(CACHE_DIR): 83 os.mkdir(CACHE_DIR) 84 with open(DATA_FILE, "w") as file: 85 json.dump(days, file) 86 os.remove(WEBPAGE) 87 print('Done.') 88 89 def getData(): 90 if os.access(DATA_FILE, os.F_OK): 91 data = [] 92 try: 93 with open(DATA_FILE, "r") as file: 94 data = json.load(file) 95 dataDate = strptime(data[0]["date"], DATE_FMT) 96 actualDate = date.today() 97 if dataDate.tm_year == actualDate.year and dataDate.tm_mon == actualDate.month: 98 return data 99 else: 100 print("Data is out of date.") 101 except: 102 print("Data file found, but is unreadable.") 103 else: 104 print("No data file found.") 105 106 downloadData() 107 return getData() 108 109 110 111 args = ''.join(sorted([item for item in ''.join(argv[1:]) if item != '-'])) 112 for arg in args: 113 if ARGS_LIST.find(arg) == -1: 114 print(f"Unknown argument: {arg}.") 115 print(HELP_MSG) 116 exit(1) 117 if args.find("h") > -1: 118 print(HELP_MSG) 119 exit(0) 120 if args == "" or args.find("a") > -1: 121 args = "scn" 122 if args.find("A") > -1: 123 args = "SCN" 124 125 data = getData() 126 TIME_FMT = "%I:%M %p" 127 TIME_DISPLAY_FMT = "%I:%M %p" if(args.find("w") > -1) else "%H:%M" 128 129 if args.islower(): 130 # Only today's data--otherwise, the whole month 131 data = [data[date.today().day - 1]] 132 133 args = args.lower() 134 135 for times in data: 136 sunrise = mktime(strptime(times["sunrise"], TIME_FMT)) 137 sunset = mktime(strptime(times["sunset"], TIME_FMT)) 138 secsPerHr = (sunset - sunrise) / 12 139 minsPerHr, remainder = divmod(secsPerHr, 60) 140 141 todayStr = ' (Today)' if times['date'] == strftime(DATE_FMT, date.today().timetuple()) else '' 142 print(f"On {times['date']}{todayStr}:") 143 print(f"There are {minsPerHr:.0f} minutes and {remainder:.0f} seconds to each hour.") 144 145 if args.find("s") > -1: 146 print("The sun rises at %s and sets at %s"% (strftime(TIME_DISPLAY_FMT, localtime(sunrise)), strftime(TIME_DISPLAY_FMT, localtime(sunset)))) 147 if args.find("t") > -1: 148 dawn, dusk = [strftime(TIME_DISPLAY_FMT, localtime(mktime(strptime(times[key], TIME_FMT)))) for key in ['dawn', 'dusk']] 149 print("First light is at %s and last light at %s."% (dawn, dusk)) 150 if args.find("p") > -1: 151 myTimeSecs = sunrise 152 print("Laudes:", strftime(TIME_DISPLAY_FMT, localtime(myTimeSecs))) 153 myTimeSecs += secsPerHr 154 print("Prima:", strftime(TIME_DISPLAY_FMT, localtime(myTimeSecs))) 155 myTimeSecs += secsPerHr * 2 156 print("Tertia:", strftime(TIME_DISPLAY_FMT, localtime(myTimeSecs))) 157 158 for hora in ['Sexta', 'Nona', 'Vesperae']: 159 myTimeSecs += secsPerHr * 3 160 print(f"{hora}:", strftime(TIME_DISPLAY_FMT, localtime(myTimeSecs))) 161 if args.find("c") > -1: 162 horas = ['Aurora', 'Prima', 'Secunda', 'Tertia', 'Quarta', 'Quinta', 'Sexta', 'Septima', 163 'Octava', 'Nona', 'Decima', 'Undecima', 'Crepusculum'] 164 myTimeSecs = sunrise 165 for hora in horas: 166 print(f"{hora}:", strftime(TIME_DISPLAY_FMT, localtime(myTimeSecs))) 167 myTimeSecs += secsPerHr 168 if args.find("n") > -1: 169 print("The noonday devil attacks between" 170 , strftime(TIME_DISPLAY_FMT, localtime(sunrise + secsPerHr * 4)) 171 , f"and {strftime(TIME_DISPLAY_FMT, localtime(sunrise + secsPerHr * 8))}.") 172 173 exit(0)