local

package
v0.80.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsPlayable

func IsPlayable(name string) bool

IsPlayable returns true if the filename's extension is a known video/audio type.

Types

type Browser

type Browser struct {
	// contains filtered or unexported fields
}

func NewBrowser

func NewBrowser(mounts []config.ExternalMount) *Browser

func (*Browser) Config

func (b *Browser) Config() []config.ExternalMount

Config returns a copy of the raw mount config (admin-only; includes AllowedUsers).

func (*Browser) IsUserSubpath

func (b *Browser) IsUserSubpath(mountName string) bool

IsUserSubpath reports whether the named mount uses per-user subdirectories.

func (*Browser) List

func (b *Browser) List(mountName, relPath string) ([]Entry, error)

func (*Browser) MigrateToUserSubpath

func (b *Browser) MigrateToUserSubpath(mountName string, knownUsers map[string]bool, fallbackUser string, attribute func(absPath string) (string, bool)) (MigrationResult, error)

MigrateToUserSubpath relocates loose entries at a UserSubpath mount's root into per-user subdirs (mount/{username}/...), so flipping a previously-shared mount to per-user doesn't orphan existing files.

attribute maps an entry's absolute path to (username, true) when an owner is known; entries it can't attribute (or whose owner isn't a known user) go to fallbackUser. knownUsers is the set of valid usernames: a root *directory* whose name is a known user is treated as already-scoped and left untouched, which makes the operation idempotent (safe to run on every boot). Moves use os.Rename — atomic and copy-free since source and dest share the mount root.

func (*Browser) Mounts

func (b *Browser) Mounts() []Mount

func (*Browser) MountsFor

func (b *Browser) MountsFor(username string) []Mount

MountsFor returns mounts visible to the given username. Empty username = only public mounts (AllowedUsers empty).

func (*Browser) RemoveEmptyDirs

func (b *Browser) RemoveEmptyDirs(mountName, relPath string) (int, error)

RemoveEmptyDirs deletes empty subdirectories under relPath inside the mount, bottom-up so a directory that only held now-removed empty children is itself removed. Returns how many directories were deleted.

Safety: the start directory itself and the mount root are never removed; hidden dirs (".thumbs", ".artwork", …) are skipped entirely; os.Remove only succeeds on a truly empty dir (non-empty → ENOTEMPTY, ignored). Path traversal is already guarded by ResolvePath.

func (*Browser) ResolvePath

func (b *Browser) ResolvePath(mountName, relPath string) (string, error)

ResolvePath joins mount.Path with relPath safely, rejecting any attempt to escape the mount root via "..", absolute paths, or symlink-like trickery. Returns the absolute path on disk.

func (*Browser) ResolvePathFor

func (b *Browser) ResolvePathFor(mountName, relPath, username string) (string, error)

ResolvePathFor is like ResolvePath but respects UserSubpath mounts for the given user.

func (*Browser) SetFolderLock

func (b *Browser) SetFolderLock(mountName, relPath string, locked bool) error

SetFolderLock pins (locked=true) or unpins a directory by creating/removing the keep marker inside it. Pinned folders survive RemoveEmptyDirs. The path must resolve to a directory inside the mount (ResolvePath guards traversal); the mount root itself can't be pinned. Idempotent: locking an already-locked folder (or unlocking an unlocked one) is a no-op success.

func (*Browser) SetMounts

func (b *Browser) SetMounts(mounts []config.ExternalMount)

SetMounts swaps the live mount configuration (used by the admin mounts editor so changes apply without a restart).

func (*Browser) StripUserScope

func (b *Browser) StripUserScope(mountName, username string, entries []Entry) []Entry

StripUserScope removes the leading username prefix from Entry paths for UserSubpath mounts, so the frontend sees paths as if the mount root were the user's personal subdir.

func (*Browser) UserCanAccess

func (b *Browser) UserCanAccess(username, mountName string) bool

UserCanAccess checks if a username is allowed to access a given mount name. It iterates effectiveMounts (NOT the raw snapshot) so an unrestricted duplicate can never grant access that its restricted twin denies.

func (*Browser) UserScopedPath

func (b *Browser) UserScopedPath(mountName, relPath, username string) string

UserScopedPath prepends the username to relPath for UserSubpath mounts. For regular mounts, returns relPath unchanged. Safe to use on all mounts.

func (*Browser) Walk

func (b *Browser) Walk(mountName, relPath string, mediaOnly bool) ([]Entry, error)

Walk recursively lists all files (not dirs) under relPath inside the given mount. If mediaOnly is true, only files with a playable extension are returned. Paths in each Entry are relative to the mount root — same format as List.

type Entry

type Entry struct {
	Name       string    `json:"name"`
	Path       string    `json:"path"`
	IsDir      bool      `json:"isDir"`
	Size       int64     `json:"size"`
	ModTime    time.Time `json:"modTime"`
	IsPlayable bool      `json:"isPlayable"`
	// ChildCount is the number of (non-hidden) entries directly inside a
	// directory — shown in the UI where files show their size. 0 for files.
	ChildCount int `json:"childCount"`
	// Locked marks a directory the user pinned (a ".keep" marker inside) so
	// "clean empty folders" never removes it even when it holds no files.
	Locked bool `json:"locked,omitempty"`
	// Incomplete flags a download still in progress: a ".part" file, or a
	// directory whose tree still holds one. Lets the browser show a "baixando"
	// indicator instead of presenting a half-written file as if it were ready.
	Incomplete bool `json:"incomplete,omitempty"`
}

type MigratedEntry

type MigratedEntry struct {
	Name     string // the entry's filename at the (old) mount root
	ToUser   string // the username subdir it was moved into
	Fallback bool   // true when attribution failed and it went to fallbackUser
}

MigratedEntry records one relocated root entry during a UserSubpath migration.

type MigrationResult

type MigrationResult struct {
	Mount     string
	Moved     []MigratedEntry
	Skipped   int // entries already inside a known user's subdir (idempotency)
	Active    int // entries left in place because they're downloads in progress (.part)
	Conflicts int // entries left in place because the per-user dest already exists
}

MigrationResult summarizes a MigrateToUserSubpath run.

type Mount

type Mount struct {
	Name        string `json:"name"`
	Path        string `json:"path"`
	UserSubpath bool   `json:"userSubpath"` // per-user subdirs — drives the admin "view as user" selector
	Restricted  bool   `json:"restricted"`  // visible only to specific users (AllowedUsers non-empty); names NOT exposed here
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL