feat: add option to control whether to deleted task

This commit is contained in:
Simon Ding
2024-07-30 21:55:54 +08:00
parent 3525d1bb83
commit 769f217506
17 changed files with 402 additions and 102 deletions

View File

@@ -552,3 +552,7 @@ func (c *Client) GetMovieDummyEpisode(movieId int) (*ent.Episode, error) {
}
return ep, nil
}
func (c *Client) GetDownloadClient(id int) (*ent.DownloadClients, error) {
return c.ent.DownloadClients.Query().Where(downloadclients.ID(id)).First(context.Background())
}

View File

@@ -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(", ")

View File

@@ -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()

View File

@@ -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))

View File

@@ -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

View File

@@ -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)
}

View File

@@ -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},
}

View File

@@ -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

View File

@@ -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(),
}

View File

@@ -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) {

View File

@@ -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")
@@ -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)
}

View File

@@ -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")
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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<String, dynamic> 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<String, dynamic> 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;
}
}

View File

@@ -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<DownloaderSettings> {
"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<DownloaderSettings> {
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<DownloaderSettings> {
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";
}