Ztorrent/internal/history/history.go

134 lines
2.8 KiB
Go

package history
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sync"
"time"
)
// Item represents a single downloaded torrent in history.
type Item struct {
InfoHash string `json:"info_hash"`
Name string `json:"name"`
TorrentPath string `json:"torrent_path"` // Magnet link or path to .torrent file
OutputDir string `json:"output_dir"`
Status string `json:"status"` // e.g. "downloading", "seeding", "stopped", "completed"
Progress float64 `json:"progress"`
Size int64 `json:"size"`
AddedAt time.Time `json:"added_at"`
}
var (
mu sync.Mutex
)
// getHistoryPath returns the path to ~/.ztrr/history.json
func getHistoryPath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
dir := filepath.Join(home, ".ztrr")
if err := os.MkdirAll(dir, 0755); err != nil {
return "", err
}
return filepath.Join(dir, "history.json"), nil
}
// Load reads all items from the history file.
func Load() ([]Item, error) {
mu.Lock()
defer mu.Unlock()
path, err := getHistoryPath()
if err != nil {
return nil, err
}
data, err := os.ReadFile(path)
if err != nil {
if os.IsNotExist(err) {
return []Item{}, nil
}
return nil, err
}
var items []Item
if err := json.Unmarshal(data, &items); err != nil {
return nil, err
}
return items, nil
}
// Save writes all items to the history file.
func Save(items []Item) error {
mu.Lock()
defer mu.Unlock()
path, err := getHistoryPath()
if err != nil {
return err
}
data, err := json.MarshalIndent(items, "", " ")
if err != nil {
return err
}
return os.WriteFile(path, data, 0644)
}
// Update adds or updates an item in the history.
func Update(item Item) error {
items, err := Load()
if err != nil {
return fmt.Errorf("failed to load history: %v", err)
}
found := false
for i, existing := range items {
if existing.InfoHash == item.InfoHash || (existing.InfoHash == "" && existing.TorrentPath == item.TorrentPath) {
// Maintain original added_at if we are updating
item.AddedAt = existing.AddedAt
if item.InfoHash == "" {
item.InfoHash = existing.InfoHash
}
items[i] = item
found = true
break
}
}
if !found {
if item.AddedAt.IsZero() {
item.AddedAt = time.Now()
}
items = append(items, item)
}
return Save(items)
}
// Remove deletes an item from the history.
func Remove(infoHash, torrentPath string) error {
items, err := Load()
if err != nil {
return fmt.Errorf("failed to load history: %v", err)
}
var newItems []Item
for _, existing := range items {
if existing.InfoHash == infoHash && existing.InfoHash != "" {
continue
}
if existing.TorrentPath == torrentPath && infoHash == "" {
continue
}
newItems = append(newItems, existing)
}
return Save(newItems)
}