package app import ( "context" "encoding/hex" "sync" "time" "github.com/veggiedefender/torrent-client/internal/config" "github.com/veggiedefender/torrent-client/internal/history" "github.com/veggiedefender/torrent-client/internal/tgbot" "github.com/veggiedefender/torrent-client/internal/torrent" ) type Controller struct { mu sync.Mutex engine *torrent.Engine ctx context.Context cancel context.CancelFunc currentPath string currentOut string } func NewController() *Controller { engine := torrent.NewEngine() ctx, cancel := context.WithCancel(context.Background()) return &Controller{ engine: engine, ctx: ctx, cancel: cancel, } } func (c *Controller) StartTorrent(path, outputRoot string) error { c.mu.Lock() if c.cancel != nil { c.cancel() } c.ctx, c.cancel = context.WithCancel(context.Background()) c.currentPath = path c.currentOut = outputRoot c.mu.Unlock() err := c.engine.LoadTorrent(path, outputRoot) if err != nil { return err } c.updateHistory() go func(ctx context.Context) { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() for { select { case <-ctx.Done(): return case <-ticker.C: c.updateHistory() } } }(c.ctx) return nil } func (c *Controller) StartTorrentDownload() { c.engine.StartDownload() } func (c *Controller) DownloadMagnet(magnetURI string) error { cfg, _ := config.Load() outDir := "." if cfg != nil && cfg.DefaultDir != "" { outDir = cfg.DefaultDir } return c.StartTorrent(magnetURI, outDir) } func (c *Controller) InitTelegramBot(token string) error { if token == "" { return nil } bot, err := tgbot.NewBot(c, token) if err != nil { return err } if bot != nil { bot.Start() } return nil } func (c *Controller) StopTorrent() { c.mu.Lock() if c.cancel != nil { c.cancel() } c.mu.Unlock() c.updateHistory() c.engine.Stop() } func (c *Controller) updateHistory() { status := c.engine.Status() if status.Phase == "" { return } hashHex := "" if len(status.InfoHash) > 0 { hashHex = hex.EncodeToString(status.InfoHash[:]) } c.mu.Lock() path := c.currentPath out := c.currentOut c.mu.Unlock() hItem := history.Item{ InfoHash: hashHex, Name: status.Name, TorrentPath: path, OutputDir: out, Status: status.Phase, Progress: c.engine.Progress() * 100, // store as percentage 0-100 Size: status.TotalBytes, } history.Update(hItem) } func (c *Controller) Progress() float64 { return c.engine.Progress() } func (c *Controller) Status() torrent.Status { if c.engine == nil { return torrent.Status{} } return c.engine.Status() } func (c *Controller) ToggleFilePriority(fileIdx int) { if c.engine != nil { c.engine.ToggleFilePriority(fileIdx) } }