#857: custom in-container completed-downloads path for Torrent/Usenet sources (settings + UI; resolver already consumed the keys)

pull/869/head
BoulderBadgeDad 2 weeks ago
parent 15067b63ca
commit 2428df1144

@ -508,6 +508,22 @@ class ConfigManager:
# its partial data, fail the download so the next source can
# try) or "pause" (pause in the client, leave for the user).
"torrent_stall_action": "abandon",
# Where THIS container can read completed torrent/usenet
# downloads (#857). The downloader (qBit/SAB) reports a save
# path from inside ITS OWN container — often a category folder
# like /data/downloads/music — which may be mounted at a
# different point here. Set these to the in-container path(s)
# where SoulSync sees those finished downloads; the resolver
# then finds the release by name under them. Empty = fall back
# to the soulseek download/transfer dirs (the shared-volume
# default). See core.download_plugins.album_bundle.resolve_reported_save_path.
"torrent_download_path": "",
"usenet_download_path": "",
# Explicit remote→local prefix mappings for non-shared / oddly
# mounted layouts (Sonarr/Radarr "Remote Path Mapping" style):
# a list of {"from": "<client path>", "to": "<soulsync path>"}.
# Tried before the basename fallback above.
"usenet_path_mappings": [],
},
"post_processing": {
# When a download is quarantined (AcoustID mismatch, integrity /

@ -551,6 +551,26 @@ def test_resolve_skips_mapping_when_target_missing_then_tries_basename(tmp_path:
assert resolved == str(tmp_path / "MyAlbum")
def test_resolve_uses_custom_torrent_download_path(tmp_path: Path) -> None:
"""#857: the user's torrent client saves to a category folder (e.g. a
'Music' category) mounted here at a custom in-container path. Setting
download_source.torrent_download_path lets SoulSync find the release there."""
music_mount = tmp_path / "downloads" / "music"
(music_mount / "MyAlbum").mkdir(parents=True)
cfg = _cfg({'download_source.torrent_download_path': str(music_mount)})
resolved = resolve_reported_save_path('/data/Downloads/Music/MyAlbum', config_get=cfg)
assert resolved == str(music_mount / "MyAlbum")
def test_resolve_uses_custom_usenet_download_path(tmp_path: Path) -> None:
"""#857: same for the usenet source's custom completed-downloads path."""
nzb_mount = tmp_path / "nzb" / "music"
(nzb_mount / "MyAlbum").mkdir(parents=True)
cfg = _cfg({'download_source.usenet_download_path': str(nzb_mount)})
resolved = resolve_reported_save_path('/config/Downloads/complete/MyAlbum', config_get=cfg)
assert resolved == str(nzb_mount / "MyAlbum")
# ---------------------------------------------------------------------------
# poll_album_download — lifted poll loop for both torrent + usenet plugins.
# ---------------------------------------------------------------------------

@ -5431,6 +5431,13 @@
Override where the torrent client writes downloads. This path is on the <strong>torrent client's</strong> machine, not SoulSync's.
</div>
</div>
<div class="form-group">
<label>Completed Downloads Path — in SoulSync (optional):</label>
<input type="text" id="torrent-download-path" placeholder="leave blank for the shared-volume default">
<div class="setting-help-text">
Where <strong>SoulSync</strong> can read finished torrents — its own in-container path. Set this when your client saves to a category folder (e.g. a "Music" category at <code>/data/downloads/music</code>) that's mounted here at a different path. SoulSync finds the release by name under this folder. Blank = use the Soulseek download/transfer folders.
</div>
</div>
<div class="form-group">
<label>Stalled torrent timeout (minutes):</label>
<input type="number" id="torrent-stall-timeout" min="0" step="1" placeholder="10">
@ -5511,6 +5518,13 @@
SoulSync tags every NZB with this category so it ends up in a predictable post-processing folder.
</div>
</div>
<div class="form-group">
<label>Completed Downloads Path — in SoulSync (optional):</label>
<input type="text" id="usenet-download-path" placeholder="leave blank for the shared-volume default">
<div class="setting-help-text">
Where <strong>SoulSync</strong> can read finished NZB downloads — its own in-container path. Set this when SABnzbd/NZBGet writes that category to a folder (e.g. <code>/data/downloads/music</code>) mounted here at a different path. SoulSync finds the release by name under this folder. Blank = use the Soulseek download/transfer folders.
</div>
</div>
<div class="form-group">
<label>Status:</label>
<div class="form-actions" style="margin-top: 4px;">

@ -1179,6 +1179,8 @@ async function loadSettingsData() {
_tcStall.value = (secs === undefined || secs === null) ? 10 : Math.round(Number(secs) / 60);
}
if (_tcStallAct) _tcStallAct.value = settings.download_source?.torrent_stall_action || 'abandon';
const _tcDlPath = document.getElementById('torrent-download-path');
if (_tcDlPath) _tcDlPath.value = settings.download_source?.torrent_download_path || '';
const _ucType = document.getElementById('usenet-client-type');
const _ucUrl = document.getElementById('usenet-client-url');
const _ucKey = document.getElementById('usenet-client-api-key');
@ -1191,6 +1193,8 @@ async function loadSettingsData() {
if (_ucUser) _ucUser.value = settings.usenet_client?.username || '';
if (_ucPass) _ucPass.value = settings.usenet_client?.password || '';
if (_ucCat) _ucCat.value = settings.usenet_client?.category || 'soulsync';
const _ucDlPath = document.getElementById('usenet-download-path');
if (_ucDlPath) _ucDlPath.value = settings.download_source?.usenet_download_path || '';
if (typeof updateUsenetClientUI === 'function') updateUsenetClientUI();
// Sync ARL to connections tab field + bidirectional listeners
const _connArl = document.getElementById('deezer-connection-arl');
@ -3001,6 +3005,10 @@ async function saveSettings(quiet = false) {
return (Number.isFinite(m) && m >= 0 ? m : 10) * 60;
})(),
torrent_stall_action: document.getElementById('torrent-stall-action')?.value || 'abandon',
// In-container path(s) where SoulSync reads finished torrent/usenet
// downloads (#857). Rendered in the torrent/usenet client sections.
torrent_download_path: document.getElementById('torrent-download-path')?.value || '',
usenet_download_path: document.getElementById('usenet-download-path')?.value || '',
},
tidal_download: {
quality: document.getElementById('tidal-download-quality').value || 'lossless',

Loading…
Cancel
Save