feat(par2): generate single PAR2 set per folder with relative paths in FileDesc#225
Merged
Merged
Conversation
…eDesc Fixes #219 — SABnzbd/NZBGet now reconstruct the original folder tree when downloading a postie-generated NZB, matching the behavior of nyuu. ## Root cause * SABnzbd's `quick_check_set()` reads PAR2 FileDesc filenames and calls `renamer(..., create_local_directories=True)` using those names. If the FileDesc contains a relative path (e.g. `folder2/file.txt`) the directory is recreated on disk. * par2go v0.0.7 hardcoded `filepath.Base(path)` in `quickScanFile`, so every FileDesc carried only the bare filename — no folder tree. * postie also generated a separate PAR2 set per file instead of one set for the whole folder, so there was no shared set to carry the tree. ## Changes ### `Par2Executor` interface — new `CreateSet` method `internal/par2/par2.go` and `internal/par2/binary.go` gain a `CreateSet(ctx, files, outputDir, setName)` entrypoint that generates **one PAR2 set covering all files** in a folder, with each FileDesc carrying the file's `RelativePath` (forward-slash separated). * `NativeExecutor.CreateSet` uses the new `par2go v0.0.8` `CreateWithNames` API to embed relative paths in FileDesc packets. * `BinaryExecutor.CreateSet` invokes parpar with `--filepath-base <commonRoot> --filepath-format outrel` so parpar derives the relative path from each input's disk path. * `checkExistingPar2SetInPath` detects pre-existing sets by set name, avoiding redundant regeneration. ### Caller update — `pkg/postie/postie.go` `postFolder` now calls `CreateSet` with the folder name as the set name instead of two separate `CreateInDirectory` calls. ### Dependency bump `github.com/javi11/par2go` v0.0.7 → v0.0.8, which adds `InputFile` / `CreateWithNames` for per-file logical name overrides. ### Tests * `internal/par2/par2_integration_test.go` — integration test that creates a real multi-file folder tree, runs `NativeExecutor.CreateSet`, then parses the resulting PAR2 binary to verify each FileDesc contains the correct relative path (e.g. `folder2/file2.txt`). * `pkg/postie/postfolder_test.go` — `mockPar2Executor` gains a `CreateSet` stub so existing postFolder unit tests continue to compile and pass.
- Add `folderDir string` parameter to `Par2Executor.CreateSet` interface so both executors receive the on-disk root of the folder being posted. - NativeExecutor: compute each file's FileDesc name via `filepath.Rel(folderDir, file.Path)` instead of using RelativePath verbatim. RelativePath includes the top-level folder name as a prefix (e.g. "ShowS01/extras/bonus.mkv") which would cause SABnzbd to double-nest the reconstructed directory tree. The Rel-based path produces "extras/bonus.mkv" as SABnzbd expects. - BinaryExecutor: pass folderDir directly as --filepath-base instead of the fragile commonParentDir() derivation, which silently dropped the subdirectory prefix when all input files were in the same subdir. Remove the now-unused commonParentDir / commonPrefixDir helpers. - postie.go: both CreateSet call sites now derive `folderDir = filepath.Join(rootDir, folderName)` and forward it. - Integration test: update expected FileDesc names to reflect the fix and add TestIntegration_NativeExecutor_CreateSet_AllFilesInSubdir to guard the single-subdirectory edge case.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #219 — SABnzbd and NZBGet now reconstruct the original folder hierarchy after downloading a postie-generated NZB, matching the behavior nyuu users expect.
Root cause
SABnzbd's
quick_check_set()reads the filename field of each PAR2 FileDesc packet and callsrenamer(..., create_local_directories=True)with that value. If the field holds a relative path likefolder2/file.txt, the subdirectory is recreated on disk. If it holds onlyfile.txt, everything lands flat.Two bugs conspired:
filepath.Base(path)inquickScanFile, so FileDesc always contained bare filenames.CreateInDirectoryonce per file, producing N independent PAR2 sets instead of one set covering the whole folder. A single shared set is required to carry the folder-relative paths.What changed
New
CreateSetmethod onPar2Executorinternal/par2/par2.go(NativeExecutor) andinternal/par2/binary.go(BinaryExecutor) both gain:par2go v0.0.8CreateWithNamesAPI. Each input file is paired with itsRelativePath(forward-slash separated) so par2go embeds that path verbatim in the FileDesc packet.--filepath-base <commonRoot> --filepath-format outrelso parpar derives the relative path automatically from each file's disk path.checkExistingPar2SetInPathdetects a pre-existing set by name to skip redundant regeneration.Caller —
pkg/postie/postie.gopostFolderreplaces the two separateCreateInDirectorycalls with a singleCreateSet(ctx, files, par2OutputDir, folderName).Dependency
github.com/javi11/par2gobumped from v0.0.7 → v0.0.8, which addsInputFile/CreateWithNames(PR javi11/par2go#5).Tests
internal/par2/par2_integration_test.gofolder1/folder2/file.txttree, runsNativeExecutor.CreateSet, parses the resulting PAR2 binary, asserts each FileDesc contains the correct relative pathpkg/postie/postfolder_test.gomockPar2Executorgains aCreateSetstub so existing unit tests compile and passBackward compatibility
postFile) still use the existing per-fileCreateInDirectorypath — no behaviour change.MaintainPar2Filesmode continues to work;CreateSetrespects the sameoutputDirrouting.