mojang_status.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import requests
  2. from queue import Queue
  3. from datetime import datetime, timedelta
  4. from typing import TypedDict, Literal, TypeAlias
  5. from homepagebuilder.interfaces import script
  6. API_URL = "https://www.mcstate.net/api/mojang-status"
  7. QUEUE_MAX_SIZE = 3
  8. GREEN_COLOR = "#41D041"
  9. YELLOW_COLOR = "#D1A041"
  10. RED_COLOR = "#D14241"
  11. GRAY_COLOR = "#888888"
  12. StatusState: TypeAlias = Literal['up', 'down', 'unknown']
  13. class StatusDetials(TypedDict):
  14. session: StatusState = "unknown"
  15. accounts: StatusState = "unknown"
  16. microsoft: StatusState = "unknown"
  17. api: StatusState = "unknown"
  18. textures: StatusState = "unknown"
  19. website: StatusState = "unknown"
  20. class StatusRecord(TypedDict):
  21. status: StatusDetials
  22. check_time: datetime = datetime.min
  23. CHECK_TIME: datetime = datetime.now()
  24. UPDATE_INTERVAL = 150
  25. UPDATE_TIME = datetime.min
  26. STATUS_RECORDS: Queue[StatusRecord | None] = Queue(maxsize=QUEUE_MAX_SIZE)
  27. CALCULATED_STATUS_CACHE: StatusRecord = None
  28. def get_status():
  29. try:
  30. response = requests.get(API_URL)
  31. response.raise_for_status() # Raise an error for bad responses
  32. return response.json() # Return the JSON response as a dictionary
  33. except requests.RequestException as e:
  34. print(f"Error fetching Mojang status: {e}")
  35. return None
  36. def get_service_status(status_dict, service_id):
  37. return next((service['status'] for service in status_dict['services'] if service['id'] == service_id), 'unknown')
  38. def update_status():
  39. global UPDATE_TIME, CALCULATED_STATUS_CACHE
  40. result = get_status()
  41. status: StatusRecord = {'status': StatusDetials()}
  42. if result is not None:
  43. status['status']['session'] = get_service_status(result, 'session')
  44. status['status']['accounts'] = get_service_status(result, 'accounts')
  45. status['status']['microsoft'] = get_service_status(result, 'microsoft')
  46. status['status']['api'] = get_service_status(result, 'api')
  47. status['status']['textures'] = get_service_status(result, 'textures')
  48. status['status']['website'] = get_service_status(result, 'website')
  49. status['check_time'] = datetime.strptime(result.get('checkedAt'), "%Y-%m-%dT%H:%M:%S.%fZ") + timedelta(hours=8)
  50. if STATUS_RECORDS.full():
  51. STATUS_RECORDS.get()
  52. STATUS_RECORDS.put(status)
  53. UPDATE_TIME = datetime.now()
  54. CALCULATED_STATUS_CACHE = None
  55. def should_update_status():
  56. global UPDATE_TIME
  57. return (datetime.now() - UPDATE_TIME).total_seconds() >= UPDATE_INTERVAL
  58. def get_calculated_status():
  59. global CALCULATED_STATUS_CACHE, STATUS_RECORDS
  60. if CALCULATED_STATUS_CACHE is not None:
  61. return CALCULATED_STATUS_CACHE
  62. status: StatusRecord = StatusRecord()
  63. status['status'] = StatusDetials()
  64. for item in STATUS_RECORDS.queue:
  65. if item is None:
  66. continue
  67. for key, value in item['status'].items():
  68. if key == 'check_time':
  69. continue
  70. if value == 'down' and status.get(key) != 'up':
  71. status['status'][key] = 'down'
  72. elif value == 'up':
  73. status['status'][key] = 'up'
  74. status['check_time'] = max((item['check_time'] for item in STATUS_RECORDS.queue if item is not None), default=datetime.min)
  75. return status
  76. def get_mojang_major_status():
  77. status = get_calculated_status()['status']
  78. if all(value == 'unknown' for value in status.values()):
  79. return "未知"
  80. if status['api'] == 'down' or status['session'] == 'down' or status['microsoft'] == 'down':
  81. return "异常"
  82. elif status['accounts'] == 'down' or status['textures'] == 'down' or status['website'] == 'down':
  83. return "问题"
  84. else:
  85. return "正常"
  86. @script('MojangStatusText')
  87. def mojang_status_text(name, **_):
  88. if should_update_status():
  89. update_status()
  90. status = get_calculated_status()['status'].get(name, 'unknown')
  91. if status == 'up':
  92. return "正常"
  93. elif status == 'down':
  94. return "异常"
  95. else:
  96. return "未知"
  97. @script('MojangMajorStatusText')
  98. def mojang_major_status_text(**_):
  99. if should_update_status():
  100. update_status()
  101. return get_mojang_major_status()
  102. @script('MojangStatusColor')
  103. def mojang_status_color(name, **_):
  104. if should_update_status():
  105. update_status()
  106. status = get_calculated_status()['status'].get(name, 'unknown')
  107. if status == 'up':
  108. return GREEN_COLOR
  109. elif status == 'down':
  110. return RED_COLOR
  111. else:
  112. return GRAY_COLOR
  113. @script('MojangMajorStatusColor')
  114. def mojang_major_status_color(**_):
  115. if should_update_status():
  116. update_status()
  117. major_status = get_mojang_major_status()
  118. if major_status == "正常":
  119. return GREEN_COLOR
  120. elif major_status == "异常":
  121. return RED_COLOR
  122. elif major_status == "问题":
  123. return YELLOW_COLOR
  124. else:
  125. return GRAY_COLOR
  126. @script('MojangStatusTime')
  127. def mojang_status_time(**_):
  128. return get_calculated_status()['check_time'].strftime("%Y年%m月%d日 %H:%M")
  129. @script('MojangStatusTimeCompressed')
  130. def mojang_status_time(**_):
  131. return get_calculated_status()['check_time'].strftime("%H:%M")
  132. @script('MojangStatusCardReference')
  133. def mojang_status(**_):
  134. status = get_mojang_major_status()
  135. if status == "异常":
  136. return "MojangStatusDetail"
  137. else:
  138. return "MojangStatusCompress"