Skip to content

feat: Usenet settings in Speed & data limits, with an on/off switch - #229

Merged
Arpit-Khandelwal merged 9 commits into
anmolkapil:mainfrom
dxmoc:feat/usenet-settings
Nov 6, 2026
Merged

Arpit-Khandelwal merged 9 commits into
anmolkapil:mainfrom
dxmoc:feat/usenet-settings

Conversation

@dxmoc

@dxmoc dxmoc commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Usenet settings in Speed & data limits

Follow-up to #133 (issue #126). In #133 the news server could only be reached from an NZB: the New download dialog, or the server button on a download or error screen. This gives it a fixed place, as discussed there: a Usenet page in Speed & data limits, with an on/off switch.

What changed

  • Usenet page in Speed & data limits, under General next to All downloads. It shows the server (host and port, SSL, username, connections). "Change server" / "Set up server" opens the same UsenetServerDialog the other entry points use, so there is still only one form.
  • "Usenet downloads" switch. Like the rest of the dialog it only takes effect on Save. It is stored with the server in usenet-server.json. A file saved before this change has no flag, so it reads as on. checkedServer validates the flag the same way it handles tls.
  • When the switch is off:
    • An NZB link probes as an ordinary HTTP download, so the .nzb file itself gets saved (for another newsreader, say). Indexer errors are still caught.
    • Opening or dropping a local .nzb shows "Usenet downloads are off. Turn them on in Speed & data limits."
    • NZB downloads that are running fail with the same message and stay resumable. Paused or queued ones fail the same way when they would start, before they connect. After the switch goes back on, Retry/Resume continues where the download stopped.
  • The server can only be switched off once one is set up, because the flag is kept with it. Without a server the switch is shown on and disabled.
  • The entry points from feat: NZB downloads from a Usenet news server (#126) #133 (New download, download screen, error screen) work as before. Saving from the server form doesn't change the switch.

Main-process changes: usenetServer.ts (flag, usenetEnabled()), probe.ts, downloadManager.ts / nzbTransfer.ts (refuse to connect when off), handlers.ts (stop running NZB downloads when it's saved as off). No new IPC channels: the switch is saved through saveUsenetServer, and leaving out the password keeps the saved one.

How to test

  1. Open the networks menu, then Speed & data limits, then Usenet. Set up a server, or check that the one you already have is shown.
  2. Turn "Usenet downloads" off and save. Paste an NZB link: New download now offers it as a plain file. Open a .nzb file: you get the "Usenet downloads are off" message.
  3. Start an NZB download with the switch on, then turn it off: the download stops with that message. Turn it back on, press Retry, and it finishes.
  4. Restart Plexo: the switch keeps its state.

e2e: three new tests in e2e/nzb.spec.ts under "Usenet settings":

  • the switch is saved on Save, is kept across a restart, and an old file without the flag reads as on
  • off, an NZB file is refused, an NZB link probes as http, and a running download stops and doesn't reconnect when resumed; back on, it finishes
  • setting up the server from the limits dialog, then downloading with it

npx playwright test e2e/nzb.spec.ts: 18 passed. The smoke suite passes except ui.spec.ts:288, which fails the same way on main in my Linux container.

The news server gets a fixed place: a Usenet page in Speed & data limits
shows it and opens the same server dialog the download screens use.

Its switch is saved with the server (usenet-server.json; a file without
it reads as on). Off, an NZB link probes as a plain file, an NZB file
can't be added, and NZB downloads stop and don't connect until it's on
again.
@dxmoc

dxmoc commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author
image image image

@Arpit-Khandelwal Arpit-Khandelwal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dxmoc. A fixed place for the server makes sense: right now you can only get to it from an NZB. I merged current main (no conflicts). Typecheck node/web/e2e, lint, format:check and the build are clean. nzb.spec.ts passes (18), and so do limits, ui, scheduleQueue, probeRedirects, taskbarProgress and download (75). The switch does what it says: usenetTurnedOff only fails downloads that are running, paused and queued ones fail before they connect, and the test checks that no article is asked for while it's off. With #230 on top, I checked that switching off stops the backup server's connections too.

One thing before I approve:

  1. Saving the switch rebuilds the server from a fixed list of fields (LimitsDialog.tsx:758): { host, port, tls, username, connections, enabled }. Any field the server gets later goes back to its default whenever someone flips the switch. #231 already adds one: with it, deleteArchives would be turned back on every time Usenet is switched off or on. A small setUsenetEnabled(enabled) call that only changes the flag would avoid this. Or send the saved server as it is: saveUsenetServer({ ...usenet, password: undefined, enabled: usenetEnabled }). checkedServer already drops the fields it doesn't know.

Nits:

  • probe.ts:227: usenetEnabled() now reads usenet-server.json and unseals the password on every HTTP probe, including links that aren't NZBs. It only needs to run when the link looks like an NZB, e.g. if (isNzbLink(...) && (await usenetEnabled())), and the same before the XML check.
  • LimitsDialog.tsx:559: "Saved in its own dialog." reads a bit odd. Maybe: "Changes to the server are saved in its own window, right away."

Scope: @anmolkapil, this is the first of the three follow-ups proposed in #133 (this settings page, a backup server in #230, par2/unpack in #231). You said those would be discussed separately, so a quick yes from you on giving Usenet a page in Speed & data limits would be good. #233 also puts non-limit settings in this dialog.

}
try {
if (usenet && usenetEnabled !== undefined && usenetEnabled !== usenet.enabled) {
const { host, port, tls, username, connections } = usenet

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rebuilds the server from a fixed list of fields, so any field added later (like deleteArchives in #231) goes back to its default when the switch is saved. A setUsenetEnabled(enabled) call, or saveUsenetServer({ ...usenet, password: undefined, enabled: usenetEnabled }), would keep everything else as saved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 87affcf. The switch now saves the server as it was loaded, { ...usenet, enabled: usenetEnabled }, so a field added later (like deleteArchives in #231) keeps its value when the switch is flipped. No password is in the view, so the stored one stays. I also moved this save to come after the other settings. Switching off stops running NZBs, and that shouldn't happen if the rest of the save fails.

Comment thread src/main/download/probe.ts Outdated
const suggestedFileName = fileNameFromHeaders(response.headers, current)
if (isNzbLink(response.headers, current, suggestedFileName)) {
// Off, an NZB is a file like any other: for another newsreader to take.
const usenet = await usenetEnabled()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this reads the server file and unseals the password for every HTTP probe. It's only needed when the link looks like an NZB: if (isNzbLink(response.headers, current, suggestedFileName) && (await usenetEnabled())), and the same before the XML sniff below.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 2993832. The probe checks isNzbLink(...) first and reads the switch only after that. The XML sniff does the same once it finds <nzb. usenetEnabled() now only reads the JSON through checkedServer and no longer unseals the password.

<section className={sectionClass}>
<h4 className={headingClass}>News server</h4>
<p className={hintClass}>
Where NZB downloads come from, as your Usenet provider gives it. Saved in its own dialog.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "Saved in its own dialog." reads a bit odd. Maybe: "Changes to the server are saved in its own window, right away."

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to your wording: "Changes to the server are saved in its own window, right away."

dxmoc added 8 commits November 5, 2026 13:47
…e it last

The switch rebuilt the server from a fixed list of fields, so any field
added later went back to its default on every flip. It now sends the
server as loaded. It is also saved after the other settings: switching
off stops running NZBs, which shouldn't happen when the rest failed.
usenetEnabled() now reads the switch without unsealing the password.
… is saved without one

Without a keyring at login (or with one that can't decrypt it), the saved
password reads as none, and flipping the switch dropped it from the file.
Switching Usenet off failed the running NZBs, which freed their slots, so
pump started the next queued NZB, which failed on the switch too, and so on
until every queued NZB was in error, each with a notification.

While the switch is off, pump now leaves queued NZBs waiting (HTTP and
torrent downloads still start), and switching it back on starts them. The
switch is read once at startup and kept as it is saved. A download failed by
the switch gets no notification: the user switched it off.
…orm is saved

The form sent an empty password whenever the session had none to show, so on
Linux without a keyring (or with another keychain) editing any other field of
the server deleted the sealed password. A blank field now always means "keep
the stored one", as it already did when the password could be shown.
Switching Usenet off failed the running NZBs while the queued ones waited, so
on switching it back on the queued ones started by themselves and the ones
further along stayed in error until each was resumed by hand. Running NZBs now
go back in the queue the way the download schedule stops downloads, and start
again with the rest once the switch is on. Resuming one by hand while off
still fails with the switch's message.
@dxmoc

dxmoc commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. All three points are fixed, on current main. A second look turned up a few more things, also fixed:

  • A password this session can't unseal is no longer dropped (cbc446c, 4f21eda). On Linux without a keyring at login, Electron falls back to basic_text, and the loaded server then has no password. Saving without a password, from the switch or from the server form with the field left blank, used to rewrite the file without the sealed blob, so it was gone once the keyring was back. Now a save without a new password keeps the stored one. The e2e test writes a blob this session can't read, saves through the switch and through the form, and checks the blob is still in the file.
  • Switching off now puts running NZBs back in the queue (6363008, 58b80af), the same way the download schedule does. Before, the running ones failed. That freed their slots, so pump() started each queued NZB only for it to fail on USENET_OFF, with a "Download failed" notification each time. Now they all wait while Usenet is off and start again on their own when it's switched back on. HTTP and torrent downloads keep going meanwhile. Resuming an NZB by hand while it's off still fails with the switch's message. The two tests check that running and queued NZBs stay queued with no articles asked for, and that they complete once the switch is back on.
  • The other settings are saved before the switch (87affcf).
  • The Usenet entry in the sidebar shows nothing until the server has loaded, instead of "On" for a moment (89ff661).

Checks: typecheck, lint, format:check and the build pass. Full e2e suite in a Linux container: the only failure was torrentProbe.spec.ts:170 (DHT gives up), with three suites running side by side; it passes on its own.

#230 is rebuilt on this. #231 still reads deleteArchives through checkedServer, so whichever lands second gets a small rebase.

@Arpit-Khandelwal Arpit-Khandelwal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dxmoc, all three points are fixed, and the extra fixes look right to me. The switch now saves { ...usenet, enabled }, so every server field stays as saved, and the probe only reads the switch after isNzbLink (and usenetEnabled() no longer unseals the password). Putting running NZBs back in the queue instead of failing them is a better fit, and the new test shows nothing is asked for while it's off and both finish once it's back on. I checked it on current main (#224, #234, #127 are in): typecheck node/web/e2e, lint, format:check and the build are clean, and nzb, limits, scheduleQueue, telegram, ui and probeRedirects pass (62).

Re-checked after #227 and #192 landed: it still merges cleanly, and nzb, limits, ui and disk pass (48/48).

@Arpit-Khandelwal
Arpit-Khandelwal merged commit 211136d into anmolkapil:main Nov 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants