Use json instead
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
package torrent
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/gob"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -56,7 +56,7 @@ func NewTorrentManager(cfg config.ConfigInterface, api *realdebrid.RealDebrid, p
|
||||
ResponseCache: cache,
|
||||
accessKeySet: set.NewStringSet(),
|
||||
latestState: &initialSate,
|
||||
requiredVersion: "18.11.2023",
|
||||
requiredVersion: "02.12.2023",
|
||||
workerPool: p,
|
||||
log: log,
|
||||
}
|
||||
@@ -317,27 +317,18 @@ func (t *TorrentManager) startRefreshJob() {
|
||||
// getMoreInfo gets original name, size and files for a torrent
|
||||
func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent {
|
||||
infoCache, _ := t.DirectoryMap.Get(INT_INFO_CACHE)
|
||||
if tor, exists := infoCache.Get(rdTorrent.ID); exists {
|
||||
// in memory cache is always fresh
|
||||
if tor, exists := infoCache.Get(rdTorrent.ID); exists && tor.SelectedFiles.Count() == len(rdTorrent.Links) {
|
||||
return tor
|
||||
}
|
||||
|
||||
var info *realdebrid.TorrentInfo
|
||||
var err error
|
||||
torrentFromFile := t.readTorrentFromFile(rdTorrent.ID)
|
||||
// check staleness of file cache
|
||||
if torrentFromFile != nil && len(torrentFromFile.ID) > 0 && len(torrentFromFile.Links) > 0 && len(torrentFromFile.Links) == len(rdTorrent.Links) && torrentFromFile.Links[0] == rdTorrent.Links[0] {
|
||||
info = torrentFromFile
|
||||
info.Progress = rdTorrent.Progress
|
||||
} else {
|
||||
torrentFromFile = nil
|
||||
if torrentFromFile != nil && torrentFromFile.SelectedFiles.Count() == len(rdTorrent.Links) {
|
||||
return torrentFromFile
|
||||
}
|
||||
if info == nil {
|
||||
info, err = t.Api.GetTorrentInfo(rdTorrent.ID)
|
||||
if err != nil {
|
||||
t.log.Warnf("Cannot get info for id=%s: %v\n", rdTorrent.ID, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
info, err := t.Api.GetTorrentInfo(rdTorrent.ID)
|
||||
if err != nil {
|
||||
t.log.Warnf("Cannot get info for id=%s: %v\n", rdTorrent.ID, err)
|
||||
return nil
|
||||
}
|
||||
// SelectedFiles is a subset of Files with only the selected ones
|
||||
// it also has a Link field, which can be empty
|
||||
@@ -373,18 +364,18 @@ func (t *TorrentManager) getMoreInfo(rdTorrent realdebrid.Torrent) *Torrent {
|
||||
torrent := Torrent{
|
||||
AccessKey: t.computeAccessKey(info.Name, info.OriginalName),
|
||||
LatestAdded: info.Added,
|
||||
Instances: []realdebrid.TorrentInfo{*info},
|
||||
Instances: []*realdebrid.TorrentInfo{info},
|
||||
}
|
||||
torrent.SelectedFiles = cmap.New[*File]()
|
||||
for _, file := range selectedFiles {
|
||||
torrent.SelectedFiles.Set(filepath.Base(file.Path), file)
|
||||
}
|
||||
|
||||
if len(selectedFiles) > 0 && torrentFromFile == nil {
|
||||
t.writeTorrentToFile(info) // only when there are selected files, else it's useless
|
||||
}
|
||||
|
||||
infoCache.Set(rdTorrent.ID, &torrent)
|
||||
err = t.writeTorrentToFile(rdTorrent.ID, &torrent)
|
||||
if err != nil {
|
||||
t.log.Warnf("Cannot write torrent to file: %v", err)
|
||||
}
|
||||
|
||||
return &torrent
|
||||
}
|
||||
@@ -403,28 +394,31 @@ func (t *TorrentManager) computeAccessKey(name, originalName string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TorrentManager) writeTorrentToFile(torrent *realdebrid.TorrentInfo) error {
|
||||
filePath := "data/" + torrent.ID + ".bin"
|
||||
func (t *TorrentManager) writeTorrentToFile(instanceID string, torrent *Torrent) error {
|
||||
filePath := "data/" + instanceID + ".json"
|
||||
file, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed creating file: %w", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
w := bufio.NewWriter(file)
|
||||
defer w.Flush()
|
||||
|
||||
torrent.Version = t.requiredVersion
|
||||
dataEncoder := gob.NewEncoder(w)
|
||||
if err := dataEncoder.Encode(torrent); err != nil {
|
||||
return fmt.Errorf("failed encoding torrent: %w", err)
|
||||
|
||||
jsonData, err := json.Marshal(torrent)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed marshaling torrent: %w", err)
|
||||
}
|
||||
t.log.Debugf("Saved torrent %s to file", torrent.ID)
|
||||
|
||||
if _, err := file.Write(jsonData); err != nil {
|
||||
return fmt.Errorf("failed writing to file: %w", err)
|
||||
}
|
||||
|
||||
t.log.Debugf("Saved torrent %s to file", instanceID)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TorrentManager) readTorrentFromFile(torrentID string) *realdebrid.TorrentInfo {
|
||||
filePath := "data/" + torrentID + ".bin"
|
||||
func (t *TorrentManager) readTorrentFromFile(torrentID string) *Torrent {
|
||||
filePath := "data/" + torrentID + ".json"
|
||||
file, err := os.Open(filePath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@@ -435,23 +429,25 @@ func (t *TorrentManager) readTorrentFromFile(torrentID string) *realdebrid.Torre
|
||||
return nil
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
r := bufio.NewReader(file)
|
||||
var torrent realdebrid.TorrentInfo
|
||||
dataDecoder := gob.NewDecoder(r)
|
||||
if err := dataDecoder.Decode(&torrent); err != nil {
|
||||
t.log.Debugf("[file] error decoding torrent: %v", err)
|
||||
jsonData, err := io.ReadAll(file)
|
||||
if err != nil {
|
||||
t.log.Debugf("[file] error reading file: %v", err)
|
||||
return nil
|
||||
}
|
||||
var torrent *Torrent
|
||||
if err := json.Unmarshal(jsonData, &torrent); err != nil {
|
||||
t.log.Debugf("[file] error unmarshaling torrent: %v", err)
|
||||
return nil
|
||||
}
|
||||
if torrent.Version != t.requiredVersion {
|
||||
t.log.Debugf("[file] not the right version: %s", torrent.Version)
|
||||
return nil
|
||||
}
|
||||
return &torrent
|
||||
return torrent
|
||||
}
|
||||
|
||||
func (t *TorrentManager) deleteTorrentFile(torrentID string) {
|
||||
filePath := "data/" + torrentID + ".bin"
|
||||
filePath := "data/" + torrentID + ".json"
|
||||
err := os.Remove(filePath)
|
||||
if err != nil {
|
||||
t.log.Warnf("Cannot delete file %s: %v", filePath, err)
|
||||
@@ -567,18 +563,17 @@ func (t *TorrentManager) checkForOtherDeletedTorrents() {
|
||||
}
|
||||
|
||||
func (t *TorrentManager) CheckDeletedState(torrent *Torrent) bool {
|
||||
unselected := 0
|
||||
var unselectedIDs []int
|
||||
torrent.SelectedFiles.IterCb(func(_ string, file *File) {
|
||||
if file.Link == "unselect" {
|
||||
unselected++
|
||||
unselectedIDs = append(unselectedIDs, file.ID)
|
||||
}
|
||||
})
|
||||
if unselected == torrent.SelectedFiles.Count() && unselected > 0 {
|
||||
if len(unselectedIDs) == torrent.SelectedFiles.Count() && len(unselectedIDs) > 0 {
|
||||
return true
|
||||
} else if unselected > 0 {
|
||||
// save to file
|
||||
} else if len(unselectedIDs) > 0 {
|
||||
for i := range torrent.Instances {
|
||||
t.writeTorrentToFile(&torrent.Instances[i])
|
||||
t.writeTorrentToFile(torrent.Instances[i].ID, torrent)
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
@@ -1,16 +1,68 @@
|
||||
package torrent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/debridmediamanager/zurg/pkg/realdebrid"
|
||||
cmap "github.com/orcaman/concurrent-map/v2"
|
||||
)
|
||||
|
||||
type Torrent struct {
|
||||
AccessKey string
|
||||
SelectedFiles cmap.ConcurrentMap[string, *File]
|
||||
LatestAdded string
|
||||
AccessKey string `json:"AccessKey"`
|
||||
SelectedFiles cmap.ConcurrentMap[string, *File] `json:"-"`
|
||||
LatestAdded string `json:"LatestAdded"`
|
||||
Version string `json:"Version"`
|
||||
|
||||
Instances []realdebrid.TorrentInfo
|
||||
Instances []*realdebrid.TorrentInfo `json:"Instances"`
|
||||
}
|
||||
|
||||
func (t *Torrent) MarshalJSON() ([]byte, error) {
|
||||
type Alias Torrent
|
||||
temp := &struct {
|
||||
SelectedFilesJson json.RawMessage `json:"SelectedFiles"`
|
||||
// InstancesJson json.RawMessage `json:"Instances"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(t),
|
||||
}
|
||||
selectedFilesJson, err := t.SelectedFiles.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
temp.SelectedFilesJson = selectedFilesJson
|
||||
// instancesJson, err := json.Marshal(t.Instances)
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// temp.InstancesJson = instancesJson
|
||||
return json.Marshal(temp)
|
||||
}
|
||||
|
||||
func (t *Torrent) UnmarshalJSON(data []byte) error {
|
||||
type Alias Torrent
|
||||
temp := &struct {
|
||||
SelectedFilesJson json.RawMessage `json:"SelectedFiles"`
|
||||
// InstancesJson json.RawMessage `json:"Instances"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(t),
|
||||
}
|
||||
if err := json.Unmarshal(data, temp); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(temp.SelectedFilesJson) > 0 {
|
||||
t.SelectedFiles = cmap.New[*File]()
|
||||
if err := t.SelectedFiles.UnmarshalJSON(temp.SelectedFilesJson); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if len(temp.InstancesJson) > 0 {
|
||||
// instances := make([]*realdebrid.TorrentInfo, 0)
|
||||
// if err := json.Unmarshal(temp.SelectedFilesJson, &instances); err != nil {
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Torrent) AnyInProgress() bool {
|
||||
@@ -34,7 +86,7 @@ func (t *Torrent) AllInProgress() bool {
|
||||
|
||||
type File struct {
|
||||
realdebrid.File
|
||||
Added string
|
||||
Ended string
|
||||
Link string
|
||||
Added string `json:"Added"`
|
||||
Ended string `json:"Ended"`
|
||||
Link string `json:"Link"`
|
||||
}
|
||||
|
||||
@@ -37,15 +37,11 @@ func (i *Torrent) UnmarshalJSON(data []byte) error {
|
||||
}{
|
||||
Alias: (*Alias)(i),
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Progress = int(math.Round(aux.Progress))
|
||||
|
||||
i.Progress = int(math.Floor(aux.Progress))
|
||||
i.Added = strings.Replace(aux.Added, "Z", "+01:00", 1)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -62,7 +58,24 @@ type TorrentInfo struct {
|
||||
OriginalName string `json:"original_filename"`
|
||||
OriginalBytes int64 `json:"original_bytes"`
|
||||
Files []File `json:"files"`
|
||||
Version string `json:"-"`
|
||||
}
|
||||
|
||||
func (i *TorrentInfo) MarshalJSON() ([]byte, error) {
|
||||
type Alias TorrentInfo
|
||||
aux := &struct {
|
||||
Progress float64 `json:"progress"`
|
||||
Added string `json:"added"`
|
||||
Ended string `json:"ended"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(i),
|
||||
Progress: float64(i.Progress), // Convert int to float64 for JSON representation
|
||||
Added: i.Added,
|
||||
}
|
||||
if i.Ended != "" {
|
||||
aux.Ended = i.Ended
|
||||
}
|
||||
return json.Marshal(aux)
|
||||
}
|
||||
|
||||
func (i *TorrentInfo) UnmarshalJSON(data []byte) error {
|
||||
@@ -75,19 +88,14 @@ func (i *TorrentInfo) UnmarshalJSON(data []byte) error {
|
||||
}{
|
||||
Alias: (*Alias)(i),
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(data, &aux); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i.Progress = int(math.Round(aux.Progress))
|
||||
|
||||
i.Progress = int(math.Floor(aux.Progress))
|
||||
i.Added = strings.Replace(aux.Added, "Z", "+01:00", 1)
|
||||
|
||||
if aux.Ended != "" {
|
||||
i.Ended = strings.Replace(aux.Ended, "Z", "+01:00", 1)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user