mirror of
https://github.com/simon-ding/polaris.git
synced 2026-02-06 15:10:49 +08:00
feat: improve support for pt
This commit is contained in:
@@ -31,6 +31,8 @@ type History struct {
|
||||
Size int `json:"size,omitempty"`
|
||||
// DownloadClientID holds the value of the "download_client_id" field.
|
||||
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 history.Status `json:"status,omitempty"`
|
||||
// Saved holds the value of the "saved" field.
|
||||
@@ -43,7 +45,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, history.FieldDownloadClientID:
|
||||
case history.FieldID, history.FieldMediaID, history.FieldEpisodeID, history.FieldSize, history.FieldDownloadClientID, history.FieldIndexerID:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case history.FieldSourceTitle, history.FieldTargetDir, history.FieldStatus, history.FieldSaved:
|
||||
values[i] = new(sql.NullString)
|
||||
@@ -112,6 +114,12 @@ func (h *History) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
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:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
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(fmt.Sprintf("%v", h.DownloadClientID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("indexer_id=")
|
||||
builder.WriteString(fmt.Sprintf("%v", h.IndexerID))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("status=")
|
||||
builder.WriteString(fmt.Sprintf("%v", h.Status))
|
||||
builder.WriteString(", ")
|
||||
|
||||
@@ -27,6 +27,8 @@ const (
|
||||
FieldSize = "size"
|
||||
// FieldDownloadClientID holds the string denoting the download_client_id field in the database.
|
||||
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 = "status"
|
||||
// FieldSaved holds the string denoting the saved field in the database.
|
||||
@@ -45,6 +47,7 @@ var Columns = []string{
|
||||
FieldTargetDir,
|
||||
FieldSize,
|
||||
FieldDownloadClientID,
|
||||
FieldIndexerID,
|
||||
FieldStatus,
|
||||
FieldSaved,
|
||||
}
|
||||
@@ -132,6 +135,11 @@ func ByDownloadClientID(opts ...sql.OrderTermOption) OrderOption {
|
||||
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.
|
||||
func ByStatus(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldStatus, opts...).ToFunc()
|
||||
|
||||
@@ -89,6 +89,11 @@ func DownloadClientID(v int) predicate.History {
|
||||
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.
|
||||
func Saved(v string) predicate.History {
|
||||
return predicate.History(sql.FieldEQ(FieldSaved, v))
|
||||
@@ -444,6 +449,56 @@ func DownloadClientIDNotNil() predicate.History {
|
||||
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.
|
||||
func StatusEQ(v Status) predicate.History {
|
||||
return predicate.History(sql.FieldEQ(FieldStatus, v))
|
||||
|
||||
@@ -86,6 +86,20 @@ func (hc *HistoryCreate) SetNillableDownloadClientID(i *int) *HistoryCreate {
|
||||
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.
|
||||
func (hc *HistoryCreate) SetStatus(h history.Status) *HistoryCreate {
|
||||
hc.mutation.SetStatus(h)
|
||||
@@ -226,6 +240,10 @@ func (hc *HistoryCreate) createSpec() (*History, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(history.FieldDownloadClientID, field.TypeInt, 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 {
|
||||
_spec.SetField(history.FieldStatus, field.TypeEnum, value)
|
||||
_node.Status = value
|
||||
|
||||
@@ -166,6 +166,33 @@ func (hu *HistoryUpdate) ClearDownloadClientID() *HistoryUpdate {
|
||||
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.
|
||||
func (hu *HistoryUpdate) SetStatus(h history.Status) *HistoryUpdate {
|
||||
hu.mutation.SetStatus(h)
|
||||
@@ -293,6 +320,15 @@ func (hu *HistoryUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if hu.mutation.DownloadClientIDCleared() {
|
||||
_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 {
|
||||
_spec.SetField(history.FieldStatus, field.TypeEnum, value)
|
||||
}
|
||||
@@ -460,6 +496,33 @@ func (huo *HistoryUpdateOne) ClearDownloadClientID() *HistoryUpdateOne {
|
||||
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.
|
||||
func (huo *HistoryUpdateOne) SetStatus(h history.Status) *HistoryUpdateOne {
|
||||
huo.mutation.SetStatus(h)
|
||||
@@ -617,6 +680,15 @@ func (huo *HistoryUpdateOne) sqlSave(ctx context.Context) (_node *History, err e
|
||||
if huo.mutation.DownloadClientIDCleared() {
|
||||
_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 {
|
||||
_spec.SetField(history.FieldStatus, field.TypeEnum, value)
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ var (
|
||||
{Name: "target_dir", Type: field.TypeString},
|
||||
{Name: "size", Type: field.TypeInt, Default: 0},
|
||||
{Name: "download_client_id", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "indexer_id", Type: field.TypeInt, Nullable: true},
|
||||
{Name: "status", Type: field.TypeEnum, Enums: []string{"running", "success", "fail", "uploading"}},
|
||||
{Name: "saved", Type: field.TypeString, Nullable: true},
|
||||
}
|
||||
|
||||
109
ent/mutation.go
109
ent/mutation.go
@@ -1719,6 +1719,8 @@ type HistoryMutation struct {
|
||||
addsize *int
|
||||
download_client_id *int
|
||||
adddownload_client_id *int
|
||||
indexer_id *int
|
||||
addindexer_id *int
|
||||
status *history.Status
|
||||
saved *string
|
||||
clearedFields map[string]struct{}
|
||||
@@ -2185,6 +2187,76 @@ func (m *HistoryMutation) ResetDownloadClientID() {
|
||||
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.
|
||||
func (m *HistoryMutation) SetStatus(h history.Status) {
|
||||
m.status = &h
|
||||
@@ -2304,7 +2376,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, 9)
|
||||
fields := make([]string, 0, 10)
|
||||
if m.media_id != nil {
|
||||
fields = append(fields, history.FieldMediaID)
|
||||
}
|
||||
@@ -2326,6 +2398,9 @@ func (m *HistoryMutation) Fields() []string {
|
||||
if m.download_client_id != nil {
|
||||
fields = append(fields, history.FieldDownloadClientID)
|
||||
}
|
||||
if m.indexer_id != nil {
|
||||
fields = append(fields, history.FieldIndexerID)
|
||||
}
|
||||
if m.status != nil {
|
||||
fields = append(fields, history.FieldStatus)
|
||||
}
|
||||
@@ -2354,6 +2429,8 @@ func (m *HistoryMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Size()
|
||||
case history.FieldDownloadClientID:
|
||||
return m.DownloadClientID()
|
||||
case history.FieldIndexerID:
|
||||
return m.IndexerID()
|
||||
case history.FieldStatus:
|
||||
return m.Status()
|
||||
case history.FieldSaved:
|
||||
@@ -2381,6 +2458,8 @@ func (m *HistoryMutation) OldField(ctx context.Context, name string) (ent.Value,
|
||||
return m.OldSize(ctx)
|
||||
case history.FieldDownloadClientID:
|
||||
return m.OldDownloadClientID(ctx)
|
||||
case history.FieldIndexerID:
|
||||
return m.OldIndexerID(ctx)
|
||||
case history.FieldStatus:
|
||||
return m.OldStatus(ctx)
|
||||
case history.FieldSaved:
|
||||
@@ -2443,6 +2522,13 @@ func (m *HistoryMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetDownloadClientID(v)
|
||||
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:
|
||||
v, ok := value.(history.Status)
|
||||
if !ok {
|
||||
@@ -2477,6 +2563,9 @@ func (m *HistoryMutation) AddedFields() []string {
|
||||
if m.adddownload_client_id != nil {
|
||||
fields = append(fields, history.FieldDownloadClientID)
|
||||
}
|
||||
if m.addindexer_id != nil {
|
||||
fields = append(fields, history.FieldIndexerID)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -2493,6 +2582,8 @@ func (m *HistoryMutation) AddedField(name string) (ent.Value, bool) {
|
||||
return m.AddedSize()
|
||||
case history.FieldDownloadClientID:
|
||||
return m.AddedDownloadClientID()
|
||||
case history.FieldIndexerID:
|
||||
return m.AddedIndexerID()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -2530,6 +2621,13 @@ func (m *HistoryMutation) AddField(name string, value ent.Value) error {
|
||||
}
|
||||
m.AddDownloadClientID(v)
|
||||
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)
|
||||
}
|
||||
@@ -2544,6 +2642,9 @@ func (m *HistoryMutation) ClearedFields() []string {
|
||||
if m.FieldCleared(history.FieldDownloadClientID) {
|
||||
fields = append(fields, history.FieldDownloadClientID)
|
||||
}
|
||||
if m.FieldCleared(history.FieldIndexerID) {
|
||||
fields = append(fields, history.FieldIndexerID)
|
||||
}
|
||||
if m.FieldCleared(history.FieldSaved) {
|
||||
fields = append(fields, history.FieldSaved)
|
||||
}
|
||||
@@ -2567,6 +2668,9 @@ func (m *HistoryMutation) ClearField(name string) error {
|
||||
case history.FieldDownloadClientID:
|
||||
m.ClearDownloadClientID()
|
||||
return nil
|
||||
case history.FieldIndexerID:
|
||||
m.ClearIndexerID()
|
||||
return nil
|
||||
case history.FieldSaved:
|
||||
m.ClearSaved()
|
||||
return nil
|
||||
@@ -2599,6 +2703,9 @@ func (m *HistoryMutation) ResetField(name string) error {
|
||||
case history.FieldDownloadClientID:
|
||||
m.ResetDownloadClientID()
|
||||
return nil
|
||||
case history.FieldIndexerID:
|
||||
m.ResetIndexerID()
|
||||
return nil
|
||||
case history.FieldStatus:
|
||||
m.ResetStatus()
|
||||
return nil
|
||||
|
||||
@@ -20,6 +20,7 @@ func (History) Fields() []ent.Field {
|
||||
field.String("target_dir"),
|
||||
field.Int("size").Default(0),
|
||||
field.Int("download_client_id").Optional(),
|
||||
field.Int("indexer_id").Optional(),
|
||||
field.Enum("status").Values("running", "success", "fail", "uploading"),
|
||||
field.String("saved").Optional(),
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"polaris/db"
|
||||
"polaris/log"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -71,17 +72,22 @@ func (i *Item) GetAttr(key string) string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
func (r *Response) ToResults() []Result {
|
||||
func (r *Response) ToResults(indexer *db.TorznabInfo) []Result {
|
||||
var res []Result
|
||||
for _, item := range r.Channel.Item {
|
||||
r := Result{
|
||||
Name: item.Title,
|
||||
Link: item.Link,
|
||||
Size: mustAtoI(item.Size),
|
||||
Seeders: mustAtoI(item.GetAttr("seeders")),
|
||||
Peers: mustAtoI(item.GetAttr("peers")),
|
||||
Category: mustAtoI(item.GetAttr("category")),
|
||||
Source: r.Channel.Title,
|
||||
Name: item.Title,
|
||||
Link: item.Link,
|
||||
Size: mustAtoI(item.Size),
|
||||
Seeders: mustAtoI(item.GetAttr("seeders")),
|
||||
Peers: mustAtoI(item.GetAttr("peers")),
|
||||
Category: mustAtoI(item.GetAttr("category")),
|
||||
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)
|
||||
}
|
||||
@@ -96,11 +102,21 @@ func mustAtoI(key string) int {
|
||||
}
|
||||
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)
|
||||
defer cancel()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, torznabUrl, nil)
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, indexer.URL, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "new request")
|
||||
}
|
||||
@@ -124,15 +140,20 @@ func Search(torznabUrl, api, keyWord string) ([]Result, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "json unmarshal")
|
||||
}
|
||||
return res.ToResults(), nil
|
||||
return res.ToResults(indexer), nil
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
Name string
|
||||
Link string
|
||||
Size int
|
||||
Seeders int
|
||||
Peers int
|
||||
Category int
|
||||
Source string
|
||||
Name string `json:"name"`
|
||||
Link string `json:"link"`
|
||||
Size int `json:"size"`
|
||||
Seeders int `json:"seeders"`
|
||||
Peers int `json:"peers"`
|
||||
Category int `json:"category"`
|
||||
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 {
|
||||
return nil, errors.New("no resource found")
|
||||
}
|
||||
|
||||
filtered = dedup(filtered)
|
||||
return filtered, nil
|
||||
|
||||
}
|
||||
@@ -117,6 +117,7 @@ func SearchMovie(db1 *db.Client, movieId int, checkResolution bool) ([]torznab.R
|
||||
if len(filtered) == 0 {
|
||||
return nil, errors.New("no resource found")
|
||||
}
|
||||
filtered = dedup(filtered)
|
||||
|
||||
return filtered, nil
|
||||
|
||||
@@ -134,7 +135,7 @@ func searchWithTorznab(db *db.Client, q string) []torznab.Result {
|
||||
go func() {
|
||||
log.Debugf("search torznab %v with %v", tor.Name, q)
|
||||
defer wg.Done()
|
||||
resp, err := torznab.Search(tor.URL, tor.ApiKey, q)
|
||||
resp, err := torznab.Search(tor, tor.ApiKey, q)
|
||||
if err != nil {
|
||||
log.Errorf("search %s error: %v", tor.Name, err)
|
||||
return
|
||||
@@ -152,11 +153,54 @@ func searchWithTorznab(db *db.Client, q string) []torznab.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 s2 = res[j]
|
||||
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
|
||||
}
|
||||
@@ -62,6 +62,7 @@ func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum in
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlClient.ID,
|
||||
IndexerID: r1.IndexerId,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "save record")
|
||||
@@ -110,6 +111,7 @@ func (s *Server) downloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum,
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlc.ID,
|
||||
IndexerID: r1.IndexerId,
|
||||
})
|
||||
if err != nil {
|
||||
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)
|
||||
if err != nil {
|
||||
if err.Error() == "no resource found" {
|
||||
return []TorznabSearchResult{}, nil
|
||||
return gin.H{}, nil
|
||||
}
|
||||
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)
|
||||
if err != nil {
|
||||
if err.Error() == "no resource found" {
|
||||
return []TorznabSearchResult{}, nil
|
||||
return gin.H{}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var searchResults []TorznabSearchResult
|
||||
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
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (s *Server) SearchTvAndDownload(c *gin.Context) (interface{}, error) {
|
||||
@@ -223,19 +215,11 @@ func (s *Server) SearchTvAndDownload(c *gin.Context) (interface{}, error) {
|
||||
}, 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 {
|
||||
MediaID int `json:"id" binding:"required"`
|
||||
Season int `json:"season"`
|
||||
Episode int `json:"episode"`
|
||||
TorznabSearchResult
|
||||
torznab.Result
|
||||
}
|
||||
|
||||
func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
||||
@@ -263,7 +247,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
||||
if name == "" {
|
||||
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)
|
||||
} else {
|
||||
//movie
|
||||
@@ -292,6 +276,7 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
||||
Size: in.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlc.ID,
|
||||
IndexerID: in.IndexerId,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("save history error: %v", err)
|
||||
|
||||
@@ -98,7 +98,7 @@ class SeriesDetails {
|
||||
mediaType = json["media_type"];
|
||||
storage = Storage.fromJson(json["storage"]);
|
||||
targetDir = json["target_dir"];
|
||||
downloadHistoryEpisodes = json["download_history_episodes"]??false;
|
||||
downloadHistoryEpisodes = json["download_history_episodes"] ?? false;
|
||||
if (json['episodes'] != null) {
|
||||
episodes = <Episodes>[];
|
||||
json['episodes'].forEach((v) {
|
||||
@@ -195,13 +195,27 @@ class MediaTorrentResource extends AutoDisposeFamilyAsyncNotifier<
|
||||
}
|
||||
|
||||
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;
|
||||
int? size;
|
||||
int? seeders;
|
||||
int? peers;
|
||||
String? link;
|
||||
String? source;
|
||||
int? indexerId;
|
||||
double? downloadFactor;
|
||||
double? uploadFactor;
|
||||
bool? isPrivate;
|
||||
|
||||
factory TorrentResource.fromJson(Map<String, dynamic> json) {
|
||||
return TorrentResource(
|
||||
@@ -209,13 +223,20 @@ class TorrentResource {
|
||||
size: json["size"],
|
||||
seeders: json["seeders"],
|
||||
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() {
|
||||
final Map<String, dynamic> data = <String, dynamic>{};
|
||||
data['name'] = name;
|
||||
data['size'] = size;
|
||||
data["link"] = link;
|
||||
data["indexer_id"] = indexerId;
|
||||
data["source"] = source;
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,8 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
||||
.read(mediaDetailsProvider(widget.seriesId)
|
||||
.notifier)
|
||||
.searchAndDownload(widget.seriesId,
|
||||
ep.seasonNumber!, ep.episodeNumber!).then((v) => showSnakeBar("开始下载: $v"));
|
||||
ep.seasonNumber!, ep.episodeNumber!)
|
||||
.then((v) => showSnakeBar("开始下载: $v"));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
icon: const Icon(Icons.download)),
|
||||
@@ -118,7 +119,8 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
||||
final f = ref
|
||||
.read(mediaDetailsProvider(widget.seriesId)
|
||||
.notifier)
|
||||
.searchAndDownload(widget.seriesId, k, 0).then((v) => showSnakeBar("开始下载: $v"));
|
||||
.searchAndDownload(widget.seriesId, k, 0)
|
||||
.then((v) => showSnakeBar("开始下载: $v"));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
icon: const Icon(Icons.download)),
|
||||
@@ -165,47 +167,71 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
||||
//title: Text("资源"),
|
||||
content: SelectionArea(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width*0.7,
|
||||
height: MediaQuery.of(context).size.height*0.6,
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
height: MediaQuery.of(context).size.height * 0.6,
|
||||
child: torrents.when(
|
||||
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(
|
||||
child: DataTable(
|
||||
dataTextStyle:
|
||||
const TextStyle(fontSize: 12),
|
||||
columns: const [
|
||||
DataColumn(label: Text("名称")),
|
||||
DataColumn(label: Text("大小")),
|
||||
DataColumn(label: Text("seeders")),
|
||||
DataColumn(label: Text("peers")),
|
||||
DataColumn(label: Text("操作"))
|
||||
],
|
||||
dataTextStyle: const TextStyle(fontSize: 12),
|
||||
columns: columns,
|
||||
rows: List.generate(v.length, (i) {
|
||||
final torrent = v[i];
|
||||
return DataRow(cells: [
|
||||
final rows = [
|
||||
DataCell(Text("${torrent.name}")),
|
||||
DataCell(Text(
|
||||
"${torrent.size?.readableFileSize()}")),
|
||||
DataCell(Text("${torrent.seeders}")),
|
||||
DataCell(Text("${torrent.peers}")),
|
||||
DataCell(IconButton(
|
||||
icon: const Icon(Icons.download),
|
||||
onPressed: () async {
|
||||
var f = ref
|
||||
.read(mediaTorrentsDataProvider((
|
||||
mediaId: id,
|
||||
seasonNumber: season,
|
||||
episodeNumber: episode
|
||||
)).notifier)
|
||||
.download(torrent).then((v) => showSnakeBar("开始下载:${torrent.name}"));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
))
|
||||
]);
|
||||
DataCell(Text(
|
||||
"${torrent.seeders}/${torrent.peers}")),
|
||||
DataCell(Text(torrent.source ?? "-")),
|
||||
];
|
||||
if (hasPrivate) {
|
||||
rows.add(DataCell(Text(torrent.isPrivate == true
|
||||
? "${torrent.downloadFactor}dl/${torrent.uploadFactor}up"
|
||||
: "-")));
|
||||
}
|
||||
|
||||
rows.add(DataCell(IconButton(
|
||||
icon: const Icon(Icons.download),
|
||||
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) {
|
||||
return Text("$err");
|
||||
return "$err".contains("no resource found")
|
||||
? const Center(
|
||||
child: Text("没有资源"),
|
||||
)
|
||||
: Text("$err");
|
||||
},
|
||||
loading: () => const MyProgressIndicator()),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user