From 65cae0d8224214e354789224202d60f097772fbc Mon Sep 17 00:00:00 2001 From: rouggy Date: Fri, 28 Aug 2026 08:54:42 +0200 Subject: [PATCH] perf(lotw): stop asking for the QSL details by default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A tester compared LogHX's two download options on the same account: two minutes for the confirmations, twenty for the confirmations with QSO details. OpsLog was always sending qso_qsldetail=yes — LogHX's slow option — which is the whole of the wait people were reporting. Marking a confirmation needs call, date, band and mode; the detail adds the QSL date and the station's grid, state and county. Now a choice, off by default, and forced on when the download is also ADDING the QSOs it cannot find — the one case where those fields have no other source. --- app.go | 20 +++++++++++++++++++- changelog.json | 10 ++++++++++ frontend/src/components/QSLManagerModal.tsx | 17 +++++++++++++++-- frontend/src/lib/i18n.tsx | 4 ++++ frontend/wailsjs/go/main/App.d.ts | 4 ++++ frontend/wailsjs/go/main/App.js | 8 ++++++++ internal/extsvc/lotw.go | 19 +++++++++++++++---- 7 files changed, 75 insertions(+), 7 deletions(-) diff --git a/app.go b/app.go index d6adcc9..a9ace98 100644 --- a/app.go +++ b/app.go @@ -402,6 +402,7 @@ const ( keyExtLoTWTQSLPath = "extsvc.lotw.tqsl_path" keyExtLoTWStationLoc = "extsvc.lotw.station_location" + keyExtLoTWQSLDetail = "extsvc.lotw.qsl_detail" // ask LoTW for the QSL dates and station details (an order of magnitude slower) keyExtLoTWAllCalls = "extsvc.lotw.download_all_calls" // download confirmations for EVERY call on the account, not just this profile's keyExtLoTWForceCall = "extsvc.lotw.force_station_callsign" // override STATION_CALLSIGN at sign time (e.g. F4BPO/P on the F4BPO cert) keyExtLoTWKeyPassword = "extsvc.lotw.key_password" @@ -12097,6 +12098,16 @@ func manualRefFor(existing, code string) string { return "" } +// GetLoTWQSLDetail reports whether the download asks LoTW for the QSL detail. +func (a *App) GetLoTWQSLDetail() bool { + return a.settingOr(keyExtLoTWQSLDetail, "") == "1" +} + +// SetLoTWQSLDetail stores that choice. +func (a *App) SetLoTWQSLDetail(on bool) { + a.setSetting(keyExtLoTWQSLDetail, map[bool]string{true: "1", false: "0"}[on]) +} + // GetLoTWDownloadAllCalls reports whether the LoTW download ignores the // profile's own call and pulls every callsign on the account. func (a *App) GetLoTWDownloadAllCalls() bool { @@ -12215,7 +12226,14 @@ func (a *App) runDownloadConfirmations(ctx context.Context, svc extsvc.Service, // The report arrives over minutes, and a window that says nothing while it // does is indistinguishable from one that has hung — which is what it was // being reported as. Every half-megabyte, say how much has landed. - adifText, err := extsvc.DownloadLoTWConfirmations(ctx, nil, cfg.LoTW, sinceDate, ownCall, emit) + // Adding the QSOs LoTW knows and we do not is the one job that needs the + // slow report: without the detail those records would come in with no + // grid, state or county, and nothing else would ever fill them. + detail := addNotFound || a.settingOr(keyExtLoTWQSLDetail, "") == "1" + if detail { + emit("Asking for the QSL details too — LoTW takes considerably longer to build that report.") + } + adifText, err := extsvc.DownloadLoTWConfirmations(ctx, nil, cfg.LoTW, sinceDate, ownCall, detail, emit) if err != nil { emit("Download failed: " + err.Error()) done(matched, total) diff --git a/changelog.json b/changelog.json index 288d1f4..d86afa5 100644 --- a/changelog.json +++ b/changelog.json @@ -1,4 +1,14 @@ [ + { + "version": "0.26.22", + "date": "", + "en": [ + "LoTW download: the QSL details (QSL date, grid, state, county) are now optional and off by default — LoTW takes about ten times longer to build that report, twenty minutes against two on the same account, and marking a confirmation needs none of it. Still asked for automatically when adding the QSOs not found in the log." + ], + "fr": [ + "Téléchargement LoTW : les détails QSL (date du QSL, locator, état, comté) deviennent optionnels et désactivés par défaut — LoTW met environ dix fois plus longtemps à construire ce rapport, vingt minutes contre deux sur le même compte, et marquer une confirmation n'en a pas besoin. Toujours demandés automatiquement quand on ajoute les QSO absents du log." + ] + }, { "version": "0.26.21", "date": "", diff --git a/frontend/src/components/QSLManagerModal.tsx b/frontend/src/components/QSLManagerModal.tsx index dbae2b8..50f11ce 100644 --- a/frontend/src/components/QSLManagerModal.tsx +++ b/frontend/src/components/QSLManagerModal.tsx @@ -8,7 +8,7 @@ import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from '@/components/ui/select'; import { cn } from '@/lib/utils'; -import { GetLoTWDownloadAllCalls, SetLoTWDownloadAllCalls, OpenExternalURL, FindQSOsForUpload, UploadQSOsManual, DownloadConfirmations, CancelConfirmations, ImportHamlogConfirmations, ExportHamlogUnmatched, OpenADIFFile, SaveADIFFile, SyncPOTAHunterLog, ListQSO, BulkUpdateQSL, UploadCallsign, GetSlotStats } from '../../wailsjs/go/main/App'; +import { GetLoTWQSLDetail, SetLoTWQSLDetail, GetLoTWDownloadAllCalls, SetLoTWDownloadAllCalls, OpenExternalURL, FindQSOsForUpload, UploadQSOsManual, DownloadConfirmations, CancelConfirmations, ImportHamlogConfirmations, ExportHamlogUnmatched, OpenADIFFile, SaveADIFFile, SyncPOTAHunterLog, ListQSO, BulkUpdateQSL, UploadCallsign, GetSlotStats } from '../../wailsjs/go/main/App'; import { Input } from '@/components/ui/input'; import { RecentQSOsGrid } from '@/components/RecentQSOsGrid'; import { EventsOn } from '../../wailsjs/runtime/runtime'; @@ -257,7 +257,13 @@ export function QSLManagerPanel({ onEditQSO, actions, paperRequest }: { const [addNotFound, setAddNotFound] = useState(false); // LoTW only: pull the whole account rather than this profile's callsign. const [lotwAllCalls, setLotwAllCalls] = useState(false); - useEffect(() => { GetLoTWDownloadAllCalls().then((v: boolean) => setLotwAllCalls(!!v)).catch(() => {}); }, []); + // LoTW only: ask for the QSL dates and station details. Ten times slower to + // build, so it is a choice rather than the default it used to be. + const [lotwDetail, setLotwDetail] = useState(false); + useEffect(() => { + GetLoTWDownloadAllCalls().then((v: boolean) => setLotwAllCalls(!!v)).catch(() => {}); + GetLoTWQSLDetail().then((v: boolean) => setLotwDetail(!!v)).catch(() => {}); + }, []); // Download date window: 'last' = incremental since last pull, 'date' = from a // chosen date, 'all' = everything. const [sinceMode, setSinceMode] = useState<'last' | 'date' | 'all'>('last'); @@ -751,6 +757,13 @@ export function QSLManagerPanel({ onEditQSO, actions, paperRequest }: { setAddNotFound(!!c)} /> {t('qslm.addNotFound')} + {service === 'lotw' && ( + + )} {service === 'lotw' && (