horas

A python program to print the hours according to the ancients' conception of time
git clone git://git.wilsonrgheen.com/horas
Log | Files | Refs | README

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)