## Summary
I'd like to propose a new completed-file action called **Preserve Symlink**.
The use case is download clients / virtual filesystems such as nzbDAV / InfiniDysk, where a completed audiobook may already be exposed as a filesystem symlink to virtual storage rather than as a normal local file.
Listenarr's existing Move / Copy / Hardlink-Copy actions are not safe for this workflow because copying or falling back to a copy can materialize the entire virtual file onto local storage.
## Proposed behaviour
When **Preserve Symlink** is selected:
- The completed source must be a symbolic link.
- The symlink target must be absolute.
- Listenarr recreates the same symlink at the organised library destination.
- A regular source file is rejected.
- A broken source symlink is rejected.
- An existing different destination is not overwritten.
- There is **no File.Copy, stream-copy, hardlink or move fallback**.
- Destination planning should avoid content-equivalence checks that would dereference/read the virtual audiobook payload.
- On success the destination is returned/registered normally by Listenarr.
The important safety property is that selecting Preserve Symlink can never silently turn into a full file copy.
## Why I think this should be generic
Although I developed and tested it with nzbDAV / InfiniDysk, the implementation does not contain any InfiniDysk-specific paths or APIs.
It should therefore also be useful for other download clients or storage systems that expose completed files as symlinks.
Example:
```text
Download client
↓
/mnt/nzbdav/completed-symlinks/audio/book.m4b
↓ symlink to
/mnt/nzbdav/.ids/<id>
↓
Listenarr Preserve Symlink
↓
/audiobooks/Author/Book/book.m4b
↓ same symlink target
/mnt/nzbdav/.ids/<id>
Current implementation / testing
I have a working implementation in my fork:
https://github.com/sawdoctor/Listenarr/tree/infinidysk-compat
The feature has been tested with:
- real nzbDAV / InfiniDysk audiobook imports
- multi-file audiobook imports
- Audiobookshelf reading the resulting library symlinks
- seeking/playback through the virtual files
- source-symlink → destination-symlink unit testing
- regular-file rejection testing
- frontend support for selecting
preserve-symlink
Targeted tests currently pass:
- frontend: 10 passed
- Preserve Symlink backend tests: 2 passed, 0 failed
The implementation deliberately fails closed if the completed source is not a symlink.
Upstream PR
If this is something you would accept upstream, I'm happy to prepare a clean PR rebased onto the latest canary.
My current fork branch also contains two unrelated fixes found during testing, so I would split those out and submit Preserve Symlink only in its own PR in accordance with the contribution guidelines.
Current implementation / testing
I have a working implementation in my fork:
https://github.com/sawdoctor/Listenarr/tree/infinidysk-compat
The feature has been tested with:
preserve-symlinkTargeted tests currently pass:
The implementation deliberately fails closed if the completed source is not a symlink.
Upstream PR
If this is something you would accept upstream, I'm happy to prepare a clean PR rebased onto the latest
canary.My current fork branch also contains two unrelated fixes found during testing, so I would split those out and submit Preserve Symlink only in its own PR in accordance with the contribution guidelines.