You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.1 KiB

7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
7 years ago
  1. from dateutil.parser import parse as date_parse
  2. import argparse
  3. import ctabus
  4. import datetime
  5. import os
  6. import re
  7. import time
  8. # for logging
  9. import os.path as osp
  10. import sys
  11. import re
  12. # https://stackoverflow.com/a/5967539
  13. def atoi(text):
  14. return int(text) if text.isdigit() else text
  15. def clearscr():
  16. os.system('cls' if os.name == 'nt' else 'clear')
  17. def numb_sort(text):
  18. '''
  19. alist.sort(key=natural_keys) sorts in human order
  20. http://nedbatchelder.com/blog/200712/human_sorting.html
  21. (See Toothy's implementation in the comments)
  22. '''
  23. return [ atoi(c) for c in re.split(r'(\d+)', text) ]
  24. def pprint_delta(delta):
  25. delta = str(delta)
  26. days= None
  27. s1 = delta.split(', ')
  28. if len(s1) > 1:
  29. days,time = s1
  30. else:
  31. time = s1[0]
  32. time = time.split('.')[0]
  33. hour,minute,second = map(int,time.split(':'))
  34. time = ''
  35. if hour:
  36. time += f'{hour} hour' + ('s' if hour != 1 else '')
  37. if minute:
  38. if time and not time.endswith(', '):
  39. time += ', '
  40. time += f'{minute} minute' + ('s' if minute != 1 else '')
  41. if second:
  42. if time and not time.endswith(', '):
  43. time += ', '
  44. time += f'{second} second' + ('s' if second != 1 else '')
  45. ret = ''
  46. if days:
  47. ret = days + ', ' if time else ''
  48. ret += time
  49. return ret
  50. def gen_list(objs,data,*displays,key = None,sort = 0,num_pic = True):
  51. k = displays[sort]
  52. display_data = {obj[k]:obj[data] for obj in objs}
  53. srt_keys = sorted(display_data.keys(),key=key)
  54. display = sorted(
  55. [
  56. [obj[d] for d in displays] for obj in objs
  57. ],
  58. key = lambda row: key(row[sort]) if key else row[sort]
  59. )
  60. if num_pic:
  61. display = [[i] + data for i,data in enumerate(display)]
  62. opts = {
  63. 'spacer':' ',
  64. 'seperator':' ',
  65. 'interactive': True,
  66. 'bottom':'=',
  67. 'l_end':'<',
  68. 'r_end':'>',
  69. }
  70. print2d(display,**opts)
  71. if num_pic:
  72. which = None
  73. while not which:
  74. try:
  75. which = input('Which one?: ')
  76. except KeyboardInterrupt:
  77. quit()
  78. try:
  79. which = srt_keys[int(which)]
  80. except ValueError:
  81. which = None
  82. return display_data[which]
  83. else:
  84. ret = None
  85. while not ret:
  86. try:
  87. ret = display_data[input('Which one?: ')]
  88. except KeyError:
  89. pass
  90. return ret
  91. config = '''\
  92. {route} - {end} ({direction})
  93. {nm}, stop {stop_id}
  94. {delta} ({t})\
  95. '''
  96. def show(stop_id,rt_filter=None,_clear=False):
  97. times = ctabus.get_times(stop_id)['prd']
  98. today = datetime.datetime.today()
  99. arrivals = sorted(times,key = lambda t: t["prdtm"])
  100. if rt_filter is not None:
  101. arrivals =filter(lambda arrival: arrival['rt'] == rt_filter,arrivals)
  102. if _clear:
  103. clearscr()
  104. for time in arrivals:
  105. arrival = date_parse(time['prdtm'])
  106. if arrival > today:
  107. delta = pprint_delta(arrival-today)
  108. t = arrival.strftime('%H:%M:%S')
  109. route = time['rt']
  110. direction = time['rtdir']
  111. end = time['des']
  112. nm = time['stpnm']
  113. print(
  114. config.format(**locals()),end= '\n'*2
  115. )
  116. if __name__ == "__main__":
  117. parser = argparse.ArgumentParser(prog = 'ctabus')
  118. parser.add_argument('-l','--lucky',action='store_true',help = 'picks first result')
  119. parser.add_argument('-p','--periodic',metavar = 'SEC',type=int,help='checks periodically')
  120. parser.add_argument('-r','--route',default = None)
  121. parser.add_argument('-d','--direction',default = None)
  122. parser.add_argument('arg',nargs = '+',metavar = '(stop-id | cross streets)')
  123. args = parser.parse_args()
  124. sys.stderr = open(osp.join(osp.dirname(__file__),'stderr.log'),'w')
  125. args.arg = ' '.join(args.arg)
  126. if not args.arg.isdecimal():
  127. # save on import time slightly
  128. from print2d import print2d
  129. from search import Search,StopSearch
  130. #routes
  131. if not args.route:
  132. data = ctabus.get_routes()['routes']
  133. route = gen_list(data,'rt','rt','rtnm',num_pic = False,key=numb_sort)
  134. else:
  135. route = args.route
  136. data = ctabus.get_directions(route)['directions']
  137. #direction
  138. if not args.direction:
  139. direction = gen_list(data,'dir','dir')
  140. else:
  141. s = Search(args.direction)
  142. direction = sorted((obj['dir'] for obj in data),key = s)[0]
  143. #direction
  144. stops = ctabus.get_stops(route,direction)['stops']
  145. s = StopSearch(args.arg)
  146. if args.lucky:
  147. stop_id = sorted(stops,key=lambda stop: s(stop['stpnm']))[0]['stpid']
  148. else:
  149. stop_id = gen_list(stops,'stpid','stpnm',key = s)
  150. else:
  151. stop_id = args.arg
  152. if args.periodic is not None:
  153. _done = False
  154. while not _done:
  155. try:
  156. show(stop_id,args.route,True)
  157. time.sleep(args.periodic)
  158. except KeyboardInterrupt as e:
  159. _done = True
  160. else:
  161. show(stop_id,args.route)