mirror of
https://github.com/simon-ding/polaris.git
synced 2026-02-06 23:21:00 +08:00
feat: improve support for pt
This commit is contained in:
@@ -31,6 +31,8 @@ type History struct {
|
|||||||
Size int `json:"size,omitempty"`
|
Size int `json:"size,omitempty"`
|
||||||
// DownloadClientID holds the value of the "download_client_id" field.
|
// DownloadClientID holds the value of the "download_client_id" field.
|
||||||
DownloadClientID int `json:"download_client_id,omitempty"`
|
DownloadClientID int `json:"download_client_id,omitempty"`
|
||||||
|
// IndexerID holds the value of the "indexer_id" field.
|
||||||
|
IndexerID int `json:"indexer_id,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"`
|
||||||
// Saved holds the value of the "saved" field.
|
// Saved holds the value of the "saved" field.
|
||||||
@@ -43,7 +45,7 @@ func (*History) scanValues(columns []string) ([]any, error) {
|
|||||||
values := make([]any, len(columns))
|
values := make([]any, len(columns))
|
||||||
for i := range columns {
|
for i := range columns {
|
||||||
switch columns[i] {
|
switch columns[i] {
|
||||||
case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSize, history.FieldDownloadClientID:
|
case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSize, history.FieldDownloadClientID, history.FieldIndexerID:
|
||||||
values[i] = new(sql.NullInt64)
|
values[i] = new(sql.NullInt64)
|
||||||
case history.FieldSourceTitle, history.FieldTargetDir, history.FieldStatus, history.FieldSaved:
|
case history.FieldSourceTitle, history.FieldTargetDir, history.FieldStatus, history.FieldSaved:
|
||||||
values[i] = new(sql.NullString)
|
values[i] = new(sql.NullString)
|
||||||
@@ -112,6 +114,12 @@ func (h *History) assignValues(columns []string, values []any) error {
|
|||||||
} else if value.Valid {
|
} else if value.Valid {
|
||||||
h.DownloadClientID = int(value.Int64)
|
h.DownloadClientID = int(value.Int64)
|
||||||
}
|
}
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
if value, ok := values[i].(*sql.NullInt64); !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field indexer_id", values[i])
|
||||||
|
} else if value.Valid {
|
||||||
|
h.IndexerID = int(value.Int64)
|
||||||
|
}
|
||||||
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])
|
||||||
@@ -181,6 +189,9 @@ func (h *History) String() string {
|
|||||||
builder.WriteString("download_client_id=")
|
builder.WriteString("download_client_id=")
|
||||||
builder.WriteString(fmt.Sprintf("%v", h.DownloadClientID))
|
builder.WriteString(fmt.Sprintf("%v", h.DownloadClientID))
|
||||||
builder.WriteString(", ")
|
builder.WriteString(", ")
|
||||||
|
builder.WriteString("indexer_id=")
|
||||||
|
builder.WriteString(fmt.Sprintf("%v", h.IndexerID))
|
||||||
|
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(", ")
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ const (
|
|||||||
FieldSize = "size"
|
FieldSize = "size"
|
||||||
// FieldDownloadClientID holds the string denoting the download_client_id field in the database.
|
// FieldDownloadClientID holds the string denoting the download_client_id field in the database.
|
||||||
FieldDownloadClientID = "download_client_id"
|
FieldDownloadClientID = "download_client_id"
|
||||||
|
// FieldIndexerID holds the string denoting the indexer_id field in the database.
|
||||||
|
FieldIndexerID = "indexer_id"
|
||||||
// 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.
|
||||||
@@ -45,6 +47,7 @@ var Columns = []string{
|
|||||||
FieldTargetDir,
|
FieldTargetDir,
|
||||||
FieldSize,
|
FieldSize,
|
||||||
FieldDownloadClientID,
|
FieldDownloadClientID,
|
||||||
|
FieldIndexerID,
|
||||||
FieldStatus,
|
FieldStatus,
|
||||||
FieldSaved,
|
FieldSaved,
|
||||||
}
|
}
|
||||||
@@ -132,6 +135,11 @@ func ByDownloadClientID(opts ...sql.OrderTermOption) OrderOption {
|
|||||||
return sql.OrderByField(FieldDownloadClientID, opts...).ToFunc()
|
return sql.OrderByField(FieldDownloadClientID, opts...).ToFunc()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ByIndexerID orders the results by the indexer_id field.
|
||||||
|
func ByIndexerID(opts ...sql.OrderTermOption) OrderOption {
|
||||||
|
return sql.OrderByField(FieldIndexerID, 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()
|
||||||
|
|||||||
@@ -89,6 +89,11 @@ func DownloadClientID(v int) predicate.History {
|
|||||||
return predicate.History(sql.FieldEQ(FieldDownloadClientID, v))
|
return predicate.History(sql.FieldEQ(FieldDownloadClientID, v))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexerID applies equality check predicate on the "indexer_id" field. It's identical to IndexerIDEQ.
|
||||||
|
func IndexerID(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldEQ(FieldIndexerID, 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))
|
||||||
@@ -444,6 +449,56 @@ func DownloadClientIDNotNil() predicate.History {
|
|||||||
return predicate.History(sql.FieldNotNull(FieldDownloadClientID))
|
return predicate.History(sql.FieldNotNull(FieldDownloadClientID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexerIDEQ applies the EQ predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDEQ(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldEQ(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDNEQ applies the NEQ predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDNEQ(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldNEQ(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDIn applies the In predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDIn(vs ...int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldIn(FieldIndexerID, vs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDNotIn applies the NotIn predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDNotIn(vs ...int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldNotIn(FieldIndexerID, vs...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDGT applies the GT predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDGT(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldGT(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDGTE applies the GTE predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDGTE(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldGTE(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDLT applies the LT predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDLT(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldLT(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDLTE applies the LTE predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDLTE(v int) predicate.History {
|
||||||
|
return predicate.History(sql.FieldLTE(FieldIndexerID, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDIsNil applies the IsNil predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDIsNil() predicate.History {
|
||||||
|
return predicate.History(sql.FieldIsNull(FieldIndexerID))
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDNotNil applies the NotNil predicate on the "indexer_id" field.
|
||||||
|
func IndexerIDNotNil() predicate.History {
|
||||||
|
return predicate.History(sql.FieldNotNull(FieldIndexerID))
|
||||||
|
}
|
||||||
|
|
||||||
// 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))
|
||||||
|
|||||||
@@ -86,6 +86,20 @@ func (hc *HistoryCreate) SetNillableDownloadClientID(i *int) *HistoryCreate {
|
|||||||
return hc
|
return hc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndexerID sets the "indexer_id" field.
|
||||||
|
func (hc *HistoryCreate) SetIndexerID(i int) *HistoryCreate {
|
||||||
|
hc.mutation.SetIndexerID(i)
|
||||||
|
return hc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableIndexerID sets the "indexer_id" field if the given value is not nil.
|
||||||
|
func (hc *HistoryCreate) SetNillableIndexerID(i *int) *HistoryCreate {
|
||||||
|
if i != nil {
|
||||||
|
hc.SetIndexerID(*i)
|
||||||
|
}
|
||||||
|
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)
|
||||||
@@ -226,6 +240,10 @@ func (hc *HistoryCreate) createSpec() (*History, *sqlgraph.CreateSpec) {
|
|||||||
_spec.SetField(history.FieldDownloadClientID, field.TypeInt, value)
|
_spec.SetField(history.FieldDownloadClientID, field.TypeInt, value)
|
||||||
_node.DownloadClientID = value
|
_node.DownloadClientID = value
|
||||||
}
|
}
|
||||||
|
if value, ok := hc.mutation.IndexerID(); ok {
|
||||||
|
_spec.SetField(history.FieldIndexerID, field.TypeInt, value)
|
||||||
|
_node.IndexerID = 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
|
||||||
|
|||||||
@@ -166,6 +166,33 @@ func (hu *HistoryUpdate) ClearDownloadClientID() *HistoryUpdate {
|
|||||||
return hu
|
return hu
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndexerID sets the "indexer_id" field.
|
||||||
|
func (hu *HistoryUpdate) SetIndexerID(i int) *HistoryUpdate {
|
||||||
|
hu.mutation.ResetIndexerID()
|
||||||
|
hu.mutation.SetIndexerID(i)
|
||||||
|
return hu
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableIndexerID sets the "indexer_id" field if the given value is not nil.
|
||||||
|
func (hu *HistoryUpdate) SetNillableIndexerID(i *int) *HistoryUpdate {
|
||||||
|
if i != nil {
|
||||||
|
hu.SetIndexerID(*i)
|
||||||
|
}
|
||||||
|
return hu
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddIndexerID adds i to the "indexer_id" field.
|
||||||
|
func (hu *HistoryUpdate) AddIndexerID(i int) *HistoryUpdate {
|
||||||
|
hu.mutation.AddIndexerID(i)
|
||||||
|
return hu
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIndexerID clears the value of the "indexer_id" field.
|
||||||
|
func (hu *HistoryUpdate) ClearIndexerID() *HistoryUpdate {
|
||||||
|
hu.mutation.ClearIndexerID()
|
||||||
|
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)
|
||||||
@@ -293,6 +320,15 @@ func (hu *HistoryUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
|||||||
if hu.mutation.DownloadClientIDCleared() {
|
if hu.mutation.DownloadClientIDCleared() {
|
||||||
_spec.ClearField(history.FieldDownloadClientID, field.TypeInt)
|
_spec.ClearField(history.FieldDownloadClientID, field.TypeInt)
|
||||||
}
|
}
|
||||||
|
if value, ok := hu.mutation.IndexerID(); ok {
|
||||||
|
_spec.SetField(history.FieldIndexerID, field.TypeInt, value)
|
||||||
|
}
|
||||||
|
if value, ok := hu.mutation.AddedIndexerID(); ok {
|
||||||
|
_spec.AddField(history.FieldIndexerID, field.TypeInt, value)
|
||||||
|
}
|
||||||
|
if hu.mutation.IndexerIDCleared() {
|
||||||
|
_spec.ClearField(history.FieldIndexerID, field.TypeInt)
|
||||||
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
@@ -460,6 +496,33 @@ func (huo *HistoryUpdateOne) ClearDownloadClientID() *HistoryUpdateOne {
|
|||||||
return huo
|
return huo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndexerID sets the "indexer_id" field.
|
||||||
|
func (huo *HistoryUpdateOne) SetIndexerID(i int) *HistoryUpdateOne {
|
||||||
|
huo.mutation.ResetIndexerID()
|
||||||
|
huo.mutation.SetIndexerID(i)
|
||||||
|
return huo
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNillableIndexerID sets the "indexer_id" field if the given value is not nil.
|
||||||
|
func (huo *HistoryUpdateOne) SetNillableIndexerID(i *int) *HistoryUpdateOne {
|
||||||
|
if i != nil {
|
||||||
|
huo.SetIndexerID(*i)
|
||||||
|
}
|
||||||
|
return huo
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddIndexerID adds i to the "indexer_id" field.
|
||||||
|
func (huo *HistoryUpdateOne) AddIndexerID(i int) *HistoryUpdateOne {
|
||||||
|
huo.mutation.AddIndexerID(i)
|
||||||
|
return huo
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIndexerID clears the value of the "indexer_id" field.
|
||||||
|
func (huo *HistoryUpdateOne) ClearIndexerID() *HistoryUpdateOne {
|
||||||
|
huo.mutation.ClearIndexerID()
|
||||||
|
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)
|
||||||
@@ -617,6 +680,15 @@ func (huo *HistoryUpdateOne) sqlSave(ctx context.Context) (_node *History, err e
|
|||||||
if huo.mutation.DownloadClientIDCleared() {
|
if huo.mutation.DownloadClientIDCleared() {
|
||||||
_spec.ClearField(history.FieldDownloadClientID, field.TypeInt)
|
_spec.ClearField(history.FieldDownloadClientID, field.TypeInt)
|
||||||
}
|
}
|
||||||
|
if value, ok := huo.mutation.IndexerID(); ok {
|
||||||
|
_spec.SetField(history.FieldIndexerID, field.TypeInt, value)
|
||||||
|
}
|
||||||
|
if value, ok := huo.mutation.AddedIndexerID(); ok {
|
||||||
|
_spec.AddField(history.FieldIndexerID, field.TypeInt, value)
|
||||||
|
}
|
||||||
|
if huo.mutation.IndexerIDCleared() {
|
||||||
|
_spec.ClearField(history.FieldIndexerID, field.TypeInt)
|
||||||
|
}
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ var (
|
|||||||
{Name: "target_dir", Type: field.TypeString},
|
{Name: "target_dir", Type: field.TypeString},
|
||||||
{Name: "size", Type: field.TypeInt, Default: 0},
|
{Name: "size", Type: field.TypeInt, Default: 0},
|
||||||
{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: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading"}},
|
{Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading"}},
|
||||||
{Name: "saved", Type: field.TypeString, Nullable: true},
|
{Name: "saved", Type: field.TypeString, Nullable: true},
|
||||||
}
|
}
|
||||||
|
|||||||
109
ent/mutation.go
109
ent/mutation.go
@@ -1719,6 +1719,8 @@ type HistoryMutation struct {
|
|||||||
addsize *int
|
addsize *int
|
||||||
download_client_id *int
|
download_client_id *int
|
||||||
adddownload_client_id *int
|
adddownload_client_id *int
|
||||||
|
indexer_id *int
|
||||||
|
addindexer_id *int
|
||||||
status *history.Status
|
status *history.Status
|
||||||
saved *string
|
saved *string
|
||||||
clearedFields map[string]struct{}
|
clearedFields map[string]struct{}
|
||||||
@@ -2185,6 +2187,76 @@ func (m *HistoryMutation) ResetDownloadClientID() {
|
|||||||
delete(m.clearedFields, history.FieldDownloadClientID)
|
delete(m.clearedFields, history.FieldDownloadClientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetIndexerID sets the "indexer_id" field.
|
||||||
|
func (m *HistoryMutation) SetIndexerID(i int) {
|
||||||
|
m.indexer_id = &i
|
||||||
|
m.addindexer_id = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerID returns the value of the "indexer_id" field in the mutation.
|
||||||
|
func (m *HistoryMutation) IndexerID() (r int, exists bool) {
|
||||||
|
v := m.indexer_id
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// OldIndexerID returns the old "indexer_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) OldIndexerID(ctx context.Context) (v int, err error) {
|
||||||
|
if !m.op.Is(OpUpdateOne) {
|
||||||
|
return v, errors.New("OldIndexerID is only allowed on UpdateOne operations")
|
||||||
|
}
|
||||||
|
if m.id == nil || m.oldValue == nil {
|
||||||
|
return v, errors.New("OldIndexerID requires an ID field in the mutation")
|
||||||
|
}
|
||||||
|
oldValue, err := m.oldValue(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return v, fmt.Errorf("querying old value for OldIndexerID: %w", err)
|
||||||
|
}
|
||||||
|
return oldValue.IndexerID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddIndexerID adds i to the "indexer_id" field.
|
||||||
|
func (m *HistoryMutation) AddIndexerID(i int) {
|
||||||
|
if m.addindexer_id != nil {
|
||||||
|
*m.addindexer_id += i
|
||||||
|
} else {
|
||||||
|
m.addindexer_id = &i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddedIndexerID returns the value that was added to the "indexer_id" field in this mutation.
|
||||||
|
func (m *HistoryMutation) AddedIndexerID() (r int, exists bool) {
|
||||||
|
v := m.addindexer_id
|
||||||
|
if v == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return *v, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClearIndexerID clears the value of the "indexer_id" field.
|
||||||
|
func (m *HistoryMutation) ClearIndexerID() {
|
||||||
|
m.indexer_id = nil
|
||||||
|
m.addindexer_id = nil
|
||||||
|
m.clearedFields[history.FieldIndexerID] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IndexerIDCleared returns if the "indexer_id" field was cleared in this mutation.
|
||||||
|
func (m *HistoryMutation) IndexerIDCleared() bool {
|
||||||
|
_, ok := m.clearedFields[history.FieldIndexerID]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetIndexerID resets all changes to the "indexer_id" field.
|
||||||
|
func (m *HistoryMutation) ResetIndexerID() {
|
||||||
|
m.indexer_id = nil
|
||||||
|
m.addindexer_id = nil
|
||||||
|
delete(m.clearedFields, history.FieldIndexerID)
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -2304,7 +2376,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, 9)
|
fields := make([]string, 0, 10)
|
||||||
if m.media_id != nil {
|
if m.media_id != nil {
|
||||||
fields = append(fields, history.FieldMediaID)
|
fields = append(fields, history.FieldMediaID)
|
||||||
}
|
}
|
||||||
@@ -2326,6 +2398,9 @@ func (m *HistoryMutation) Fields() []string {
|
|||||||
if m.download_client_id != nil {
|
if m.download_client_id != nil {
|
||||||
fields = append(fields, history.FieldDownloadClientID)
|
fields = append(fields, history.FieldDownloadClientID)
|
||||||
}
|
}
|
||||||
|
if m.indexer_id != nil {
|
||||||
|
fields = append(fields, history.FieldIndexerID)
|
||||||
|
}
|
||||||
if m.status != nil {
|
if m.status != nil {
|
||||||
fields = append(fields, history.FieldStatus)
|
fields = append(fields, history.FieldStatus)
|
||||||
}
|
}
|
||||||
@@ -2354,6 +2429,8 @@ func (m *HistoryMutation) Field(name string) (ent.Value, bool) {
|
|||||||
return m.Size()
|
return m.Size()
|
||||||
case history.FieldDownloadClientID:
|
case history.FieldDownloadClientID:
|
||||||
return m.DownloadClientID()
|
return m.DownloadClientID()
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
return m.IndexerID()
|
||||||
case history.FieldStatus:
|
case history.FieldStatus:
|
||||||
return m.Status()
|
return m.Status()
|
||||||
case history.FieldSaved:
|
case history.FieldSaved:
|
||||||
@@ -2381,6 +2458,8 @@ func (m *HistoryMutation) OldField(ctx context.Context, name string) (ent.Value,
|
|||||||
return m.OldSize(ctx)
|
return m.OldSize(ctx)
|
||||||
case history.FieldDownloadClientID:
|
case history.FieldDownloadClientID:
|
||||||
return m.OldDownloadClientID(ctx)
|
return m.OldDownloadClientID(ctx)
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
return m.OldIndexerID(ctx)
|
||||||
case history.FieldStatus:
|
case history.FieldStatus:
|
||||||
return m.OldStatus(ctx)
|
return m.OldStatus(ctx)
|
||||||
case history.FieldSaved:
|
case history.FieldSaved:
|
||||||
@@ -2443,6 +2522,13 @@ func (m *HistoryMutation) SetField(name string, value ent.Value) error {
|
|||||||
}
|
}
|
||||||
m.SetDownloadClientID(v)
|
m.SetDownloadClientID(v)
|
||||||
return nil
|
return nil
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
v, ok := value.(int)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.SetIndexerID(v)
|
||||||
|
return nil
|
||||||
case history.FieldStatus:
|
case history.FieldStatus:
|
||||||
v, ok := value.(history.Status)
|
v, ok := value.(history.Status)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -2477,6 +2563,9 @@ func (m *HistoryMutation) AddedFields() []string {
|
|||||||
if m.adddownload_client_id != nil {
|
if m.adddownload_client_id != nil {
|
||||||
fields = append(fields, history.FieldDownloadClientID)
|
fields = append(fields, history.FieldDownloadClientID)
|
||||||
}
|
}
|
||||||
|
if m.addindexer_id != nil {
|
||||||
|
fields = append(fields, history.FieldIndexerID)
|
||||||
|
}
|
||||||
return fields
|
return fields
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2493,6 +2582,8 @@ func (m *HistoryMutation) AddedField(name string) (ent.Value, bool) {
|
|||||||
return m.AddedSize()
|
return m.AddedSize()
|
||||||
case history.FieldDownloadClientID:
|
case history.FieldDownloadClientID:
|
||||||
return m.AddedDownloadClientID()
|
return m.AddedDownloadClientID()
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
return m.AddedIndexerID()
|
||||||
}
|
}
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -2530,6 +2621,13 @@ func (m *HistoryMutation) AddField(name string, value ent.Value) error {
|
|||||||
}
|
}
|
||||||
m.AddDownloadClientID(v)
|
m.AddDownloadClientID(v)
|
||||||
return nil
|
return nil
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
v, ok := value.(int)
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||||
|
}
|
||||||
|
m.AddIndexerID(v)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return fmt.Errorf("unknown History numeric field %s", name)
|
return fmt.Errorf("unknown History numeric field %s", name)
|
||||||
}
|
}
|
||||||
@@ -2544,6 +2642,9 @@ func (m *HistoryMutation) ClearedFields() []string {
|
|||||||
if m.FieldCleared(history.FieldDownloadClientID) {
|
if m.FieldCleared(history.FieldDownloadClientID) {
|
||||||
fields = append(fields, history.FieldDownloadClientID)
|
fields = append(fields, history.FieldDownloadClientID)
|
||||||
}
|
}
|
||||||
|
if m.FieldCleared(history.FieldIndexerID) {
|
||||||
|
fields = append(fields, history.FieldIndexerID)
|
||||||
|
}
|
||||||
if m.FieldCleared(history.FieldSaved) {
|
if m.FieldCleared(history.FieldSaved) {
|
||||||
fields = append(fields, history.FieldSaved)
|
fields = append(fields, history.FieldSaved)
|
||||||
}
|
}
|
||||||
@@ -2567,6 +2668,9 @@ func (m *HistoryMutation) ClearField(name string) error {
|
|||||||
case history.FieldDownloadClientID:
|
case history.FieldDownloadClientID:
|
||||||
m.ClearDownloadClientID()
|
m.ClearDownloadClientID()
|
||||||
return nil
|
return nil
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
m.ClearIndexerID()
|
||||||
|
return nil
|
||||||
case history.FieldSaved:
|
case history.FieldSaved:
|
||||||
m.ClearSaved()
|
m.ClearSaved()
|
||||||
return nil
|
return nil
|
||||||
@@ -2599,6 +2703,9 @@ func (m *HistoryMutation) ResetField(name string) error {
|
|||||||
case history.FieldDownloadClientID:
|
case history.FieldDownloadClientID:
|
||||||
m.ResetDownloadClientID()
|
m.ResetDownloadClientID()
|
||||||
return nil
|
return nil
|
||||||
|
case history.FieldIndexerID:
|
||||||
|
m.ResetIndexerID()
|
||||||
|
return nil
|
||||||
case history.FieldStatus:
|
case history.FieldStatus:
|
||||||
m.ResetStatus()
|
m.ResetStatus()
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func (History) Fields() []ent.Field {
|
|||||||
field.String("target_dir"),
|
field.String("target_dir"),
|
||||||
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.Enum("status").Values("running", "success", "fail", "uploading"),
|
field.Enum("status").Values("running", "success", "fail", "uploading"),
|
||||||
field.String("saved").Optional(),
|
field.String("saved").Optional(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"polaris/db"
|
||||||
"polaris/log"
|
"polaris/log"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@@ -71,17 +72,22 @@ func (i *Item) GetAttr(key string) string {
|
|||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
func (r *Response) ToResults() []Result {
|
func (r *Response) ToResults(indexer *db.TorznabInfo) []Result {
|
||||||
var res []Result
|
var res []Result
|
||||||
for _, item := range r.Channel.Item {
|
for _, item := range r.Channel.Item {
|
||||||
r := Result{
|
r := Result{
|
||||||
Name: item.Title,
|
Name: item.Title,
|
||||||
Link: item.Link,
|
Link: item.Link,
|
||||||
Size: mustAtoI(item.Size),
|
Size: mustAtoI(item.Size),
|
||||||
Seeders: mustAtoI(item.GetAttr("seeders")),
|
Seeders: mustAtoI(item.GetAttr("seeders")),
|
||||||
Peers: mustAtoI(item.GetAttr("peers")),
|
Peers: mustAtoI(item.GetAttr("peers")),
|
||||||
Category: mustAtoI(item.GetAttr("category")),
|
Category: mustAtoI(item.GetAttr("category")),
|
||||||
Source: r.Channel.Title,
|
DownloadVolumeFactor: tryParseFloat(item.GetAttr("downloadvolumefactor")),
|
||||||
|
UploadVolumeFactor: tryParseFloat(item.GetAttr("uploadvolumefactor")),
|
||||||
|
Source: indexer.Name,
|
||||||
|
IndexerId: indexer.ID,
|
||||||
|
Priority: indexer.Priority,
|
||||||
|
IsPrivate: item.Type == "private",
|
||||||
}
|
}
|
||||||
res = append(res, r)
|
res = append(res, r)
|
||||||
}
|
}
|
||||||
@@ -96,11 +102,21 @@ func mustAtoI(key string) int {
|
|||||||
}
|
}
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
func Search(torznabUrl, api, keyWord string) ([]Result, error) {
|
|
||||||
|
func tryParseFloat(s string) float32 {
|
||||||
|
r, err := strconv.ParseFloat(s, 32)
|
||||||
|
if err != nil {
|
||||||
|
log.Warnf("parse float error: %v", err)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return float32(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Search(indexer *db.TorznabInfo, api, keyWord string) ([]Result, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.TODO(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, torznabUrl, nil)
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, indexer.URL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "new request")
|
return nil, errors.Wrap(err, "new request")
|
||||||
}
|
}
|
||||||
@@ -124,15 +140,20 @@ func Search(torznabUrl, api, keyWord string) ([]Result, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "json unmarshal")
|
return nil, errors.Wrap(err, "json unmarshal")
|
||||||
}
|
}
|
||||||
return res.ToResults(), nil
|
return res.ToResults(indexer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Name string
|
Name string `json:"name"`
|
||||||
Link string
|
Link string `json:"link"`
|
||||||
Size int
|
Size int `json:"size"`
|
||||||
Seeders int
|
Seeders int `json:"seeders"`
|
||||||
Peers int
|
Peers int `json:"peers"`
|
||||||
Category int
|
Category int `json:"category"`
|
||||||
Source string
|
Source string `json:"source"`
|
||||||
|
DownloadVolumeFactor float32 `json:"download_volume_factor"`
|
||||||
|
UploadVolumeFactor float32 `json:"upload_volume_factor"`
|
||||||
|
IndexerId int `json:"indexer_id"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
IsPrivate bool `json:"is_private"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ func SearchEpisode(db1 *db.Client, seriesId, seasonNum, episodeNum int, checkRes
|
|||||||
if len(filtered) == 0 {
|
if len(filtered) == 0 {
|
||||||
return nil, errors.New("no resource found")
|
return nil, errors.New("no resource found")
|
||||||
}
|
}
|
||||||
|
filtered = dedup(filtered)
|
||||||
return filtered, nil
|
return filtered, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -117,6 +117,7 @@ func SearchMovie(db1 *db.Client, movieId int, checkResolution bool) ([]torznab.R
|
|||||||
if len(filtered) == 0 {
|
if len(filtered) == 0 {
|
||||||
return nil, errors.New("no resource found")
|
return nil, errors.New("no resource found")
|
||||||
}
|
}
|
||||||
|
filtered = dedup(filtered)
|
||||||
|
|
||||||
return filtered, nil
|
return filtered, nil
|
||||||
|
|
||||||
@@ -134,7 +135,7 @@ func searchWithTorznab(db *db.Client, q string) []torznab.Result {
|
|||||||
go func() {
|
go func() {
|
||||||
log.Debugf("search torznab %v with %v", tor.Name, q)
|
log.Debugf("search torznab %v with %v", tor.Name, q)
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
resp, err := torznab.Search(tor.URL, tor.ApiKey, q)
|
resp, err := torznab.Search(tor, tor.ApiKey, q)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("search %s error: %v", tor.Name, err)
|
log.Errorf("search %s error: %v", tor.Name, err)
|
||||||
return
|
return
|
||||||
@@ -152,11 +153,54 @@ func searchWithTorznab(db *db.Client, q string) []torznab.Result {
|
|||||||
res = append(res, result...)
|
res = append(res, result...)
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(res, func(i, j int) bool {
|
//res = dedup(res)
|
||||||
|
|
||||||
|
sort.SliceStable(res, func(i, j int) bool { //先按做种人数排序
|
||||||
var s1 = res[i]
|
var s1 = res[i]
|
||||||
var s2 = res[j]
|
var s2 = res[j]
|
||||||
return s1.Seeders > s2.Seeders
|
return s1.Seeders > s2.Seeders
|
||||||
})
|
})
|
||||||
|
|
||||||
|
sort.SliceStable(res, func(i, j int) bool { //再按优先级排序,优先级高的种子排前面
|
||||||
|
var s1 = res[i]
|
||||||
|
var s2 = res[j]
|
||||||
|
return s1.Priority > s2.Priority
|
||||||
|
})
|
||||||
|
|
||||||
|
//pt资源中,同一indexer内部,优先下载free的资源
|
||||||
|
sort.SliceStable(res, func(i, j int) bool {
|
||||||
|
var s1 = res[i]
|
||||||
|
var s2 = res[j]
|
||||||
|
if s1.IndexerId == s2.IndexerId && s1.IsPrivate {
|
||||||
|
return s1.DownloadVolumeFactor < s2.DownloadVolumeFactor
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
//同一indexer内部,如果下载消耗一样,则优先下载上传奖励较多的
|
||||||
|
sort.SliceStable(res, func(i, j int) bool {
|
||||||
|
var s1 = res[i]
|
||||||
|
var s2 = res[j]
|
||||||
|
if s1.IndexerId == s2.IndexerId && s1.IsPrivate && s1.DownloadVolumeFactor == s2.DownloadVolumeFactor{
|
||||||
|
return s1.UploadVolumeFactor > s2.UploadVolumeFactor
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func dedup(list []torznab.Result) []torznab.Result {
|
||||||
|
var res = make([]torznab.Result, 0, len(list))
|
||||||
|
seen := make(map[string]bool, 0)
|
||||||
|
for _, r := range list {
|
||||||
|
key := fmt.Sprintf("%s%s%d%d", r.Name, r.Source, r.Seeders,r.Peers)
|
||||||
|
if seen[key] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
seen[key] = true
|
||||||
|
res = append(res, r)
|
||||||
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
@@ -62,6 +62,7 @@ func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum in
|
|||||||
Size: r1.Size,
|
Size: r1.Size,
|
||||||
Saved: torrent.Save(),
|
Saved: torrent.Save(),
|
||||||
DownloadClientID: dlClient.ID,
|
DownloadClientID: dlClient.ID,
|
||||||
|
IndexerID: r1.IndexerId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "save record")
|
return nil, errors.Wrap(err, "save record")
|
||||||
@@ -110,6 +111,7 @@ func (s *Server) downloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum,
|
|||||||
Size: r1.Size,
|
Size: r1.Size,
|
||||||
Saved: torrent.Save(),
|
Saved: torrent.Save(),
|
||||||
DownloadClientID: dlc.ID,
|
DownloadClientID: dlc.ID,
|
||||||
|
IndexerID: r1.IndexerId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "save record")
|
return nil, errors.Wrap(err, "save record")
|
||||||
@@ -165,7 +167,7 @@ func (s *Server) SearchAvailableTorrents(c *gin.Context) (interface{}, error) {
|
|||||||
res, err = core.SearchEpisode(s.db, in.ID, in.Season, in.Episode, false)
|
res, err = core.SearchEpisode(s.db, in.ID, in.Season, in.Episode, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "no resource found" {
|
if err.Error() == "no resource found" {
|
||||||
return []TorznabSearchResult{}, nil
|
return gin.H{}, nil
|
||||||
}
|
}
|
||||||
return nil, errors.Wrap(err, "search episode")
|
return nil, errors.Wrap(err, "search episode")
|
||||||
}
|
}
|
||||||
@@ -176,22 +178,12 @@ func (s *Server) SearchAvailableTorrents(c *gin.Context) (interface{}, error) {
|
|||||||
res, err = core.SearchMovie(s.db, in.ID, false)
|
res, err = core.SearchMovie(s.db, in.ID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() == "no resource found" {
|
if err.Error() == "no resource found" {
|
||||||
return []TorznabSearchResult{}, nil
|
return gin.H{}, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var searchResults []TorznabSearchResult
|
return res, nil
|
||||||
for _, r := range res {
|
|
||||||
searchResults = append(searchResults, TorznabSearchResult{
|
|
||||||
Name: r.Name,
|
|
||||||
Size: r.Size,
|
|
||||||
Seeders: r.Seeders,
|
|
||||||
Peers: r.Peers,
|
|
||||||
Link: r.Link,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return searchResults, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) SearchTvAndDownload(c *gin.Context) (interface{}, error) {
|
func (s *Server) SearchTvAndDownload(c *gin.Context) (interface{}, error) {
|
||||||
@@ -223,19 +215,11 @@ func (s *Server) SearchTvAndDownload(c *gin.Context) (interface{}, error) {
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type TorznabSearchResult struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Size int `json:"size"`
|
|
||||||
Link string `json:"link"`
|
|
||||||
Seeders int `json:"seeders"`
|
|
||||||
Peers int `json:"peers"`
|
|
||||||
Source string `json:"source"`
|
|
||||||
}
|
|
||||||
type downloadTorrentIn struct {
|
type downloadTorrentIn struct {
|
||||||
MediaID int `json:"id" binding:"required"`
|
MediaID int `json:"id" binding:"required"`
|
||||||
Season int `json:"season"`
|
Season int `json:"season"`
|
||||||
Episode int `json:"episode"`
|
Episode int `json:"episode"`
|
||||||
TorznabSearchResult
|
torznab.Result
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
||||||
@@ -263,7 +247,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
|||||||
if name == "" {
|
if name == "" {
|
||||||
name = fmt.Sprintf("%v S%02dE%02d", m.OriginalName, in.Season, in.Episode)
|
name = fmt.Sprintf("%v S%02dE%02d", m.OriginalName, in.Season, in.Episode)
|
||||||
}
|
}
|
||||||
res := torznab.Result{Name: name, Link: in.Link, Size: in.Size}
|
res := torznab.Result{Name: name, Link: in.Link, Size: in.Size, IndexerId: in.IndexerId}
|
||||||
return s.downloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode)
|
return s.downloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode)
|
||||||
} else {
|
} else {
|
||||||
//movie
|
//movie
|
||||||
@@ -292,6 +276,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
|||||||
Size: in.Size,
|
Size: in.Size,
|
||||||
Saved: torrent.Save(),
|
Saved: torrent.Save(),
|
||||||
DownloadClientID: dlc.ID,
|
DownloadClientID: dlc.ID,
|
||||||
|
IndexerID: in.IndexerId,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("save history error: %v", err)
|
log.Errorf("save history error: %v", err)
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class SeriesDetails {
|
|||||||
mediaType = json["media_type"];
|
mediaType = json["media_type"];
|
||||||
storage = Storage.fromJson(json["storage"]);
|
storage = Storage.fromJson(json["storage"]);
|
||||||
targetDir = json["target_dir"];
|
targetDir = json["target_dir"];
|
||||||
downloadHistoryEpisodes = json["download_history_episodes"]??false;
|
downloadHistoryEpisodes = json["download_history_episodes"] ?? false;
|
||||||
if (json['episodes'] != null) {
|
if (json['episodes'] != null) {
|
||||||
episodes = <Episodes>[];
|
episodes = <Episodes>[];
|
||||||
json['episodes'].forEach((v) {
|
json['episodes'].forEach((v) {
|
||||||
@@ -195,13 +195,27 @@ class MediaTorrentResource extends AutoDisposeFamilyAsyncNotifier<
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TorrentResource {
|
class TorrentResource {
|
||||||
TorrentResource({this.name, this.size, this.seeders, this.peers, this.link});
|
TorrentResource(
|
||||||
|
{this.name,
|
||||||
|
this.size,
|
||||||
|
this.seeders,
|
||||||
|
this.peers,
|
||||||
|
this.link,
|
||||||
|
this.source,
|
||||||
|
this.indexerId,
|
||||||
|
this.downloadFactor,
|
||||||
|
this.uploadFactor, this.isPrivate});
|
||||||
|
|
||||||
String? name;
|
String? name;
|
||||||
int? size;
|
int? size;
|
||||||
int? seeders;
|
int? seeders;
|
||||||
int? peers;
|
int? peers;
|
||||||
String? link;
|
String? link;
|
||||||
|
String? source;
|
||||||
|
int? indexerId;
|
||||||
|
double? downloadFactor;
|
||||||
|
double? uploadFactor;
|
||||||
|
bool? isPrivate;
|
||||||
|
|
||||||
factory TorrentResource.fromJson(Map<String, dynamic> json) {
|
factory TorrentResource.fromJson(Map<String, dynamic> json) {
|
||||||
return TorrentResource(
|
return TorrentResource(
|
||||||
@@ -209,13 +223,20 @@ class TorrentResource {
|
|||||||
size: json["size"],
|
size: json["size"],
|
||||||
seeders: json["seeders"],
|
seeders: json["seeders"],
|
||||||
peers: json["peers"],
|
peers: json["peers"],
|
||||||
link: json["link"]);
|
link: json["link"],
|
||||||
|
source: json["source"],
|
||||||
|
indexerId: json["indexer_id"],
|
||||||
|
isPrivate: json["is_private"]??false,
|
||||||
|
downloadFactor: json["download_volume_factor"],
|
||||||
|
uploadFactor: json["upload_volume_factor"]);
|
||||||
}
|
}
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final Map<String, dynamic> data = <String, dynamic>{};
|
final Map<String, dynamic> data = <String, dynamic>{};
|
||||||
data['name'] = name;
|
data['name'] = name;
|
||||||
data['size'] = size;
|
data['size'] = size;
|
||||||
data["link"] = link;
|
data["link"] = link;
|
||||||
|
data["indexer_id"] = indexerId;
|
||||||
|
data["source"] = source;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
|||||||
.read(mediaDetailsProvider(widget.seriesId)
|
.read(mediaDetailsProvider(widget.seriesId)
|
||||||
.notifier)
|
.notifier)
|
||||||
.searchAndDownload(widget.seriesId,
|
.searchAndDownload(widget.seriesId,
|
||||||
ep.seasonNumber!, ep.episodeNumber!).then((v) => showSnakeBar("开始下载: $v"));
|
ep.seasonNumber!, ep.episodeNumber!)
|
||||||
|
.then((v) => showSnakeBar("开始下载: $v"));
|
||||||
showLoadingWithFuture(f);
|
showLoadingWithFuture(f);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.download)),
|
icon: const Icon(Icons.download)),
|
||||||
@@ -118,7 +119,8 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
|||||||
final f = ref
|
final f = ref
|
||||||
.read(mediaDetailsProvider(widget.seriesId)
|
.read(mediaDetailsProvider(widget.seriesId)
|
||||||
.notifier)
|
.notifier)
|
||||||
.searchAndDownload(widget.seriesId, k, 0).then((v) => showSnakeBar("开始下载: $v"));
|
.searchAndDownload(widget.seriesId, k, 0)
|
||||||
|
.then((v) => showSnakeBar("开始下载: $v"));
|
||||||
showLoadingWithFuture(f);
|
showLoadingWithFuture(f);
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.download)),
|
icon: const Icon(Icons.download)),
|
||||||
@@ -165,47 +167,71 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
|||||||
//title: Text("资源"),
|
//title: Text("资源"),
|
||||||
content: SelectionArea(
|
content: SelectionArea(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: MediaQuery.of(context).size.width*0.7,
|
width: MediaQuery.of(context).size.width * 0.7,
|
||||||
height: MediaQuery.of(context).size.height*0.6,
|
height: MediaQuery.of(context).size.height * 0.6,
|
||||||
child: torrents.when(
|
child: torrents.when(
|
||||||
data: (v) {
|
data: (v) {
|
||||||
|
bool hasPrivate = false;
|
||||||
|
for (final item in v) {
|
||||||
|
if (item.isPrivate == true) {
|
||||||
|
hasPrivate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
final columns = [
|
||||||
|
const DataColumn(label: Text("名称")),
|
||||||
|
const DataColumn(label: Text("大小")),
|
||||||
|
const DataColumn(label: Text("S/P")),
|
||||||
|
const DataColumn(label: Text("来源")),
|
||||||
|
];
|
||||||
|
if (hasPrivate) {
|
||||||
|
columns.add(const DataColumn(label: Text("消耗")));
|
||||||
|
}
|
||||||
|
columns.add(const DataColumn(label: Text("下载")));
|
||||||
|
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: DataTable(
|
child: DataTable(
|
||||||
dataTextStyle:
|
dataTextStyle: const TextStyle(fontSize: 12),
|
||||||
const TextStyle(fontSize: 12),
|
columns: columns,
|
||||||
columns: const [
|
|
||||||
DataColumn(label: Text("名称")),
|
|
||||||
DataColumn(label: Text("大小")),
|
|
||||||
DataColumn(label: Text("seeders")),
|
|
||||||
DataColumn(label: Text("peers")),
|
|
||||||
DataColumn(label: Text("操作"))
|
|
||||||
],
|
|
||||||
rows: List.generate(v.length, (i) {
|
rows: List.generate(v.length, (i) {
|
||||||
final torrent = v[i];
|
final torrent = v[i];
|
||||||
return DataRow(cells: [
|
final rows = [
|
||||||
DataCell(Text("${torrent.name}")),
|
DataCell(Text("${torrent.name}")),
|
||||||
DataCell(Text(
|
DataCell(Text(
|
||||||
"${torrent.size?.readableFileSize()}")),
|
"${torrent.size?.readableFileSize()}")),
|
||||||
DataCell(Text("${torrent.seeders}")),
|
DataCell(Text(
|
||||||
DataCell(Text("${torrent.peers}")),
|
"${torrent.seeders}/${torrent.peers}")),
|
||||||
DataCell(IconButton(
|
DataCell(Text(torrent.source ?? "-")),
|
||||||
icon: const Icon(Icons.download),
|
];
|
||||||
onPressed: () async {
|
if (hasPrivate) {
|
||||||
var f = ref
|
rows.add(DataCell(Text(torrent.isPrivate == true
|
||||||
.read(mediaTorrentsDataProvider((
|
? "${torrent.downloadFactor}dl/${torrent.uploadFactor}up"
|
||||||
mediaId: id,
|
: "-")));
|
||||||
seasonNumber: season,
|
}
|
||||||
episodeNumber: episode
|
|
||||||
)).notifier)
|
rows.add(DataCell(IconButton(
|
||||||
.download(torrent).then((v) => showSnakeBar("开始下载:${torrent.name}"));
|
icon: const Icon(Icons.download),
|
||||||
showLoadingWithFuture(f);
|
onPressed: () async {
|
||||||
},
|
var f = ref
|
||||||
))
|
.read(mediaTorrentsDataProvider((
|
||||||
]);
|
mediaId: id,
|
||||||
|
seasonNumber: season,
|
||||||
|
episodeNumber: episode
|
||||||
|
)).notifier)
|
||||||
|
.download(torrent)
|
||||||
|
.then((v) =>
|
||||||
|
showSnakeBar("开始下载:${torrent.name}"));
|
||||||
|
showLoadingWithFuture(f);
|
||||||
|
},
|
||||||
|
)));
|
||||||
|
return DataRow(cells: rows);
|
||||||
})));
|
})));
|
||||||
},
|
},
|
||||||
error: (err, trace) {
|
error: (err, trace) {
|
||||||
return Text("$err");
|
return "$err".contains("no resource found")
|
||||||
|
? const Center(
|
||||||
|
child: Text("没有资源"),
|
||||||
|
)
|
||||||
|
: Text("$err");
|
||||||
},
|
},
|
||||||
loading: () => const MyProgressIndicator()),
|
loading: () => const MyProgressIndicator()),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user