diff --git a/internal/app.go b/internal/app.go index 8522515..5ad9b21 100644 --- a/internal/app.go +++ b/internal/app.go @@ -150,6 +150,7 @@ func MainApp(configPath string) { config, api, workerPool, + hosts, log.Named("router"), ) diff --git a/internal/handlers/home.go b/internal/handlers/home.go index 10e941e..b1dae4b 100644 --- a/internal/handlers/home.go +++ b/internal/handlers/home.go @@ -5,6 +5,7 @@ import ( "net/http" "os" "runtime" + "sort" "strings" "github.com/debridmediamanager/zurg/internal/config" @@ -25,7 +26,8 @@ type RootResponse struct { Dav string `json:"dav"` Infuse string `json:"infuse"` Logs string `json:"logs"` - UserInfo *realdebrid.User `json:"user_info"` // Replace UserInfoType with the actual type + UserInfo *realdebrid.User `json:"user_info"` + RDTrafficUsed uint64 `json:"rd_traffic_used"` LibrarySize int `json:"library_size"` // Number of torrents in the library RepairQueueStr string `json:"repair_queue"` // List of torrents in the repair queue MemAlloc uint64 `json:"mem_alloc"` // Memory allocation in MB @@ -35,7 +37,8 @@ type RootResponse struct { PID int `json:"pid"` // Process ID Sponsor SponsorResponse `json:"sponsor_zurg"` // Sponsorship links Config config.ZurgConfig `json:"config"` - OnceDoneBin []string `json:"once_done_bin"` + IDsToDelete []string `json:"ids_to_delete"` + Hosts []string `json:"hosts"` } func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { @@ -45,6 +48,12 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { return } + trafficDetails, err := zr.api.GetTrafficDetails() + if err != nil { + http.Error(resp, err.Error(), http.StatusInternalServerError) + return + } + var mem runtime.MemStats runtime.ReadMemStats(&mem) @@ -65,6 +74,16 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { } } + sortedIDs := zr.torMgr.OnceDoneBin.ToSlice() + sort.Strings(sortedIDs) + + // check if real-debrid.com is in the traffic details + var rdTrafficUsed int64 + rdTrafficUsed = 0 + if _, ok := trafficDetails["real-debrid.com"]; ok { + rdTrafficUsed = trafficDetails["real-debrid.com"] + } + response := RootResponse{ Version: version.GetVersion(), BuiltAt: version.GetBuiltAt(), @@ -74,6 +93,7 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { Infuse: fmt.Sprintf("//%s/infuse/", req.Host), Logs: fmt.Sprintf("//%s/logs/", req.Host), UserInfo: userInfo, + RDTrafficUsed: bToGb(uint64(rdTrafficUsed)), LibrarySize: allTorrents.Count(), RepairQueueStr: repairQueueStr, MemAlloc: bToMb(mem.Alloc), @@ -87,7 +107,8 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { Paypal: "https://paypal.me/yowmamasita", }, Config: zr.cfg.GetConfig(), - OnceDoneBin: zr.torMgr.OnceDoneBin.ToSlice(), + IDsToDelete: sortedIDs, + Hosts: zr.hosts, } out := `
| Library Size | %d items | -||||
| Repair Queue | -%s | -||||
| Memory Allocation | %d MB | @@ -150,6 +167,10 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {Process ID | %d | ||
| RD Traffic Used | +%d GB | +||||
| Sponsor Zurg | Patreon | @@ -189,7 +210,7 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {%s | |||
| Config | +Config | Version | %s | Retries Until Failed | %d | +
| Auto-Analyze New Torrents | +%t | +||||
| Cache Network Test Results | +%t | +||||
| Additional Playable Extensions | +%s | +||||
| Network Buffer Size | %d bytes | @@ -273,6 +306,14 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) {IDs to be deleted | %v | ||
| Repair Queue | +%s | +||||
| Hosts | +%v | +||||
| Utilities | @@ -324,12 +365,12 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { response.Logs, response.Logs, response.LibrarySize, - response.RepairQueueStr, response.MemAlloc, response.TotalAlloc, response.Sys, response.NumGC, response.PID, + response.RDTrafficUsed, response.Sponsor.Patreon, response.Sponsor.Patreon, response.Sponsor.Github, @@ -360,11 +401,16 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { response.Config.GetApiTimeoutSecs(), response.Config.GetDownloadTimeoutSecs(), response.Config.GetRetriesUntilFailed(), + response.Config.ShouldAutoAnalyzeNewTorrents(), + response.Config.ShouldCacheNetworkTestResults(), + response.Config.GetPlayableExtensions(), response.Config.GetNetworkBufferSize(), response.Config.ShouldServeFromRclone(), response.Config.ShouldForceIPv6(), response.Config.GetOnLibraryUpdate(), - response.OnceDoneBin, + response.IDsToDelete, + response.RepairQueueStr, + response.Hosts, ) fmt.Fprint(resp, out) @@ -373,3 +419,7 @@ func (zr *Handlers) handleHome(resp http.ResponseWriter, req *http.Request) { func bToMb(b uint64) uint64 { return b / 1024 / 1024 } + +func bToGb(b uint64) uint64 { + return b / 1024 / 1024 / 1024 +} diff --git a/internal/handlers/router.go b/internal/handlers/router.go index cd642eb..5c802cc 100644 --- a/internal/handlers/router.go +++ b/internal/handlers/router.go @@ -25,6 +25,7 @@ type Handlers struct { cfg config.ConfigInterface api *realdebrid.RealDebrid workerPool *ants.Pool + hosts []string log *logutil.Logger } @@ -34,13 +35,14 @@ func init() { chi.RegisterMethod("MOVE") } -func AttachHandlers(router *chi.Mux, downloader *universal.Downloader, torMgr *torrent.TorrentManager, cfg config.ConfigInterface, api *realdebrid.RealDebrid, workerPool *ants.Pool, log *logutil.Logger) { +func AttachHandlers(router *chi.Mux, downloader *universal.Downloader, torMgr *torrent.TorrentManager, cfg config.ConfigInterface, api *realdebrid.RealDebrid, workerPool *ants.Pool, hosts []string, log *logutil.Logger) { hs := &Handlers{ downloader: downloader, torMgr: torMgr, cfg: cfg, api: api, workerPool: workerPool, + hosts: hosts, log: log, } diff --git a/pkg/http/ip.go b/pkg/http/ip.go index 6e0b10b..b55f34a 100644 --- a/pkg/http/ip.go +++ b/pkg/http/ip.go @@ -93,15 +93,15 @@ func (r *IPRepository) GetHosts(numberOfHosts int, ipv6 bool) []string { return kvList[i].Value < kvList[j].Value }) - var optimalHosts []string + var hosts []string if numberOfHosts == 0 { numberOfHosts = len(kvList) } for i := 0; i < numberOfHosts && i < len(kvList); i++ { - optimalHosts = append(optimalHosts, kvList[i].Key) + hosts = append(hosts, kvList[i].Key) } - return optimalHosts + return hosts } func (r *IPRepository) runLatencyTest() { diff --git a/pkg/realdebrid/api.go b/pkg/realdebrid/api.go index b27f048..aa35585 100644 --- a/pkg/realdebrid/api.go +++ b/pkg/realdebrid/api.go @@ -297,6 +297,52 @@ func (rd *RealDebrid) GetUserInformation() (*User, error) { return &user, nil } +// TrafficDetails represents the structure of the traffic details response +type TrafficDetails map[string]struct { + Host map[string]int64 `json:"host"` + Bytes int64 `json:"bytes"` +} + +// GetTrafficDetails gets the traffic details from the Real-Debrid API +func (rd *RealDebrid) GetTrafficDetails() (map[string]int64, error) { + // Construct request URL + reqURL := "https://api.real-debrid.com/rest/1.0/traffic/details" + req, err := http.NewRequest(http.MethodGet, reqURL, nil) + if err != nil { + rd.log.Errorf("Error when creating a traffic details request: %v", err) + return nil, err + } + + // Send the request + resp, err := rd.apiClient.Do(req) + if err != nil { + rd.log.Errorf("Error when executing the traffic details request: %v", err) + return nil, err + } + defer resp.Body.Close() + + // Decode the JSON response into the TrafficDetails struct + var trafficDetails TrafficDetails + err = json.NewDecoder(resp.Body).Decode(&trafficDetails) + if err != nil { + rd.log.Errorf("Error when decoding traffic details JSON: %v", err) + return nil, err + } + + // Find the latest date in the traffic details + var latestDate string + for date := range trafficDetails { + if latestDate == "" || date > latestDate { + latestDate = date + } + } + + // Get the traffic details for the latest date + latestTraffic := trafficDetails[latestDate].Host + + return latestTraffic, nil +} + // AvailabilityCheck checks the instant availability of torrents func (rd *RealDebrid) AvailabilityCheck(hashes []string) (AvailabilityResponse, error) { if len(hashes) == 0 { | ||||