source.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. from class_xml import XML
  2. import config
  3. import datetime
  4. from itertools import chain
  5. # SOURCE CLASSES
  6. class Source:
  7. pass
  8. class Source_ratp(Source):
  9. def __init__(self, ident, status, message):
  10. self.source = 'ratp_trafic'
  11. self.id = ident
  12. self.status = status
  13. self.message = message
  14. def problem(self):
  15. return self.status != 'normal'
  16. class Source_jcdecaux_vls(Source):
  17. def __init__(self, ident, nom, timestamp, status):
  18. self.source = 'jcdecaux_vls'
  19. self.id = ident
  20. self.status = status # TODO dans l'API pour 1 station il semble que c'est toujours OPEN :-(
  21. self.date = datetime.datetime.fromtimestamp(int(timestamp)/1000).strftime('à %Hh%M le %d/%m')
  22. if status != "OPEN":
  23. self.message = 'Station vélo ' + nom.lower() + ' ' + self.date + ' : fermée !'
  24. else:
  25. self.message = None
  26. def problem(self):
  27. return self.status != "OPEN"
  28. class Source_jcdecaux_vls_full(Source_jcdecaux_vls):
  29. def __init__(self, ident, nom, timestamp, places, status):
  30. super(Source_jcdecaux_vls_full, self).__init__(ident, nom, timestamp, status)
  31. self.id += "_full"
  32. self.places = int(places)
  33. if not self.message:
  34. self.message = 'Station vélo ' + nom.lower() + ' ' + self.date + ' : '
  35. if self.places == 0:
  36. self.message += 'plus de place !'
  37. elif self.places == 1:
  38. self.message += 'plus qu\'une place !'
  39. else:
  40. self.message += 'plus que ' + places + ' places disponibles !'
  41. def problem(self):
  42. return super(Source_jcdecaux_vls_full, self).problem() or self.places <= config.sources_params['jcdecaux_vls']['limit_full']
  43. class Source_jcdecaux_vls_empty(Source_jcdecaux_vls):
  44. def __init__(self, ident, nom, timestamp, bikes, status):
  45. super(Source_jcdecaux_vls_empty, self).__init__(ident, nom, timestamp, status)
  46. self.id += "_empty"
  47. self.bikes = int(bikes)
  48. if not self.message:
  49. self.message = 'Station vélo ' + nom.lower() + ' ' + self.date + ' : '
  50. if self.bikes == 0:
  51. self.message += 'plus de vélo !'
  52. elif self.bikes == 1:
  53. self.message += 'plus qu\'un vélo !'
  54. else:
  55. self.message += 'plus que ' + bikes + ' vélos !'
  56. def problem(self):
  57. return super(Source_jcdecaux_vls_empty, self).problem() or self.bikes <= config.sources_params['jcdecaux_vls']['limit_empty']
  58. class Source_transilien(Source):
  59. def __init__(self, ident, message):
  60. self.source = 'transilien'
  61. self.id = ident
  62. self.message = message
  63. def problem(self):
  64. return self.message != 'Trafic normal'
  65. # SOURCES GENERATORS
  66. def ratp_trafic():
  67. for tag in XML(url="http://www.ratp.fr/meteo/", lang="html").data.select('div.encadre_ligne'):
  68. yield Source_ratp(tag['id'], tag.img['alt'],\
  69. tag['id'].replace('_', ' ') + ' : ' + tag.select('span.perturb_message')[0].string)
  70. def jcdecaux_vls(ids):
  71. ids = set(map(lambda s : s.rsplit('_', 1)[0], ids))
  72. for station in ids:
  73. (contract, number) = list(station.split('_'))
  74. xml = XML(url="https://api.jcdecaux.com/vls/v1/stations/" + number + "?contract=" + contract + "&apiKey="+config.api_key['jcdecaux_vls'], lang="json")
  75. tag = xml.data.json
  76. yield Source_jcdecaux_vls_full(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bike_stands.string, tag.status.string)
  77. yield Source_jcdecaux_vls_empty(contract + '_' + number, tag.find('name').string, tag.last_update.string, tag.available_bikes.string, tag.status.string)
  78. def transilien():
  79. xml = XML(url="http://www.transilien.com/info-trafic/temps-reel", lang="html").data
  80. container = xml.select('div.b_info_trafic')[0]
  81. for line in container.find_all('div', recursive=False):
  82. id = line.select('.picto-transport')[1].get_text()
  83. message = ""
  84. for c in line.select_one('.title').children:
  85. if c.name: # a tag
  86. if 'picto-transport' not in c.attrs.get('class', ''):
  87. message += c.get_text()
  88. else: # a string
  89. message += c
  90. for det in line.select('.item-disruption'):
  91. message += det.get_text()
  92. message = " ".join(message.split()) # delete multiple spaces
  93. yield Source_transilien(id, message)
  94. # interface functions
  95. def from_location(location):
  96. """return a list of source ids useful for location
  97. TODO : for the moment returns the whole config.sources"""
  98. return config.sources
  99. def gen_sources(ids):
  100. return chain(ratp_trafic(),\
  101. transilien(),\
  102. jcdecaux_vls(ids.get('jcdecaux_vls', [])))