radio: classic ham-site public view (Opa's Radiohoek) with link directory
Deploy production / deploy (push) Successful in 1m23s

- PublicRadio.svelte: websdr.org-style grey page, steel-blue bars, dense tables,
  NL default / EN toggle, radio facts, frequency list per band, banks, ISS, nets
- links.ts: all 34 showcase links, status (online/warn/offline) + archive links
- owner keeps the dashboard; ?view=public lets the owner preview the public page
This commit is contained in:
stan committed 2026-10-27 09:49:00 +00:00
1 parent 3a2d3cc78c
commit 2c8d1bd881
4 files changed
+1580 -3

No files matched your search

File diff suppressed because it is too large. Load diff
+453
View File
@@ -0,0 +1,453 @@
// Link directory for the public radio page (/trackers/radio#links), from the links Opa sent by
// email and WhatsApp (checked 24 Oct 2026). Plain data: add or edit entries here. Every entry is
// shown; offline ones get a label and, when there is one, a web.archive.org copy. Public sites only:
// never add a phone number, an email address or a link into someone's own mailbox.
export type Text = { nl: string; en: string };
export type LinkStatus = 'online' | 'warn' | 'offline';
export type RadioLink = {
title: string;
/** An http(s) URL, or "#anchor" for a section on this page. */
url: string;
about: Text;
/** How it reached us: Opa by email or WhatsApp, or a supporting link we added. */
via: 'email' | 'whatsapp' | 'added';
/** Date Opa sent it (YYYY-MM-DD), when known. */
sent?: string;
status: LinkStatus;
archive?: string;
note?: Text;
};
export type LinkCategory = { id: string; title: Text; links: RadioLink[] };
export const LINKS_CHECKED = '2026-10-24';
export const LINK_CATEGORIES: LinkCategory[] = [
{
id: 'websdr',
title: {
nl: 'WebSDR — luisteren via de browser',
en: 'WebSDR — listen in the browser'
},
links: [
{
title: 'websdr.org',
url: 'http://websdr.org/',
about: {
nl: 'Overzicht en kaart van alle WebSDR-ontvangers ter wereld',
en: 'Directory and map of every WebSDR receiver worldwide'
},
via: 'whatsapp',
status: 'online'
},
{
title: 'WebSDR Universiteit Twente',
url: 'http://websdr.ewi.utwente.nl:8901/',
about: {
nl: '0–29 MHz, de allereerste WebSDR',
en: '0–29 MHz, the original WebSDR'
},
via: 'whatsapp',
status: 'online'
},
{
title: 'WebSDR Maasbree (PH4RTM)',
url: 'http://sdr.websdrmaasbree.nl:8901/',
about: {
nl: 'Kortegolf, o.a. de KLM-ronde op 3785 kHz LSB',
en: 'Shortwave, e.g. the KLM net on 3785 kHz LSB'
},
via: 'whatsapp',
status: 'online',
sent: '2026-09-20'
},
{
title: 'WebSDR PI1DFT (OpenWebRX+)',
url: 'https://websdr.pi1dft.ampr.org/#freq=145450000,mod=nfm,sql=-66',
about: {
nl: 'Delft/Den Haag, al afgestemd op 145.450 NFM: de Haagse ronde',
en: 'Delft/The Hague, pre-tuned to 145.450 NFM for the Hague net'
},
via: 'email',
status: 'online',
sent: '2025-03-07'
},
{
title: 'WebSDR Utrecht (PI4UTR)',
url: 'https://websdr.pi4utr.nl/',
about: {
nl: 'WebSDR Utrecht van PI4UTR',
en: 'WebSDR Utrecht run by PI4UTR'
},
via: 'whatsapp',
status: 'offline',
note: {
nl: 'adres niet bereikbaar; zie de site van PI4UTR hieronder',
en: 'address unreachable; see the PI4UTR site below'
}
},
{
title: 'PI4UTR',
url: 'https://www.pi4utr.nl/',
about: {
nl: 'VERON-afdeling Utrecht, beheert de Utrechtse WebSDR',
en: 'VERON Utrecht club, runs the Utrecht WebSDR'
},
via: 'added',
status: 'online'
}
]
},
{
id: 'air',
title: {
nl: 'Luchtvaart en ADS-B (1090 MHz)',
en: 'Aviation and ADS-B (1090 MHz)'
},
links: [
{
title: 'RTL-SDR: ADS-B-radar',
url: 'https://www.rtl-sdr.com/adsb-aircraft-radar-with-rtl-sdr/',
about: {
nl: 'Eigen vliegtuigradar met een RTL-SDR-stickje',
en: 'Build your own aircraft radar with an RTL-SDR dongle'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'Flightradar24: ADS-B-antenne',
url: 'https://www.flightradar24.com/blog/ads-b/ads-b-antenna-and-location-guide/',
about: {
nl: 'Waar en hoe je een ADS-B-antenne plaatst',
en: 'Where and how to place an ADS-B antenna'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'SDRshop: ADS-B-antenne',
url: 'https://sdrshop.nl/ads-b-antenne/',
about: {
nl: 'ADS-B-antenne (1090 MHz)',
en: 'ADS-B antenna (1090 MHz)'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'Elektor: ADS-B buitenantenne',
url: 'https://www.elektor.nl/products/ads-b-outdoor-antenna-1090-mhz',
about: {
nl: 'ADS-B buitenantenne 1090 MHz',
en: 'Outdoor 1090 MHz ADS-B antenna'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'Van Dijken: De Flight-antenne',
url: 'https://www.vandijkenelektronica.nl/product/de-flight-antenna-voor-ontvangst-van-ads-b-signalen-op-1090-mhz/',
about: {
nl: '“De Flight”-antenne voor ADS-B op 1090 MHz',
en: '“De Flight” antenna for ADS-B on 1090 MHz'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'RTL-SDR: FlightAware-antenne',
url: 'https://www.rtl-sdr.com/review-flightaware-ads-b-antenna-and-filter/',
about: {
nl: 'Review van de FlightAware ADS-B-antenne en filter',
en: 'Review of the FlightAware ADS-B antenna and filter'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'Linux Magazine: Raspberry Pi',
url: 'https://linuxmag.nl/vliegtuigen-spotten-met-je-raspberry-pi/',
about: {
nl: 'Vliegtuigen spotten met een Raspberry Pi',
en: 'Plane spotting with a Raspberry Pi'
},
via: 'email',
status: 'online',
sent: '2025-03-11'
},
{
title: 'PD0G: ADS-B decoderen',
url: 'https://pd0g.wordpress.com/2018/04/02/ads-b-decoding-with-rtl-sdr-adsbsharp-and-virtual-radar-server/',
about: {
nl: 'ADS-B met RTL-SDR, ADSBSharp en Virtual Radar Server',
en: 'ADS-B with RTL-SDR, ADSBSharp and Virtual Radar Server'
},
via: 'email',
status: 'online',
sent: '2025-03-11'
},
{
title: 'PD2EW: ADS-B',
url: 'https://www.wijkamp.com/pd2ew/ads-b.html',
about: {
nl: 'ADS-B-pagina van zendamateur PD2EW',
en: "A ham's ADS-B page (PD2EW)"
},
via: 'email',
status: 'online',
sent: '2025-03-11'
}
]
},
{
id: 'iss',
title: {
nl: 'ISS en satellieten',
en: 'ISS and satellites'
},
links: [
{
title: 'ARISS live',
url: 'https://live.ariss.org/',
about: {
nl: 'Radiocontacten tussen scholen en de ISS (145.800 MHz)',
en: 'Radio contacts between schools and the ISS (145.800 MHz)'
},
via: 'email',
status: 'online',
sent: '2022-12-08'
},
{
title: 'Weerstation Grootegast',
url: 'https://www.weerstation-grootegast.nl/pagina32.html',
about: {
nl: 'Ontvangst van NOAA-weersatellieten',
en: 'Receiving NOAA weather satellites'
},
via: 'email',
status: 'warn',
sent: '2025-03-06',
archive:
'https://web.archive.org/web/20250611043333/https://weerstation-grootegast.nl/pagina32.html',
note: {
nl: 'verouderde beveiliging, opent soms niet; gebruik dan het archief',
en: 'outdated security, may not open; use the archive copy'
}
}
]
},
{
id: 'marine',
title: {
nl: 'Marifoon',
en: 'Marine VHF'
},
links: [
{
title: "Opa's marifoonlijst (banken 7–10)",
url: '#band-marine',
about: {
nl: 'Kanaal 301–495, staat in de frequentielijst op deze pagina',
en: 'Channels 301–495, included in the frequency list on this page'
},
via: 'email',
status: 'online',
sent: '2025-05-21'
}
]
},
{
id: 'sdr',
title: {
nl: 'Scanner en SDR: apparatuur en software',
en: 'Scanner and SDR: hardware and software'
},
links: [
{
title: 'SDRshop: SDRplay RSP',
url: 'https://sdrshop.nl/sdrplayrsp/',
about: {
nl: 'SDRplay RSP-ontvangers (Opa heeft de RSP1B)',
en: 'SDRplay RSP receivers (Opa has the RSP1B)'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'SDRshop: SDRplay-overzicht',
url: 'https://sdrshop.nl/sdrplay-overzicht/',
about: {
nl: 'Vergelijking van alle SDRplay-modellen',
en: 'Comparison of all SDRplay models'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'SDRshop: SDRuno-boek',
url: 'https://sdrshop.nl/sdrplay-en-sdruno-boek/',
about: {
nl: 'Nederlandstalig SDRplay/SDRuno-boek (ADS-B op blz. 140)',
en: 'Dutch SDRplay/SDRuno handbook (ADS-B on p. 140)'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'SDRuno-boek: inhoud (pdf)',
url: 'https://sdrshop.nl/wp-content/uploads/SDRuno-handleiding-inhoud-1.pdf',
about: {
nl: 'Inhoudsopgave van dat boek',
en: 'Table of contents of that book'
},
via: 'added',
status: 'online'
},
{
title: 'SDRplay RSP1B',
url: 'https://www.sdrplay.com/rsp1b/',
about: {
nl: 'Officiële pagina van de RSP1B',
en: 'Official RSP1B page'
},
via: 'added',
status: 'online'
},
{
title: 'RTL-SDR.com',
url: 'https://www.rtl-sdr.com/',
about: {
nl: "Nieuws en projecten met goedkope SDR's",
en: 'News and projects with cheap SDRs'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'RTL-SDR: wat is het?',
url: 'https://www.rtl-sdr.com/about-rtl-sdr/',
about: {
nl: 'Wat is een RTL-SDR?',
en: 'What is an RTL-SDR?'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'PC5E: frequentielijst Nederland (pdf)',
url: 'https://www.pc5e.nl/downloads/scanner/20240102%20Frequenties%20Nederland.pdf',
about: {
nl: 'Lijst van PC5E, 2 jan 2024, 364 blz., op pc5e.nl',
en: "PC5E's list, 2 Jan 2024, 364 pages, on pc5e.nl"
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'PC5E',
url: 'https://www.pc5e.nl/',
about: {
nl: 'Homepage van zendamateur PC5E (Heerenveen), met scannerfrequenties',
en: 'Homepage of ham PC5E (Heerenveen), with scanner frequencies'
},
via: 'whatsapp',
status: 'online'
}
]
},
{
id: 'forums',
title: {
nl: 'Forums en clubs',
en: 'Forums and clubs'
},
links: [
{
title: 'Het Scannerforum',
url: 'https://www.scannerforum.nl/',
about: {
nl: 'Alles over scanners, frequenties en P2000',
en: 'Dutch scanner, frequency and P2000 forum'
},
via: 'whatsapp',
status: 'online'
},
{
title: 'Scannerforum: zoeken',
url: 'https://www.scannerforum.nl/index.php?action=search2',
about: {
nl: 'Zoekpagina (zoek op “ads-b”)',
en: 'Search page (search for “ads-b”)'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'Zendamateur.com',
url: 'https://www.zendamateur.com/',
about: {
nl: '“24 uur per dag QRV”, het NL/BE-radioamateurforum (inloggen aanbevolen)',
en: '“On the air 24/7”, the Dutch/Belgian ham forum (logging in recommended)'
},
via: 'whatsapp',
status: 'online'
},
{
title: 'Zendamateur.com: ADS-B-topic',
url: 'https://www.zendamateur.com/viewtopic.php?t=26620',
about: {
nl: 'Forumtopic over ADS-B',
en: 'Forum topic about ADS-B'
},
via: 'email',
status: 'online',
sent: '2025-03-06'
},
{
title: 'QRZ.com: PA4VB',
url: 'https://www.qrz.com/db/PA4VB',
about: {
nl: 'QRZ-pagina van roepnaam PA4VB (details na inloggen)',
en: 'QRZ page for callsign PA4VB (details need a login)'
},
via: 'email',
status: 'online',
sent: '2026-10-01'
},
{
title: 'VRZA Zuid-West (PI4ZWN)',
url: 'https://www.pi4zwn.nl/',
about: {
nl: 'Afdelingsnieuws en agenda',
en: 'Club news and calendar'
},
via: 'added',
status: 'online'
},
{
title: 'PI4ZWN: SDRplay populair',
url: 'https://www.pi4zwn.nl/sdrplay-blijkt-populaire-ontvanger/',
about: {
nl: 'Artikel: “SDRplay blijkt populaire ontvanger”',
en: 'Article: “SDRplay turns out to be a popular receiver”'
},
via: 'email',
status: 'online',
sent: '2025-03-07'
}
]
}
];
+4 -1
View File
@@ -20,7 +20,9 @@ import type { Actions, PageServerLoad } from './$types';
// below check the owner, and hooks.server.ts refuses non-GET requests here (ownerWritePrefixes).
// Language: ?lang=nl|en (remembered in a cookie), else the cookie, else Accept-Language, else NL.
export const load: PageServerLoad = async (event) => {
const owner = isOwner(event);
const isOwnerReq = isOwner(event);
// ?view=public lets the owner preview exactly what visitors get.
const owner = isOwnerReq && event.url.searchParams.get('view') !== 'public';
// Varies by login, cookie and Accept-Language, so never cache it in between.
event.setHeaders({ 'cache-control': 'private, no-store', vary: 'cookie, accept-language' });
const asked = event.url.searchParams.get('lang');
@@ -41,6 +43,7 @@ export const load: PageServerLoad = async (event) => {
return {
...(owner ? radio : publicRadio(radio)),
owner,
ownerPreview: isOwnerReq && !owner,
lang,
now: Date.now(),
seo: {
+20 -2
View File
@@ -11,6 +11,7 @@
import Nets from '#lib/radio/Nets.svelte';
import IssPasses from '#lib/radio/IssPasses.svelte';
import LogList from '#lib/radio/LogList.svelte';
import PublicRadio from '#lib/radio/PublicRadio.svelte';
import { BANDS } from '#lib/radio/index.js';
import { DICTS, LANGS, setRadio } from '#lib/radio/i18n.js';
import LayoutDashboard from 'lucide-svelte/icons/layout-dashboard';
@@ -91,7 +92,23 @@
resolve(`/trackers/radio?tab=frequencies&band=${band}` as '/');
</script>
<div class="radio" lang={data.lang}>
<!-- Visitors (and the owner with ?view=public) get the classic ham-site page; the owner gets
the dashboard with edit controls. -->
{#if !data.owner}
<PublicRadio
frequencies={data.frequencies}
channels={data.channels}
nets={data.nets}
passes={data.passes}
log={data.log}
logTotal={data.logTotal}
lang={data.lang}
{now}
{langHref}
ownerPreview={data.ownerPreview}
/>
{:else}
<div class="radio" lang={data.lang}>
<header class="head">
<a href={resolve('/trackers/radio')} class="title-link" aria-label={t.title}
><TrackerIcon name="radio" class="size-12" /></a
@@ -209,7 +226,8 @@
<LogList log={data.log} frequencies={data.frequencies} {now} frequencyId={logFreq} />
</section>
{/if}
</div>
</div>
{/if}
<style>
/* Built to be read by an older visitor on a phone or tablet: big type, strong contrast, large