- Add mounting support

- Fix minor issues
This commit is contained in:
Mukhtar Akere
2025-08-04 16:57:09 +01:00
parent a60d93677f
commit 139249a1f3
25 changed files with 1565 additions and 112 deletions

View File

@@ -14,6 +14,7 @@ import (
"github.com/sirrobot01/decypharr/pkg/debrid/providers/torbox"
"github.com/sirrobot01/decypharr/pkg/debrid/store"
"github.com/sirrobot01/decypharr/pkg/debrid/types"
"github.com/sirrobot01/decypharr/pkg/mount"
"sync"
)
@@ -30,6 +31,12 @@ func (de *Debrid) Cache() *store.Cache {
return de.cache
}
func (de *Debrid) Reset() {
if de.cache != nil {
de.cache.Reset()
}
}
type Storage struct {
debrids map[string]*Debrid
mu sync.RWMutex
@@ -43,16 +50,28 @@ func NewStorage() *Storage {
debrids := make(map[string]*Debrid)
bindAddress := cfg.BindAddress
if bindAddress == "" {
bindAddress = "localhost"
}
webdavUrl := fmt.Sprintf("http://%s:%s%s/webdav", bindAddress, cfg.Port, cfg.URLBase)
for _, dc := range cfg.Debrids {
client, err := createDebridClient(dc)
if err != nil {
_logger.Error().Err(err).Str("Debrid", dc.Name).Msg("failed to connect to debrid client")
continue
}
var cache *store.Cache
var (
cache *store.Cache
mounter *mount.Mount
)
_log := client.Logger()
if dc.UseWebDav {
cache = store.NewDebridCache(dc, client)
if cfg.Rclone.Enabled {
mounter = mount.NewMount(dc.Name, webdavUrl)
}
cache = store.NewDebridCache(dc, client, mounter)
_log.Info().Msg("Debrid Service started with WebDAV")
} else {
_log.Info().Msg("Debrid Service started")
@@ -102,8 +121,17 @@ func (d *Storage) Client(name string) types.Client {
func (d *Storage) Reset() {
d.mu.Lock()
defer d.mu.Unlock()
// Reset all debrid clients and caches
for _, debrid := range d.debrids {
if debrid != nil {
debrid.Reset()
}
}
// Reinitialize the debrids map
d.debrids = make(map[string]*Debrid)
d.mu.Unlock()
d.lastUsed = ""
}

View File

@@ -46,7 +46,7 @@ type RealDebrid struct {
addSamples bool
Profile *types.Profile
minimumFreeSlot int // Minimum number of active pots to maintain (used for cached stuffs, etc.)
limit int
}
func New(dc config.Debrid) (*RealDebrid, error) {
@@ -101,6 +101,7 @@ func New(dc config.Debrid) (*RealDebrid, error) {
checkCached: dc.CheckCached,
addSamples: dc.AddSamples,
minimumFreeSlot: dc.MinimumFreeSlot,
limit: dc.Limit,
}
if _, err := r.GetProfile(); err != nil {
@@ -794,6 +795,10 @@ func (r *RealDebrid) getTorrents(offset int, limit int) (int, []*types.Torrent,
func (r *RealDebrid) GetTorrents() ([]*types.Torrent, error) {
limit := 5000
if r.limit != 0 {
limit = r.limit
}
hardLimit := r.limit
// Get first batch and total count
allTorrents := make([]*types.Torrent, 0)
@@ -812,6 +817,10 @@ func (r *RealDebrid) GetTorrents() ([]*types.Torrent, error) {
}
allTorrents = append(allTorrents, torrents...)
offset += totalTorrents
if hardLimit != 0 && len(allTorrents) >= hardLimit {
// If hard limit is set, stop fetching more torrents
break
}
}
if fetchError != nil {

View File

@@ -6,6 +6,7 @@ import (
"context"
"errors"
"fmt"
"github.com/sirrobot01/decypharr/pkg/mount"
"os"
"path"
"path/filepath"
@@ -106,9 +107,10 @@ type Cache struct {
config config.Debrid
customFolders []string
mounter *mount.Mount
}
func NewDebridCache(dc config.Debrid, client types.Client) *Cache {
func NewDebridCache(dc config.Debrid, client types.Client, mounter *mount.Mount) *Cache {
cfg := config.Get()
cet, err := time.LoadLocation("CET")
if err != nil {
@@ -163,6 +165,7 @@ func NewDebridCache(dc config.Debrid, client types.Client) *Cache {
config: dc,
customFolders: customFolders,
mounter: mounter,
ready: make(chan struct{}),
}
@@ -186,6 +189,15 @@ func (c *Cache) StreamWithRclone() bool {
// and before you discard the instance on a restart.
func (c *Cache) Reset() {
// Unmount first
if c.mounter != nil && c.mounter.IsMounted() {
if err := c.mounter.Unmount(); err != nil {
c.logger.Error().Err(err).Msgf("Failed to unmount %s", c.config.Name)
} else {
c.logger.Info().Msgf("Unmounted %s", c.config.Name)
}
}
if err := c.scheduler.StopJobs(); err != nil {
c.logger.Error().Err(err).Msg("Failed to stop scheduler jobs")
}
@@ -198,7 +210,9 @@ func (c *Cache) Reset() {
c.listingDebouncer.Stop()
// Close the repair channel
close(c.repairChan)
if c.repairChan != nil {
close(c.repairChan)
}
// 1. Reset torrent storage
c.torrents.reset()
@@ -219,6 +233,9 @@ func (c *Cache) Reset() {
// 6. Reset repair channel so the next Start() can spin it up
c.repairChan = make(chan RepairRequest, 100)
// Reset the ready channel
c.ready = make(chan struct{})
}
func (c *Cache) Start(ctx context.Context) error {
@@ -250,10 +267,15 @@ func (c *Cache) Start(ctx context.Context) error {
addr := cfg.BindAddress + ":" + cfg.Port + cfg.URLBase + "webdav/" + name + "/"
c.logger.Info().Msgf("%s WebDav server running at %s", name, addr)
<-ctx.Done()
c.logger.Info().Msgf("Stopping %s WebDav server", name)
c.Reset()
if c.mounter != nil {
if err := c.mounter.Mount(ctx); err != nil {
c.logger.Error().Err(err).Msgf("Failed to mount %s", c.config.Name)
} else {
c.logger.Info().Msgf("Mounted %s at %s", c.config.Name, c.mounter.LocalPath)
}
} else {
c.logger.Warn().Msgf("Mounting is disabled for %s", c.config.Name)
}
return nil
}
@@ -881,3 +903,7 @@ func (c *Cache) RemoveFile(torrentId string, filename string) error {
func (c *Cache) Logger() zerolog.Logger {
return c.logger
}
func (c *Cache) GetConfig() config.Debrid {
return c.config
}

View File

@@ -127,6 +127,21 @@ func (c *Cache) refreshTorrents(ctx context.Context) {
func (c *Cache) refreshRclone() error {
cfg := c.config
dirs := strings.FieldsFunc(cfg.RcRefreshDirs, func(r rune) bool {
return r == ',' || r == '&'
})
if len(dirs) == 0 {
dirs = []string{"__all__"}
}
if c.mounter != nil {
return c.mounter.Refresh(dirs)
} else {
return c.refreshRcloneWithRC(dirs)
}
}
func (c *Cache) refreshRcloneWithRC(dirs []string) error {
cfg := c.config
if cfg.RcUrl == "" {
return nil
@@ -138,7 +153,7 @@ func (c *Cache) refreshRclone() error {
client := http.DefaultClient
// Create form data
data := c.buildRcloneRequestData()
data := c.buildRcloneRequestData(dirs)
if err := c.sendRcloneRequest(client, "vfs/forget", data); err != nil {
c.logger.Error().Err(err).Msg("Failed to send rclone vfs/forget request")
@@ -151,16 +166,7 @@ func (c *Cache) refreshRclone() error {
return nil
}
func (c *Cache) buildRcloneRequestData() string {
cfg := c.config
dirs := strings.FieldsFunc(cfg.RcRefreshDirs, func(r rune) bool {
return r == ',' || r == '&'
})
if len(dirs) == 0 {
return "dir=__all__"
}
func (c *Cache) buildRcloneRequestData(dirs []string) string {
var data strings.Builder
for index, dir := range dirs {
if dir != "" {