Settings -> Media servers -> "Hide quarantine from Plex" writes a .plexignore into every pair's quarantine folder (.playlink-trash by default), with patterns for every folder depth quarantined files live at. Quarantine folders opened later get the file automatically. The file carries a marker line: turning the option off removes only playlink's own file, and an existing .plexignore written by someone else is never overwritten or deleted (reported instead). Writes go through a temporary file and a rename. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
75 lines
2.3 KiB
Go
75 lines
2.3 KiB
Go
package engine
|
|
|
|
import (
|
|
"errors"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/cdnutter/playlink/internal/store"
|
|
)
|
|
|
|
func TestPlexIgnoreToggle(t *testing.T) {
|
|
ev := setup(t, false)
|
|
q := ev.pair.QuarantineDir
|
|
ignore := filepath.Join(q, PlexIgnoreName)
|
|
|
|
if err := ev.st.SetSetting(ctx, "plex_ignore", "1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
res := ev.e.ApplyPlexIgnore(ctx, true)
|
|
if len(res) != 1 || res[0].Error != "" {
|
|
t.Fatalf("apply: %+v", res)
|
|
}
|
|
b, err := os.ReadFile(ignore)
|
|
if err != nil || !strings.HasPrefix(string(b), plexIgnoreMarker) || !strings.Contains(string(b), "\n*\n*/*\n") {
|
|
t.Fatalf("expected playlink's .plexignore, got %q (%v)", b, err)
|
|
}
|
|
|
|
// A quarantine created later (new pair) gets the file automatically.
|
|
other := store.Pair{Name: "other", MasterRoot: ev.master, SlaveRoot: ev.slave, QuarantineDir: filepath.Join(ev.root, "q2")}
|
|
if _, err := ev.e.NormalizePair(&other); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(ev.root, "q2", PlexIgnoreName)); err != nil {
|
|
t.Fatalf("new quarantine folder should get a .plexignore: %v", err)
|
|
}
|
|
|
|
// Turning it off removes playlink's file.
|
|
if err := ev.st.SetSetting(ctx, "plex_ignore", "0"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ev.e.ApplyPlexIgnore(ctx, false)
|
|
if _, err := os.Stat(ignore); !errors.Is(err, os.ErrNotExist) {
|
|
t.Fatal(".plexignore should be removed when the option is turned off")
|
|
}
|
|
}
|
|
|
|
func TestPlexIgnoreLeavesUserFileAlone(t *testing.T) {
|
|
dir := t.TempDir()
|
|
p := filepath.Join(dir, PlexIgnoreName)
|
|
os.WriteFile(p, []byte("my own rules\n"), 0o644)
|
|
if err := syncPlexIgnore(dir, true); !errors.Is(err, ErrForeignIgnore) {
|
|
t.Fatalf("want ErrForeignIgnore, got %v", err)
|
|
}
|
|
if err := syncPlexIgnore(dir, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if b, _ := os.ReadFile(p); string(b) != "my own rules\n" {
|
|
t.Fatal("a user's .plexignore must never be changed or removed")
|
|
}
|
|
}
|
|
|
|
func TestPlexIgnoreCoversDeepQuarantinePaths(t *testing.T) {
|
|
lines := strings.Split(strings.TrimSpace(string(plexIgnoreContent())), "\n")
|
|
deepest := lines[len(lines)-1]
|
|
// e.g. 12/slave/Artist/Album/Disc 1/01 Song.flac is 6 levels deep.
|
|
if strings.Count(deepest, "*") < 6 {
|
|
t.Fatalf("patterns do not reach deep enough: %q", deepest)
|
|
}
|
|
if err := syncPlexIgnore(t.TempDir(), true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|