__init__.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import datetime
  2. import json
  3. import os
  4. import ssl
  5. import urllib.parse
  6. import urllib.request
  7. """
  8. official api documentation:
  9. https://github.com/ToontownRewritten/api-doc/blob/master/login.md
  10. https://github.com/ToontownRewritten/api-doc/blob/master/invasions.md
  11. """
  12. INVASIONS_API_URL = 'https://www.toontownrewritten.com/api/invasions?format=json'
  13. LOGIN_API_URL = 'https://www.toontownrewritten.com/api/login?format=json'
  14. def api_request(url, params=None, validate_ssl_cert=True):
  15. resp = urllib.request.urlopen(
  16. url=url,
  17. data=urllib.parse.urlencode(params).encode('ascii')
  18. if params else None,
  19. context=None if validate_ssl_cert
  20. else ssl._create_unverified_context(),
  21. )
  22. return json.loads(resp.read().decode('ascii'))
  23. class LoginSuccessful:
  24. def __init__(self, playcookie, gameserver):
  25. self.playcookie = playcookie
  26. self.gameserver = gameserver
  27. class LoginDelayed:
  28. def __init__(self, queue_token):
  29. self.queue_token = queue_token
  30. def login(username=None, password=None,
  31. queue_token=None, validate_ssl_cert=True):
  32. if username is not None and queue_token is None:
  33. assert password is not None
  34. req_params = {
  35. 'username': username,
  36. 'password': password,
  37. }
  38. elif username is None and queue_token is not None:
  39. req_params = {
  40. 'queueToken': queue_token,
  41. }
  42. else:
  43. raise Exception('either specify username or queue token')
  44. resp_data = api_request(
  45. url=LOGIN_API_URL,
  46. params=req_params,
  47. validate_ssl_cert=validate_ssl_cert,
  48. )
  49. if resp_data['success'] == 'true':
  50. return LoginSuccessful(
  51. playcookie=resp_data['cookie'],
  52. gameserver=resp_data['gameserver'],
  53. )
  54. elif resp_data['success'] == 'delayed':
  55. return LoginDelayed(
  56. queue_token=resp_data['queueToken'],
  57. )
  58. else:
  59. raise Exception(repr(resp_data))
  60. class InvasionProgress:
  61. def __init__(self, district, date, cog_type,
  62. despawned_number, total_number):
  63. self.district = district
  64. self.date = date
  65. self.cog_type = cog_type
  66. self.despawned_number = despawned_number
  67. self.total_number = total_number
  68. @property
  69. def remaining_number(self):
  70. return self.total_number - self.despawned_number
  71. class InvasionsResponse:
  72. def __init__(self, update_date, invasions):
  73. self.update_date = update_date
  74. self.invasions = invasions
  75. def request_active_invasions(validate_ssl_certs=True):
  76. resp_data = api_request(INVASIONS_API_URL)
  77. if resp_data['error'] is not None:
  78. raise Exception(resp_data['error'])
  79. else:
  80. invs = {}
  81. for district, inv_data in resp_data['invasions'].items():
  82. despawned_number, total_number = inv_data['progress'].split('/')
  83. invs[district] = InvasionProgress(
  84. district=district,
  85. date=datetime.datetime.utcfromtimestamp(inv_data['asOf']),
  86. cog_type=inv_data['type'],
  87. despawned_number=int(despawned_number),
  88. total_number=int(total_number),
  89. )
  90. return InvasionsResponse(
  91. update_date=datetime.datetime.utcfromtimestamp(
  92. resp_data['lastUpdated']
  93. ),
  94. invasions=invs,
  95. )