feat: save hash instead of link, and refactor torrent download

This commit is contained in:
Simon Ding
2025-02-01 14:22:34 +08:00
parent 8b6558b2b5
commit 2821d49673
18 changed files with 463 additions and 236 deletions

View File

@@ -462,18 +462,10 @@ func (c *Client) SetDefaultStorageByName(name string) error {
} }
func (c *Client) SaveHistoryRecord(h ent.History) (*ent.History, error) { func (c *Client) SaveHistoryRecord(h ent.History) (*ent.History, error) {
if h.Link != "" {
r, err := utils.Link2Magnet(h.Link)
if err != nil {
log.Warnf("convert link to magnet error, link %v, error: %v", h.Link, err)
} else {
h.Link = r
}
}
return c.ent.History.Create().SetMediaID(h.MediaID).SetEpisodeID(h.EpisodeID).SetDate(time.Now()). return c.ent.History.Create().SetMediaID(h.MediaID).SetEpisodeID(h.EpisodeID).SetDate(time.Now()).
SetStatus(h.Status).SetTargetDir(h.TargetDir).SetSourceTitle(h.SourceTitle).SetIndexerID(h.IndexerID). SetStatus(h.Status).SetTargetDir(h.TargetDir).SetSourceTitle(h.SourceTitle).SetIndexerID(h.IndexerID).
SetDownloadClientID(h.DownloadClientID).SetSize(h.Size).SetSaved(h.Saved).SetSeasonNum(h.SeasonNum). SetDownloadClientID(h.DownloadClientID).SetSize(h.Size).SetSaved(h.Saved).SetSeasonNum(h.SeasonNum).
SetEpisodeNums(h.EpisodeNums).SetLink(h.Link).Save(context.TODO()) SetEpisodeNums(h.EpisodeNums).SetHash(h.Hash).SetLink(h.Link).Save(context.TODO())
} }
func (c *Client) SetHistoryStatus(id int, status history.Status) error { func (c *Client) SetHistoryStatus(id int, status history.Status) error {

View File

@@ -38,8 +38,10 @@ type History struct {
DownloadClientID int `json:"download_client_id,omitempty"` DownloadClientID int `json:"download_client_id,omitempty"`
// IndexerID holds the value of the "indexer_id" field. // IndexerID holds the value of the "indexer_id" field.
IndexerID int `json:"indexer_id,omitempty"` IndexerID int `json:"indexer_id,omitempty"`
// Link holds the value of the "link" field. // deprecated, use hash instead
Link string `json:"link,omitempty"` Link string `json:"link,omitempty"`
// torrent hash
Hash string `json:"hash,omitempty"`
// Status holds the value of the "status" field. // Status holds the value of the "status" field.
Status history.Status `json:"status,omitempty"` Status history.Status `json:"status,omitempty"`
// deprecated // deprecated
@@ -56,7 +58,7 @@ func (*History) scanValues(columns []string) ([]any, error) {
values[i] = new([]byte) values[i] = new([]byte)
case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSeasonNum, history.FieldSize, history.FieldDownloadClientID, history.FieldIndexerID: case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSeasonNum, history.FieldSize, history.FieldDownloadClientID, history.FieldIndexerID:
values[i] = new(sql.NullInt64) values[i] = new(sql.NullInt64)
case history.FieldSourceTitle, history.FieldTargetDir, history.FieldLink, history.FieldStatus, history.FieldSaved: case history.FieldSourceTitle, history.FieldTargetDir, history.FieldLink, history.FieldHash, history.FieldStatus, history.FieldSaved:
values[i] = new(sql.NullString) values[i] = new(sql.NullString)
case history.FieldDate: case history.FieldDate:
values[i] = new(sql.NullTime) values[i] = new(sql.NullTime)
@@ -149,6 +151,12 @@ func (h *History) assignValues(columns []string, values []any) error {
} else if value.Valid { } else if value.Valid {
h.Link = value.String h.Link = value.String
} }
case history.FieldHash:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field hash", values[i])
} else if value.Valid {
h.Hash = value.String
}
case history.FieldStatus: case history.FieldStatus:
if value, ok := values[i].(*sql.NullString); !ok { if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field status", values[i]) return fmt.Errorf("unexpected type %T for field status", values[i])
@@ -230,6 +238,9 @@ func (h *History) String() string {
builder.WriteString("link=") builder.WriteString("link=")
builder.WriteString(h.Link) builder.WriteString(h.Link)
builder.WriteString(", ") builder.WriteString(", ")
builder.WriteString("hash=")
builder.WriteString(h.Hash)
builder.WriteString(", ")
builder.WriteString("status=") builder.WriteString("status=")
builder.WriteString(fmt.Sprintf("%v", h.Status)) builder.WriteString(fmt.Sprintf("%v", h.Status))
builder.WriteString(", ") builder.WriteString(", ")

View File

@@ -35,6 +35,8 @@ const (
FieldIndexerID = "indexer_id" FieldIndexerID = "indexer_id"
// FieldLink holds the string denoting the link field in the database. // FieldLink holds the string denoting the link field in the database.
FieldLink = "link" FieldLink = "link"
// FieldHash holds the string denoting the hash field in the database.
FieldHash = "hash"
// FieldStatus holds the string denoting the status field in the database. // FieldStatus holds the string denoting the status field in the database.
FieldStatus = "status" FieldStatus = "status"
// FieldSaved holds the string denoting the saved field in the database. // FieldSaved holds the string denoting the saved field in the database.
@@ -57,6 +59,7 @@ var Columns = []string{
FieldDownloadClientID, FieldDownloadClientID,
FieldIndexerID, FieldIndexerID,
FieldLink, FieldLink,
FieldHash,
FieldStatus, FieldStatus,
FieldSaved, FieldSaved,
} }
@@ -160,6 +163,11 @@ func ByLink(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldLink, opts...).ToFunc() return sql.OrderByField(FieldLink, opts...).ToFunc()
} }
// ByHash orders the results by the hash field.
func ByHash(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldHash, opts...).ToFunc()
}
// ByStatus orders the results by the status field. // ByStatus orders the results by the status field.
func ByStatus(opts ...sql.OrderTermOption) OrderOption { func ByStatus(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldStatus, opts...).ToFunc() return sql.OrderByField(FieldStatus, opts...).ToFunc()

View File

@@ -104,6 +104,11 @@ func Link(v string) predicate.History {
return predicate.History(sql.FieldEQ(FieldLink, v)) return predicate.History(sql.FieldEQ(FieldLink, v))
} }
// Hash applies equality check predicate on the "hash" field. It's identical to HashEQ.
func Hash(v string) predicate.History {
return predicate.History(sql.FieldEQ(FieldHash, v))
}
// Saved applies equality check predicate on the "saved" field. It's identical to SavedEQ. // Saved applies equality check predicate on the "saved" field. It's identical to SavedEQ.
func Saved(v string) predicate.History { func Saved(v string) predicate.History {
return predicate.History(sql.FieldEQ(FieldSaved, v)) return predicate.History(sql.FieldEQ(FieldSaved, v))
@@ -644,6 +649,81 @@ func LinkContainsFold(v string) predicate.History {
return predicate.History(sql.FieldContainsFold(FieldLink, v)) return predicate.History(sql.FieldContainsFold(FieldLink, v))
} }
// HashEQ applies the EQ predicate on the "hash" field.
func HashEQ(v string) predicate.History {
return predicate.History(sql.FieldEQ(FieldHash, v))
}
// HashNEQ applies the NEQ predicate on the "hash" field.
func HashNEQ(v string) predicate.History {
return predicate.History(sql.FieldNEQ(FieldHash, v))
}
// HashIn applies the In predicate on the "hash" field.
func HashIn(vs ...string) predicate.History {
return predicate.History(sql.FieldIn(FieldHash, vs...))
}
// HashNotIn applies the NotIn predicate on the "hash" field.
func HashNotIn(vs ...string) predicate.History {
return predicate.History(sql.FieldNotIn(FieldHash, vs...))
}
// HashGT applies the GT predicate on the "hash" field.
func HashGT(v string) predicate.History {
return predicate.History(sql.FieldGT(FieldHash, v))
}
// HashGTE applies the GTE predicate on the "hash" field.
func HashGTE(v string) predicate.History {
return predicate.History(sql.FieldGTE(FieldHash, v))
}
// HashLT applies the LT predicate on the "hash" field.
func HashLT(v string) predicate.History {
return predicate.History(sql.FieldLT(FieldHash, v))
}
// HashLTE applies the LTE predicate on the "hash" field.
func HashLTE(v string) predicate.History {
return predicate.History(sql.FieldLTE(FieldHash, v))
}
// HashContains applies the Contains predicate on the "hash" field.
func HashContains(v string) predicate.History {
return predicate.History(sql.FieldContains(FieldHash, v))
}
// HashHasPrefix applies the HasPrefix predicate on the "hash" field.
func HashHasPrefix(v string) predicate.History {
return predicate.History(sql.FieldHasPrefix(FieldHash, v))
}
// HashHasSuffix applies the HasSuffix predicate on the "hash" field.
func HashHasSuffix(v string) predicate.History {
return predicate.History(sql.FieldHasSuffix(FieldHash, v))
}
// HashIsNil applies the IsNil predicate on the "hash" field.
func HashIsNil() predicate.History {
return predicate.History(sql.FieldIsNull(FieldHash))
}
// HashNotNil applies the NotNil predicate on the "hash" field.
func HashNotNil() predicate.History {
return predicate.History(sql.FieldNotNull(FieldHash))
}
// HashEqualFold applies the EqualFold predicate on the "hash" field.
func HashEqualFold(v string) predicate.History {
return predicate.History(sql.FieldEqualFold(FieldHash, v))
}
// HashContainsFold applies the ContainsFold predicate on the "hash" field.
func HashContainsFold(v string) predicate.History {
return predicate.History(sql.FieldContainsFold(FieldHash, v))
}
// StatusEQ applies the EQ predicate on the "status" field. // StatusEQ applies the EQ predicate on the "status" field.
func StatusEQ(v Status) predicate.History { func StatusEQ(v Status) predicate.History {
return predicate.History(sql.FieldEQ(FieldStatus, v)) return predicate.History(sql.FieldEQ(FieldStatus, v))

View File

@@ -134,6 +134,20 @@ func (hc *HistoryCreate) SetNillableLink(s *string) *HistoryCreate {
return hc return hc
} }
// SetHash sets the "hash" field.
func (hc *HistoryCreate) SetHash(s string) *HistoryCreate {
hc.mutation.SetHash(s)
return hc
}
// SetNillableHash sets the "hash" field if the given value is not nil.
func (hc *HistoryCreate) SetNillableHash(s *string) *HistoryCreate {
if s != nil {
hc.SetHash(*s)
}
return hc
}
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (hc *HistoryCreate) SetStatus(h history.Status) *HistoryCreate { func (hc *HistoryCreate) SetStatus(h history.Status) *HistoryCreate {
hc.mutation.SetStatus(h) hc.mutation.SetStatus(h)
@@ -290,6 +304,10 @@ func (hc *HistoryCreate) createSpec() (*History, *sqlgraph.CreateSpec) {
_spec.SetField(history.FieldLink, field.TypeString, value) _spec.SetField(history.FieldLink, field.TypeString, value)
_node.Link = value _node.Link = value
} }
if value, ok := hc.mutation.Hash(); ok {
_spec.SetField(history.FieldHash, field.TypeString, value)
_node.Hash = value
}
if value, ok := hc.mutation.Status(); ok { if value, ok := hc.mutation.Status(); ok {
_spec.SetField(history.FieldStatus, field.TypeEnum, value) _spec.SetField(history.FieldStatus, field.TypeEnum, value)
_node.Status = value _node.Status = value

View File

@@ -259,6 +259,26 @@ func (hu *HistoryUpdate) ClearLink() *HistoryUpdate {
return hu return hu
} }
// SetHash sets the "hash" field.
func (hu *HistoryUpdate) SetHash(s string) *HistoryUpdate {
hu.mutation.SetHash(s)
return hu
}
// SetNillableHash sets the "hash" field if the given value is not nil.
func (hu *HistoryUpdate) SetNillableHash(s *string) *HistoryUpdate {
if s != nil {
hu.SetHash(*s)
}
return hu
}
// ClearHash clears the value of the "hash" field.
func (hu *HistoryUpdate) ClearHash() *HistoryUpdate {
hu.mutation.ClearHash()
return hu
}
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (hu *HistoryUpdate) SetStatus(h history.Status) *HistoryUpdate { func (hu *HistoryUpdate) SetStatus(h history.Status) *HistoryUpdate {
hu.mutation.SetStatus(h) hu.mutation.SetStatus(h)
@@ -421,6 +441,12 @@ func (hu *HistoryUpdate) sqlSave(ctx context.Context) (n int, err error) {
if hu.mutation.LinkCleared() { if hu.mutation.LinkCleared() {
_spec.ClearField(history.FieldLink, field.TypeString) _spec.ClearField(history.FieldLink, field.TypeString)
} }
if value, ok := hu.mutation.Hash(); ok {
_spec.SetField(history.FieldHash, field.TypeString, value)
}
if hu.mutation.HashCleared() {
_spec.ClearField(history.FieldHash, field.TypeString)
}
if value, ok := hu.mutation.Status(); ok { if value, ok := hu.mutation.Status(); ok {
_spec.SetField(history.FieldStatus, field.TypeEnum, value) _spec.SetField(history.FieldStatus, field.TypeEnum, value)
} }
@@ -680,6 +706,26 @@ func (huo *HistoryUpdateOne) ClearLink() *HistoryUpdateOne {
return huo return huo
} }
// SetHash sets the "hash" field.
func (huo *HistoryUpdateOne) SetHash(s string) *HistoryUpdateOne {
huo.mutation.SetHash(s)
return huo
}
// SetNillableHash sets the "hash" field if the given value is not nil.
func (huo *HistoryUpdateOne) SetNillableHash(s *string) *HistoryUpdateOne {
if s != nil {
huo.SetHash(*s)
}
return huo
}
// ClearHash clears the value of the "hash" field.
func (huo *HistoryUpdateOne) ClearHash() *HistoryUpdateOne {
huo.mutation.ClearHash()
return huo
}
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (huo *HistoryUpdateOne) SetStatus(h history.Status) *HistoryUpdateOne { func (huo *HistoryUpdateOne) SetStatus(h history.Status) *HistoryUpdateOne {
huo.mutation.SetStatus(h) huo.mutation.SetStatus(h)
@@ -872,6 +918,12 @@ func (huo *HistoryUpdateOne) sqlSave(ctx context.Context) (_node *History, err e
if huo.mutation.LinkCleared() { if huo.mutation.LinkCleared() {
_spec.ClearField(history.FieldLink, field.TypeString) _spec.ClearField(history.FieldLink, field.TypeString)
} }
if value, ok := huo.mutation.Hash(); ok {
_spec.SetField(history.FieldHash, field.TypeString, value)
}
if huo.mutation.HashCleared() {
_spec.ClearField(history.FieldHash, field.TypeString)
}
if value, ok := huo.mutation.Status(); ok { if value, ok := huo.mutation.Status(); ok {
_spec.SetField(history.FieldStatus, field.TypeEnum, value) _spec.SetField(history.FieldStatus, field.TypeEnum, value)
} }

View File

@@ -83,6 +83,7 @@ var (
{Name: "download_client_id", Type: field.TypeInt, Nullable: true}, {Name: "download_client_id", Type: field.TypeInt, Nullable: true},
{Name: "indexer_id", Type: field.TypeInt, Nullable: true}, {Name: "indexer_id", Type: field.TypeInt, Nullable: true},
{Name: "link", Type: field.TypeString, Nullable: true}, {Name: "link", Type: field.TypeString, Nullable: true},
{Name: "hash", Type: field.TypeString, Nullable: true},
{Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading", "seeding"}}, {Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading", "seeding"}},
{Name: "saved", Type: field.TypeString, Nullable: true}, {Name: "saved", Type: field.TypeString, Nullable: true},
} }

View File

@@ -2350,6 +2350,7 @@ type HistoryMutation struct {
indexer_id *int indexer_id *int
addindexer_id *int addindexer_id *int
link *string link *string
hash *string
status *history.Status status *history.Status
saved *string saved *string
clearedFields map[string]struct{} clearedFields map[string]struct{}
@@ -3070,6 +3071,55 @@ func (m *HistoryMutation) ResetLink() {
delete(m.clearedFields, history.FieldLink) delete(m.clearedFields, history.FieldLink)
} }
// SetHash sets the "hash" field.
func (m *HistoryMutation) SetHash(s string) {
m.hash = &s
}
// Hash returns the value of the "hash" field in the mutation.
func (m *HistoryMutation) Hash() (r string, exists bool) {
v := m.hash
if v == nil {
return
}
return *v, true
}
// OldHash returns the old "hash" 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) OldHash(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldHash is only allowed on UpdateOne operations")
}
if m.id == nil || m.oldValue == nil {
return v, errors.New("OldHash requires an ID field in the mutation")
}
oldValue, err := m.oldValue(ctx)
if err != nil {
return v, fmt.Errorf("querying old value for OldHash: %w", err)
}
return oldValue.Hash, nil
}
// ClearHash clears the value of the "hash" field.
func (m *HistoryMutation) ClearHash() {
m.hash = nil
m.clearedFields[history.FieldHash] = struct{}{}
}
// HashCleared returns if the "hash" field was cleared in this mutation.
func (m *HistoryMutation) HashCleared() bool {
_, ok := m.clearedFields[history.FieldHash]
return ok
}
// ResetHash resets all changes to the "hash" field.
func (m *HistoryMutation) ResetHash() {
m.hash = nil
delete(m.clearedFields, history.FieldHash)
}
// SetStatus sets the "status" field. // SetStatus sets the "status" field.
func (m *HistoryMutation) SetStatus(h history.Status) { func (m *HistoryMutation) SetStatus(h history.Status) {
m.status = &h m.status = &h
@@ -3189,7 +3239,7 @@ func (m *HistoryMutation) Type() string {
// order to get all numeric fields that were incremented/decremented, call // order to get all numeric fields that were incremented/decremented, call
// AddedFields(). // AddedFields().
func (m *HistoryMutation) Fields() []string { func (m *HistoryMutation) Fields() []string {
fields := make([]string, 0, 13) fields := make([]string, 0, 14)
if m.media_id != nil { if m.media_id != nil {
fields = append(fields, history.FieldMediaID) fields = append(fields, history.FieldMediaID)
} }
@@ -3223,6 +3273,9 @@ func (m *HistoryMutation) Fields() []string {
if m.link != nil { if m.link != nil {
fields = append(fields, history.FieldLink) fields = append(fields, history.FieldLink)
} }
if m.hash != nil {
fields = append(fields, history.FieldHash)
}
if m.status != nil { if m.status != nil {
fields = append(fields, history.FieldStatus) fields = append(fields, history.FieldStatus)
} }
@@ -3259,6 +3312,8 @@ func (m *HistoryMutation) Field(name string) (ent.Value, bool) {
return m.IndexerID() return m.IndexerID()
case history.FieldLink: case history.FieldLink:
return m.Link() return m.Link()
case history.FieldHash:
return m.Hash()
case history.FieldStatus: case history.FieldStatus:
return m.Status() return m.Status()
case history.FieldSaved: case history.FieldSaved:
@@ -3294,6 +3349,8 @@ func (m *HistoryMutation) OldField(ctx context.Context, name string) (ent.Value,
return m.OldIndexerID(ctx) return m.OldIndexerID(ctx)
case history.FieldLink: case history.FieldLink:
return m.OldLink(ctx) return m.OldLink(ctx)
case history.FieldHash:
return m.OldHash(ctx)
case history.FieldStatus: case history.FieldStatus:
return m.OldStatus(ctx) return m.OldStatus(ctx)
case history.FieldSaved: case history.FieldSaved:
@@ -3384,6 +3441,13 @@ func (m *HistoryMutation) SetField(name string, value ent.Value) error {
} }
m.SetLink(v) m.SetLink(v)
return nil return nil
case history.FieldHash:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetHash(v)
return nil
case history.FieldStatus: case history.FieldStatus:
v, ok := value.(history.Status) v, ok := value.(history.Status)
if !ok { if !ok {
@@ -3521,6 +3585,9 @@ func (m *HistoryMutation) ClearedFields() []string {
if m.FieldCleared(history.FieldLink) { if m.FieldCleared(history.FieldLink) {
fields = append(fields, history.FieldLink) fields = append(fields, history.FieldLink)
} }
if m.FieldCleared(history.FieldHash) {
fields = append(fields, history.FieldHash)
}
if m.FieldCleared(history.FieldSaved) { if m.FieldCleared(history.FieldSaved) {
fields = append(fields, history.FieldSaved) fields = append(fields, history.FieldSaved)
} }
@@ -3556,6 +3623,9 @@ func (m *HistoryMutation) ClearField(name string) error {
case history.FieldLink: case history.FieldLink:
m.ClearLink() m.ClearLink()
return nil return nil
case history.FieldHash:
m.ClearHash()
return nil
case history.FieldSaved: case history.FieldSaved:
m.ClearSaved() m.ClearSaved()
return nil return nil
@@ -3600,6 +3670,9 @@ func (m *HistoryMutation) ResetField(name string) error {
case history.FieldLink: case history.FieldLink:
m.ResetLink() m.ResetLink()
return nil return nil
case history.FieldHash:
m.ResetHash()
return nil
case history.FieldStatus: case history.FieldStatus:
m.ResetStatus() m.ResetStatus()
return nil return nil

View File

@@ -23,7 +23,8 @@ func (History) Fields() []ent.Field {
field.Int("size").Default(0), field.Int("size").Default(0),
field.Int("download_client_id").Optional(), field.Int("download_client_id").Optional(),
field.Int("indexer_id").Optional(), field.Int("indexer_id").Optional(),
field.String("link").Optional(), //should be magnet link field.String("link").Optional().Comment("deprecated, use hash instead"), //should be magnet link
field.String("hash").Optional().Comment("torrent hash"),
field.Enum("status").Values("running", "success", "fail", "uploading", "seeding"), field.Enum("status").Values("running", "success", "fail", "uploading", "seeding"),
field.String("saved").Optional().Comment("deprecated"), //deprecated field.String("saved").Optional().Comment("deprecated"), //deprecated
} }

8
go.sum
View File

@@ -216,6 +216,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@@ -249,6 +251,8 @@ github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt
github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g= github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/nikoksr/notify v1.0.0 h1:qe9/6FRsWdxBgQgWcpvQ0sv8LRGJZDpRB4TkL2uNdO8= 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/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/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -306,6 +310,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/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 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= 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 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
@@ -447,6 +453,8 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golift.io/starr v1.0.0 h1:IDSaSL+ZYxdLT/Lg//dg/iwZ39LHO3D5CmbLCOgSXbI= golift.io/starr v1.0.0 h1:IDSaSL+ZYxdLT/Lg//dg/iwZ39LHO3D5CmbLCOgSXbI=

View File

@@ -18,5 +18,5 @@ type Torrent interface {
type Downloader interface { type Downloader interface {
GetAll() ([]Torrent, error) GetAll() ([]Torrent, error)
Download(link, dir string) (Torrent, error) Download(link, hash, dir string) (Torrent, error)
} }

View File

@@ -61,49 +61,45 @@ func (c *Client) GetAll() ([]pkg.Torrent, error) {
return res, nil return res, nil
} }
func (c *Client) Download(link, dir string) (pkg.Torrent, error) { func (c *Client) Download(link, hash, dir string) (pkg.Torrent, error) {
err := c.c.DownloadLinks([]string{link}, qbt.DownloadOptions{Savepath: &dir, Category: &c.category}) err := c.c.DownloadLinks([]string{link}, qbt.DownloadOptions{Savepath: &dir, Category: &c.category})
if err != nil { if err != nil {
return nil, errors.Wrap(err, "qbt download") return nil, errors.Wrap(err, "qbt download")
} }
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, errors.Wrap(err, "get hash")
}
return &Torrent{hash: hash, c: c.c}, nil return &Torrent{hash: hash, c: c.c}, nil
} }
func NewTorrent(info Info, link string) (*Torrent, error) { func NewTorrentHash(info Info, hash string) (*Torrent, error) {
c, err := NewClient(info.URL, info.User, info.Password) c, err := NewClient(info.URL, info.User, info.Password)
if err != nil { if err != nil {
return nil, err return nil, err
} }
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, err
}
t := &Torrent{ t := &Torrent{
c: c.c, c: c.c,
hash: hash, hash: hash,
} }
if !t.Exists() { if !t.Exists() {
return nil, errors.Errorf("torrent not exist: %v", magnet) return nil, errors.Errorf("torrent not exist: %v", hash)
} }
return t, nil return t, nil
} }
func NewTorrent(info Info, link string) (*Torrent, error) {
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, err
}
return NewTorrentHash(info, hash)
}
type Torrent struct { type Torrent struct {
c *qbt.Client c *qbt.Client
hash string hash string

View File

@@ -63,7 +63,7 @@ func (c *Client) GetAll() ([]pkg.Torrent, error) {
return torrents, nil return torrents, nil
} }
func (c *Client) Download(link, dir string) (pkg.Torrent, error) { func (c *Client) Download(link, hash, dir string) (pkg.Torrent, error) {
t, err := c.c.TorrentAdd(context.TODO(), transmissionrpc.TorrentAddPayload{ t, err := c.c.TorrentAdd(context.TODO(), transmissionrpc.TorrentAddPayload{
Filename: &link, Filename: &link,
@@ -74,16 +74,6 @@ func (c *Client) Download(link, dir string) (pkg.Torrent, error) {
} }
log.Debugf("get torrent info: %+v", t) log.Debugf("get torrent info: %+v", t)
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, errors.Wrap(err, "get hash")
}
return &Torrent{ return &Torrent{
hash: hash, hash: hash,
c: c.c, c: c.c,
@@ -91,33 +81,38 @@ func (c *Client) Download(link, dir string) (pkg.Torrent, error) {
}, err }, err
} }
func NewTorrent(cfg Config, link string) (*Torrent, error) { func NewTorrentHash(cfg Config, hash string) (*Torrent, error) {
c, err := NewClient(cfg) c, err := NewClient(cfg)
if err != nil { if err != nil {
return nil, err return nil, err
} }
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, err
}
t := &Torrent{ t := &Torrent{
c: c.c, c: c.c,
hash: hash, hash: hash,
//cfg: cfg, //cfg: cfg,
} }
if !t.Exists() { if !t.Exists() {
return nil, errors.Errorf("torrent not exist: %v", magnet) return nil, errors.Errorf("torrent not exist: %v", hash)
} }
return t, nil return t, nil
} }
func NewTorrent(cfg Config, link string) (*Torrent, error) {
magnet, err := utils.Link2Magnet(link)
if err != nil {
return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
}
hash, err := utils.MagnetHash(magnet)
if err != nil {
return nil, err
}
return NewTorrentHash(cfg, hash)
}
type Torrent struct { type Torrent struct {
//t *transmissionrpc.Torrent //t *transmissionrpc.Torrent
c *transmissionrpc.Client c *transmissionrpc.Client

View File

@@ -222,6 +222,33 @@ func isWSL() bool {
return strings.Contains(strings.ToLower(string(releaseData)), "microsoft") return strings.Contains(strings.ToLower(string(releaseData)), "microsoft")
} }
func Link2Hash(link string) (string, error) {
if strings.HasPrefix(strings.ToLower(link), "magnet:") {
return MagnetHash(link)
}
client := &http.Client{
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse //do not follow redirects
},
}
resp, err := client.Get(link)
if err != nil {
return "", errors.Wrap(err, "get link")
}
defer resp.Body.Close()
if resp.StatusCode >= 300 && resp.StatusCode < 400 {
//redirects
tourl := resp.Header.Get("Location")
return Link2Hash(tourl)
}
info, err := metainfo.Load(resp.Body)
if err != nil {
return "", errors.Wrap(err, "parse response")
}
return info.HashInfoBytes().AsString(), nil
}
func Link2Magnet(link string) (string, error) { func Link2Magnet(link string) (string, error) {
if strings.HasPrefix(strings.ToLower(link), "magnet:") { if strings.HasPrefix(strings.ToLower(link), "magnet:") {
return link, nil return link, nil

View File

@@ -59,27 +59,55 @@ func (c *Client) reloadTasks() {
} }
if dl.Implementation == downloadclients.ImplementationTransmission { if dl.Implementation == downloadclients.ImplementationTransmission {
to, err := transmission.NewTorrent(transmission.Config{ if t.Hash != "" { //优先使用hash
URL: dl.URL, to, err := transmission.NewTorrentHash(transmission.Config{
User: dl.User, URL: dl.URL,
Password: dl.Password, User: dl.User,
}, t.Link) Password: dl.Password,
if err != nil { }, t.Hash)
log.Warnf("get task error: %v", err) if err != nil {
continue log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} else if t.Link != "" {
to, err := transmission.NewTorrent(transmission.Config{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} }
c.tasks[t.ID] = &Task{Torrent: to}
} else if dl.Implementation == downloadclients.ImplementationQbittorrent { } else if dl.Implementation == downloadclients.ImplementationQbittorrent {
to, err := qbittorrent.NewTorrent(qbittorrent.Info{ if t.Hash != "" {
URL: dl.URL, to, err := qbittorrent.NewTorrentHash(qbittorrent.Info{
User: dl.User, URL: dl.URL,
Password: dl.Password, User: dl.User,
}, t.Link) Password: dl.Password,
if err != nil { }, t.Hash)
log.Warnf("get task error: %v", err) if err != nil {
continue log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} else if t.Link != "" {
to, err := qbittorrent.NewTorrent(qbittorrent.Info{
URL: dl.URL,
User: dl.User,
Password: dl.Password,
}, t.Link)
if err != nil {
log.Warnf("get task error: %v", err)
continue
}
c.tasks[t.ID] = &Task{Torrent: to}
} }
c.tasks[t.ID] = &Task{Torrent: to}
} }
} }

View File

@@ -6,6 +6,7 @@ import (
"polaris/ent" "polaris/ent"
"polaris/ent/episode" "polaris/ent/episode"
"polaris/ent/history" "polaris/ent/history"
"polaris/ent/media"
"polaris/log" "polaris/log"
"polaris/pkg/metadata" "polaris/pkg/metadata"
"polaris/pkg/notifier/message" "polaris/pkg/notifier/message"
@@ -16,95 +17,13 @@ import (
) )
func (c *Client) DownloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum int, episodeNums ...int) (*string, error) { func (c *Client) DownloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum int, episodeNums ...int) (*string, error) {
trc, dlc, err := c.GetDownloadClient()
series, err := c.db.GetMedia(seriesId)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "connect transmission")
}
series := c.db.GetMediaDetails(seriesId)
if series == nil {
return nil, fmt.Errorf("no tv series of id %v", seriesId) return nil, fmt.Errorf("no tv series of id %v", seriesId)
} }
//check space available return c.downloadTorrent(series, r1, seasonNum, episodeNums...)
downloadDir := c.db.GetDownloadDir()
size := utils.AvailableSpace(downloadDir)
if size < uint64(r1.Size) {
log.Errorf("space available %v, space needed %v", size, r1.Size)
return nil, errors.New("no enough space")
}
// magnet, err := utils.Link2Magnet(r1.Link)
// if err != nil {
// return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", r1.Link, err)
// }
dir := fmt.Sprintf("%s/Season %02d/", series.TargetDir, seasonNum)
if len(episodeNums) > 0 {
for _, epNum := range episodeNums {
var ep *ent.Episode
for _, e := range series.Episodes {
if e.SeasonNumber == seasonNum && e.EpisodeNumber == epNum {
ep = e
}
}
if ep == nil {
return nil, errors.Errorf("no episode of season %d episode %d", seasonNum, epNum)
}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
} else { //season package download
c.db.SetSeasonAllEpisodeStatus(seriesId, seasonNum, episode.StatusDownloading)
}
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: seriesId,
EpisodeNums: episodeNums,
SeasonNum: seasonNum,
SourceTitle: r1.Name,
TargetDir: dir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: r1.Link,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
return nil, errors.Wrap(err, "save record")
}
torrent, err := trc.Download(r1.Link, downloadDir)
if err != nil {
return nil, errors.Wrap(err, "downloading")
}
torrent.Start()
c.tasks[history.ID] = &Task{Torrent: torrent}
name := r1.Name
if len(episodeNums) > 0 {
buff := &bytes.Buffer{}
for i, ep := range episodeNums {
if i != 0 {
buff.WriteString(",")
}
buff.WriteString(fmt.Sprint(ep))
}
name = fmt.Sprintf("第%s集 (%s)", buff.String(), name)
} else {
name = fmt.Sprintf("全集 (%s)", name)
}
c.sendMsg(fmt.Sprintf(message.BeginDownload, name))
log.Infof("success add %s to download task", r1.Name)
return &r1.Name, nil
} }
/* /*
@@ -192,53 +111,95 @@ lo:
return torrentNames, nil return torrentNames, nil
} }
func (c *Client) DownloadMovie(m *ent.Media, link, name string, size int64, indexerID int) (*string, error) { func (c *Client) DownloadMovie(m *ent.Media, r1 torznab.Result) (*string, error) {
return c.downloadTorrent(m, r1, 0)
}
func (c *Client) downloadTorrent(m *ent.Media, r1 torznab.Result, seasonNum int, episodeNums ...int) (*string, error) {
trc, dlc, err := c.GetDownloadClient() trc, dlc, err := c.GetDownloadClient()
if err != nil { if err != nil {
return nil, errors.Wrap(err, "connect transmission") return nil, errors.Wrap(err, "connect transmission")
} }
// magnet, err := utils.Link2Magnet(link)
// if err != nil {
// return nil, errors.Errorf("converting link to magnet error, link: %v, error: %v", link, err)
// }
torrent, err := trc.Download(link, c.db.GetDownloadDir()) //check space available
downloadDir := c.db.GetDownloadDir()
size := utils.AvailableSpace(downloadDir)
if size < uint64(r1.Size) {
log.Errorf("space available %v, space needed %v", size, r1.Size)
return nil, errors.New("no enough space")
}
var name = r1.Name
var targetDir = m.TargetDir
if m.MediaType == media.MediaTypeTv { //tv download
targetDir = fmt.Sprintf("%s/Season %02d/", m.TargetDir, seasonNum)
if len(episodeNums) > 0 {
for _, epNum := range episodeNums {
ep, err := c.db.GetEpisode(m.ID, seasonNum, epNum)
if err != nil {
return nil, errors.Errorf("no episode of season %d episode %d", seasonNum, epNum)
}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
buff := &bytes.Buffer{}
for i, ep := range episodeNums {
if i != 0 {
buff.WriteString(",")
}
buff.WriteString(fmt.Sprint(ep))
}
name = fmt.Sprintf("第%s集 (%s)", buff.String(), name)
} else { //season package download
name = fmt.Sprintf("全集 (%s)", name)
c.db.SetSeasonAllEpisodeStatus(m.ID, seasonNum, episode.StatusDownloading)
}
} else {
ep, _ := c.db.GetMovieDummyEpisode(m.ID)
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}
hash, err := utils.Link2Hash(r1.Link)
if err != nil {
return nil, errors.Wrap(err, "get hash")
}
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: m.ID,
EpisodeNums: episodeNums,
SeasonNum: seasonNum,
SourceTitle: r1.Name,
TargetDir: targetDir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: r1.Link,
Hash: hash,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
return nil, errors.Wrap(err, "save record")
}
torrent, err := trc.Download(r1.Link, hash, downloadDir)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "downloading") return nil, errors.Wrap(err, "downloading")
} }
torrent.Start() torrent.Start()
if name == "" { c.tasks[history.ID] = &Task{Torrent: torrent}
name = m.OriginalName
}
go func() {
ep, _ := c.db.GetMovieDummyEpisode(m.ID)
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: m.ID,
EpisodeID: ep.ID,
SourceTitle: name,
TargetDir: m.TargetDir,
Status: history.StatusRunning,
Size: int(size),
//Saved: torrent.Save(),
Link: link,
DownloadClientID: dlc.ID,
IndexerID: indexerID,
})
if err != nil {
log.Errorf("save history error: %v", err)
}
c.tasks[history.ID] = &Task{Torrent: torrent}
if ep.Status == episode.StatusMissing {
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
}
}()
c.sendMsg(fmt.Sprintf(message.BeginDownload, name)) c.sendMsg(fmt.Sprintf(message.BeginDownload, name))
log.Infof("success add %s to download task", name)
return &name, nil
log.Infof("success add %s to download task", r1.Name)
return &r1.Name, nil
} }

View File

@@ -459,18 +459,15 @@ func (c *Client) DownloadMovieByID(id int) (string, error) {
return "", nil return "", nil
} }
if name, err := c.downloadMovieSingleEpisode(ep, detail.TargetDir); err != nil { if name, err := c.downloadMovieSingleEpisode(detail.Media, ep); err != nil {
return "", errors.Wrap(err, "download movie") return "", errors.Wrap(err, "download movie")
} else { } else {
return name, nil return name, nil
} }
} }
func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) (string, error) { func (c *Client) downloadMovieSingleEpisode(m *ent.Media, ep *ent.Episode) (string, error) {
trc, dlc, err := c.GetDownloadClient()
if err != nil {
return "", errors.Wrap(err, "connect transmission")
}
qiangban := c.db.GetSetting(db.SettingAllowQiangban) qiangban := c.db.GetSetting(db.SettingAllowQiangban)
allowQiangban := false allowQiangban := false
if qiangban == "true" { if qiangban == "true" {
@@ -484,43 +481,16 @@ func (c *Client) downloadMovieSingleEpisode(ep *ent.Episode, targetDir string) (
FilterQiangban: !allowQiangban, FilterQiangban: !allowQiangban,
}) })
if err != nil { if err != nil {
return "", errors.Wrap(err, "search movie") return "", errors.Wrap(err, "search movie")
} }
r1 := res[0] r1 := res[0]
log.Infof("begin download torrent resource: %v", r1.Name) log.Infof("begin download torrent resource: %v", r1.Name)
magnet, err := utils.Link2Magnet(r1.Link) s, err := c.downloadTorrent(m, r1, 0)
if err != nil { if err != nil {
return "", errors.Errorf("converting link to magnet error, link: %v, error: %v", r1.Link, err) return "", err
} }
return *s, nil
torrent, err := trc.Download(magnet, c.db.GetDownloadDir())
if err != nil {
return "", errors.Wrap(err, "downloading")
}
torrent.Start()
history, err := c.db.SaveHistoryRecord(ent.History{
MediaID: ep.MediaID,
EpisodeID: ep.ID,
SourceTitle: r1.Name,
TargetDir: targetDir,
Status: history.StatusRunning,
Size: int(r1.Size),
//Saved: torrent.Save(),
Link: magnet,
DownloadClientID: dlc.ID,
IndexerID: r1.IndexerId,
})
if err != nil {
log.Errorf("save history error: %v", err)
}
c.tasks[history.ID] = &Task{Torrent: torrent}
c.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
return r1.Name, nil
} }
func (c *Client) checkAllSeriesNewSeason() error { func (c *Client) checkAllSeriesNewSeason() error {

View File

@@ -164,7 +164,13 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
return s.core.DownloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode) return s.core.DownloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode)
} else { } else {
//movie //movie
return s.core.DownloadMovie(m, in.Link, in.Name, in.Size, in.IndexerId) name := in.Name
if name == "" {
name = m.OriginalName
}
res := torznab.Result{Name: name, Link: in.Link, Size: in.Size, IndexerId: in.IndexerId}
return s.core.DownloadMovie(m, res)
} }
} }