Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added altmount
Binary file not shown.
17 changes: 16 additions & 1 deletion internal/config/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ type ImportConfig struct {
ImportStrategy ImportStrategy `yaml:"import_strategy" mapstructure:"import_strategy" json:"import_strategy"`
ImportDir *string `yaml:"import_dir" mapstructure:"import_dir" json:"import_dir,omitempty"`
SkipHealthCheck *bool `yaml:"skip_health_check" mapstructure:"skip_health_check" json:"skip_health_check,omitempty"`
WatchDir *string `yaml:"watch_dir" mapstructure:"watch_dir" json:"watch_dir,omitempty"`
WatchIntervalSeconds *int `yaml:"watch_interval_seconds" mapstructure:"watch_interval_seconds" json:"watch_interval_seconds,omitempty"`
}

// LogConfig represents logging configuration with rotation support
Expand Down Expand Up @@ -336,6 +338,16 @@ func (c *Config) Validate() error {
}
}

// Validate watch directory if configured
if c.Import.WatchDir != nil && *c.Import.WatchDir != "" {
if !filepath.IsAbs(*c.Import.WatchDir) {
return fmt.Errorf("import watch_dir must be an absolute path")
}
if c.Import.WatchIntervalSeconds != nil && *c.Import.WatchIntervalSeconds <= 0 {
return fmt.Errorf("import watch_interval_seconds must be greater than 0")
}
}

// Validate log level (both old and new config)
if c.Log.Level != "" {
validLevels := []string{"debug", "info", "warn", "error"}
Expand Down Expand Up @@ -830,7 +842,8 @@ func DefaultConfig(configDir ...string) *Config {
scrapperEnabled := false
fuseEnabled := false
loginRequired := true // Require login by default
skipHealthCheck := false
skipHealthCheck := true
watchIntervalSeconds := 10 // Default watch interval

// Set paths based on whether we're running in Docker or have a specific config directory
var dbPath, metadataPath, logPath, rclonePath, cachePath string
Expand Down Expand Up @@ -937,6 +950,8 @@ func DefaultConfig(configDir ...string) *Config {
ImportStrategy: ImportStrategyNone, // Default: no import strategy (direct import)
ImportDir: nil, // No default import directory
SkipHealthCheck: &skipHealthCheck,
WatchDir: nil,
WatchIntervalSeconds: &watchIntervalSeconds,
},
Log: LogConfig{
File: logPath, // Default log file path
Expand Down
19 changes: 6 additions & 13 deletions internal/health/library_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ import (
"os"
"path/filepath"
"testing"
"time"

"github.com/javi11/altmount/internal/config"
"github.com/javi11/altmount/internal/database"
"github.com/javi11/altmount/internal/metadata"
metapb "github.com/javi11/altmount/internal/metadata/proto"
_ "github.com/mattn/go-sqlite3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -87,18 +87,11 @@ func TestSyncLibrary_WorkerPool(t *testing.T) {
fileName := filepath.Join("movies", "movie_"+fmt.Sprintf("%d", i)+".mkv")

// Create a dummy metadata object
meta := metadataService.CreateFileMetadata(
1000,
"source.nzb",
0, // Status
nil,
0, // Encryption
"", "",
time.Now().Unix(),
nil,
"",
)
err := metadataService.WriteFileMetadata(fileName, meta)
meta := metadataService.CreateFileMetadata(
100, "test.nzb", metapb.FileStatus_FILE_STATUS_HEALTHY, nil,
metapb.Encryption_NONE, "", "", nil, nil, 0, nil, "",
)
err := metadataService.WriteFileMetadata(fileName, meta)
require.NoError(t, err)
}

Expand Down
2 changes: 2 additions & 0 deletions internal/importer/multifile/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ func ProcessRegularFiles(
file.Encryption,
file.Password,
file.Salt,
file.AesKey,
file.AesIv,
file.ReleaseDate.Unix(),
par2Refs,
file.NzbdavID,
Expand Down
32 changes: 27 additions & 5 deletions internal/importer/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package parser

import (
"context"
"encoding/base64"
stderrors "errors"
"fmt"
"io"
Expand Down Expand Up @@ -295,12 +296,31 @@ func (p *Parser) parseFile(ctx context.Context, meta map[string]string, nzbFilen
filename := info.Filename
enc := metapb.Encryption_NONE // Default to no encryption
var nzbdavID string
var aesKey []byte
var aesIv []byte

// Extract nzbdavID from subject if present
// Extract extra metadata from subject if present (nzbdav compatibility)
if strings.HasPrefix(info.NzbFile.Subject, "NZBDAV_ID:") {
parts := strings.SplitN(info.NzbFile.Subject, " ", 2)
if len(parts) > 0 {
nzbdavID = strings.TrimPrefix(parts[0], "NZBDAV_ID:")
parts := strings.Split(info.NzbFile.Subject, " ")
for _, part := range parts {
if strings.HasPrefix(part, "NZBDAV_ID:") {
nzbdavID = strings.TrimPrefix(part, "NZBDAV_ID:")
} else if strings.HasPrefix(part, "AES_KEY:") {
keyStr := strings.TrimPrefix(part, "AES_KEY:")
if key, err := base64.StdEncoding.DecodeString(keyStr); err == nil {
aesKey = key
enc = metapb.Encryption_AES
}
} else if strings.HasPrefix(part, "AES_IV:") {
ivStr := strings.TrimPrefix(part, "AES_IV:")
if iv, err := base64.StdEncoding.DecodeString(ivStr); err == nil {
aesIv = iv
}
} else if strings.HasPrefix(part, "DECODED_SIZE:") {
if size, err := strconv.ParseInt(strings.TrimPrefix(part, "DECODED_SIZE:"), 10, 64); err == nil && size > 0 {
totalSize = size
}
}
}
}

Expand Down Expand Up @@ -365,6 +385,8 @@ func (p *Parser) parseFile(ctx context.Context, meta map[string]string, nzbFilen
Encryption: enc,
Password: password,
Salt: salt,
AesKey: aesKey,
AesIv: aesIv,
ReleaseDate: info.ReleaseDate,
IsPar2Archive: info.IsPar2Archive,
OriginalIndex: info.OriginalIndex,
Expand Down Expand Up @@ -784,4 +806,4 @@ func (p *Parser) ValidateNzb(parsed *ParsedNzb) error {
}

return nil
}
}
2 changes: 2 additions & 0 deletions internal/importer/parser/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,6 @@ type ParsedFile struct {
ReleaseDate time.Time // Release date from the Usenet post
OriginalIndex int // Original position in the parsed NZB file list
NzbdavID string // Original ID from nzbdav (for backward compatibility)
AesKey []byte // AES encryption key (for nzbdav compatibility)
AesIv []byte // AES initialization vector (for nzbdav compatibility)
}
9 changes: 7 additions & 2 deletions internal/importer/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func NewProcessor(metadataService *metadata.MetadataService, poolManager pool.Ma
}

// ProcessNzbFile processes an NZB or STRM file maintaining the folder structure relative to relative path
func (proc *Processor) ProcessNzbFile(ctx context.Context, filePath, relativePath string, queueID int, allowedExtensionsOverride *[]string) (string, error) {
func (proc *Processor) ProcessNzbFile(ctx context.Context, filePath, relativePath string, queueID int, allowedExtensionsOverride *[]string, virtualDirOverride *string) (string, error) {
// Determine max connections to use
maxConnections := proc.maxImportConnections

Expand Down Expand Up @@ -207,7 +207,12 @@ func NewProcessor(metadataService *metadata.MetadataService, poolManager pool.Ma
}

// Step 2: Calculate virtual directory
virtualDir := filesystem.CalculateVirtualDirectory(filePath, relativePath)
virtualDir := ""
if virtualDirOverride != nil {
virtualDir = *virtualDirOverride
} else {
virtualDir = filesystem.CalculateVirtualDirectory(filePath, relativePath)
}

proc.log.InfoContext(ctx, "Processing file",
"file_path", filePath,
Expand Down
Loading