From 6fd39d818c2330de3210261eb82f72caa232c218 Mon Sep 17 00:00:00 2001 From: Simon Ding Date: Sun, 11 Aug 2024 23:09:34 +0800 Subject: [PATCH] feat: better seeding status --- db/db.go | 2 +- ent/history/history.go | 3 ++- ent/migrate/schema.go | 2 +- ent/schema/history.go | 2 +- go.sum | 8 +++++++ server/activity.go | 47 ++++++++++++++++++++++------------------ server/core/client.go | 7 +++--- server/core/scheduler.go | 16 +++++--------- ui/lib/activity.dart | 19 ++++++++-------- 9 files changed, 57 insertions(+), 49 deletions(-) diff --git a/db/db.go b/db/db.go index 80abd74..575a9df 100644 --- a/db/db.go +++ b/db/db.go @@ -491,7 +491,7 @@ func (c *Client) GetHistories() ent.Histories { func (c *Client) GetRunningHistories() ent.Histories { h, err := c.ent.History.Query().Where(history.Or(history.StatusEQ(history.StatusRunning), - history.StatusEQ(history.StatusUploading))).All(context.TODO()) + history.StatusEQ(history.StatusUploading), history.StatusEQ(history.StatusSeeding))).All(context.TODO()) if err != nil { return nil } diff --git a/ent/history/history.go b/ent/history/history.go index 044c040..caa7a90 100644 --- a/ent/history/history.go +++ b/ent/history/history.go @@ -76,6 +76,7 @@ const ( StatusSuccess Status = "success" StatusFail Status = "fail" StatusUploading Status = "uploading" + StatusSeeding Status = "seeding" ) func (s Status) String() string { @@ -85,7 +86,7 @@ func (s Status) String() string { // StatusValidator is a validator for the "status" field enum values. It is called by the builders before save. func StatusValidator(s Status) error { switch s { - case StatusRunning, StatusSuccess, StatusFail, StatusUploading: + case StatusRunning, StatusSuccess, StatusFail, StatusUploading, StatusSeeding: return nil default: return fmt.Errorf("history: invalid enum value for status field: %q", s) diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index b7e2511..373f0cf 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -66,7 +66,7 @@ var ( {Name: "size", Type: field.TypeInt, Default: 0}, {Name: "download_client_id", Type: field.TypeInt, Nullable: true}, {Name: "indexer_id", Type: field.TypeInt, Nullable: true}, - {Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading"}}, + {Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading", "seeding"}}, {Name: "saved", Type: field.TypeString, Nullable: true}, } // HistoriesTable holds the schema information for the "histories" table. diff --git a/ent/schema/history.go b/ent/schema/history.go index cdaa9c9..b1a95ab 100644 --- a/ent/schema/history.go +++ b/ent/schema/history.go @@ -21,7 +21,7 @@ func (History) Fields() []ent.Field { field.Int("size").Default(0), field.Int("download_client_id").Optional(), field.Int("indexer_id").Optional(), - field.Enum("status").Values("running", "success", "fail", "uploading"), + field.Enum("status").Values("running", "success", "fail", "uploading", "seeding"), field.String("saved").Optional(), } } diff --git a/go.sum b/go.sum index 598e776..9c46dbe 100644 --- a/go.sum +++ b/go.sum @@ -101,6 +101,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= @@ -116,6 +118,8 @@ github.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4 github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk= github.com/nikoksr/notify v1.0.0 h1:qe9/6FRsWdxBgQgWcpvQ0sv8LRGJZDpRB4TkL2uNdO8= github.com/nikoksr/notify v1.0.0/go.mod h1:hPaaDt30d6LAA7/5nb0e48Bp/MctDfycCSs8VEgN29I= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -139,6 +143,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= +github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= @@ -201,6 +207,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= diff --git a/server/activity.go b/server/activity.go index 3f3c151..1192ad4 100644 --- a/server/activity.go +++ b/server/activity.go @@ -21,30 +21,35 @@ type Activity struct { func (s *Server) GetAllActivities(c *gin.Context) (interface{}, error) { q := c.Query("status") - his := s.db.GetHistories() - var activities = make([]Activity, 0, len(his)) - for _, h := range his { - if q == "archive" && (h.Status == history.StatusRunning || h.Status == history.StatusUploading) { - continue //archived downloads - } - - a := Activity{ - History: h, - } - existInDownloadClient := false - for id, task := range s.core.GetTasks() { - if h.ID == id && task.Exists() { - a.Progress = task.Progress() - a.SeedRatio = float32(*task.SeedRatio()) - existInDownloadClient = true + var activities = make([]Activity, 0) + if q == "active" { + his := s.db.GetRunningHistories() + for _, h := range his { + a := Activity{ + History: h, } + for id, task := range s.core.GetTasks() { + if h.ID == id && task.Exists() { + a.Progress = task.Progress() + a.SeedRatio = float32(*task.SeedRatio()) + } + } + activities = append(activities, a) } - if q == "active" && !existInDownloadClient { - continue - } - activities = append(activities, a) - } + } else { + his := s.db.GetHistories() + for _, h := range his { + if h.Status == history.StatusRunning || h.Status == history.StatusUploading || h.Status == history.StatusSeeding { + continue //archived downloads + } + a := Activity{ + History: h, + } + activities = append(activities, a) + } + + } return activities, nil } diff --git a/server/core/client.go b/server/core/client.go index 7ca28eb..7359693 100644 --- a/server/core/client.go +++ b/server/core/client.go @@ -33,7 +33,7 @@ func (c *Client) Init() { } func (c *Client) reloadTasks() { - allTasks := c.db.GetHistories() + allTasks := c.db.GetRunningHistories() for _, t := range allTasks { torrent, err := transmission.ReloadTorrent(t.Saved) if err != nil { @@ -78,8 +78,7 @@ func (c *Client) MustTMDB() *tmdb.Client { return t } - -func (c *Client) RemoveTaskAndTorrent(id int)error { +func (c *Client) RemoveTaskAndTorrent(id int) error { torrent := c.tasks[id] if torrent != nil { if err := torrent.Remove(); err != nil { @@ -92,4 +91,4 @@ func (c *Client) RemoveTaskAndTorrent(id int)error { func (c *Client) GetTasks() map[int]*Task { return c.tasks -} \ No newline at end of file +} diff --git a/server/core/scheduler.go b/server/core/scheduler.go index 6755b06..74f65c8 100644 --- a/server/core/scheduler.go +++ b/server/core/scheduler.go @@ -40,23 +40,18 @@ func (c *Client) checkTasks() { if !t.Exists() { log.Infof("task no longer exists: %v", id) - if r.Status == history.StatusRunning || r.Status == history.StatusUploading { - log.Warnf("task is running but no longer available in download client, mark as fail, task name: %s", r.SourceTitle) - c.db.SetHistoryStatus(id, history.StatusFail) - } - delete(c.tasks, id) continue } log.Infof("task (%s) percentage done: %d%%", t.Name(), t.Progress()) if t.Progress() == 100 { - if r.Status == history.StatusSuccess { + if r.Status == history.StatusSeeding { //task already success, check seed ratio torrent := c.tasks[id] ok := c.isSeedRatioLimitReached(r.IndexerID, torrent) if ok { - log.Infof("torrent file seed ratio reached, remove: %v, current seed ratio: %v", torrent.Name(), torrent.SeedRatio()) + log.Infof("torrent file seed ratio reached, remove: %v, current seed ratio: %v", torrent.Name(), *torrent.SeedRatio()) torrent.Remove() delete(c.tasks, id) } else { @@ -104,7 +99,7 @@ func (c *Client) moveCompletedTask(id int) (err1 error) { } else { c.db.SetSeasonAllEpisodeStatus(r.MediaID, seasonNum, episode.StatusMissing) } - c.sendMsg(fmt.Sprintf(message.ProcessingFailed, err)) + c.sendMsg(fmt.Sprintf(message.ProcessingFailed, err1)) if downloadclient.RemoveFailedDownloads { log.Debugf("task failed, remove failed torrent and files related") delete(c.tasks, r.ID) @@ -134,7 +129,7 @@ func (c *Client) moveCompletedTask(id int) (err1 error) { return errors.Wrap(err, "move file") } - c.db.SetHistoryStatus(r.ID, history.StatusSuccess) + c.db.SetHistoryStatus(r.ID, history.StatusSeeding) if r.EpisodeID != 0 { c.db.SetEpisodeStatus(r.EpisodeID, episode.StatusDownloaded) } else { @@ -145,7 +140,8 @@ func (c *Client) moveCompletedTask(id int) (err1 error) { //判断是否需要删除本地文件 ok := c.isSeedRatioLimitReached(r.IndexerID, torrent) if downloadclient.RemoveCompletedDownloads && ok { - log.Debugf("download complete,remove torrent and files related, torrent: %v, seed ratio: %v", torrentName, torrent.SeedRatio()) + log.Debugf("download complete,remove torrent and files related, torrent: %v, seed ratio: %v", torrentName, *torrent.SeedRatio()) + c.db.SetHistoryStatus(r.ID, history.StatusSuccess) delete(c.tasks, r.ID) torrent.Remove() } diff --git a/ui/lib/activity.dart b/ui/lib/activity.dart index fd7fe57..f580ffb 100644 --- a/ui/lib/activity.dart +++ b/ui/lib/activity.dart @@ -89,17 +89,16 @@ class _ActivityPageState extends ConsumerState Icons.close, color: Colors.red, )); + } else if (ac.status == "seeding") { + //seeding + return const Tooltip( + message: "做种中", + child: Icon( + Icons.upload, + //color: Colors.blue, + ), + ); } else if (ac.status == "success") { - if (ac.progress == 100) { - //seeding - return const Tooltip( - message: "做种中", - child: Icon( - Icons.upload, - //color: Colors.blue, - ), - ); - } return const Tooltip( message: "下载成功", child: Icon(