From 816d05b0729ea1a5cb31ab777b2cfa71559b2fec Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 02:23:02 -0800 Subject: [PATCH 01/14] Use consistent default values/types --- modules/extensions.py | 4 ++-- modules/ui_extensions.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/extensions.py b/modules/extensions.py index 1063e5eb7..17a1d006b 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -106,8 +106,8 @@ class Extension: self.branch = None self.remote = None self.have_info_from_repo = False - self.mtime = 0 - self.ctime = 0 + self.mtime = "2000-01-01T00:00Z" + self.ctime = "2000-01-01T00:00Z" def read_info(self, force=False): if self.have_info_from_repo and not force: diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index c9271780e..fa58c0c05 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -308,7 +308,7 @@ def create_html(search_text, sort_column): ext['enabled'] = installed.enabled if installed is not None else '' ext['remote'] = installed.remote if installed is not None else None ext['path'] = installed.path if installed is not None else '' - ext['sort_default'] = f"{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00')}" + ext['sort_default'] = f"{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00Z')}" sort_reverse, sort_function = sort_ordering[sort_column] def dt(x: str): From 1e4b1cbbaea3be7b213b3c6a53f462971316fc8d Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 02:44:00 -0800 Subject: [PATCH 02/14] Add helper functions --- modules/extensions.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/modules/extensions.py b/modules/extensions.py index 17a1d006b..1d6484479 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -1,6 +1,6 @@ from __future__ import annotations import os -from datetime import datetime +from datetime import datetime, timezone import git from modules import shared, errors from modules.paths import extensions_dir, extensions_builtin_dir @@ -11,6 +11,19 @@ if not os.path.exists(extensions_dir): os.makedirs(extensions_dir) +def parse_isotime(time_string: str) -> datetime: + # If Python minimum version is 3.11+, this function can be replaced with datetime.fromisoformat() + time_string = time_string.rstrip("Z") + time_string = time_string[:-4] if "." in time_string[-4:] else time_string + return datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=timezone.utc) + + +def format_eztime(d: datetime, local = False) -> str: + if d.tzinfo is None: + return d.strftime('%Y-%m-%d %H:%M') + return d.astimezone(timezone.utc if local else None).strftime('%Y-%m-%d %H:%M %Z') + + def active(): if shared.opts.disable_all_extensions == "all": return [] From 4649e7a86500c7ac52ef77386045c1e3f30030e7 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 03:11:17 -0800 Subject: [PATCH 03/14] Switch to type-safe file loading --- modules/ui_extensions.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index fa58c0c05..d9cd7ecb5 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -37,12 +37,9 @@ def get_installed(ext): def list_extensions(): global extensions_list # pylint: disable=global-statement fn = os.path.join(paths.script_path, "html", "extensions.json") - extensions_list = shared.readfile(fn, silent=True) or [] - if type(extensions_list) != list: - shared.log.warning(f'Invalid extensions list: file="{fn}"') - extensions_list = [] + extensions_list = shared.readfile(fn, silent=True, as_type="list") if len(extensions_list) == 0: - shared.log.info('Extension list is empty: refresh required') + shared.log.info(f'Extension list is empty or invalid: refresh required, file="{fn}"') found = [] for ext in extensions.extensions: ext.read_info() From 4bd9d2097293f3ba072b11f390233e82a22614a0 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 03:37:59 -0800 Subject: [PATCH 04/14] TZ-aware and time formatting --- modules/extensions.py | 2 +- modules/ui_extensions.py | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/modules/extensions.py b/modules/extensions.py index 1d6484479..e4d7bdd35 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -155,7 +155,7 @@ class Extension: except Exception: self.branch = 'unknown' self.commit_hash = head.hexsha - self.version = f"

{self.commit_hash[:8]}

{datetime.fromtimestamp(self.commit_date).strftime('%a %b%d %Y %H:%M')}

" + self.version = f"

{self.commit_hash[:8]}

{format_eztime(datetime.fromtimestamp(self.commit_date, timezone.utc))}

" except Exception as ex: shared.log.error(f"Extension: failed reading data from git repo={self.name}: {ex}") self.remote = None diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index d9cd7ecb5..41126b207 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -3,7 +3,7 @@ import json import shutil import errno import html -from datetime import datetime, timedelta +from datetime import datetime, timezone, timedelta import gradio as gr from modules import extensions, shared, paths, errors, ui_symbols, call_queue @@ -108,10 +108,10 @@ def check_updates(_id_task, disable_list, search_text, sort_column): ext.git_fetch() ext.read_info() commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {datetime.utcfromtimestamp(commit_date)}') + shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') else: commit_date = ext.commit_date or 1577836800 - shared.log.debug(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {datetime.utcfromtimestamp(commit_date)}') + shared.log.debug(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') except FileNotFoundError as e: if 'FETCH_HEAD' not in str(e): raise @@ -229,10 +229,10 @@ def update_extension(extension_path, search_text, sort_column): ext.git_fetch() ext.read_info() commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {datetime.utcfromtimestamp(commit_date)}') + shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') else: commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {datetime.utcfromtimestamp(commit_date)}') + shared.log.info(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') except FileNotFoundError as e: if 'FETCH_HEAD' not in str(e): raise @@ -311,7 +311,7 @@ def create_html(search_text, sort_column): def dt(x: str): val = ext.get(x, None) try: - return datetime.fromisoformat(val[:-1]).strftime('%a %b%d %Y %H:%M') if val is not None else "N/A" + return extensions.format_eztime(extensions.parse_isotime(val)) if val is not None else "N/A" except Exception: return 'N/A' @@ -319,22 +319,23 @@ def create_html(search_text, sort_column): for ext in sorted(extensions_list, key=sort_function, reverse=sort_reverse): installed = get_installed(ext) author = '' - updated = datetime.timestamp(datetime.now()) + updated = datetime.now(timezone.utc) # TZ-aware try: if 'github' in ext['url']: author = 'Author: ' + ext['url'].split('/')[-2].split(':')[-1] if '/' in ext['url'] else ext['url'].split(':')[1].split('/')[0] - updated = datetime.timestamp(datetime.fromisoformat(ext.get('updated', '2000-01-01T00:00:00.000Z').rstrip('Z'))) + updated = extensions.parse_isotime(ext.get('updated', '2000-01-01T00:00:00Z')) # TZ-aware else: debug(f'Extension not from github: name={ext["name"]} url={ext["url"]}') except Exception as e: debug(f'Extension get updated error: name={ext["name"]} url={ext["url"]} {e}') - update_available = (installed is not None) and (ext['remote'] is not None) and (updated > ext['commit_date']) + local_ver_date = datetime.fromtimestamp(ext['commit_date'], timezone.utc) # TZ-aware + update_available = (installed is not None) and (ext['remote'] is not None) and (updated > local_ver_date) # TZ-aware if update_available: - debug(f'Extension update available: name={ext["name"]} updated={updated}/{datetime.utcfromtimestamp(updated)} commit={ext["commit_date"]}/{datetime.utcfromtimestamp(ext["commit_date"])}') + debug(f'Extension update available: name={ext["name"]} updated={extensions.format_eztime(updated), True} commit={extensions.format_eztime(local_ver_date), True}') # TZ-aware ext['sort_user'] = f"{'0' if ext['is_builtin'] else '1'}{'1' if ext['installed'] else '0'}{ext.get('name', '')}" - ext['sort_enabled'] = f"{'0' if ext['enabled'] else '1'}{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00')}" - ext['sort_update'] = f"{'1' if update_available else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00')}" - delta = datetime.now() - datetime.fromisoformat(ext.get('created', '2000-01-01T00:00Z')[:-1]) + ext['sort_enabled'] = f"{'0' if ext['enabled'] else '1'}{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00Z')}" + ext['sort_update'] = f"{'1' if update_available else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00Z')}" + delta = datetime.now(timezone.utc) - extensions.parse_isotime(ext.get('created', '2000-01-01T00:00Z')) # TZ-aware to prep for 3.11+ datetime.fromisoformat() behavior ext['sort_trending'] = round(ext.get('stars', 0) / max(delta.days, 5), 1) tags = ext.get("tags", []) if not isinstance(tags, list): @@ -396,7 +397,7 @@ def create_html(search_text, sort_column): else: status = f"
{ui_symbols.svg_bullet.color('#008EBC')}
" else: - if updated < datetime.timestamp(datetime.now() - timedelta(6*30)): + if updated < datetime.now(timezone.utc) - timedelta(6*30): # TZ-aware status = f"
{ui_symbols.svg_bullet.color('#C000CF')}
" else: status = f"
{ui_symbols.svg_bullet.color('#7C7C7C')}
" From 214d84feeade8bd918c567b315e10f4a55b2a63d Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 03:50:28 -0800 Subject: [PATCH 05/14] Ensure information is actually updated I'm assuming this is what was intended because otherwise there would be no reason to refresh information again after updating. --- modules/ui_extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 41126b207..3cd79d4be 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -106,7 +106,7 @@ def check_updates(_id_task, disable_list, search_text, sort_column): ext.check_updates() if ext.can_update: ext.git_fetch() - ext.read_info() + ext.read_info(True) commit_date = ext.commit_date or 1577836800 shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') else: @@ -227,7 +227,7 @@ def update_extension(extension_path, search_text, sort_column): ext.check_updates() if ext.can_update: ext.git_fetch() - ext.read_info() + ext.read_info(True) commit_date = ext.commit_date or 1577836800 shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') else: From b25bfb6cbae0836325b31b8fb0a66f105c183ffe Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 16:58:37 -0800 Subject: [PATCH 06/14] More robust time string handling --- modules/extensions.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/extensions.py b/modules/extensions.py index e4d7bdd35..b44d49c1d 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -13,9 +13,16 @@ if not os.path.exists(extensions_dir): def parse_isotime(time_string: str) -> datetime: # If Python minimum version is 3.11+, this function can be replaced with datetime.fromisoformat() - time_string = time_string.rstrip("Z") - time_string = time_string[:-4] if "." in time_string[-4:] else time_string - return datetime.strptime(time_string, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=timezone.utc) + trimmed = time_string.rstrip("Z") + if "." in trimmed: + trimmed = trimmed.split(".")[0] + match len(trimmed): + case 16: + return datetime.strptime(trimmed, "%Y-%m-%dT%H:%M").replace(tzinfo=timezone.utc) + case 19: + return datetime.strptime(trimmed, "%Y-%m-%dT%H:%M:%S").replace(tzinfo=timezone.utc) + case _: + raise ValueError(f"Unexpected time string format: '{time_string}'") def format_eztime(d: datetime, local = False) -> str: From d05ad24309b86ebbb42538a353560280cbed6a48 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sat, 27 Dec 2025 18:51:40 -0800 Subject: [PATCH 07/14] Fix reversed logic --- modules/extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/extensions.py b/modules/extensions.py index b44d49c1d..a8dba7c3d 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -28,7 +28,7 @@ def parse_isotime(time_string: str) -> datetime: def format_eztime(d: datetime, local = False) -> str: if d.tzinfo is None: return d.strftime('%Y-%m-%d %H:%M') - return d.astimezone(timezone.utc if local else None).strftime('%Y-%m-%d %H:%M %Z') + return d.astimezone(None if local else timezone.utc).strftime('%Y-%m-%d %H:%M %Z') def active(): From 4d3dfac0a04d9a15c02cc2531292b8160f821151 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 00:10:35 -0800 Subject: [PATCH 08/14] Add timestamp-to-UTC datetime util --- modules/extensions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/extensions.py b/modules/extensions.py index a8dba7c3d..d561989aa 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -31,6 +31,10 @@ def format_eztime(d: datetime, local = False) -> str: return d.astimezone(None if local else timezone.utc).strftime('%Y-%m-%d %H:%M %Z') +def ts2utc(timestamp: int) -> datetime: + return datetime.fromtimestamp(timestamp, timezone.utc) + + def active(): if shared.opts.disable_all_extensions == "all": return [] From 885cbcd118de977b94253dc02a44012acc26f159 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 01:25:23 -0800 Subject: [PATCH 09/14] Finalize utility format and usage - Renamed to `format_dt` - Only show values in UTC and omit "UTC" display --- modules/extensions.py | 6 +++--- modules/ui_extensions.py | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/modules/extensions.py b/modules/extensions.py index d561989aa..134176e3d 100644 --- a/modules/extensions.py +++ b/modules/extensions.py @@ -25,10 +25,10 @@ def parse_isotime(time_string: str) -> datetime: raise ValueError(f"Unexpected time string format: '{time_string}'") -def format_eztime(d: datetime, local = False) -> str: +def format_dt(d: datetime) -> str: if d.tzinfo is None: return d.strftime('%Y-%m-%d %H:%M') - return d.astimezone(None if local else timezone.utc).strftime('%Y-%m-%d %H:%M %Z') + return d.astimezone(timezone.utc).strftime('%Y-%m-%d %H:%M:%S') # Ensure UTC time is shown (just in case) def ts2utc(timestamp: int) -> datetime: @@ -166,7 +166,7 @@ class Extension: except Exception: self.branch = 'unknown' self.commit_hash = head.hexsha - self.version = f"

{self.commit_hash[:8]}

{format_eztime(datetime.fromtimestamp(self.commit_date, timezone.utc))}

" + self.version = f"

{self.commit_hash[:8]}

{format_dt(ts2utc(self.commit_date))}

" except Exception as ex: shared.log.error(f"Extension: failed reading data from git repo={self.name}: {ex}") self.remote = None diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 3cd79d4be..b90d7def8 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -108,10 +108,10 @@ def check_updates(_id_task, disable_list, search_text, sort_column): ext.git_fetch() ext.read_info(True) commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') + shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') else: commit_date = ext.commit_date or 1577836800 - shared.log.debug(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') + shared.log.debug(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') except FileNotFoundError as e: if 'FETCH_HEAD' not in str(e): raise @@ -229,10 +229,10 @@ def update_extension(extension_path, search_text, sort_column): ext.git_fetch() ext.read_info(True) commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') + shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') else: commit_date = ext.commit_date or 1577836800 - shared.log.info(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_eztime(datetime.fromtimestamp(commit_date, timezone.utc), True)}') + shared.log.info(f'Extensions no update available: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') except FileNotFoundError as e: if 'FETCH_HEAD' not in str(e): raise @@ -311,7 +311,7 @@ def create_html(search_text, sort_column): def dt(x: str): val = ext.get(x, None) try: - return extensions.format_eztime(extensions.parse_isotime(val)) if val is not None else "N/A" + return extensions.format_dt(extensions.parse_isotime(val)) if val is not None else "N/A" except Exception: return 'N/A' @@ -331,7 +331,7 @@ def create_html(search_text, sort_column): local_ver_date = datetime.fromtimestamp(ext['commit_date'], timezone.utc) # TZ-aware update_available = (installed is not None) and (ext['remote'] is not None) and (updated > local_ver_date) # TZ-aware if update_available: - debug(f'Extension update available: name={ext["name"]} updated={extensions.format_eztime(updated), True} commit={extensions.format_eztime(local_ver_date), True}') # TZ-aware + debug(f'Extension update available: name={ext["name"]} updated={extensions.format_dt(updated)} commit={extensions.format_dt(local_ver_date)}') # TZ-aware ext['sort_user'] = f"{'0' if ext['is_builtin'] else '1'}{'1' if ext['installed'] else '0'}{ext.get('name', '')}" ext['sort_enabled'] = f"{'0' if ext['enabled'] else '1'}{'1' if ext['is_builtin'] else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00Z')}" ext['sort_update'] = f"{'1' if update_available else '0'}{'1' if ext['installed'] else '0'}{ext.get('updated', '2000-01-01T00:00Z')}" From 96e9cdae31bb74c994d04ed0269ab52b3fe80155 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 01:30:10 -0800 Subject: [PATCH 10/14] Fix update availability logic Bug that was hidden by the other bug that was fixed on this line. (See PR https://github.com/vladmandic/sdnext/pull/4501) --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index b90d7def8..0c2c3f3f8 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -329,7 +329,7 @@ def create_html(search_text, sort_column): except Exception as e: debug(f'Extension get updated error: name={ext["name"]} url={ext["url"]} {e}') local_ver_date = datetime.fromtimestamp(ext['commit_date'], timezone.utc) # TZ-aware - update_available = (installed is not None) and (ext['remote'] is not None) and (updated > local_ver_date) # TZ-aware + update_available = (installed is not None) and (not ext['is_builtin']) and (ext['remote'] is not None) and (updated > local_ver_date) # TZ-aware if update_available: debug(f'Extension update available: name={ext["name"]} updated={extensions.format_dt(updated)} commit={extensions.format_dt(local_ver_date)}') # TZ-aware ext['sort_user'] = f"{'0' if ext['is_builtin'] else '1'}{'1' if ext['installed'] else '0'}{ext.get('name', '')}" From f1414b0d61aa4ee40b4a315f364cebc9c7af0f09 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 01:33:11 -0800 Subject: [PATCH 11/14] Update log message --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 0c2c3f3f8..da3ae39d0 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -39,7 +39,7 @@ def list_extensions(): fn = os.path.join(paths.script_path, "html", "extensions.json") extensions_list = shared.readfile(fn, silent=True, as_type="list") if len(extensions_list) == 0: - shared.log.info(f'Extension list is empty or invalid: refresh required, file="{fn}"') + shared.log.info(f'Extension list is empty or invalid. Try refreshing or verifying downloaded data. file="{fn}"') found = [] for ext in extensions.extensions: ext.read_info() From 6761ebd2a7d764849936010fc4baee689e5905f3 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 02:01:20 -0800 Subject: [PATCH 12/14] Remove sending `force` argument `git_fetch()` un-sets the `have_info_from_repo` flag so it's not needed --- modules/ui_extensions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index da3ae39d0..d1fd68e76 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -106,7 +106,7 @@ def check_updates(_id_task, disable_list, search_text, sort_column): ext.check_updates() if ext.can_update: ext.git_fetch() - ext.read_info(True) + ext.read_info() commit_date = ext.commit_date or 1577836800 shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') else: @@ -227,7 +227,7 @@ def update_extension(extension_path, search_text, sort_column): ext.check_updates() if ext.can_update: ext.git_fetch() - ext.read_info(True) + ext.read_info() commit_date = ext.commit_date or 1577836800 shared.log.info(f'Extensions updated: {ext.name} {ext.commit_hash[:8]} {extensions.format_dt(extensions.ts2utc(commit_date))}') else: From 39e9bbed1ba4c103b16d4189d13e97a5eaee6a56 Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 03:14:44 -0800 Subject: [PATCH 13/14] Update message Bad data message will be handled by a different update to `readfile` --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index d1fd68e76..871aaec57 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -39,7 +39,7 @@ def list_extensions(): fn = os.path.join(paths.script_path, "html", "extensions.json") extensions_list = shared.readfile(fn, silent=True, as_type="list") if len(extensions_list) == 0: - shared.log.info(f'Extension list is empty or invalid. Try refreshing or verifying downloaded data. file="{fn}"') + shared.log.info("Extension List: No information found. Refresh required.") found = [] for ext in extensions.extensions: ext.read_info() From be954a981269aaa89deab34573ed4410cf59948a Mon Sep 17 00:00:00 2001 From: awsr <43862868+awsr@users.noreply.github.com> Date: Sun, 28 Dec 2025 03:21:28 -0800 Subject: [PATCH 14/14] Use helper function --- modules/ui_extensions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ui_extensions.py b/modules/ui_extensions.py index 871aaec57..a6c5ca3ec 100644 --- a/modules/ui_extensions.py +++ b/modules/ui_extensions.py @@ -328,7 +328,7 @@ def create_html(search_text, sort_column): debug(f'Extension not from github: name={ext["name"]} url={ext["url"]}') except Exception as e: debug(f'Extension get updated error: name={ext["name"]} url={ext["url"]} {e}') - local_ver_date = datetime.fromtimestamp(ext['commit_date'], timezone.utc) # TZ-aware + local_ver_date = extensions.ts2utc(ext['commit_date']) # TZ-aware update_available = (installed is not None) and (not ext['is_builtin']) and (ext['remote'] is not None) and (updated > local_ver_date) # TZ-aware if update_available: debug(f'Extension update available: name={ext["name"]} updated={extensions.format_dt(updated)} commit={extensions.format_dt(local_ver_date)}') # TZ-aware