| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174 |
- import requests
- from queue import Queue
- from datetime import datetime, timedelta
- from typing import TypedDict, Literal, TypeAlias
- from homepagebuilder.interfaces import script
- API_URL = "https://www.mcstate.net/api/mojang-status"
- QUEUE_MAX_SIZE = 3
- GREEN_COLOR = "#41D041"
- YELLOW_COLOR = "#D1A041"
- RED_COLOR = "#D14241"
- GRAY_COLOR = "#888888"
- USER_AGENT = (
- "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
- "AppleWebKit/537.36 (KHTML, like Gecko) "
- "Chrome/139.0 Safari/537.36"
- )
- HEADERS = {
- "User-Agent": USER_AGENT,
- "Accept": (
- "application/json"
- ),
- }
- StatusState: TypeAlias = Literal['up', 'down', 'unknown']
- class StatusDetials(TypedDict):
- session: StatusState = "unknown"
- accounts: StatusState = "unknown"
- microsoft: StatusState = "unknown"
- api: StatusState = "unknown"
- textures: StatusState = "unknown"
- website: StatusState = "unknown"
- class StatusRecord(TypedDict):
- status: StatusDetials
- check_time: datetime = datetime.min
- CHECK_TIME: datetime = datetime.now()
- UPDATE_INTERVAL = 150
- UPDATE_TIME = datetime.min
- STATUS_RECORDS: Queue[StatusRecord | None] = Queue(maxsize=QUEUE_MAX_SIZE)
- CALCULATED_STATUS_CACHE: StatusRecord = None
-
- def get_status():
- try:
- response = requests.get(API_URL, headers=HEADERS, timeout=10)
- response.raise_for_status() # Raise an error for bad responses
- return response.json() # Return the JSON response as a dictionary
- except requests.RequestException as e:
- print(f"Error fetching Mojang status: {e}")
- return None
- def get_service_status(status_dict, service_id):
- return next((service['status'] for service in status_dict['services'] if service['id'] == service_id), 'unknown')
- def update_status():
- global UPDATE_TIME, CALCULATED_STATUS_CACHE
- result = get_status()
- status: StatusRecord = {'status': StatusDetials()}
- if result is not None:
- status['status']['session'] = get_service_status(result, 'session')
- status['status']['accounts'] = get_service_status(result, 'accounts')
- status['status']['microsoft'] = get_service_status(result, 'microsoft')
- status['status']['api'] = get_service_status(result, 'api')
- status['status']['textures'] = get_service_status(result, 'textures')
- status['status']['website'] = get_service_status(result, 'website')
- status['check_time'] = datetime.strptime(result.get('checkedAt'), "%Y-%m-%dT%H:%M:%S.%fZ") + timedelta(hours=8)
- else:
- status['check_time'] = datetime.now()
- if STATUS_RECORDS.full():
- STATUS_RECORDS.get()
- STATUS_RECORDS.put(status)
- UPDATE_TIME = datetime.now()
- CALCULATED_STATUS_CACHE = None
- def should_update_status():
- global UPDATE_TIME
- return (datetime.now() - UPDATE_TIME).total_seconds() >= UPDATE_INTERVAL
- def get_calculated_status():
- global CALCULATED_STATUS_CACHE, STATUS_RECORDS
- if CALCULATED_STATUS_CACHE is not None:
- return CALCULATED_STATUS_CACHE
- status: StatusRecord = StatusRecord()
- status['status'] = StatusDetials()
- for item in STATUS_RECORDS.queue:
- if item is None:
- continue
- for key, value in item['status'].items():
- if key == 'check_time':
- continue
- if value == 'down' and status.get(key) != 'up':
- status['status'][key] = 'down'
- elif value == 'up':
- status['status'][key] = 'up'
- status['check_time'] = max((item.get('check_time', datetime.min) for item in STATUS_RECORDS.queue if item is not None), default=datetime.min)
- return status
-
- def get_mojang_major_status():
- status = get_calculated_status()['status']
- if all(value == 'unknown' for value in status.values()):
- return "未知"
- if status['api'] == 'down' or status['session'] == 'down' or status['microsoft'] == 'down':
- return "异常"
- elif status['accounts'] == 'down' or status['textures'] == 'down' or status['website'] == 'down':
- return "问题"
- else:
- return "正常"
- @script('MojangStatusText')
- def mojang_status_text(name, **_):
- if should_update_status():
- update_status()
- status = get_calculated_status()['status'].get(name, 'unknown')
- if status == 'up':
- return "正常"
- elif status == 'down':
- return "异常"
- else:
- return "未知"
- @script('MojangMajorStatusText')
- def mojang_major_status_text(**_):
- if should_update_status():
- update_status()
- return get_mojang_major_status()
- @script('MojangStatusColor')
- def mojang_status_color(name, **_):
- if should_update_status():
- update_status()
- status = get_calculated_status()['status'].get(name, 'unknown')
- if status == 'up':
- return GREEN_COLOR
- elif status == 'down':
- return RED_COLOR
- else:
- return GRAY_COLOR
- @script('MojangMajorStatusColor')
- def mojang_major_status_color(**_):
- if should_update_status():
- update_status()
- major_status = get_mojang_major_status()
- if major_status == "正常":
- return GREEN_COLOR
- elif major_status == "异常":
- return RED_COLOR
- elif major_status == "问题":
- return YELLOW_COLOR
- else:
- return GRAY_COLOR
- @script('MojangStatusTime')
- def mojang_status_time(**_):
- return get_calculated_status()['check_time'].strftime("%Y年%m月%d日 %H:%M")
- @script('MojangStatusTimeCompressed')
- def mojang_status_time(**_):
- return get_calculated_status()['check_time'].strftime("%H:%M")
- @script('MojangStatusCardReference')
- def mojang_status(**_):
- status = get_mojang_major_status()
- if status == "异常":
- return "MojangStatusDetail"
- else:
- return "MojangStatusCompress"
|