@@ -79,12 +79,6 @@ def load_versions() -> List[dict]:
7979 return []
8080
8181
82- def get_latest_version_entry () -> Optional [dict ]:
83- """Returns the most recent version entry from the version file."""
84- data = load_versions ()
85- return data [- 1 ] if data else None
86-
87-
8882def fetch_latest_thaliak_patch () -> Optional [str ]:
8983 """
9084 Fetches the latest date-based version string from the Thaliak API.
@@ -131,23 +125,44 @@ def extract_patch_version(html):
131125 if not html or not (m := re .search (r"patch\s+(\d+\.\d+)" , html , re .I )):
132126 return None
133127 v = m .group (1 )
134- v = v + "0" if len (v .split ("." )[1 ]) == 1 else v
135- return v + "h" if "HotFixes" in html else v
128+ if len (v .split ("." )[1 ]) == 1 :
129+ v += "0"
130+ return v
131+
132+
133+ def get_next_hotfix_version (base_v , existing_versions ):
134+ matching = [
135+ v ["retail_version" ]
136+ for v in existing_versions
137+ if v ["retail_version" ].startswith (base_v )
138+ ]
139+ hotfixes = [v for v in matching if "h" in v ]
140+ if not hotfixes :
141+ return f"{ base_v } h"
142+
143+ # Extract numeric suffix: h -> 1, h2 -> 2, etc.
144+ nums = [int (h .split ("h" )[1 ]) if h .split ("h" )[1 ].isdigit () else 1 for h in hotfixes ]
145+ return f"{ base_v } h{ max (nums ) + 1 } "
146+
147+
148+ def determine_retail_version (base_v , existing_versions , thaliak_version_new ):
149+ matching = [v for v in existing_versions if v ["retail_version" ].startswith (base_v )]
150+ latest = matching [- 1 ] if matching else None
151+
152+ # If we have a record for this base version but the Thaliak version is new, it's a hotfix.
153+ if latest and thaliak_version_new and thaliak_version_new != latest ["version_string" ]:
154+ return get_next_hotfix_version (base_v , existing_versions )
155+
156+ return latest ["retail_version" ] if latest else base_v
157+
136158
137159def is_maintenance_post (title ):
138160 """Returns True if the title represents a primary world maintenance post."""
139161 t = title .lower ()
140162 return "all worlds" in t and "maintenance" in t and "follow-up" not in t
141163
142164
143- def format_retail_version (v , count ):
144- """Formats the version with hotfix suffixes: 7.41, 7.41h, 7.41h2, etc."""
145- if count <= 1 :
146- return v
147- return f"{ v } h{ count - 1 if count > 2 else '' } "
148-
149-
150- def scrape_latest_maintenance ():
165+ def scrape_latest_maintenance (thaliak_version_new = None ):
151166 """
152167 Scrapes the Lodestone to find the most recent 'All Worlds Maintenance' post.
153168 """
@@ -164,6 +179,7 @@ def scrape_latest_maintenance():
164179 return None
165180
166181 news_items = parse_lodestone_news_list (html )
182+ existing_versions = load_versions ()
167183
168184 for item in news_items :
169185 title = item ["title" ]
@@ -173,12 +189,18 @@ def scrape_latest_maintenance():
173189 continue
174190
175191 detail_html = fetch_url (link )
176- version = extract_patch_version (detail_html )
192+ if not detail_html :
193+ continue
177194
178- if version :
179- # We assume the first (most recent) valid maintenance post
180- # with a patch version is our target.
181- return {"retail_version" : version , "title" : title , "url" : link }
195+ base_version = extract_patch_version (detail_html )
196+ if not base_version :
197+ continue
198+
199+ retail_version = determine_retail_version (
200+ base_version , existing_versions , thaliak_version_new
201+ )
202+
203+ return {"retail_version" : retail_version , "title" : title , "url" : link }
182204
183205 return None
184206
@@ -187,15 +209,15 @@ def get_version_info() -> Optional[dict]:
187209 """
188210 Returns the latest version information by combining Thaliak and Lodestone data.
189211 """
190- date_new = fetch_latest_thaliak_patch ()
191- maintenance = scrape_latest_maintenance ()
212+ thaliak_version_new = fetch_latest_thaliak_patch ()
213+ maintenance = scrape_latest_maintenance (thaliak_version_new = thaliak_version_new )
192214
193- if not maintenance and not date_new :
215+ if not maintenance and not thaliak_version_new :
194216 return None
195217
196218 return {
197219 "retail_version" : maintenance ["retail_version" ] if maintenance else "Unknown" ,
198- "version_string" : date_new ,
220+ "version_string" : thaliak_version_new ,
199221 "title" : maintenance ["title" ] if maintenance else "Unknown" ,
200222 "url" : maintenance ["url" ] if maintenance else "Unknown" ,
201223 }
@@ -204,27 +226,26 @@ def get_version_info() -> Optional[dict]:
204226def get_patch_context ():
205227 """
206228 Returns a dictionary containing:
207- - retail_prev, date_prev : The latest registered version.
208- - retail_new, date_new : The latest versions found externally.
209- - is_new: True if date_new is not in the registry.
229+ - retail_prev, thaliak_version_prev : The latest registered version.
230+ - retail_new, thaliak_version_new : The latest versions found externally.
231+ - is_new: True if thaliak_version_new is not in the registry.
210232 """
211233 versions = load_versions ()
212234 prev = versions [- 1 ] if versions else None
213235
214- date_new = fetch_latest_thaliak_patch ()
215-
216- maintenance = scrape_latest_maintenance ()
236+ thaliak_version_new = fetch_latest_thaliak_patch ()
237+ maintenance = scrape_latest_maintenance (thaliak_version_new = thaliak_version_new )
217238 retail_new = maintenance ["retail_version" ] if maintenance else None
218239
219- is_new = False
220- if date_new :
221- is_new = not any ( v [ "version_string" ] == date_new for v in versions )
240+ is_new = thaliak_version_new is not None and not any (
241+ v [ "version_string" ] == thaliak_version_new for v in versions
242+ )
222243
223244 return {
224245 "retail_prev" : prev ["retail_version" ] if prev else None ,
225- "date_prev " : prev ["version_string" ] if prev else None ,
246+ "thaliak_version_prev " : prev ["version_string" ] if prev else None ,
226247 "retail_new" : retail_new ,
227- "date_new " : date_new ,
248+ "thaliak_version_new " : thaliak_version_new ,
228249 "is_new" : is_new ,
229250 }
230251
@@ -236,23 +257,26 @@ def update_and_get_info():
236257 """
237258 ctx = get_patch_context ()
238259
239- if ctx ["date_prev " ]:
240- print (f"date_prev ={ ctx ['date_prev ' ]} " )
260+ if ctx ["thaliak_version_prev " ]:
261+ print (f"thaliak_version_prev ={ ctx ['thaliak_version_prev ' ]} " )
241262 if ctx ["retail_prev" ]:
242263 print (f"retail_prev={ ctx ['retail_prev' ]} " )
243- if ctx ["date_new " ]:
244- print (f"date_new ={ ctx ['date_new ' ]} " )
264+ if ctx ["thaliak_version_new " ]:
265+ print (f"thaliak_version_new ={ ctx ['thaliak_version_new ' ]} " )
245266 if ctx ["retail_new" ]:
246267 print (f"retail_new={ ctx ['retail_new' ]} " )
247268 print (f"is_new={ 'true' if ctx ['is_new' ] else 'false' } " )
248269
249- if ctx ["is_new" ] and ctx ["date_new " ] and ctx ["retail_new" ]:
270+ if ctx ["is_new" ] and ctx ["thaliak_version_new " ] and ctx ["retail_new" ]:
250271 data = load_versions ()
251272 data .append (
252- {"retail_version" : ctx ["retail_new" ], "version_string" : ctx ["date_new" ]}
273+ {
274+ "retail_version" : ctx ["retail_new" ],
275+ "version_string" : ctx ["thaliak_version_new" ],
276+ }
253277 )
254278 print (
255- f"Added new version mapping: { ctx ['retail_new' ]} -> { ctx ['date_new ' ]} " ,
279+ f"Added new version mapping: { ctx ['retail_new' ]} -> { ctx ['thaliak_version_new ' ]} " ,
256280 file = sys .stderr ,
257281 )
258282 with open (VERSIONS_FILE , "w" ) as f :
0 commit comments