fix: format console sync times locally and refresh catalogs every three hours

This commit is contained in:
najdek committed 2026-10-13 18:54:35 +02:00
1 parent 9ccba6adab
commit 8d373c04a7
5 files changed
+46 -3

No files matched your search

+3 -2
View File
@@ -5,6 +5,7 @@ import { QRCodeSVG } from 'qrcode.react'
import { cn, isPS5, isIOS } from '../../utils/helpers'
import { getPayloadStatus, resolveSourceDisplayName, isRepositoryPayloadVisible } from '../../utils/payloadStatus'
import { slug } from '../../utils/versions'
import { formatSyncTime } from '../../utils/syncTime'
import PayloadName from '../ui/PayloadName'
import Modal from '../ui/Modal'
import { useRepository } from '../../contexts/RepositoryContext'
@@ -576,7 +577,7 @@ const StorageHub = ({
{!multiSources && src.last_update > 0 && (
<p className="px-3 sm:px-4 text-xs uppercase tracking-widest text-zinc-500">
{t("storage_hub.last_sync", "Last Sync: {{date}}", {
date: new Date(src.last_update * 1000).toLocaleString(i18n.resolvedLanguage),
date: formatSyncTime(src.last_update, i18n.resolvedLanguage, isPS5),
})}
</p>
)}
@@ -601,7 +602,7 @@ const StorageHub = ({
{src.last_update > 0 && (
<p className="text-xs text-zinc-500 uppercase tracking-widest mt-1">
{t("storage_hub.updated_at", "Updated {{date}}", {
date: new Date(src.last_update * 1000).toLocaleString(i18n.resolvedLanguage),
date: formatSyncTime(src.last_update, i18n.resolvedLanguage, isPS5),
})}
</p>
)}
+7
View File
@@ -0,0 +1,7 @@
export function formatSyncTime(unixSeconds, locale, useLocalFields = false) {
const date = new Date(unixSeconds * 1000)
if (!useLocalFields) return date.toLocaleString(locale)
// Older console WebKit can format locale dates in UTC. Read local fields directly.
const pad = value => String(value).padStart(2, '0')
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`
}
+27
View File
@@ -0,0 +1,27 @@
import test from 'node:test'
import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import { formatSyncTime } from '../src/utils/syncTime.js'
test('console sync time uses local fields even when locale formatting is broken', () => {
for (const [zone, expected] of [
['Europe/Warsaw', ['2026-10-13 14:00:00', '2026-01-13 13:00:00']],
['America/Los_Angeles', ['2026-10-13 05:00:00', '2026-01-13 04:00:00']],
['Asia/Kathmandu', ['2026-10-13 17:45:00', '2026-01-13 17:45:00']],
]) {
const code = `import { formatSyncTime } from './src/utils/syncTime.js';
Date.prototype.toLocaleString = function () { throw Error('Broken console formatter'); };
console.log(JSON.stringify(['2026-10-13T12:00:00Z','2026-01-13T12:00:00Z'].map(iso => formatSyncTime(Date.parse(iso)/1000,'en-US',true))));`
const actual = execFileSync(process.execPath, ['--input-type=module', '-e', code], {
cwd: new URL('../', import.meta.url), env: { ...process.env, TZ: zone }, encoding: 'utf8',
})
assert.deepEqual(JSON.parse(actual), expected)
}
})
test('other browsers retain localized local time formatting', () => {
const timestamp = Date.parse('2026-10-13T12:00:00Z') / 1000
for (const locale of ['en-US', 'pl-PL']) {
assert.equal(formatSyncTime(timestamp, locale), new Date(timestamp * 1000).toLocaleString(locale))
}
})
+1 -1
View File
@@ -47,7 +47,7 @@
#define PAYLOADS_STORAGE_DIR "/data/pldmgr/payloads"
#define REPOSITORY_SOURCE_URL \
"https://itsplk.github.io/ps5-payloads-mirror/payloads.json"
#define REPOSITORY_REFRESH_INTERVAL_SEC 86400
#define REPOSITORY_REFRESH_INTERVAL_SEC 10800
/* Logging (implementation in log_server.c) */
void pldmgr_log(const char *fmt, ...);
+8
View File
@@ -90,6 +90,14 @@ with tempfile.TemporaryDirectory(prefix='pldmgr-icons-') as temporary:
catalog.write_text(json.dumps(items));assert revision(force=True)=='' # bare catalogs without icons supported
catalog_cache=storage/('repo_cache_'+hashlib.sha256(source.encode()).hexdigest()[:8]+'.json')
manifest();images.write_text(json.dumps({'icons':{'shared':image,'absent':image}}));revision(force=True)
catalog_timestamp = Path(str(catalog_cache)+'.ts')
before = requests().count(source)
icons_before = len(icon_requests())
catalog_timestamp.write_text(str(int(time.time())-2*3600))
revision();assert requests().count(source)==before # still fresh before three hours
catalog_timestamp.write_text(str(int(time.time())-3*3600-5))
revision();assert requests().count(source)==before+1 # expired catalogs refresh on access
assert len(icon_requests())==icons_before # catalog expiry does not expire the weekly icon cache
Path(str(catalog_cache)+'.ts').write_text('0')
outage=dict(env,ICON_TEST_FAIL_CATALOG='1',ICON_TEST_FAIL='1')
cached_listing=json.loads(subprocess.check_output([str(binary),'list'],cwd=ROOT,env=outage,text=True))