44
55import asyncio
66from datetime import datetime , timezone
7+ import json
78import re
89import time
910from typing import Any
1213
1314from app .platform .meta import get_project_version
1415
15- _UPDATE_BASE_URL = "https://pro.muyuai.top/updates"
16+ _GITHUB_RELEASES_API_URL = "https://api.github.com/repos/AuuCoder/gptGrok2api/releases?per_page=20"
17+ _GITHUB_CHANGELOG_URL = "https://raw.githubusercontent.com/AuuCoder/gptGrok2api/main/CHANGELOG.md"
1618_RELEASE_PAGE_URL = "https://github.com/AuuCoder/gptGrok2api/releases"
1719_CACHE_TTL_SECONDS = 86400.0
1820_ERROR_TTL_SECONDS = 300.0
@@ -72,12 +74,12 @@ def _select_latest_release(releases: list[dict[str, Any]]) -> dict[str, Any] | N
7274
7375def _normalize_error_message (value : str ) -> str :
7476 text = str (value or "" ).strip ()
75- if text .startswith ("Update source query failed:" ):
76- status_match = re .search (r"Update source query failed:\s*(\d{3})" , text )
77+ if text .startswith ("GitHub update query failed:" ):
78+ status_match = re .search (r"GitHub update query failed:\s*(\d{3})" , text )
7779 if status_match :
78- return f"Update source query failed ({ status_match .group (1 )} )."
79- return "Update source query failed."
80- if text == "Update source returned an empty version" :
80+ return f"GitHub update query failed ({ status_match .group (1 )} )."
81+ return "GitHub update query failed."
82+ if text == "GitHub Releases returned no published version" :
8183 return text
8284 return text or "Update check failed."
8385
@@ -87,9 +89,10 @@ def _build_payload(release: dict[str, Any] | None = None, error: str = "") -> di
8789 release = release or {}
8890 latest_version = _normalize_version (str (release .get ("tag_name" ) or release .get ("name" ) or "" ))
8991 release_name = str (release .get ("name" ) or "" ).strip ()
90- release_url = str (release .get ("html_url" ) or "" ).strip ()
92+ release_url = str (release .get ("html_url" ) or _RELEASE_PAGE_URL ).strip ()
9193 published_at = str (release .get ("published_at" ) or "" ).strip ()
9294 release_notes = str (release .get ("body" ) or "" ).strip ()
95+ changelog = str (release .get ("changelog" ) or "" ).strip ()
9396 has_remote = bool (release )
9497 return {
9598 "current_version" : current_version ,
@@ -98,41 +101,57 @@ def _build_payload(release: dict[str, Any] | None = None, error: str = "") -> di
98101 "release_url" : release_url ,
99102 "published_at" : published_at ,
100103 "release_notes" : release_notes ,
104+ "changelog" : changelog ,
101105 "update_available" : has_remote and bool (latest_version ) and _is_newer (latest_version , current_version ),
102106 "checked_at" : _utc_now_iso (),
103107 "status" : "error" if error else "ok" ,
104108 "error" : _normalize_error_message (error ),
105109 }
106110
107111
108- async def _fetch_latest_release () -> dict [str , Any ]:
109- timeout = aiohttp .ClientTimeout (total = 10 )
112+ async def _fetch_github_text (session : aiohttp .ClientSession , url : str , accept : str ) -> str :
110113 headers = {
111- "Accept" : "text/plain" ,
114+ "Accept" : accept ,
115+ "X-GitHub-Api-Version" : "2022-11-28" ,
112116 "User-Agent" : "gptgrok2api-update-check" ,
113117 }
118+ async with session .get (url , headers = headers ) as response :
119+ content = (await response .text ()).strip ()
120+ if response .status != 200 :
121+ raise RuntimeError (f"GitHub update query failed: { response .status } { content } " .strip ())
122+ return content
123+
124+
125+ async def _fetch_github_releases (session : aiohttp .ClientSession ) -> list [dict [str , Any ]]:
126+ content = await _fetch_github_text (
127+ session ,
128+ _GITHUB_RELEASES_API_URL ,
129+ "application/vnd.github+json" ,
130+ )
131+ try :
132+ payload = json .loads (content )
133+ except ValueError as exc :
134+ raise RuntimeError ("GitHub Releases returned invalid JSON" ) from exc
135+ if not isinstance (payload , list ):
136+ raise RuntimeError ("GitHub Releases returned an invalid payload" )
137+ return [item for item in payload if isinstance (item , dict )]
138+
139+
140+ async def _fetch_github_changelog (session : aiohttp .ClientSession ) -> str :
141+ return await _fetch_github_text (session , _GITHUB_CHANGELOG_URL , "text/plain" )
142+
143+
144+ async def _fetch_latest_release () -> dict [str , Any ]:
145+ timeout = aiohttp .ClientTimeout (total = 10 )
114146 async with aiohttp .ClientSession (timeout = timeout ) as session :
115- async def fetch_text (filename : str ) -> str :
116- url = f"{ _UPDATE_BASE_URL } /{ filename } "
117- async with session .get (url , headers = headers ) as response :
118- content = (await response .text ()).strip ()
119- if response .status != 200 :
120- raise RuntimeError (f"Update source query failed: { response .status } { content } " .strip ())
121- return content
122-
123- version , changelog = await asyncio .gather (
124- fetch_text ("VERSION" ),
125- fetch_text ("CHANGELOG.md" ),
147+ releases , changelog = await asyncio .gather (
148+ _fetch_github_releases (session ),
149+ _fetch_github_changelog (session ),
126150 )
127- if not version :
128- raise RuntimeError ("Update source returned an empty version" )
129- return {
130- "tag_name" : version ,
131- "name" : f"v{ _normalize_version (version )} " ,
132- "html_url" : _RELEASE_PAGE_URL ,
133- "published_at" : "" ,
134- "body" : changelog ,
135- }
151+ latest = _select_latest_release (releases )
152+ if latest is None :
153+ raise RuntimeError ("GitHub Releases returned no published version" )
154+ return {** latest , "changelog" : changelog }
136155
137156
138157async def get_latest_release_info (force : bool = False ) -> dict [str , Any ]:
0 commit comments