diff --git a/db/db.go b/db/db.go index a4ea7a7..59e458d 100644 --- a/db/db.go +++ b/db/db.go @@ -551,4 +551,8 @@ func (c *Client) GetMovieDummyEpisode(movieId int) (*ent.Episode, error) { return nil, errors.Wrap(err, "query episode") } return ep, nil +} + +func (c *Client) GetDownloadClient(id int) (*ent.DownloadClients, error) { + return c.ent.DownloadClients.Query().Where(downloadclients.ID(id)).First(context.Background()) } \ No newline at end of file diff --git a/ent/history.go b/ent/history.go index 1746587..acee6c0 100644 --- a/ent/history.go +++ b/ent/history.go @@ -29,6 +29,8 @@ type History struct { TargetDir string `json:"target_dir,omitempty"` // Size holds the value of the "size" field. Size int `json:"size,omitempty"` + // DownloadClientID holds the value of the "download_client_id" field. + DownloadClientID int `json:"download_client_id,omitempty"` // Status holds the value of the "status" field. Status history.Status `json:"status,omitempty"` // Saved holds the value of the "saved" field. @@ -41,7 +43,7 @@ func (*History) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { - case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSize: + case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSize, history.FieldDownloadClientID: values[i] = new(sql.NullInt64) case history.FieldSourceTitle, history.FieldTargetDir, history.FieldStatus, history.FieldSaved: values[i] = new(sql.NullString) @@ -104,6 +106,12 @@ func (h *History) assignValues(columns []string, values []any) error { } else if value.Valid { h.Size = int(value.Int64) } + case history.FieldDownloadClientID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field download_client_id", values[i]) + } else if value.Valid { + h.DownloadClientID = int(value.Int64) + } case history.FieldStatus: if value, ok := values[i].(*sql.NullString); !ok { return fmt.Errorf("unexpected type %T for field status", values[i]) @@ -170,6 +178,9 @@ func (h *History) String() string { builder.WriteString("size=") builder.WriteString(fmt.Sprintf("%v", h.Size)) builder.WriteString(", ") + builder.WriteString("download_client_id=") + builder.WriteString(fmt.Sprintf("%v", h.DownloadClientID)) + builder.WriteString(", ") builder.WriteString("status=") builder.WriteString(fmt.Sprintf("%v", h.Status)) builder.WriteString(", ") diff --git a/ent/history/history.go b/ent/history/history.go index e386b85..ef5ff08 100644 --- a/ent/history/history.go +++ b/ent/history/history.go @@ -25,6 +25,8 @@ const ( FieldTargetDir = "target_dir" // FieldSize holds the string denoting the size field in the database. FieldSize = "size" + // FieldDownloadClientID holds the string denoting the download_client_id field in the database. + FieldDownloadClientID = "download_client_id" // FieldStatus holds the string denoting the status field in the database. FieldStatus = "status" // FieldSaved holds the string denoting the saved field in the database. @@ -42,6 +44,7 @@ var Columns = []string{ FieldDate, FieldTargetDir, FieldSize, + FieldDownloadClientID, FieldStatus, FieldSaved, } @@ -124,6 +127,11 @@ func BySize(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldSize, opts...).ToFunc() } +// ByDownloadClientID orders the results by the download_client_id field. +func ByDownloadClientID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDownloadClientID, opts...).ToFunc() +} + // ByStatus orders the results by the status field. func ByStatus(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldStatus, opts...).ToFunc() diff --git a/ent/history/where.go b/ent/history/where.go index cbb9793..8d561d8 100644 --- a/ent/history/where.go +++ b/ent/history/where.go @@ -84,6 +84,11 @@ func Size(v int) predicate.History { return predicate.History(sql.FieldEQ(FieldSize, v)) } +// DownloadClientID applies equality check predicate on the "download_client_id" field. It's identical to DownloadClientIDEQ. +func DownloadClientID(v int) predicate.History { + return predicate.History(sql.FieldEQ(FieldDownloadClientID, v)) +} + // Saved applies equality check predicate on the "saved" field. It's identical to SavedEQ. func Saved(v string) predicate.History { return predicate.History(sql.FieldEQ(FieldSaved, v)) @@ -389,6 +394,56 @@ func SizeLTE(v int) predicate.History { return predicate.History(sql.FieldLTE(FieldSize, v)) } +// DownloadClientIDEQ applies the EQ predicate on the "download_client_id" field. +func DownloadClientIDEQ(v int) predicate.History { + return predicate.History(sql.FieldEQ(FieldDownloadClientID, v)) +} + +// DownloadClientIDNEQ applies the NEQ predicate on the "download_client_id" field. +func DownloadClientIDNEQ(v int) predicate.History { + return predicate.History(sql.FieldNEQ(FieldDownloadClientID, v)) +} + +// DownloadClientIDIn applies the In predicate on the "download_client_id" field. +func DownloadClientIDIn(vs ...int) predicate.History { + return predicate.History(sql.FieldIn(FieldDownloadClientID, vs...)) +} + +// DownloadClientIDNotIn applies the NotIn predicate on the "download_client_id" field. +func DownloadClientIDNotIn(vs ...int) predicate.History { + return predicate.History(sql.FieldNotIn(FieldDownloadClientID, vs...)) +} + +// DownloadClientIDGT applies the GT predicate on the "download_client_id" field. +func DownloadClientIDGT(v int) predicate.History { + return predicate.History(sql.FieldGT(FieldDownloadClientID, v)) +} + +// DownloadClientIDGTE applies the GTE predicate on the "download_client_id" field. +func DownloadClientIDGTE(v int) predicate.History { + return predicate.History(sql.FieldGTE(FieldDownloadClientID, v)) +} + +// DownloadClientIDLT applies the LT predicate on the "download_client_id" field. +func DownloadClientIDLT(v int) predicate.History { + return predicate.History(sql.FieldLT(FieldDownloadClientID, v)) +} + +// DownloadClientIDLTE applies the LTE predicate on the "download_client_id" field. +func DownloadClientIDLTE(v int) predicate.History { + return predicate.History(sql.FieldLTE(FieldDownloadClientID, v)) +} + +// DownloadClientIDIsNil applies the IsNil predicate on the "download_client_id" field. +func DownloadClientIDIsNil() predicate.History { + return predicate.History(sql.FieldIsNull(FieldDownloadClientID)) +} + +// DownloadClientIDNotNil applies the NotNil predicate on the "download_client_id" field. +func DownloadClientIDNotNil() predicate.History { + return predicate.History(sql.FieldNotNull(FieldDownloadClientID)) +} + // StatusEQ applies the EQ predicate on the "status" field. func StatusEQ(v Status) predicate.History { return predicate.History(sql.FieldEQ(FieldStatus, v)) diff --git a/ent/history_create.go b/ent/history_create.go index 5902c41..ba2e520 100644 --- a/ent/history_create.go +++ b/ent/history_create.go @@ -72,6 +72,20 @@ func (hc *HistoryCreate) SetNillableSize(i *int) *HistoryCreate { return hc } +// SetDownloadClientID sets the "download_client_id" field. +func (hc *HistoryCreate) SetDownloadClientID(i int) *HistoryCreate { + hc.mutation.SetDownloadClientID(i) + return hc +} + +// SetNillableDownloadClientID sets the "download_client_id" field if the given value is not nil. +func (hc *HistoryCreate) SetNillableDownloadClientID(i *int) *HistoryCreate { + if i != nil { + hc.SetDownloadClientID(*i) + } + return hc +} + // SetStatus sets the "status" field. func (hc *HistoryCreate) SetStatus(h history.Status) *HistoryCreate { hc.mutation.SetStatus(h) @@ -208,6 +222,10 @@ func (hc *HistoryCreate) createSpec() (*History, *sqlgraph.CreateSpec) { _spec.SetField(history.FieldSize, field.TypeInt, value) _node.Size = value } + if value, ok := hc.mutation.DownloadClientID(); ok { + _spec.SetField(history.FieldDownloadClientID, field.TypeInt, value) + _node.DownloadClientID = value + } if value, ok := hc.mutation.Status(); ok { _spec.SetField(history.FieldStatus, field.TypeEnum, value) _node.Status = value diff --git a/ent/history_update.go b/ent/history_update.go index f407684..eb7df8a 100644 --- a/ent/history_update.go +++ b/ent/history_update.go @@ -139,6 +139,33 @@ func (hu *HistoryUpdate) AddSize(i int) *HistoryUpdate { return hu } +// SetDownloadClientID sets the "download_client_id" field. +func (hu *HistoryUpdate) SetDownloadClientID(i int) *HistoryUpdate { + hu.mutation.ResetDownloadClientID() + hu.mutation.SetDownloadClientID(i) + return hu +} + +// SetNillableDownloadClientID sets the "download_client_id" field if the given value is not nil. +func (hu *HistoryUpdate) SetNillableDownloadClientID(i *int) *HistoryUpdate { + if i != nil { + hu.SetDownloadClientID(*i) + } + return hu +} + +// AddDownloadClientID adds i to the "download_client_id" field. +func (hu *HistoryUpdate) AddDownloadClientID(i int) *HistoryUpdate { + hu.mutation.AddDownloadClientID(i) + return hu +} + +// ClearDownloadClientID clears the value of the "download_client_id" field. +func (hu *HistoryUpdate) ClearDownloadClientID() *HistoryUpdate { + hu.mutation.ClearDownloadClientID() + return hu +} + // SetStatus sets the "status" field. func (hu *HistoryUpdate) SetStatus(h history.Status) *HistoryUpdate { hu.mutation.SetStatus(h) @@ -257,6 +284,15 @@ func (hu *HistoryUpdate) sqlSave(ctx context.Context) (n int, err error) { if value, ok := hu.mutation.AddedSize(); ok { _spec.AddField(history.FieldSize, field.TypeInt, value) } + if value, ok := hu.mutation.DownloadClientID(); ok { + _spec.SetField(history.FieldDownloadClientID, field.TypeInt, value) + } + if value, ok := hu.mutation.AddedDownloadClientID(); ok { + _spec.AddField(history.FieldDownloadClientID, field.TypeInt, value) + } + if hu.mutation.DownloadClientIDCleared() { + _spec.ClearField(history.FieldDownloadClientID, field.TypeInt) + } if value, ok := hu.mutation.Status(); ok { _spec.SetField(history.FieldStatus, field.TypeEnum, value) } @@ -397,6 +433,33 @@ func (huo *HistoryUpdateOne) AddSize(i int) *HistoryUpdateOne { return huo } +// SetDownloadClientID sets the "download_client_id" field. +func (huo *HistoryUpdateOne) SetDownloadClientID(i int) *HistoryUpdateOne { + huo.mutation.ResetDownloadClientID() + huo.mutation.SetDownloadClientID(i) + return huo +} + +// SetNillableDownloadClientID sets the "download_client_id" field if the given value is not nil. +func (huo *HistoryUpdateOne) SetNillableDownloadClientID(i *int) *HistoryUpdateOne { + if i != nil { + huo.SetDownloadClientID(*i) + } + return huo +} + +// AddDownloadClientID adds i to the "download_client_id" field. +func (huo *HistoryUpdateOne) AddDownloadClientID(i int) *HistoryUpdateOne { + huo.mutation.AddDownloadClientID(i) + return huo +} + +// ClearDownloadClientID clears the value of the "download_client_id" field. +func (huo *HistoryUpdateOne) ClearDownloadClientID() *HistoryUpdateOne { + huo.mutation.ClearDownloadClientID() + return huo +} + // SetStatus sets the "status" field. func (huo *HistoryUpdateOne) SetStatus(h history.Status) *HistoryUpdateOne { huo.mutation.SetStatus(h) @@ -545,6 +608,15 @@ func (huo *HistoryUpdateOne) sqlSave(ctx context.Context) (_node *History, err e if value, ok := huo.mutation.AddedSize(); ok { _spec.AddField(history.FieldSize, field.TypeInt, value) } + if value, ok := huo.mutation.DownloadClientID(); ok { + _spec.SetField(history.FieldDownloadClientID, field.TypeInt, value) + } + if value, ok := huo.mutation.AddedDownloadClientID(); ok { + _spec.AddField(history.FieldDownloadClientID, field.TypeInt, value) + } + if huo.mutation.DownloadClientIDCleared() { + _spec.ClearField(history.FieldDownloadClientID, field.TypeInt) + } if value, ok := huo.mutation.Status(); ok { _spec.SetField(history.FieldStatus, field.TypeEnum, value) } diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 32bc204..3e53ef0 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -63,6 +63,7 @@ var ( {Name: "date", Type: field.TypeTime}, {Name: "target_dir", Type: field.TypeString}, {Name: "size", Type: field.TypeInt, Default: 0}, + {Name: "download_client_id", Type: field.TypeInt, Nullable: true}, {Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading"}}, {Name: "saved", Type: field.TypeString, Nullable: true}, } diff --git a/ent/mutation.go b/ent/mutation.go index 1c11422..0a117db 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -1705,24 +1705,26 @@ func (m *EpisodeMutation) ResetEdge(name string) error { // HistoryMutation represents an operation that mutates the History nodes in the graph. type HistoryMutation struct { config - op Op - typ string - id *int - media_id *int - addmedia_id *int - episode_id *int - addepisode_id *int - source_title *string - date *time.Time - target_dir *string - size *int - addsize *int - status *history.Status - saved *string - clearedFields map[string]struct{} - done bool - oldValue func(context.Context) (*History, error) - predicates []predicate.History + op Op + typ string + id *int + media_id *int + addmedia_id *int + episode_id *int + addepisode_id *int + source_title *string + date *time.Time + target_dir *string + size *int + addsize *int + download_client_id *int + adddownload_client_id *int + status *history.Status + saved *string + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*History, error) + predicates []predicate.History } var _ ent.Mutation = (*HistoryMutation)(nil) @@ -2113,6 +2115,76 @@ func (m *HistoryMutation) ResetSize() { m.addsize = nil } +// SetDownloadClientID sets the "download_client_id" field. +func (m *HistoryMutation) SetDownloadClientID(i int) { + m.download_client_id = &i + m.adddownload_client_id = nil +} + +// DownloadClientID returns the value of the "download_client_id" field in the mutation. +func (m *HistoryMutation) DownloadClientID() (r int, exists bool) { + v := m.download_client_id + if v == nil { + return + } + return *v, true +} + +// OldDownloadClientID returns the old "download_client_id" field's value of the History entity. +// If the History object wasn't provided to the builder, the object is fetched from the database. +// An error is returned if the mutation operation is not UpdateOne, or the database query fails. +func (m *HistoryMutation) OldDownloadClientID(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDownloadClientID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDownloadClientID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDownloadClientID: %w", err) + } + return oldValue.DownloadClientID, nil +} + +// AddDownloadClientID adds i to the "download_client_id" field. +func (m *HistoryMutation) AddDownloadClientID(i int) { + if m.adddownload_client_id != nil { + *m.adddownload_client_id += i + } else { + m.adddownload_client_id = &i + } +} + +// AddedDownloadClientID returns the value that was added to the "download_client_id" field in this mutation. +func (m *HistoryMutation) AddedDownloadClientID() (r int, exists bool) { + v := m.adddownload_client_id + if v == nil { + return + } + return *v, true +} + +// ClearDownloadClientID clears the value of the "download_client_id" field. +func (m *HistoryMutation) ClearDownloadClientID() { + m.download_client_id = nil + m.adddownload_client_id = nil + m.clearedFields[history.FieldDownloadClientID] = struct{}{} +} + +// DownloadClientIDCleared returns if the "download_client_id" field was cleared in this mutation. +func (m *HistoryMutation) DownloadClientIDCleared() bool { + _, ok := m.clearedFields[history.FieldDownloadClientID] + return ok +} + +// ResetDownloadClientID resets all changes to the "download_client_id" field. +func (m *HistoryMutation) ResetDownloadClientID() { + m.download_client_id = nil + m.adddownload_client_id = nil + delete(m.clearedFields, history.FieldDownloadClientID) +} + // SetStatus sets the "status" field. func (m *HistoryMutation) SetStatus(h history.Status) { m.status = &h @@ -2232,7 +2304,7 @@ func (m *HistoryMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *HistoryMutation) Fields() []string { - fields := make([]string, 0, 8) + fields := make([]string, 0, 9) if m.media_id != nil { fields = append(fields, history.FieldMediaID) } @@ -2251,6 +2323,9 @@ func (m *HistoryMutation) Fields() []string { if m.size != nil { fields = append(fields, history.FieldSize) } + if m.download_client_id != nil { + fields = append(fields, history.FieldDownloadClientID) + } if m.status != nil { fields = append(fields, history.FieldStatus) } @@ -2277,6 +2352,8 @@ func (m *HistoryMutation) Field(name string) (ent.Value, bool) { return m.TargetDir() case history.FieldSize: return m.Size() + case history.FieldDownloadClientID: + return m.DownloadClientID() case history.FieldStatus: return m.Status() case history.FieldSaved: @@ -2302,6 +2379,8 @@ func (m *HistoryMutation) OldField(ctx context.Context, name string) (ent.Value, return m.OldTargetDir(ctx) case history.FieldSize: return m.OldSize(ctx) + case history.FieldDownloadClientID: + return m.OldDownloadClientID(ctx) case history.FieldStatus: return m.OldStatus(ctx) case history.FieldSaved: @@ -2357,6 +2436,13 @@ func (m *HistoryMutation) SetField(name string, value ent.Value) error { } m.SetSize(v) return nil + case history.FieldDownloadClientID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDownloadClientID(v) + return nil case history.FieldStatus: v, ok := value.(history.Status) if !ok { @@ -2388,6 +2474,9 @@ func (m *HistoryMutation) AddedFields() []string { if m.addsize != nil { fields = append(fields, history.FieldSize) } + if m.adddownload_client_id != nil { + fields = append(fields, history.FieldDownloadClientID) + } return fields } @@ -2402,6 +2491,8 @@ func (m *HistoryMutation) AddedField(name string) (ent.Value, bool) { return m.AddedEpisodeID() case history.FieldSize: return m.AddedSize() + case history.FieldDownloadClientID: + return m.AddedDownloadClientID() } return nil, false } @@ -2432,6 +2523,13 @@ func (m *HistoryMutation) AddField(name string, value ent.Value) error { } m.AddSize(v) return nil + case history.FieldDownloadClientID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddDownloadClientID(v) + return nil } return fmt.Errorf("unknown History numeric field %s", name) } @@ -2443,6 +2541,9 @@ func (m *HistoryMutation) ClearedFields() []string { if m.FieldCleared(history.FieldEpisodeID) { fields = append(fields, history.FieldEpisodeID) } + if m.FieldCleared(history.FieldDownloadClientID) { + fields = append(fields, history.FieldDownloadClientID) + } if m.FieldCleared(history.FieldSaved) { fields = append(fields, history.FieldSaved) } @@ -2463,6 +2564,9 @@ func (m *HistoryMutation) ClearField(name string) error { case history.FieldEpisodeID: m.ClearEpisodeID() return nil + case history.FieldDownloadClientID: + m.ClearDownloadClientID() + return nil case history.FieldSaved: m.ClearSaved() return nil @@ -2492,6 +2596,9 @@ func (m *HistoryMutation) ResetField(name string) error { case history.FieldSize: m.ResetSize() return nil + case history.FieldDownloadClientID: + m.ResetDownloadClientID() + return nil case history.FieldStatus: m.ResetStatus() return nil diff --git a/ent/schema/history.go b/ent/schema/history.go index 0b82b2e..846509e 100644 --- a/ent/schema/history.go +++ b/ent/schema/history.go @@ -19,6 +19,7 @@ func (History) Fields() []ent.Field { field.Time("date"), field.String("target_dir"), field.Int("size").Default(0), + field.Int("download_client_id").Optional(), field.Enum("status").Values("running", "success", "fail", "uploading"), field.String("saved").Optional(), } diff --git a/pkg/storage/local.go b/pkg/storage/local.go index 36c6e08..eb2b257 100644 --- a/pkg/storage/local.go +++ b/pkg/storage/local.go @@ -13,6 +13,7 @@ import ( type Storage interface { Move(src, dest string) error + Copy(src, dest string) error ReadDir(dir string) ([]fs.FileInfo, error) ReadFile(string)([]byte, error) WriteFile(string, []byte) error @@ -28,7 +29,7 @@ type LocalStorage struct { dir string } -func (l *LocalStorage) Move(src, destDir string) error { +func (l *LocalStorage) Copy(src, destDir string) error { os.MkdirAll(filepath.Join(l.dir, destDir), os.ModePerm) targetBase := filepath.Join(l.dir, destDir, filepath.Base(src)) //文件的场景,要加上文件名, move filename ./dir/ @@ -80,8 +81,14 @@ func (l *LocalStorage) Move(src, destDir string) error { if err != nil { return errors.Wrap(err, "move file error") } - return os.RemoveAll(src) + return nil +} +func (l *LocalStorage) Move(src, destDir string) error { + if err := l.Copy(src, destDir); err != nil { + return err + } + return os.RemoveAll(src) } func (l *LocalStorage) ReadDir(dir string) ([]fs.FileInfo, error) { diff --git a/pkg/storage/webdav.go b/pkg/storage/webdav.go index 63fb4c8..9875da6 100644 --- a/pkg/storage/webdav.go +++ b/pkg/storage/webdav.go @@ -14,8 +14,8 @@ import ( ) type WebdavStorage struct { - fs *gowebdav.Client - dir string + fs *gowebdav.Client + dir string changeMediaHash bool } @@ -25,14 +25,13 @@ func NewWebdavStorage(url, user, password, path string, changeMediaHash bool) (* return nil, errors.Wrap(err, "connect webdav") } return &WebdavStorage{ - fs: c, + fs: c, dir: path, }, nil } -func (w *WebdavStorage) Move(local, remoteDir string) error { - - remoteBase := filepath.Join(w.dir,remoteDir, filepath.Base(local)) +func (w *WebdavStorage) Copy(local, remoteDir string) error { + remoteBase := filepath.Join(w.dir, remoteDir, filepath.Base(local)) info, err := os.Stat(local) if err != nil { return errors.Wrap(err, "read source dir") @@ -80,7 +79,7 @@ func (w *WebdavStorage) Move(local, remoteDir string) error { r.Header.Set("Content-Type", mtype.String()) r.ContentLength = info.Size() } - + if err := w.fs.WriteStream(remoteName, f, 0666, callback); err != nil { return errors.Wrap(err, "transmitting data error") } @@ -92,6 +91,13 @@ func (w *WebdavStorage) Move(local, remoteDir string) error { if err != nil { return errors.Wrap(err, "move file error") } + return nil +} + +func (w *WebdavStorage) Move(local, remoteDir string) error { + if err := w.Copy(local, remoteDir); err != nil { + return err + } return os.RemoveAll(local) } @@ -99,12 +105,10 @@ func (w *WebdavStorage) ReadDir(dir string) ([]fs.FileInfo, error) { return w.fs.ReadDir(filepath.Join(w.dir, dir)) } - func (w *WebdavStorage) ReadFile(name string) ([]byte, error) { return w.fs.Read(filepath.Join(w.dir, name)) } - -func (w *WebdavStorage) WriteFile(name string, data []byte) error { +func (w *WebdavStorage) WriteFile(name string, data []byte) error { return w.fs.Write(filepath.Join(w.dir, name), data, os.ModePerm) -} \ No newline at end of file +} diff --git a/server/activity.go b/server/activity.go index 08ca63d..2e61a95 100644 --- a/server/activity.go +++ b/server/activity.go @@ -102,7 +102,7 @@ type TorrentInfo struct { } func (s *Server) GetAllTorrents(c *gin.Context) (interface{}, error) { - trc, err := s.getDownloadClient() + trc, _, err := s.getDownloadClient() if err != nil { return nil, errors.Wrap(err, "connect transmission") } diff --git a/server/resources.go b/server/resources.go index 996a156..2c6e2b6 100644 --- a/server/resources.go +++ b/server/resources.go @@ -30,7 +30,7 @@ func (s *Server) searchAndDownloadSeasonPackage(seriesId, seasonNum int) (*strin } func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum int) (*string, error) { - trc, err := s.getDownloadClient() + trc, dlClient, err := s.getDownloadClient() if err != nil { return nil, errors.Wrap(err, "connect transmission") } @@ -61,6 +61,7 @@ func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum in Status: history.StatusRunning, Size: r1.Size, Saved: torrent.Save(), + DownloadClientID: dlClient.ID, }) if err != nil { return nil, errors.Wrap(err, "save record") @@ -75,7 +76,7 @@ func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum in } func (s *Server) downloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum, episodeNum int) (*string, error) { - trc, err := s.getDownloadClient() + trc, dlc, err := s.getDownloadClient() if err != nil { return nil, errors.Wrap(err, "connect transmission") } @@ -108,6 +109,7 @@ func (s *Server) downloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum, Status: history.StatusRunning, Size: r1.Size, Saved: torrent.Save(), + DownloadClientID: dlc.ID, }) if err != nil { return nil, errors.Wrap(err, "save record") @@ -264,7 +266,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) { res := torznab.Result{Name: name, Link: in.Link, Size: in.Size} return s.downloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode) } - trc, err := s.getDownloadClient() + trc, dlc, err := s.getDownloadClient() if err != nil { return nil, errors.Wrap(err, "connect transmission") } @@ -288,6 +290,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) { Status: history.StatusRunning, Size: in.Size, Saved: torrent.Save(), + DownloadClientID: dlc.ID, }) if err != nil { log.Errorf("save history error: %v", err) diff --git a/server/scheduler.go b/server/scheduler.go index 5c11f7a..5e7dc12 100644 --- a/server/scheduler.go +++ b/server/scheduler.go @@ -7,11 +7,9 @@ import ( "polaris/ent/episode" "polaris/ent/history" "polaris/ent/media" - storage1 "polaris/ent/storage" "polaris/log" "polaris/pkg" "polaris/pkg/notifier/message" - "polaris/pkg/storage" "polaris/pkg/utils" "polaris/server/core" "time" @@ -64,13 +62,18 @@ func (s *Server) moveCompletedTask(id int) (err1 error) { return nil } s.db.SetHistoryStatus(r.ID, history.StatusUploading) + seasonNum, err := utils.SeasonId(r.TargetDir) + if err != nil { + log.Errorf("no season id: %v", r.TargetDir) + seasonNum = -1 + } + downloadclient, err := s.db.GetDownloadClient(r.DownloadClientID) + if err != nil { + log.Errorf("get task download client error: %v, use default one", err) + downloadclient = &ent.DownloadClients{RemoveCompletedDownloads: true, RemoveFailedDownloads: true} + } defer func() { - seasonNum, err := utils.SeasonId(r.TargetDir) - if err != nil { - log.Errorf("no season id: %v", r.TargetDir) - seasonNum = -1 - } if err1 != nil { s.db.SetHistoryStatus(r.ID, history.StatusFail) @@ -80,22 +83,10 @@ func (s *Server) moveCompletedTask(id int) (err1 error) { s.db.SetSeasonAllEpisodeStatus(r.MediaID, seasonNum, episode.StatusMissing) } s.sendMsg(fmt.Sprintf(message.ProcessingFailed, err)) - } else { - // .plexmatch file - if err := s.writePlexmatch(r.MediaID, r.EpisodeID, r.TargetDir, torrent.Name()); err != nil { - log.Errorf("create .plexmatch file error: %v", err) + if downloadclient.RemoveCompletedDownloads { + delete(s.tasks, r.ID) + torrent.Remove() } - - delete(s.tasks, r.ID) - s.db.SetHistoryStatus(r.ID, history.StatusSuccess) - if r.EpisodeID != 0 { - s.db.SetEpisodeStatus(r.EpisodeID, episode.StatusDownloaded) - } else { - s.db.SetSeasonAllEpisodeStatus(r.MediaID, seasonNum, episode.StatusDownloaded) - } - s.sendMsg(fmt.Sprintf(message.ProcessingComplete, torrent.Name())) - - torrent.Remove() } }() @@ -105,40 +96,37 @@ func (s *Server) moveCompletedTask(id int) (err1 error) { } st := s.db.GetStorage(series.StorageID) log.Infof("move task files to target dir: %v", r.TargetDir) - var stImpl storage.Storage - if st.Implementation == storage1.ImplementationWebdav { - ws := st.ToWebDavSetting() - targetPath := ws.TvPath - if series.MediaType == media.MediaTypeMovie { - targetPath = ws.MoviePath - } - storageImpl, err := storage.NewWebdavStorage(ws.URL, ws.User, ws.Password, targetPath, ws.ChangeFileHash == "true") - if err != nil { - return errors.Wrap(err, "new webdav") - } - stImpl = storageImpl - - } else if st.Implementation == storage1.ImplementationLocal { - ls := st.ToLocalSetting() - targetPath := ls.TvPath - if series.MediaType == media.MediaTypeMovie { - targetPath = ls.MoviePath - } - - storageImpl, err := storage.NewLocalStorage(targetPath) - if err != nil { - return errors.Wrap(err, "new storage") - - } - stImpl = storageImpl - + stImpl, err := s.getStorage(st.ID, series.MediaType) + if err != nil { + return err } //如果种子是路径,则会把路径展开,只移动文件,类似 move dir/* dir2/, 如果种子是文件,则会直接移动文件,类似 move file dir/ - if err := stImpl.Move(filepath.Join(s.db.GetDownloadDir(), torrent.Name()), r.TargetDir); err != nil { + if err := stImpl.Copy(filepath.Join(s.db.GetDownloadDir(), torrent.Name()), r.TargetDir); err != nil { return errors.Wrap(err, "move file") } + // .plexmatch file + if err := s.writePlexmatch(r.MediaID, r.EpisodeID, r.TargetDir, torrent.Name()); err != nil { + log.Errorf("create .plexmatch file error: %v", err) + } + + + s.db.SetHistoryStatus(r.ID, history.StatusSuccess) + if r.EpisodeID != 0 { + s.db.SetEpisodeStatus(r.EpisodeID, episode.StatusDownloaded) + } else { + s.db.SetSeasonAllEpisodeStatus(r.MediaID, seasonNum, episode.StatusDownloaded) + } + s.sendMsg(fmt.Sprintf(message.ProcessingComplete, torrent.Name())) + + //判断是否需要删除本地文件 + if downloadclient.RemoveCompletedDownloads { + delete(s.tasks, r.ID) + torrent.Remove() + } + + log.Infof("move downloaded files to target dir success, file: %v, target dir: %v", torrent.Name(), r.TargetDir) return nil } @@ -253,7 +241,7 @@ func (s *Server) downloadMovie() { } func (s *Server) downloadMovieSingleEpisode(ep *ent.Episode) error { - trc, err := s.getDownloadClient() + trc, dlc, err := s.getDownloadClient() if err != nil { return errors.Wrap(err, "connect transmission") } @@ -272,13 +260,14 @@ func (s *Server) downloadMovieSingleEpisode(ep *ent.Episode) error { torrent.Start() history, err := s.db.SaveHistoryRecord(ent.History{ - MediaID: ep.MediaID, - EpisodeID: ep.ID, - SourceTitle: r1.Name, - TargetDir: "./", - Status: history.StatusRunning, - Size: r1.Size, - Saved: torrent.Save(), + MediaID: ep.MediaID, + EpisodeID: ep.ID, + SourceTitle: r1.Name, + TargetDir: "./", + Status: history.StatusRunning, + Size: r1.Size, + Saved: torrent.Save(), + DownloadClientID: dlc.ID, }) if err != nil { log.Errorf("save history error: %v", err) diff --git a/server/setting.go b/server/setting.go index c34848d..6065b88 100644 --- a/server/setting.go +++ b/server/setting.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" "polaris/db" + "polaris/ent" "polaris/log" "polaris/pkg/transmission" "strconv" @@ -129,7 +130,7 @@ func (s *Server) GetAllIndexers(c *gin.Context) (interface{}, error) { return indexers, nil } -func (s *Server) getDownloadClient() (*transmission.Client, error) { +func (s *Server) getDownloadClient() (*transmission.Client, *ent.DownloadClients, error) { tr := s.db.GetTransmission() trc, err := transmission.NewClient(transmission.Config{ URL: tr.URL, @@ -137,9 +138,9 @@ func (s *Server) getDownloadClient() (*transmission.Client, error) { Password: tr.Password, }) if err != nil { - return nil, errors.Wrap(err, "connect transmission") + return nil, nil, errors.Wrap(err, "connect transmission") } - return trc, nil + return trc, tr, nil } type downloadClientIn struct { diff --git a/ui/lib/providers/settings.dart b/ui/lib/providers/settings.dart index df3cd85..259e9d2 100644 --- a/ui/lib/providers/settings.dart +++ b/ui/lib/providers/settings.dart @@ -200,7 +200,8 @@ class DownloadClient { String? url; String? user; String? password; - + bool? removeCompletedDownloads; + bool? removeFailedDownloads; DownloadClient( {this.id, this.enable, @@ -208,7 +209,9 @@ class DownloadClient { this.implementation, this.url, this.user, - this.password}); + this.password, + this.removeCompletedDownloads, + this.removeFailedDownloads}); DownloadClient.fromJson(Map json) { id = json['id']; @@ -218,6 +221,8 @@ class DownloadClient { url = json['url']; user = json['user']; password = json['password']; + removeCompletedDownloads = json["remove_completed_downloads"] ?? false; + removeFailedDownloads = json["remove_failed_downloads"] ?? false; } Map toJson() { @@ -229,6 +234,8 @@ class DownloadClient { data['url'] = url; data['user'] = user; data['password'] = password; + data["remove_completed_downloads"] = removeCompletedDownloads; + data["remove_failed_downloads"] = removeFailedDownloads; return data; } } diff --git a/ui/lib/settings/downloader.dart b/ui/lib/settings/downloader.dart index 51e5ff3..ea59a7c 100644 --- a/ui/lib/settings/downloader.dart +++ b/ui/lib/settings/downloader.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/material.dart'; import 'package:flutter_form_builder/flutter_form_builder.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -53,7 +55,9 @@ class _DownloaderState extends ConsumerState { "url": client.url, "user": client.user, "password": client.password, - "impl": "transmission" + "impl": "transmission", + "remove_completed_downloads": client.removeCompletedDownloads, + "remove_failed_downloads": client.removeFailedDownloads, }, child: Column( children: [ @@ -82,6 +86,12 @@ class _DownloaderState extends ConsumerState { autovalidateMode: AutovalidateMode.onUserInteraction, validator: FormBuilderValidators.required(), ), + FormBuilderSwitch( + name: "remove_completed_downloads", + title: const Text("任务完成后删除")), + FormBuilderSwitch( + name: "remove_failed_downloads", + title: const Text("任务失败后删除")), StatefulBuilder( builder: (BuildContext context, StateSetter setState) { return Column( @@ -137,7 +147,9 @@ class _DownloaderState extends ConsumerState { implementation: values["impl"], url: values["url"], user: _enableAuth ? values["user"] : null, - password: _enableAuth ? values["password"] : null)); + password: _enableAuth ? values["password"] : null, + removeCompletedDownloads: values["remove_completed_downloads"], + removeFailedDownloads: values["remove_failed_downloads"])); } else { throw "validation_error"; }