package main import ( "context" "fmt" "html/template" "log" "os" "sort" "time" "github.com/hekmon/cunits/v2" "github.com/hyperreal64/transmissionrpc" ) func byteCountIEC(b int64) string { const unit = 1024 if b < unit { return fmt.Sprintf("%d B", b) } div, exp := int64(unit), 0 for n := b / unit; n >= unit; n /= unit { div *= unit exp++ } return fmt.Sprintf("%.1f %ciB", float64(b)/float64(div), "KMGTPE"[exp]) } func convertTime(seconds int64) string { switch { case seconds > 86400: day := seconds / 86400 remainder := seconds % 86400 hour := remainder / 3600 remainder = remainder % 3600 minutes := remainder / 60 remainder = remainder % 60 return fmt.Sprintf("%d days, %d hours, %d minutes, %d seconds", day, hour, minutes, remainder) case seconds < 86400 && seconds > 3600: hour := seconds / 3600 remainder := seconds % 3600 minutes := remainder / 60 remainder = remainder % 60 return fmt.Sprintf("%d hours, %d minutes, %d seconds", hour, minutes, remainder) case seconds < 3600 && seconds > 60: minutes := seconds / 60 remainder := seconds % 60 return fmt.Sprintf("%d minutes, %d seconds", minutes, remainder) default: return fmt.Sprintf("%d seconds", seconds) } } type SessionStat struct { Label string Value string } type TorrentInfo struct { Name string ActivityDate time.Time TotalSize cunits.Bits Leechers int64 Seeders int64 } type TorrentStatsPageData struct { Date string SessionStats []SessionStat CurrentStats []SessionStat CumulativeStats []SessionStat TorrentInfo []TorrentInfo } func main() { transmissionbt, err := transmissionrpc.New(os.Getenv("TRANSMISSION_RPC_URL"), os.Getenv("TRANSMISSION_RPC_USER"), os.Getenv("TRANSMISSION_RPC_PASSWORD"), nil) if err != nil { log.Fatalln(err) } stats, err := transmissionbt.SessionStats(context.TODO()) if err != nil { log.Fatalln(err) } sessionStats := []SessionStat{ {Label: "Active torrent count", Value: fmt.Sprintf("%d", stats.ActiveTorrentCount)}, {Label: "Download speed", Value: fmt.Sprintf("%s/sec", byteCountIEC(stats.DownloadSpeed))}, {Label: "Upload speed", Value: fmt.Sprintf("%s/sec", byteCountIEC(stats.UploadSpeed))}, {Label: "Paused torrent count", Value: fmt.Sprintf("%d", stats.PausedTorrentCount)}, {Label: "Torrent count", Value: fmt.Sprintf("%d", stats.TorrentCount)}, } currentStats := []SessionStat{ {Label: "Uploaded bytes", Value: fmt.Sprintf("%s", byteCountIEC(stats.CurrentStats.UploadedBytes))}, {Label: "Downloaded bytes", Value: fmt.Sprintf("%s", byteCountIEC(stats.CurrentStats.DownloadedBytes))}, {Label: "Files added", Value: fmt.Sprintf("%d", stats.CurrentStats.FilesAdded)}, {Label: "Session count", Value: fmt.Sprintf("%d", stats.CurrentStats.SessionCount)}, {Label: "Time active", Value: convertTime(stats.CurrentStats.SecondsActive)}, } cumulativeStats := []SessionStat{ {Label: "Uploaded bytes", Value: fmt.Sprintf("%s", byteCountIEC(stats.CumulativeStats.UploadedBytes))}, {Label: "Downloaded bytes", Value: fmt.Sprintf("%s", byteCountIEC(stats.CumulativeStats.DownloadedBytes))}, {Label: "Files added", Value: fmt.Sprintf("%d", stats.CumulativeStats.FilesAdded)}, {Label: "Session count", Value: fmt.Sprintf("%d", stats.CumulativeStats.SessionCount)}, {Label: "Time active", Value: convertTime(stats.CumulativeStats.SecondsActive)}, } var torrentInfo = []TorrentInfo{} var ( leecherCount int64 seederCount int64 ) torrents, err := transmissionbt.TorrentGet(context.TODO(), []string{"name", "activityDate", "totalSize", "trackerStats"}, nil) if err != nil { fmt.Fprintln(os.Stderr, err) } else { for _, torrent := range torrents { for _, stat := range torrent.TrackerStats { leecherCount = stat.LeecherCount seederCount = stat.SeederCount } torrentInfo = append(torrentInfo, TorrentInfo{ Name: *torrent.Name, ActivityDate: *torrent.ActivityDate, TotalSize: *torrent.TotalSize, Leechers: leecherCount, Seeders: seederCount, }) } } sort.Slice(torrentInfo, func(i, j int) bool { return torrentInfo[i].Name < torrentInfo[j].Name }) data := TorrentStatsPageData{ Date: time.Now().Format(time.UnixDate), SessionStats: sessionStats, CurrentStats: currentStats, CumulativeStats: cumulativeStats, TorrentInfo: torrentInfo, } htmlTemplate, err := template.ParseFiles("template.html") if err != nil { log.Fatalln(err) } htmlFile, err := os.Create(os.Getenv("HTML_FILE")) if err != nil { log.Fatalln(err) } defer htmlFile.Close() if err = htmlTemplate.Execute(htmlFile, data); err != nil { log.Fatalln(err) } }